github.com/moqsien/xraycore@v1.8.5/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  	"testing"
    11  	"time"
    12  
    13  	"github.com/google/go-cmp/cmp"
    14  	"github.com/moqsien/xraycore/app/proxyman"
    15  	"github.com/moqsien/xraycore/common"
    16  	"github.com/moqsien/xraycore/common/buf"
    17  	"github.com/moqsien/xraycore/common/net"
    18  	"github.com/moqsien/xraycore/common/serial"
    19  	"github.com/moqsien/xraycore/core"
    20  	"github.com/moqsien/xraycore/proxy/freedom"
    21  	v2http "github.com/moqsien/xraycore/proxy/http"
    22  	v2httptest "github.com/moqsien/xraycore/testing/servers/http"
    23  	"github.com/moqsien/xraycore/testing/servers/tcp"
    24  )
    25  
    26  func TestHttpConformance(t *testing.T) {
    27  	httpServerPort := tcp.PickPort()
    28  	httpServer := &v2httptest.Server{
    29  		Port:        httpServerPort,
    30  		PathHandler: make(map[string]http.HandlerFunc),
    31  	}
    32  	_, err := httpServer.Start()
    33  	common.Must(err)
    34  	defer httpServer.Close()
    35  
    36  	serverPort := tcp.PickPort()
    37  	serverConfig := &core.Config{
    38  		Inbound: []*core.InboundHandlerConfig{
    39  			{
    40  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
    41  					PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
    42  					Listen:   net.NewIPOrDomain(net.LocalHostIP),
    43  				}),
    44  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
    45  			},
    46  		},
    47  		Outbound: []*core.OutboundHandlerConfig{
    48  			{
    49  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
    50  			},
    51  		},
    52  	}
    53  
    54  	servers, err := InitializeServerConfigs(serverConfig)
    55  	common.Must(err)
    56  	defer CloseAllServers(servers)
    57  
    58  	{
    59  		transport := &http.Transport{
    60  			Proxy: func(req *http.Request) (*url.URL, error) {
    61  				return url.Parse("http://127.0.0.1:" + serverPort.String())
    62  			},
    63  		}
    64  
    65  		client := &http.Client{
    66  			Transport: transport,
    67  		}
    68  
    69  		resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
    70  		common.Must(err)
    71  		if resp.StatusCode != 200 {
    72  			t.Fatal("status: ", resp.StatusCode)
    73  		}
    74  
    75  		content, err := io.ReadAll(resp.Body)
    76  		common.Must(err)
    77  		if string(content) != "Home" {
    78  			t.Fatal("body: ", string(content))
    79  		}
    80  	}
    81  }
    82  
    83  func TestHttpError(t *testing.T) {
    84  	tcpServer := tcp.Server{
    85  		MsgProcessor: func(msg []byte) []byte {
    86  			return []byte{}
    87  		},
    88  	}
    89  	dest, err := tcpServer.Start()
    90  	common.Must(err)
    91  	defer tcpServer.Close()
    92  
    93  	time.AfterFunc(time.Second*2, func() {
    94  		tcpServer.ShouldClose = true
    95  	})
    96  
    97  	serverPort := tcp.PickPort()
    98  	serverConfig := &core.Config{
    99  		Inbound: []*core.InboundHandlerConfig{
   100  			{
   101  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   102  					PortList: &net.PortList{Range: []*net.PortRange{net.SinglePortRange(serverPort)}},
   103  					Listen:   net.NewIPOrDomain(net.LocalHostIP),
   104  				}),
   105  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
   106  			},
   107  		},
   108  		Outbound: []*core.OutboundHandlerConfig{
   109  			{
   110  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   111  			},
   112  		},
   113  	}
   114  
   115  	servers, err := InitializeServerConfigs(serverConfig)
   116  	common.Must(err)
   117  	defer CloseAllServers(servers)
   118  
   119  	{
   120  		transport := &http.Transport{
   121  			Proxy: func(req *http.Request) (*url.URL, error) {
   122  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   123  			},
   124  		}
   125  
   126  		client := &http.Client{
   127  			Transport: transport,
   128  		}
   129  
   130  		resp, err := client.Get("http://127.0.0.1:" + dest.Port.String())
   131  		common.Must(err)
   132  		if resp.StatusCode != 503 {
   133  			t.Error("status: ", resp.StatusCode)
   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  }