github.com/eagleql/xray-core@v1.4.4/testing/scenarios/http_test.go (about)

     1  package scenarios
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  	"crypto/rand"
     7  	"io"
     8  	"io/ioutil"
     9  	"net/http"
    10  	"net/url"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/google/go-cmp/cmp"
    15  
    16  	"github.com/eagleql/xray-core/app/proxyman"
    17  	"github.com/eagleql/xray-core/common"
    18  	"github.com/eagleql/xray-core/common/buf"
    19  	"github.com/eagleql/xray-core/common/net"
    20  	"github.com/eagleql/xray-core/common/serial"
    21  	"github.com/eagleql/xray-core/core"
    22  	"github.com/eagleql/xray-core/proxy/freedom"
    23  	v2http "github.com/eagleql/xray-core/proxy/http"
    24  	v2httptest "github.com/eagleql/xray-core/testing/servers/http"
    25  	"github.com/eagleql/xray-core/testing/servers/tcp"
    26  )
    27  
    28  func TestHttpConformance(t *testing.T) {
    29  	httpServerPort := tcp.PickPort()
    30  	httpServer := &v2httptest.Server{
    31  		Port:        httpServerPort,
    32  		PathHandler: make(map[string]http.HandlerFunc),
    33  	}
    34  	_, err := httpServer.Start()
    35  	common.Must(err)
    36  	defer httpServer.Close()
    37  
    38  	serverPort := tcp.PickPort()
    39  	serverConfig := &core.Config{
    40  		Inbound: []*core.InboundHandlerConfig{
    41  			{
    42  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
    43  					PortRange: net.SinglePortRange(serverPort),
    44  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
    45  				}),
    46  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
    47  			},
    48  		},
    49  		Outbound: []*core.OutboundHandlerConfig{
    50  			{
    51  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
    52  			},
    53  		},
    54  	}
    55  
    56  	servers, err := InitializeServerConfigs(serverConfig)
    57  	common.Must(err)
    58  	defer CloseAllServers(servers)
    59  
    60  	{
    61  		transport := &http.Transport{
    62  			Proxy: func(req *http.Request) (*url.URL, error) {
    63  				return url.Parse("http://127.0.0.1:" + serverPort.String())
    64  			},
    65  		}
    66  
    67  		client := &http.Client{
    68  			Transport: transport,
    69  		}
    70  
    71  		resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
    72  		common.Must(err)
    73  		if resp.StatusCode != 200 {
    74  			t.Fatal("status: ", resp.StatusCode)
    75  		}
    76  
    77  		content, err := ioutil.ReadAll(resp.Body)
    78  		common.Must(err)
    79  		if string(content) != "Home" {
    80  			t.Fatal("body: ", string(content))
    81  		}
    82  	}
    83  }
    84  
    85  func TestHttpError(t *testing.T) {
    86  	tcpServer := tcp.Server{
    87  		MsgProcessor: func(msg []byte) []byte {
    88  			return []byte{}
    89  		},
    90  	}
    91  	dest, err := tcpServer.Start()
    92  	common.Must(err)
    93  	defer tcpServer.Close()
    94  
    95  	time.AfterFunc(time.Second*2, func() {
    96  		tcpServer.ShouldClose = true
    97  	})
    98  
    99  	serverPort := tcp.PickPort()
   100  	serverConfig := &core.Config{
   101  		Inbound: []*core.InboundHandlerConfig{
   102  			{
   103  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   104  					PortRange: net.SinglePortRange(serverPort),
   105  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   106  				}),
   107  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
   108  			},
   109  		},
   110  		Outbound: []*core.OutboundHandlerConfig{
   111  			{
   112  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   113  			},
   114  		},
   115  	}
   116  
   117  	servers, err := InitializeServerConfigs(serverConfig)
   118  	common.Must(err)
   119  	defer CloseAllServers(servers)
   120  
   121  	{
   122  		transport := &http.Transport{
   123  			Proxy: func(req *http.Request) (*url.URL, error) {
   124  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   125  			},
   126  		}
   127  
   128  		client := &http.Client{
   129  			Transport: transport,
   130  		}
   131  
   132  		resp, err := client.Get("http://127.0.0.1:" + dest.Port.String())
   133  		common.Must(err)
   134  		if resp.StatusCode != 503 {
   135  			t.Error("status: ", resp.StatusCode)
   136  		}
   137  	}
   138  }
   139  
   140  func TestHTTPConnectMethod(t *testing.T) {
   141  	tcpServer := tcp.Server{
   142  		MsgProcessor: xor,
   143  	}
   144  	dest, err := tcpServer.Start()
   145  	common.Must(err)
   146  	defer tcpServer.Close()
   147  
   148  	serverPort := tcp.PickPort()
   149  	serverConfig := &core.Config{
   150  		Inbound: []*core.InboundHandlerConfig{
   151  			{
   152  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   153  					PortRange: net.SinglePortRange(serverPort),
   154  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   155  				}),
   156  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
   157  			},
   158  		},
   159  		Outbound: []*core.OutboundHandlerConfig{
   160  			{
   161  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   162  			},
   163  		},
   164  	}
   165  
   166  	servers, err := InitializeServerConfigs(serverConfig)
   167  	common.Must(err)
   168  	defer CloseAllServers(servers)
   169  
   170  	{
   171  		transport := &http.Transport{
   172  			Proxy: func(req *http.Request) (*url.URL, error) {
   173  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   174  			},
   175  		}
   176  
   177  		client := &http.Client{
   178  			Transport: transport,
   179  		}
   180  
   181  		payload := make([]byte, 1024*64)
   182  		common.Must2(rand.Read(payload))
   183  
   184  		ctx := context.Background()
   185  		req, err := http.NewRequestWithContext(ctx, "Connect", "http://"+dest.NetAddr()+"/", bytes.NewReader(payload))
   186  		req.Header.Set("X-a", "b")
   187  		req.Header.Set("X-b", "d")
   188  		common.Must(err)
   189  
   190  		resp, err := client.Do(req)
   191  		common.Must(err)
   192  		if resp.StatusCode != 200 {
   193  			t.Fatal("status: ", resp.StatusCode)
   194  		}
   195  
   196  		content := make([]byte, len(payload))
   197  		common.Must2(io.ReadFull(resp.Body, content))
   198  		if r := cmp.Diff(content, xor(payload)); r != "" {
   199  			t.Fatal(r)
   200  		}
   201  	}
   202  }
   203  
   204  func TestHttpPost(t *testing.T) {
   205  	httpServerPort := tcp.PickPort()
   206  	httpServer := &v2httptest.Server{
   207  		Port: httpServerPort,
   208  		PathHandler: map[string]http.HandlerFunc{
   209  			"/testpost": func(w http.ResponseWriter, r *http.Request) {
   210  				payload, err := buf.ReadAllToBytes(r.Body)
   211  				r.Body.Close()
   212  
   213  				if err != nil {
   214  					w.WriteHeader(500)
   215  					w.Write([]byte("Unable to read all payload"))
   216  					return
   217  				}
   218  				payload = xor(payload)
   219  				w.Write(payload)
   220  			},
   221  		},
   222  	}
   223  
   224  	_, err := httpServer.Start()
   225  	common.Must(err)
   226  	defer httpServer.Close()
   227  
   228  	serverPort := tcp.PickPort()
   229  	serverConfig := &core.Config{
   230  		Inbound: []*core.InboundHandlerConfig{
   231  			{
   232  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   233  					PortRange: net.SinglePortRange(serverPort),
   234  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   235  				}),
   236  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
   237  			},
   238  		},
   239  		Outbound: []*core.OutboundHandlerConfig{
   240  			{
   241  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   242  			},
   243  		},
   244  	}
   245  
   246  	servers, err := InitializeServerConfigs(serverConfig)
   247  	common.Must(err)
   248  	defer CloseAllServers(servers)
   249  
   250  	{
   251  		transport := &http.Transport{
   252  			Proxy: func(req *http.Request) (*url.URL, error) {
   253  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   254  			},
   255  		}
   256  
   257  		client := &http.Client{
   258  			Transport: transport,
   259  		}
   260  
   261  		payload := make([]byte, 1024*64)
   262  		common.Must2(rand.Read(payload))
   263  
   264  		resp, err := client.Post("http://127.0.0.1:"+httpServerPort.String()+"/testpost", "application/x-www-form-urlencoded", bytes.NewReader(payload))
   265  		common.Must(err)
   266  		if resp.StatusCode != 200 {
   267  			t.Fatal("status: ", resp.StatusCode)
   268  		}
   269  
   270  		content, err := ioutil.ReadAll(resp.Body)
   271  		common.Must(err)
   272  		if r := cmp.Diff(content, xor(payload)); r != "" {
   273  			t.Fatal(r)
   274  		}
   275  	}
   276  }
   277  
   278  func setProxyBasicAuth(req *http.Request, user, pass string) {
   279  	req.SetBasicAuth(user, pass)
   280  	req.Header.Set("Proxy-Authorization", req.Header.Get("Authorization"))
   281  	req.Header.Del("Authorization")
   282  }
   283  
   284  func TestHttpBasicAuth(t *testing.T) {
   285  	httpServerPort := tcp.PickPort()
   286  	httpServer := &v2httptest.Server{
   287  		Port:        httpServerPort,
   288  		PathHandler: make(map[string]http.HandlerFunc),
   289  	}
   290  	_, err := httpServer.Start()
   291  	common.Must(err)
   292  	defer httpServer.Close()
   293  
   294  	serverPort := tcp.PickPort()
   295  	serverConfig := &core.Config{
   296  		Inbound: []*core.InboundHandlerConfig{
   297  			{
   298  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   299  					PortRange: net.SinglePortRange(serverPort),
   300  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   301  				}),
   302  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{
   303  					Accounts: map[string]string{
   304  						"a": "b",
   305  					},
   306  				}),
   307  			},
   308  		},
   309  		Outbound: []*core.OutboundHandlerConfig{
   310  			{
   311  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   312  			},
   313  		},
   314  	}
   315  
   316  	servers, err := InitializeServerConfigs(serverConfig)
   317  	common.Must(err)
   318  	defer CloseAllServers(servers)
   319  
   320  	{
   321  		transport := &http.Transport{
   322  			Proxy: func(req *http.Request) (*url.URL, error) {
   323  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   324  			},
   325  		}
   326  
   327  		client := &http.Client{
   328  			Transport: transport,
   329  		}
   330  
   331  		{
   332  			resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
   333  			common.Must(err)
   334  			if resp.StatusCode != 407 {
   335  				t.Fatal("status: ", resp.StatusCode)
   336  			}
   337  		}
   338  
   339  		{
   340  			ctx := context.Background()
   341  			req, err := http.NewRequestWithContext(ctx, "GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
   342  			common.Must(err)
   343  
   344  			setProxyBasicAuth(req, "a", "c")
   345  			resp, err := client.Do(req)
   346  			common.Must(err)
   347  			if resp.StatusCode != 407 {
   348  				t.Fatal("status: ", resp.StatusCode)
   349  			}
   350  		}
   351  
   352  		{
   353  			ctx := context.Background()
   354  			req, err := http.NewRequestWithContext(ctx, "GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
   355  			common.Must(err)
   356  
   357  			setProxyBasicAuth(req, "a", "b")
   358  			resp, err := client.Do(req)
   359  			common.Must(err)
   360  			if resp.StatusCode != 200 {
   361  				t.Fatal("status: ", resp.StatusCode)
   362  			}
   363  
   364  			content, err := ioutil.ReadAll(resp.Body)
   365  			common.Must(err)
   366  			if string(content) != "Home" {
   367  				t.Fatal("body: ", string(content))
   368  			}
   369  		}
   370  	}
   371  }