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

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