github.com/imannamdari/v2ray-core/v5@v5.0.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  
    15  	core "github.com/imannamdari/v2ray-core/v5"
    16  	"github.com/imannamdari/v2ray-core/v5/app/proxyman"
    17  	"github.com/imannamdari/v2ray-core/v5/common"
    18  	"github.com/imannamdari/v2ray-core/v5/common/buf"
    19  	"github.com/imannamdari/v2ray-core/v5/common/net"
    20  	"github.com/imannamdari/v2ray-core/v5/common/serial"
    21  	"github.com/imannamdari/v2ray-core/v5/proxy/freedom"
    22  	v2http "github.com/imannamdari/v2ray-core/v5/proxy/http"
    23  	v2httptest "github.com/imannamdari/v2ray-core/v5/testing/servers/http"
    24  	"github.com/imannamdari/v2ray-core/v5/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  					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  		defer resp.Body.Close()
    73  		if resp.StatusCode != 200 {
    74  			t.Fatal("status: ", resp.StatusCode)
    75  		}
    76  
    77  		content, err := io.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  		defer resp.Body.Close()
   135  		if resp.StatusCode != 503 {
   136  			t.Error("status: ", resp.StatusCode)
   137  		}
   138  	}
   139  }
   140  
   141  func TestHTTPConnectMethod(t *testing.T) {
   142  	tcpServer := tcp.Server{
   143  		MsgProcessor: xor,
   144  	}
   145  	dest, err := tcpServer.Start()
   146  	common.Must(err)
   147  	defer tcpServer.Close()
   148  
   149  	serverPort := tcp.PickPort()
   150  	serverConfig := &core.Config{
   151  		Inbound: []*core.InboundHandlerConfig{
   152  			{
   153  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   154  					PortRange: net.SinglePortRange(serverPort),
   155  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   156  				}),
   157  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
   158  			},
   159  		},
   160  		Outbound: []*core.OutboundHandlerConfig{
   161  			{
   162  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   163  			},
   164  		},
   165  	}
   166  
   167  	servers, err := InitializeServerConfigs(serverConfig)
   168  	common.Must(err)
   169  	defer CloseAllServers(servers)
   170  
   171  	{
   172  		transport := &http.Transport{
   173  			Proxy: func(req *http.Request) (*url.URL, error) {
   174  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   175  			},
   176  		}
   177  
   178  		client := &http.Client{
   179  			Transport: transport,
   180  		}
   181  
   182  		payload := make([]byte, 1024*64)
   183  		common.Must2(rand.Read(payload))
   184  
   185  		ctx := context.Background()
   186  		req, err := http.NewRequestWithContext(ctx, "Connect", "http://"+dest.NetAddr()+"/", bytes.NewReader(payload))
   187  		req.Header.Set("X-a", "b")
   188  		req.Header.Set("X-b", "d")
   189  		common.Must(err)
   190  
   191  		resp, err := client.Do(req)
   192  		common.Must(err)
   193  		defer resp.Body.Close()
   194  		if resp.StatusCode != 200 {
   195  			t.Fatal("status: ", resp.StatusCode)
   196  		}
   197  
   198  		content := make([]byte, len(payload))
   199  		common.Must2(io.ReadFull(resp.Body, content))
   200  		if r := cmp.Diff(content, xor(payload)); r != "" {
   201  			t.Fatal(r)
   202  		}
   203  	}
   204  }
   205  
   206  func TestHttpPost(t *testing.T) {
   207  	httpServerPort := tcp.PickPort()
   208  	httpServer := &v2httptest.Server{
   209  		Port: httpServerPort,
   210  		PathHandler: map[string]http.HandlerFunc{
   211  			"/testpost": func(w http.ResponseWriter, r *http.Request) {
   212  				payload, err := buf.ReadAllToBytes(r.Body)
   213  				r.Body.Close()
   214  
   215  				if err != nil {
   216  					w.WriteHeader(500)
   217  					w.Write([]byte("Unable to read all payload"))
   218  					return
   219  				}
   220  				payload = xor(payload)
   221  				w.Write(payload)
   222  			},
   223  		},
   224  	}
   225  
   226  	_, err := httpServer.Start()
   227  	common.Must(err)
   228  	defer httpServer.Close()
   229  
   230  	serverPort := tcp.PickPort()
   231  	serverConfig := &core.Config{
   232  		Inbound: []*core.InboundHandlerConfig{
   233  			{
   234  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   235  					PortRange: net.SinglePortRange(serverPort),
   236  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   237  				}),
   238  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{}),
   239  			},
   240  		},
   241  		Outbound: []*core.OutboundHandlerConfig{
   242  			{
   243  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   244  			},
   245  		},
   246  	}
   247  
   248  	servers, err := InitializeServerConfigs(serverConfig)
   249  	common.Must(err)
   250  	defer CloseAllServers(servers)
   251  
   252  	{
   253  		transport := &http.Transport{
   254  			Proxy: func(req *http.Request) (*url.URL, error) {
   255  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   256  			},
   257  		}
   258  
   259  		client := &http.Client{
   260  			Transport: transport,
   261  		}
   262  
   263  		payload := make([]byte, 1024*64)
   264  		common.Must2(rand.Read(payload))
   265  
   266  		resp, err := client.Post("http://127.0.0.1:"+httpServerPort.String()+"/testpost", "application/x-www-form-urlencoded", bytes.NewReader(payload))
   267  		common.Must(err)
   268  		defer resp.Body.Close()
   269  		if resp.StatusCode != 200 {
   270  			t.Fatal("status: ", resp.StatusCode)
   271  		}
   272  
   273  		content, err := io.ReadAll(resp.Body)
   274  		common.Must(err)
   275  		if r := cmp.Diff(content, xor(payload)); r != "" {
   276  			t.Fatal(r)
   277  		}
   278  	}
   279  }
   280  
   281  func setProxyBasicAuth(req *http.Request, user, pass string) {
   282  	req.SetBasicAuth(user, pass)
   283  	req.Header.Set("Proxy-Authorization", req.Header.Get("Authorization"))
   284  	req.Header.Del("Authorization")
   285  }
   286  
   287  func TestHttpBasicAuth(t *testing.T) {
   288  	httpServerPort := tcp.PickPort()
   289  	httpServer := &v2httptest.Server{
   290  		Port:        httpServerPort,
   291  		PathHandler: make(map[string]http.HandlerFunc),
   292  	}
   293  	_, err := httpServer.Start()
   294  	common.Must(err)
   295  	defer httpServer.Close()
   296  
   297  	serverPort := tcp.PickPort()
   298  	serverConfig := &core.Config{
   299  		Inbound: []*core.InboundHandlerConfig{
   300  			{
   301  				ReceiverSettings: serial.ToTypedMessage(&proxyman.ReceiverConfig{
   302  					PortRange: net.SinglePortRange(serverPort),
   303  					Listen:    net.NewIPOrDomain(net.LocalHostIP),
   304  				}),
   305  				ProxySettings: serial.ToTypedMessage(&v2http.ServerConfig{
   306  					Accounts: map[string]string{
   307  						"a": "b",
   308  					},
   309  				}),
   310  			},
   311  		},
   312  		Outbound: []*core.OutboundHandlerConfig{
   313  			{
   314  				ProxySettings: serial.ToTypedMessage(&freedom.Config{}),
   315  			},
   316  		},
   317  	}
   318  
   319  	servers, err := InitializeServerConfigs(serverConfig)
   320  	common.Must(err)
   321  	defer CloseAllServers(servers)
   322  
   323  	{
   324  		transport := &http.Transport{
   325  			Proxy: func(req *http.Request) (*url.URL, error) {
   326  				return url.Parse("http://127.0.0.1:" + serverPort.String())
   327  			},
   328  		}
   329  
   330  		client := &http.Client{
   331  			Transport: transport,
   332  		}
   333  
   334  		{
   335  			resp, err := client.Get("http://127.0.0.1:" + httpServerPort.String())
   336  			common.Must(err)
   337  			defer resp.Body.Close()
   338  			if resp.StatusCode != 407 {
   339  				t.Fatal("status: ", resp.StatusCode)
   340  			}
   341  		}
   342  
   343  		{
   344  			ctx := context.Background()
   345  			req, err := http.NewRequestWithContext(ctx, "GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
   346  			common.Must(err)
   347  
   348  			setProxyBasicAuth(req, "a", "c")
   349  			resp, err := client.Do(req)
   350  			common.Must(err)
   351  			defer resp.Body.Close()
   352  			if resp.StatusCode != 407 {
   353  				t.Fatal("status: ", resp.StatusCode)
   354  			}
   355  		}
   356  
   357  		{
   358  			ctx := context.Background()
   359  			req, err := http.NewRequestWithContext(ctx, "GET", "http://127.0.0.1:"+httpServerPort.String(), nil)
   360  			common.Must(err)
   361  
   362  			setProxyBasicAuth(req, "a", "b")
   363  			resp, err := client.Do(req)
   364  			common.Must(err)
   365  			defer resp.Body.Close()
   366  			if resp.StatusCode != 200 {
   367  				t.Fatal("status: ", resp.StatusCode)
   368  			}
   369  
   370  			content, err := io.ReadAll(resp.Body)
   371  			common.Must(err)
   372  			if string(content) != "Home" {
   373  				t.Fatal("body: ", string(content))
   374  			}
   375  		}
   376  	}
   377  }