Best Gauge code snippet using conn.readResponse
proxy_test.go
Source:proxy_test.go  
1// Copyright 2015 Google Inc. All rights reserved.2//3// Licensed under the Apache License, Version 2.0 (the "License");4// you may not use this file except in compliance with the License.5// You may obtain a copy of the License at6//7//     http://www.apache.org/licenses/LICENSE-2.08//9// Unless required by applicable law or agreed to in writing, software10// distributed under the License is distributed on an "AS IS" BASIS,11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12// See the License for the specific language governing permissions and13// limitations under the License.14package martian15import (16	"bufio"17	"bytes"18	"crypto/tls"19	"crypto/x509"20	"errors"21	"fmt"22	"io"23	"io/ioutil"24	"net"25	"net/http"26	"net/url"27	"os"28	"strings"29	"testing"30	"time"31	"github.com/google/martian/log"32	"github.com/google/martian/martiantest"33	"github.com/google/martian/mitm"34	"github.com/google/martian/proxyutil"35)36type tempError struct{}37func (e *tempError) Error() string   { return "temporary" }38func (e *tempError) Timeout() bool   { return true }39func (e *tempError) Temporary() bool { return true }40type timeoutListener struct {41	net.Listener42	errCount int43	err      error44}45func newTimeoutListener(l net.Listener, errCount int) net.Listener {46	return &timeoutListener{47		Listener: l,48		errCount: errCount,49		err:      &tempError{},50	}51}52func (l *timeoutListener) Accept() (net.Conn, error) {53	if l.errCount > 0 {54		l.errCount--55		return nil, l.err56	}57	return l.Listener.Accept()58}59func TestIntegrationTemporaryTimeout(t *testing.T) {60	t.Parallel()61	l, err := net.Listen("tcp", "[::]:0")62	if err != nil {63		t.Fatalf("net.Listen(): got %v, want no error", err)64	}65	p := NewProxy()66	defer p.Close()67	tr := martiantest.NewTransport()68	p.SetRoundTripper(tr)69	p.SetTimeout(200 * time.Millisecond)70	// Start the proxy with a listener that will return a temporary error on71	// Accept() three times.72	go p.Serve(newTimeoutListener(l, 3))73	conn, err := net.Dial("tcp", l.Addr().String())74	if err != nil {75		t.Fatalf("net.Dial(): got %v, want no error", err)76	}77	defer conn.Close()78	req, err := http.NewRequest("GET", "http://example.com", nil)79	if err != nil {80		t.Fatalf("http.NewRequest(): got %v, want no error", err)81	}82	req.Header.Set("Connection", "close")83	// GET http://example.com/ HTTP/1.184	// Host: example.com85	if err := req.WriteProxy(conn); err != nil {86		t.Fatalf("req.WriteProxy(): got %v, want no error", err)87	}88	res, err := http.ReadResponse(bufio.NewReader(conn), req)89	if err != nil {90		t.Fatalf("http.ReadResponse(): got %v, want no error", err)91	}92	defer res.Body.Close()93	if got, want := res.StatusCode, 200; got != want {94		t.Errorf("res.StatusCode: got %d, want %d", got, want)95	}96}97func TestIntegrationHTTP(t *testing.T) {98	t.Parallel()99	l, err := net.Listen("tcp", "[::]:0")100	if err != nil {101		t.Fatalf("net.Listen(): got %v, want no error", err)102	}103	p := NewProxy()104	defer p.Close()105	p.SetRequestModifier(nil)106	p.SetResponseModifier(nil)107	tr := martiantest.NewTransport()108	p.SetRoundTripper(tr)109	p.SetTimeout(200 * time.Millisecond)110	tm := martiantest.NewModifier()111	tm.RequestFunc(func(req *http.Request) {112		ctx := NewContext(req)113		ctx.Set("martian.test", "true")114	})115	tm.ResponseFunc(func(res *http.Response) {116		ctx := NewContext(res.Request)117		v, _ := ctx.Get("martian.test")118		res.Header.Set("Martian-Test", v.(string))119	})120	p.SetRequestModifier(tm)121	p.SetResponseModifier(tm)122	go p.Serve(l)123	conn, err := net.Dial("tcp", l.Addr().String())124	if err != nil {125		t.Fatalf("net.Dial(): got %v, want no error", err)126	}127	defer conn.Close()128	req, err := http.NewRequest("GET", "http://example.com", nil)129	if err != nil {130		t.Fatalf("http.NewRequest(): got %v, want no error", err)131	}132	// GET http://example.com/ HTTP/1.1133	// Host: example.com134	if err := req.WriteProxy(conn); err != nil {135		t.Fatalf("req.WriteProxy(): got %v, want no error", err)136	}137	res, err := http.ReadResponse(bufio.NewReader(conn), req)138	if err != nil {139		t.Fatalf("http.ReadResponse(): got %v, want no error", err)140	}141	if got, want := res.StatusCode, 200; got != want {142		t.Fatalf("res.StatusCode: got %d, want %d", got, want)143	}144	if got, want := res.Header.Get("Martian-Test"), "true"; got != want {145		t.Errorf("res.Header.Get(%q): got %q, want %q", "Martian-Test", got, want)146	}147}148func TestIntegrationHTTP100Continue(t *testing.T) {149	t.Parallel()150	l, err := net.Listen("tcp", "[::]:0")151	if err != nil {152		t.Fatalf("net.Listen(): got %v, want no error", err)153	}154	p := NewProxy()155	defer p.Close()156	p.SetTimeout(2 * time.Second)157	sl, err := net.Listen("tcp", "[::]:0")158	if err != nil {159		t.Fatalf("net.Listen(): got %v, want no error", err)160	}161	go func() {162		conn, err := sl.Accept()163		if err != nil {164			log.Errorf("proxy_test: failed to accept connection: %v", err)165			return166		}167		defer conn.Close()168		log.Infof("proxy_test: accepted connection: %s", conn.RemoteAddr())169		req, err := http.ReadRequest(bufio.NewReader(conn))170		if err != nil {171			log.Errorf("proxy_test: failed to read request: %v", err)172			return173		}174		if req.Header.Get("Expect") == "100-continue" {175			log.Infof("proxy_test: received 100-continue request")176			conn.Write([]byte("HTTP/1.1 100 Continue\r\n\r\n"))177			log.Infof("proxy_test: sent 100-continue response")178		} else {179			log.Infof("proxy_test: received non 100-continue request")180			res := proxyutil.NewResponse(417, nil, req)181			res.Header.Set("Connection", "close")182			res.Write(conn)183			return184		}185		res := proxyutil.NewResponse(200, req.Body, req)186		res.Header.Set("Connection", "close")187		res.Write(conn)188		log.Infof("proxy_test: sent 200 response")189	}()190	tm := martiantest.NewModifier()191	p.SetRequestModifier(tm)192	p.SetResponseModifier(tm)193	go p.Serve(l)194	conn, err := net.Dial("tcp", l.Addr().String())195	if err != nil {196		t.Fatalf("net.Dial(): got %v, want no error", err)197	}198	defer conn.Close()199	host := sl.Addr().String()200	raw := fmt.Sprintf("POST http://%s/ HTTP/1.1\r\n"+201		"Host: %s\r\n"+202		"Content-Length: 12\r\n"+203		"Expect: 100-continue\r\n\r\n", host, host)204	if _, err := conn.Write([]byte(raw)); err != nil {205		t.Fatalf("conn.Write(headers): got %v, want no error", err)206	}207	go func() {208		select {209		case <-time.After(time.Second):210			conn.Write([]byte("body content"))211		}212	}()213	res, err := http.ReadResponse(bufio.NewReader(conn), nil)214	if err != nil {215		t.Fatalf("http.ReadResponse(): got %v, want no error", err)216	}217	defer res.Body.Close()218	if got, want := res.StatusCode, 200; got != want {219		t.Fatalf("res.StatusCode: got %d, want %d", got, want)220	}221	got, err := ioutil.ReadAll(res.Body)222	if err != nil {223		t.Fatalf("ioutil.ReadAll(): got %v, want no error", err)224	}225	if want := []byte("body content"); !bytes.Equal(got, want) {226		t.Errorf("res.Body: got %q, want %q", got, want)227	}228	if !tm.RequestModified() {229		t.Error("tm.RequestModified(): got false, want true")230	}231	if !tm.ResponseModified() {232		t.Error("tm.ResponseModified(): got false, want true")233	}234}235func TestIntegrationHTTPDownstreamProxy(t *testing.T) {236	t.Parallel()237	// Start first proxy to use as downstream.238	dl, err := net.Listen("tcp", "[::]:0")239	if err != nil {240		t.Fatalf("net.Listen(): got %v, want no error", err)241	}242	downstream := NewProxy()243	defer downstream.Close()244	dtr := martiantest.NewTransport()245	dtr.Respond(299)246	downstream.SetRoundTripper(dtr)247	downstream.SetTimeout(600 * time.Millisecond)248	go downstream.Serve(dl)249	// Start second proxy as upstream proxy, will write to downstream proxy.250	ul, err := net.Listen("tcp", "[::]:0")251	if err != nil {252		t.Fatalf("net.Listen(): got %v, want no error", err)253	}254	upstream := NewProxy()255	defer upstream.Close()256	// Set upstream proxy's downstream proxy to the host:port of the first proxy.257	upstream.SetDownstreamProxy(&url.URL{258		Host: dl.Addr().String(),259	})260	upstream.SetTimeout(600 * time.Millisecond)261	go upstream.Serve(ul)262	// Open connection to upstream proxy.263	conn, err := net.Dial("tcp", ul.Addr().String())264	if err != nil {265		t.Fatalf("net.Dial(): got %v, want no error", err)266	}267	defer conn.Close()268	req, err := http.NewRequest("GET", "http://example.com", nil)269	if err != nil {270		t.Fatalf("http.NewRequest(): got %v, want no error", err)271	}272	// GET http://example.com/ HTTP/1.1273	// Host: example.com274	if err := req.WriteProxy(conn); err != nil {275		t.Fatalf("req.WriteProxy(): got %v, want no error", err)276	}277	// Response from downstream proxy.278	res, err := http.ReadResponse(bufio.NewReader(conn), req)279	if err != nil {280		t.Fatalf("http.ReadResponse(): got %v, want no error", err)281	}282	if got, want := res.StatusCode, 299; got != want {283		t.Fatalf("res.StatusCode: got %d, want %d", got, want)284	}285}286func TestIntegrationHTTPDownstreamProxyError(t *testing.T) {287	t.Parallel()288	l, err := net.Listen("tcp", "[::]:0")289	if err != nil {290		t.Fatalf("net.Listen(): got %v, want no error", err)291	}292	p := NewProxy()293	defer p.Close()294	// Set proxy's downstream proxy to invalid host:port to force failure.295	p.SetDownstreamProxy(&url.URL{296		Host: "[::]:0",297	})298	p.SetTimeout(600 * time.Millisecond)299	tm := martiantest.NewModifier()300	reserr := errors.New("response error")301	tm.ResponseError(reserr)302	p.SetResponseModifier(tm)303	go p.Serve(l)304	// Open connection to upstream proxy.305	conn, err := net.Dial("tcp", l.Addr().String())306	if err != nil {307		t.Fatalf("net.Dial(): got %v, want no error", err)308	}309	defer conn.Close()310	req, err := http.NewRequest("CONNECT", "//example.com:443", nil)311	if err != nil {312		t.Fatalf("http.NewRequest(): got %v, want no error", err)313	}314	// CONNECT example.com:443 HTTP/1.1315	// Host: example.com316	if err := req.Write(conn); err != nil {317		t.Fatalf("req.Write(): got %v, want no error", err)318	}319	// Response from upstream proxy, assuming downstream proxy failed to CONNECT.320	res, err := http.ReadResponse(bufio.NewReader(conn), req)321	if err != nil {322		t.Fatalf("http.ReadResponse(): got %v, want no error", err)323	}324	if got, want := res.StatusCode, 502; got != want {325		t.Fatalf("res.StatusCode: got %d, want %d", got, want)326	}327	if got, want := res.Header["Warning"][1], reserr.Error(); !strings.Contains(got, want) {328		t.Errorf("res.Header.get(%q): got %q, want to contain %q", "Warning", got, want)329	}330}331func TestIntegrationTLSHandshakeErrorCallback(t *testing.T) {332	t.Parallel()333	l, err := net.Listen("tcp", "[::]:0")334	if err != nil {335		t.Fatalf("net.Listen(): got %v, want no error", err)336	}337	p := NewProxy()338	defer p.Close()339	// Test TLS server.340	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", time.Hour)341	if err != nil {342		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)343	}344	mc, err := mitm.NewConfig(ca, priv)345	if err != nil {346		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)347	}348	var herr error349	mc.SetHandshakeErrorCallback(func(_ *http.Request, err error) { herr = fmt.Errorf("handshake error") })350	p.SetMITM(mc)351	tl, err := net.Listen("tcp", "[::]:0")352	if err != nil {353		t.Fatalf("tls.Listen(): got %v, want no error", err)354	}355	tl = tls.NewListener(tl, mc.TLS())356	go http.Serve(tl, http.HandlerFunc(357		func(rw http.ResponseWriter, req *http.Request) {358			rw.WriteHeader(200)359		}))360	tm := martiantest.NewModifier()361	// Force the CONNECT request to dial the local TLS server.362	tm.RequestFunc(func(req *http.Request) {363		req.URL.Host = tl.Addr().String()364	})365	go p.Serve(l)366	conn, err := net.Dial("tcp", l.Addr().String())367	if err != nil {368		t.Fatalf("net.Dial(): got %v, want no error", err)369	}370	defer conn.Close()371	req, err := http.NewRequest("CONNECT", "//example.com:443", nil)372	if err != nil {373		t.Fatalf("http.NewRequest(): got %v, want no error", err)374	}375	// CONNECT example.com:443 HTTP/1.1376	// Host: example.com377	//378	// Rewritten to CONNECT to host:port in CONNECT request modifier.379	if err := req.Write(conn); err != nil {380		t.Fatalf("req.Write(): got %v, want no error", err)381	}382	// CONNECT response after establishing tunnel.383	if _, err := http.ReadResponse(bufio.NewReader(conn), req); err != nil {384		t.Fatalf("http.ReadResponse(): got %v, want no error", err)385	}386	tlsconn := tls.Client(conn, &tls.Config{387		ServerName: "example.com",388		// Client has no cert so it will get "x509: certificate signed by unknown authority" from the389		// handshake and send "remote error: bad certificate" to the server.390		RootCAs: x509.NewCertPool(),391	})392	defer tlsconn.Close()393	req, err = http.NewRequest("GET", "https://example.com", nil)394	if err != nil {395		t.Fatalf("http.NewRequest(): got %v, want no error", err)396	}397	req.Header.Set("Connection", "close")398	if got, want := req.Write(tlsconn), "x509: certificate signed by unknown authority"; !strings.Contains(got.Error(), want) {399		t.Fatalf("Got incorrect error from Client Handshake(), got: %v, want: %v", got, want)400	}401	// TODO: herr is not being asserted against. It should be pushed on to a channel402	// of err, and the assertion should pull off of it and assert. That design resulted in the test403	// hanging for unknown reasons.404	t.Skip("skipping assertion of handshake error callback error due to mysterious deadlock")405	if got, want := herr, "remote error: bad certificate"; !strings.Contains(got.Error(), want) {406		t.Fatalf("Got incorrect error from Server Handshake(), got: %v, want: %v", got, want)407	}408}409func TestIntegrationConnect(t *testing.T) {410	t.Parallel()411	l, err := net.Listen("tcp", "[::]:0")412	if err != nil {413		t.Fatalf("net.Listen(): got %v, want no error", err)414	}415	p := NewProxy()416	defer p.Close()417	// Test TLS server.418	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", time.Hour)419	if err != nil {420		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)421	}422	mc, err := mitm.NewConfig(ca, priv)423	if err != nil {424		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)425	}426	tl, err := net.Listen("tcp", "[::]:0")427	if err != nil {428		t.Fatalf("tls.Listen(): got %v, want no error", err)429	}430	tl = tls.NewListener(tl, mc.TLS())431	go http.Serve(tl, http.HandlerFunc(432		func(rw http.ResponseWriter, req *http.Request) {433			rw.WriteHeader(299)434		}))435	tm := martiantest.NewModifier()436	reqerr := errors.New("request error")437	reserr := errors.New("response error")438	// Force the CONNECT request to dial the local TLS server.439	tm.RequestFunc(func(req *http.Request) {440		req.URL.Host = tl.Addr().String()441	})442	tm.RequestError(reqerr)443	tm.ResponseError(reserr)444	p.SetRequestModifier(tm)445	p.SetResponseModifier(tm)446	go p.Serve(l)447	conn, err := net.Dial("tcp", l.Addr().String())448	if err != nil {449		t.Fatalf("net.Dial(): got %v, want no error", err)450	}451	defer conn.Close()452	req, err := http.NewRequest("CONNECT", "//example.com:443", nil)453	if err != nil {454		t.Fatalf("http.NewRequest(): got %v, want no error", err)455	}456	// CONNECT example.com:443 HTTP/1.1457	// Host: example.com458	//459	// Rewritten to CONNECT to host:port in CONNECT request modifier.460	if err := req.Write(conn); err != nil {461		t.Fatalf("req.Write(): got %v, want no error", err)462	}463	// CONNECT response after establishing tunnel.464	res, err := http.ReadResponse(bufio.NewReader(conn), req)465	if err != nil {466		t.Fatalf("http.ReadResponse(): got %v, want no error", err)467	}468	if got, want := res.StatusCode, 200; got != want {469		t.Fatalf("res.StatusCode: got %d, want %d", got, want)470	}471	if !tm.RequestModified() {472		t.Error("tm.RequestModified(): got false, want true")473	}474	if !tm.ResponseModified() {475		t.Error("tm.ResponseModified(): got false, want true")476	}477	if got, want := res.Header.Get("Warning"), reserr.Error(); !strings.Contains(got, want) {478		t.Errorf("res.Header.Get(%q): got %q, want to contain %q", "Warning", got, want)479	}480	roots := x509.NewCertPool()481	roots.AddCert(ca)482	tlsconn := tls.Client(conn, &tls.Config{483		ServerName: "example.com",484		RootCAs:    roots,485	})486	defer tlsconn.Close()487	req, err = http.NewRequest("GET", "https://example.com", nil)488	if err != nil {489		t.Fatalf("http.NewRequest(): got %v, want no error", err)490	}491	req.Header.Set("Connection", "close")492	// GET / HTTP/1.1493	// Host: example.com494	// Connection: close495	if err := req.Write(tlsconn); err != nil {496		t.Fatalf("req.Write(): got %v, want no error", err)497	}498	res, err = http.ReadResponse(bufio.NewReader(tlsconn), req)499	if err != nil {500		t.Fatalf("http.ReadResponse(): got %v, want no error", err)501	}502	defer res.Body.Close()503	if got, want := res.StatusCode, 299; got != want {504		t.Fatalf("res.StatusCode: got %d, want %d", got, want)505	}506	if got, want := res.Header.Get("Warning"), reserr.Error(); strings.Contains(got, want) {507		t.Errorf("res.Header.Get(%q): got %s, want to not contain %s", "Warning", got, want)508	}509}510func TestIntegrationConnectDownstreamProxy(t *testing.T) {511	t.Parallel()512	// Start first proxy to use as downstream.513	dl, err := net.Listen("tcp", "[::]:0")514	if err != nil {515		t.Fatalf("net.Listen(): got %v, want no error", err)516	}517	downstream := NewProxy()518	defer downstream.Close()519	dtr := martiantest.NewTransport()520	dtr.Respond(299)521	downstream.SetRoundTripper(dtr)522	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", 2*time.Hour)523	if err != nil {524		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)525	}526	mc, err := mitm.NewConfig(ca, priv)527	if err != nil {528		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)529	}530	downstream.SetMITM(mc)531	go downstream.Serve(dl)532	// Start second proxy as upstream proxy, will CONNECT to downstream proxy.533	ul, err := net.Listen("tcp", "[::]:0")534	if err != nil {535		t.Fatalf("net.Listen(): got %v, want no error", err)536	}537	upstream := NewProxy()538	defer upstream.Close()539	// Set upstream proxy's downstream proxy to the host:port of the first proxy.540	upstream.SetDownstreamProxy(&url.URL{541		Host: dl.Addr().String(),542	})543	go upstream.Serve(ul)544	// Open connection to upstream proxy.545	conn, err := net.Dial("tcp", ul.Addr().String())546	if err != nil {547		t.Fatalf("net.Dial(): got %v, want no error", err)548	}549	defer conn.Close()550	req, err := http.NewRequest("CONNECT", "//example.com:443", nil)551	if err != nil {552		t.Fatalf("http.NewRequest(): got %v, want no error", err)553	}554	// CONNECT example.com:443 HTTP/1.1555	// Host: example.com556	if err := req.Write(conn); err != nil {557		t.Fatalf("req.Write(): got %v, want no error", err)558	}559	// Response from downstream proxy starting MITM.560	res, err := http.ReadResponse(bufio.NewReader(conn), req)561	if err != nil {562		t.Fatalf("http.ReadResponse(): got %v, want no error", err)563	}564	if got, want := res.StatusCode, 200; got != want {565		t.Fatalf("res.StatusCode: got %d, want %d", got, want)566	}567	roots := x509.NewCertPool()568	roots.AddCert(ca)569	tlsconn := tls.Client(conn, &tls.Config{570		// Validate the hostname.571		ServerName: "example.com",572		// The certificate will have been MITM'd, verify using the MITM CA573		// certificate.574		RootCAs: roots,575	})576	defer tlsconn.Close()577	req, err = http.NewRequest("GET", "https://example.com", nil)578	if err != nil {579		t.Fatalf("http.NewRequest(): got %v, want no error", err)580	}581	// GET / HTTP/1.1582	// Host: example.com583	if err := req.Write(tlsconn); err != nil {584		t.Fatalf("req.Write(): got %v, want no error", err)585	}586	// Response from MITM in downstream proxy.587	res, err = http.ReadResponse(bufio.NewReader(tlsconn), req)588	if err != nil {589		t.Fatalf("http.ReadResponse(): got %v, want no error", err)590	}591	defer res.Body.Close()592	if got, want := res.StatusCode, 299; got != want {593		t.Fatalf("res.StatusCode: got %d, want %d", got, want)594	}595}596func TestIntegrationMITM(t *testing.T) {597	t.Parallel()598	l, err := net.Listen("tcp", "[::]:0")599	if err != nil {600		t.Fatalf("net.Listen(): got %v, want no error", err)601	}602	p := NewProxy()603	defer p.Close()604	tr := martiantest.NewTransport()605	tr.Func(func(req *http.Request) (*http.Response, error) {606		res := proxyutil.NewResponse(200, nil, req)607		res.Header.Set("Request-Scheme", req.URL.Scheme)608		return res, nil609	})610	p.SetRoundTripper(tr)611	p.SetTimeout(600 * time.Millisecond)612	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", 2*time.Hour)613	if err != nil {614		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)615	}616	mc, err := mitm.NewConfig(ca, priv)617	if err != nil {618		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)619	}620	p.SetMITM(mc)621	tm := martiantest.NewModifier()622	reqerr := errors.New("request error")623	reserr := errors.New("response error")624	tm.RequestError(reqerr)625	tm.ResponseError(reserr)626	p.SetRequestModifier(tm)627	p.SetResponseModifier(tm)628	go p.Serve(l)629	conn, err := net.Dial("tcp", l.Addr().String())630	if err != nil {631		t.Fatalf("net.Dial(): got %v, want no error", err)632	}633	defer conn.Close()634	req, err := http.NewRequest("CONNECT", "//example.com:443", nil)635	if err != nil {636		t.Fatalf("http.NewRequest(): got %v, want no error", err)637	}638	// CONNECT example.com:443 HTTP/1.1639	// Host: example.com640	if err := req.Write(conn); err != nil {641		t.Fatalf("req.Write(): got %v, want no error", err)642	}643	// Response MITM'd from proxy.644	res, err := http.ReadResponse(bufio.NewReader(conn), req)645	if err != nil {646		t.Fatalf("http.ReadResponse(): got %v, want no error", err)647	}648	if got, want := res.StatusCode, 200; got != want {649		t.Errorf("res.StatusCode: got %d, want %d", got, want)650	}651	if got, want := res.Header.Get("Warning"), reserr.Error(); !strings.Contains(got, want) {652		t.Errorf("res.Header.Get(%q): got %q, want to contain %q", "Warning", got, want)653	}654	roots := x509.NewCertPool()655	roots.AddCert(ca)656	tlsconn := tls.Client(conn, &tls.Config{657		ServerName: "example.com",658		RootCAs:    roots,659	})660	defer tlsconn.Close()661	req, err = http.NewRequest("GET", "https://example.com", nil)662	if err != nil {663		t.Fatalf("http.NewRequest(): got %v, want no error", err)664	}665	// GET / HTTP/1.1666	// Host: example.com667	if err := req.Write(tlsconn); err != nil {668		t.Fatalf("req.Write(): got %v, want no error", err)669	}670	// Response from MITM proxy.671	res, err = http.ReadResponse(bufio.NewReader(tlsconn), req)672	if err != nil {673		t.Fatalf("http.ReadResponse(): got %v, want no error", err)674	}675	defer res.Body.Close()676	if got, want := res.StatusCode, 200; got != want {677		t.Errorf("res.StatusCode: got %d, want %d", got, want)678	}679	if got, want := res.Header.Get("Request-Scheme"), "https"; got != want {680		t.Errorf("res.Header.Get(%q): got %q, want %q", "Request-Scheme", got, want)681	}682	if got, want := res.Header.Get("Warning"), reserr.Error(); !strings.Contains(got, want) {683		t.Errorf("res.Header.Get(%q): got %q, want to contain %q", "Warning", got, want)684	}685}686func TestIntegrationTransparentHTTP(t *testing.T) {687	t.Parallel()688	l, err := net.Listen("tcp", "[::]:0")689	if err != nil {690		t.Fatalf("net.Listen(): got %v, want no error", err)691	}692	p := NewProxy()693	defer p.Close()694	tr := martiantest.NewTransport()695	p.SetRoundTripper(tr)696	p.SetTimeout(200 * time.Millisecond)697	tm := martiantest.NewModifier()698	p.SetRequestModifier(tm)699	p.SetResponseModifier(tm)700	go p.Serve(l)701	conn, err := net.Dial("tcp", l.Addr().String())702	if err != nil {703		t.Fatalf("net.Dial(): got %v, want no error", err)704	}705	defer conn.Close()706	req, err := http.NewRequest("GET", "http://example.com", nil)707	if err != nil {708		t.Fatalf("http.NewRequest(): got %v, want no error", err)709	}710	// GET / HTTP/1.1711	// Host: www.example.com712	if err := req.Write(conn); err != nil {713		t.Fatalf("req.Write(): got %v, want no error", err)714	}715	res, err := http.ReadResponse(bufio.NewReader(conn), req)716	if err != nil {717		t.Fatalf("http.ReadResponse(): got %v, want no error", err)718	}719	if got, want := res.StatusCode, 200; got != want {720		t.Fatalf("res.StatusCode: got %d, want %d", got, want)721	}722	if !tm.RequestModified() {723		t.Error("tm.RequestModified(): got false, want true")724	}725	if !tm.ResponseModified() {726		t.Error("tm.ResponseModified(): got false, want true")727	}728}729func TestIntegrationTransparentMITM(t *testing.T) {730	t.Parallel()731	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", 2*time.Hour)732	if err != nil {733		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)734	}735	mc, err := mitm.NewConfig(ca, priv)736	if err != nil {737		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)738	}739	// Start TLS listener with config that will generate certificates based on740	// SNI from connection.741	//742	// BUG: tls.Listen will not accept a tls.Config where Certificates is empty,743	// even though it is supported by tls.Server when GetCertificate is not nil.744	l, err := net.Listen("tcp", "[::]:0")745	if err != nil {746		t.Fatalf("net.Listen(): got %v, want no error", err)747	}748	l = tls.NewListener(l, mc.TLS())749	p := NewProxy()750	defer p.Close()751	tr := martiantest.NewTransport()752	tr.Func(func(req *http.Request) (*http.Response, error) {753		res := proxyutil.NewResponse(200, nil, req)754		res.Header.Set("Request-Scheme", req.URL.Scheme)755		return res, nil756	})757	p.SetRoundTripper(tr)758	tm := martiantest.NewModifier()759	p.SetRequestModifier(tm)760	p.SetResponseModifier(tm)761	go p.Serve(l)762	roots := x509.NewCertPool()763	roots.AddCert(ca)764	tlsconn, err := tls.Dial("tcp", l.Addr().String(), &tls.Config{765		// Verify the hostname is example.com.766		ServerName: "example.com",767		// The certificate will have been generated during MITM, so we need to768		// verify it with the generated CA certificate.769		RootCAs: roots,770	})771	if err != nil {772		t.Fatalf("tls.Dial(): got %v, want no error", err)773	}774	defer tlsconn.Close()775	req, err := http.NewRequest("GET", "https://example.com", nil)776	if err != nil {777		t.Fatalf("http.NewRequest(): got %v, want no error", err)778	}779	// Write Encrypted request directly, no CONNECT.780	// GET / HTTP/1.1781	// Host: example.com782	if err := req.Write(tlsconn); err != nil {783		t.Fatalf("req.Write(): got %v, want no error", err)784	}785	res, err := http.ReadResponse(bufio.NewReader(tlsconn), req)786	if err != nil {787		t.Fatalf("http.ReadResponse(): got %v, want no error", err)788	}789	defer res.Body.Close()790	if got, want := res.StatusCode, 200; got != want {791		t.Fatalf("res.StatusCode: got %d, want %d", got, want)792	}793	if got, want := res.Header.Get("Request-Scheme"), "https"; got != want {794		t.Errorf("res.Header.Get(%q): got %q, want %q", "Request-Scheme", got, want)795	}796	if !tm.RequestModified() {797		t.Errorf("tm.RequestModified(): got false, want true")798	}799	if !tm.ResponseModified() {800		t.Errorf("tm.ResponseModified(): got false, want true")801	}802}803func TestIntegrationFailedRoundTrip(t *testing.T) {804	t.Parallel()805	l, err := net.Listen("tcp", "[::]:0")806	if err != nil {807		t.Fatalf("net.Listen(): got %v, want no error", err)808	}809	p := NewProxy()810	defer p.Close()811	tr := martiantest.NewTransport()812	trerr := errors.New("round trip error")813	tr.RespondError(trerr)814	p.SetRoundTripper(tr)815	p.SetTimeout(200 * time.Millisecond)816	go p.Serve(l)817	conn, err := net.Dial("tcp", l.Addr().String())818	if err != nil {819		t.Fatalf("net.Dial(): got %v, want no error", err)820	}821	defer conn.Close()822	req, err := http.NewRequest("GET", "http://example.com", nil)823	if err != nil {824		t.Fatalf("http.NewRequest(): got %v, want no error", err)825	}826	// GET http://example.com/ HTTP/1.1827	// Host: example.com828	if err := req.WriteProxy(conn); err != nil {829		t.Fatalf("req.WriteProxy(): got %v, want no error", err)830	}831	// Response from failed round trip.832	res, err := http.ReadResponse(bufio.NewReader(conn), req)833	if err != nil {834		t.Fatalf("http.ReadResponse(): got %v, want no error", err)835	}836	defer res.Body.Close()837	if got, want := res.StatusCode, 502; got != want {838		t.Errorf("res.StatusCode: got %d, want %d", got, want)839	}840	if got, want := res.Header.Get("Warning"), trerr.Error(); !strings.Contains(got, want) {841		t.Errorf("res.Header.Get(%q): got %q, want to contain %q", "Warning", got, want)842	}843}844func TestIntegrationSkipRoundTrip(t *testing.T) {845	t.Parallel()846	l, err := net.Listen("tcp", "[::]:0")847	if err != nil {848		t.Fatalf("net.Listen(): got %v, want no error", err)849	}850	p := NewProxy()851	defer p.Close()852	// Transport will be skipped, no 500.853	tr := martiantest.NewTransport()854	tr.Respond(500)855	p.SetRoundTripper(tr)856	p.SetTimeout(200 * time.Millisecond)857	tm := martiantest.NewModifier()858	tm.RequestFunc(func(req *http.Request) {859		ctx := NewContext(req)860		ctx.SkipRoundTrip()861	})862	p.SetRequestModifier(tm)863	go p.Serve(l)864	conn, err := net.Dial("tcp", l.Addr().String())865	if err != nil {866		t.Fatalf("net.Dial(): got %v, want no error", err)867	}868	defer conn.Close()869	req, err := http.NewRequest("GET", "http://example.com", nil)870	if err != nil {871		t.Fatalf("http.NewRequest(): got %v, want no error", err)872	}873	// GET http://example.com/ HTTP/1.1874	// Host: example.com875	if err := req.WriteProxy(conn); err != nil {876		t.Fatalf("req.WriteProxy(): got %v, want no error", err)877	}878	// Response from skipped round trip.879	res, err := http.ReadResponse(bufio.NewReader(conn), req)880	if err != nil {881		t.Fatalf("http.ReadResponse(): got %v, want no error", err)882	}883	defer res.Body.Close()884	if got, want := res.StatusCode, 200; got != want {885		t.Errorf("res.StatusCode: got %d, want %d", got, want)886	}887}888func TestHTTPThroughConnectWithMITM(t *testing.T) {889	t.Parallel()890	l, err := net.Listen("tcp", "[::]:0")891	if err != nil {892		t.Fatalf("net.Listen(): got %v, want no error", err)893	}894	p := NewProxy()895	defer p.Close()896	tm := martiantest.NewModifier()897	tm.RequestFunc(func(req *http.Request) {898		ctx := NewContext(req)899		ctx.SkipRoundTrip()900		if req.Method != "GET" && req.Method != "CONNECT" {901			t.Errorf("unexpected method on request handler: %v", req.Method)902		}903	})904	p.SetRequestModifier(tm)905	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", 2*time.Hour)906	if err != nil {907		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)908	}909	mc, err := mitm.NewConfig(ca, priv)910	if err != nil {911		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)912	}913	p.SetMITM(mc)914	go p.Serve(l)915	conn, err := net.Dial("tcp", l.Addr().String())916	if err != nil {917		t.Fatalf("net.Dial(): got %v, want no error", err)918	}919	defer conn.Close()920	req, err := http.NewRequest("CONNECT", "//example.com:80", nil)921	if err != nil {922		t.Fatalf("http.NewRequest(): got %v, want no error", err)923	}924	// CONNECT example.com:80 HTTP/1.1925	// Host: example.com926	if err := req.Write(conn); err != nil {927		t.Fatalf("req.Write(): got %v, want no error", err)928	}929	// Response skipped round trip.930	res, err := http.ReadResponse(bufio.NewReader(conn), req)931	if err != nil {932		t.Fatalf("http.ReadResponse(): got %v, want no error", err)933	}934	res.Body.Close()935	if got, want := res.StatusCode, 200; got != want {936		t.Errorf("res.StatusCode: got %d, want %d", got, want)937	}938	req, err = http.NewRequest("GET", "http://example.com", nil)939	if err != nil {940		t.Fatalf("http.NewRequest(): got %v, want no error", err)941	}942	// GET http://example.com/ HTTP/1.1943	// Host: example.com944	if err := req.WriteProxy(conn); err != nil {945		t.Fatalf("req.WriteProxy(): got %v, want no error", err)946	}947	// Response from skipped round trip.948	res, err = http.ReadResponse(bufio.NewReader(conn), req)949	if err != nil {950		t.Fatalf("http.ReadResponse(): got %v, want no error", err)951	}952	res.Body.Close()953	if got, want := res.StatusCode, 200; got != want {954		t.Errorf("res.StatusCode: got %d, want %d", got, want)955	}956	req, err = http.NewRequest("GET", "http://example.com", nil)957	if err != nil {958		t.Fatalf("http.NewRequest(): got %v, want no error", err)959	}960	// GET http://example.com/ HTTP/1.1961	// Host: example.com962	if err := req.WriteProxy(conn); err != nil {963		t.Fatalf("req.WriteProxy(): got %v, want no error", err)964	}965	// Response from skipped round trip.966	res, err = http.ReadResponse(bufio.NewReader(conn), req)967	if err != nil {968		t.Fatalf("http.ReadResponse(): got %v, want no error", err)969	}970	res.Body.Close()971	if got, want := res.StatusCode, 200; got != want {972		t.Errorf("res.StatusCode: got %d, want %d", got, want)973	}974}975func TestServerClosesConnection(t *testing.T) {976	t.Parallel()977	dstl, err := net.Listen("tcp", "[::]:0")978	if err != nil {979		t.Fatalf("Failed to create http listener: %v", err)980	}981	defer dstl.Close()982	go func() {983		t.Logf("Waiting for server side connection")984		conn, err := dstl.Accept()985		if err != nil {986			t.Fatalf("Got error while accepting connection on destination listener: %v", err)987		}988		t.Logf("Accepted server side connection")989		buf := make([]byte, 16384)990		if _, err := conn.Read(buf); err != nil {991			t.Fatalf("Error reading: %v", err)992		}993		_, err = conn.Write([]byte("HTTP/1.1 301 MOVED PERMANENTLY\r\n" +994			"Server:  \r\n" +995			"Date:  \r\n" +996			"Referer:  \r\n" +997			"Location: http://www.foo.com/\r\n" +998			"Content-type: text/html\r\n" +999			"Connection: close\r\n\r\n"))1000		if err != nil {1001			t.Fatalf("Got error while writting to connection on destination listener: %v", err)1002		}1003		conn.Close()1004	}()1005	l, err := net.Listen("tcp", "[::]:0")1006	if err != nil {1007		t.Fatalf("net.Listen(): got %v, want no error", err)1008	}1009	ca, priv, err := mitm.NewAuthority("martian.proxy", "Martian Authority", 2*time.Hour)1010	if err != nil {1011		t.Fatalf("mitm.NewAuthority(): got %v, want no error", err)1012	}1013	mc, err := mitm.NewConfig(ca, priv)1014	if err != nil {1015		t.Fatalf("mitm.NewConfig(): got %v, want no error", err)1016	}1017	p := NewProxy()1018	p.SetMITM(mc)1019	defer p.Close()1020	// Start the proxy with a listener that will return a temporary error on1021	// Accept() three times.1022	go p.Serve(newTimeoutListener(l, 3))1023	conn, err := net.Dial("tcp", l.Addr().String())1024	if err != nil {1025		t.Fatalf("net.Dial(): got %v, want no error", err)1026	}1027	defer conn.Close()1028	req, err := http.NewRequest("CONNECT", fmt.Sprintf("//%s", dstl.Addr().String()), nil)1029	if err != nil {1030		t.Fatalf("http.NewRequest(): got %v, want no error", err)1031	}1032	// CONNECT example.com:443 HTTP/1.11033	// Host: example.com1034	if err := req.Write(conn); err != nil {1035		t.Fatalf("req.Write(): got %v, want no error", err)1036	}1037	res, err := http.ReadResponse(bufio.NewReader(conn), req)1038	if err != nil {1039		t.Fatalf("http.ReadResponse(): got %v, want no error", err)1040	}1041	res.Body.Close()1042	_, err = conn.Write([]byte("GET / HTTP/1.1\r\n" +1043		"User-Agent: curl/7.35.0\r\n" +1044		fmt.Sprintf("Host: %s\r\n", dstl.Addr()) +1045		"Accept: */*\r\n\r\n"))1046	if err != nil {1047		t.Fatalf("Error while writing GET request: %v", err)1048	}1049	res, err = http.ReadResponse(bufio.NewReader(io.TeeReader(conn, os.Stderr)), req)1050	if err != nil {1051		t.Fatalf("http.ReadResponse(): got %v, want no error", err)1052	}1053	_, err = ioutil.ReadAll(res.Body)1054	if err != nil {1055		t.Fatalf("error while ReadAll: %v", err)1056	}1057	defer res.Body.Close()1058}...listener_test.go
Source:listener_test.go  
...166	connectionTestWrapper(t, conn, expected)167}168func TestProxyListener_goReadProxyRoutine_ErrorReading(t *testing.T) {169	conn := &ConnMock{170		ReadReplies: []readResponse{171			readResponse{172				Error: fmt.Errorf("EXPECTED"),173			},174		},175	}176	expected := "Error reading first byte: EXPECTED"177	connectionTestWrapper(t, conn, expected)178}179func TestProxyListener_goReadProxyRoutine_InvalidReadBytes(t *testing.T) {180	conn := &ConnMock{181		ReadReplies: []readResponse{182			readResponse{183				Data: []byte("XX"),184			},185		},186	}187	expected := "Invalid number of bytes read: 2"188	connectionTestWrapper(t, conn, expected)189}190func TestProxyListener_goReadProxyRoutine_InvalidFirstByte(t *testing.T) {191	conn := &ConnMock{192		ReadReplies: []readResponse{193			readResponse{194				Data: []byte("X"),195			},196		},197	}198	expected := "Invalid first byte: 88"199	connectionTestWrapper(t, conn, expected)200}201func TestProxyListener_readVersion1_ClosedEarly(t *testing.T) {202	conn := &ConnMock{203		ReadReplies: []readResponse{204			readResponse{205				Data: []byte("P"),206			},207		},208	}209	expected := "TCP session closed prior to PROXY line."210	connectionTestWrapper(t, conn, expected)211}212func TestProxyListener_readVersion1_TCPError(t *testing.T) {213	conn := &ConnMock{214		ReadReplies: []readResponse{215			readResponse{216				Data: []byte("P"),217			},218			readResponse{219				Error: fmt.Errorf("EXPECTED"),220			},221		},222	}223	expected := "TCP error reading PROXY line: EXPECTED"224	connectionTestWrapper(t, conn, expected)225}226func TestProxyListener_readVersion1_NonProxyStart(t *testing.T) {227	conn := &ConnMock{228		ReadReplies: []readResponse{229			readResponse{230				Data: []byte("P"),231			},232			readResponse{233				Data: []byte("WTFWTFWTF"),234			},235		},236	}237	expected := "First line did not start with 'PROXY '"238	connectionTestWrapper(t, conn, expected)239}240func TestProxyListener_readVersion1_LineTooLong(t *testing.T) {241	conn := &ConnMock{242		ReadReplies: makeReplies([]byte(strings.Repeat("X", 200))),243	}244	expected := "PROXY line malformed (too long)"245	connectionTestWrapper(t, conn, expected)246}247func TestProxyListener_readVersion1_ErrorReading(t *testing.T) {248	conn := &ConnMock{249		ReadReplies: []readResponse{250			readResponse{251				Data: []byte("P"),252			},253			readResponse{254				Data: []byte("ROXY "),255			},256			readResponse{257				Error: fmt.Errorf("EXPECTED"),258			},259		},260	}261	expected := "Error reading PROXY line: EXPECTED"262	connectionTestWrapper(t, conn, expected)263}264func TestProxyListener_readVersion1_InvalidByteResponse(t *testing.T) {265	conn := &ConnMock{266		ReadReplies: []readResponse{267			readResponse{268				Data: []byte("P"),269			},270			readResponse{271				Data: []byte("ROXY "),272			},273			readResponse{274				Data: []byte("XX"),275			},276		},277	}278	expected := "Invalid number of bytes read from socket: 2"279	connectionTestWrapper(t, conn, expected)280}281func TestProxyListener_readVersion1_WrongNumberOfElements(t *testing.T) {282	conn := &ConnMock{283		ReadReplies: makeReplies([]byte("1 2 3 4 5 6 7 8 9\n\r")),284	}285	expected := "PROXY line is malformed, incorrect number of elements: 10"286	connectionTestWrapper(t, conn, expected)287}288func TestProxyListener_readVersion1_InvalidProtocol(t *testing.T) {289	conn := &ConnMock{290		ReadReplies: makeReplies([]byte("XXX 1 2 3 4\n\r")),291	}292	expected := "Protocol element of the PROXY line is invalid: XXX"293	connectionTestWrapper(t, conn, expected)294}295func TestProxyListener_readVersion1_BadSourcePort(t *testing.T) {296	conn := &ConnMock{297		ReadReplies: makeReplies(298			[]byte("TCP4 1.1.1.1 2.2.2.2 X 1\n\r")),299	}300	expected := `destination port element of the PROXY line is not an int: ` +301		`strconv.ParseInt: parsing "X": invalid syntax`302	connectionTestWrapper(t, conn, expected)303}304func TestProxyListener_readVersion1_SecondDeadlineError(t *testing.T) {305	conn := &ConnMock{306		DeadlineErrors: []error{nil, fmt.Errorf("EXPECTED")},307		ReadReplies: makeReplies(308			[]byte("TCP4 1.1.1.1 2.2.2.2 1 2\n\r")),309	}310	expected := "Error unsetting deadline on the socket: EXPECTED"311	connectionTestWrapper(t, conn, expected)312}313func TestProxyListener_readVersion1_Success(t *testing.T) {314	errors := make([]error, 0, 2)315	pl := &ProxyListener{316		listener: &ListenerMock{317			AcceptReplies: []acceptResponse{318				acceptResponse{Conn: &ConnMock{319					ReadReplies: makeReplies(320						[]byte("TCP4 1.1.1.1 2.2.2.2 1 2\n\r"),321						[]byte("OK")),322				}},323			},324		},325		errorChan:  make(chan error),326		acceptChan: make(chan net.Conn),327		ProtocolError: func(err error) {328			errors = append(errors, err)329		},330		ProtocolDeadline: time.Second,331	}332	pl.waitGroup.Add(1)333	go pl.goAcceptRoutine()334	// Check the results.335	if len(errors) != 0 {336		t.Logf("%#v", errors)337		t.Fatalf("No error expected, at least one returned.")338	}339	select {340	case conn := <-pl.acceptChan:341		data := make([]byte, 2)342		if conn.RemoteAddr().String() != "1.1.1.1:1" {343			t.Fatalf(344				"The Addr was not parsed properly (expected 1.1.1.1:1): %s",345				conn.RemoteAddr())346		} else if n, err := conn.Read(data); err != nil {347			t.Fatalf("Error reading post-proxy data: %s", err)348		} else if n != 2 {349			t.Fatalf("Unknown read size: %d", n)350		} else if !bytes.Equal(data, []byte("OK")) {351			t.Fatalf("Unexpected response (expected OK): %#v", data)352		}353	case <-time.NewTimer(time.Millisecond * 10).C:354		t.Fatalf("No connection was passed to the channel.")355	}356	// Stop the processor.357	<-pl.errorChan358	pl.Stop()359}360func TestProxyListener_readBinary_EarlyHeaderEOF(t *testing.T) {361	conn := &ConnMock{362		ReadReplies: []readResponse{363			readResponse{364				Data: []byte{0x0D},365			},366		},367	}368	expected := "Error reading binary header data: EOF"369	connectionTestWrapper(t, conn, expected)370}371func TestProxyListener_readBinary_TCPError(t *testing.T) {372	conn := &ConnMock{373		ReadReplies: []readResponse{374			readResponse{375				Data: []byte{0x0D},376			},377			readResponse{378				Error: fmt.Errorf("EXPECTED"),379			},380		},381	}382	expected := "Error reading binary header data: EXPECTED"383	connectionTestWrapper(t, conn, expected)384}385func TestProxyListener_readBinary_InvalidHeader(t *testing.T) {386	conn := &ConnMock{387		ReadReplies: []readResponse{388			readResponse{389				Data: []byte{0x0D},390			},391			readResponse{392				Data: bytes.Repeat([]byte{0}, 15),393			},394		},395	}396	expected := "Static header bytes did not match expected value."397	connectionTestWrapper(t, conn, expected)398}399func TestProxyListener_readBinary_InvalidVersion(t *testing.T) {400	conn := &ConnMock{401		ReadReplies: []readResponse{402			readResponse{403				Data: []byte{0x0D},404			},405			readResponse{406				Data: []byte{407					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,408					0x51, 0x55, 0x49, 0x54, 0x10,409				},410			},411			readResponse{412				Data: []byte{0xF0, 0x00, 0x00, 0x00},413			},414		},415	}416	expected := "Version in the header was not 2: 15"417	connectionTestWrapper(t, conn, expected)418}419func TestProxyListener_readBinary_InvalidCommandBits(t *testing.T) {420	conn := &ConnMock{421		ReadReplies: []readResponse{422			readResponse{423				Data: []byte{0x0D},424			},425			readResponse{426				Data: []byte{427					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,428					0x51, 0x55, 0x49, 0x54, 0x10,429				},430			},431			readResponse{432				Data: []byte{0x2F, 0x00, 0x00, 0x00},433			},434		},435	}436	expected := "Command bits contained an invalid value: 15"437	connectionTestWrapper(t, conn, expected)438}439func TestProxyListener_readBinary_InvalidFamilyBits(t *testing.T) {440	conn := &ConnMock{441		ReadReplies: []readResponse{442			readResponse{443				Data: []byte{0x0D},444			},445			readResponse{446				Data: []byte{447					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,448					0x51, 0x55, 0x49, 0x54, 0x10,449				},450			},451			readResponse{452				Data: []byte{0x20, 0xF0, 0x00, 0x00},453			},454		},455	}456	expected := "Family bits contained an invalid value: 15"457	connectionTestWrapper(t, conn, expected)458}459func TestProxyListener_readBinary_InvalidProtocolBits(t *testing.T) {460	conn := &ConnMock{461		ReadReplies: []readResponse{462			readResponse{463				Data: []byte{0x0D},464			},465			readResponse{466				Data: []byte{467					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,468					0x51, 0x55, 0x49, 0x54, 0x10,469				},470			},471			readResponse{472				Data: []byte{0x20, 0x0F, 0x00, 0x00},473			},474		},475	}476	expected := "Protocol bits contained an invalid value: 15"477	connectionTestWrapper(t, conn, expected)478}479func TestProxyListener_readBinary_LengthTooLarge(t *testing.T) {480	conn := &ConnMock{481		ReadReplies: []readResponse{482			readResponse{483				Data: []byte{0x0D},484			},485			readResponse{486				Data: []byte{487					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,488					0x51, 0x55, 0x49, 0x54, 0x10,489				},490			},491			readResponse{492				Data: []byte{0x20, 0x00, 0xEE, 0xFF},493			},494		},495	}496	expected := "Length integer is too large to be valid: 61183"497	connectionTestWrapper(t, conn, expected)498}499func TestProxyListener_readBinary_ErrReadingAddressData(t *testing.T) {500	conn := &ConnMock{501		ReadReplies: []readResponse{502			readResponse{503				Data: []byte{0x0D},504			},505			readResponse{506				Data: []byte{507					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,508					0x51, 0x55, 0x49, 0x54, 0x10,509				},510			},511			readResponse{512				Data: []byte{0x20, 0x00, 0x00, 0x01},513			},514			readResponse{515				Error: fmt.Errorf("EXPECTED"),516			},517		},518	}519	expected := "Error reading binary address data: EXPECTED"520	connectionTestWrapper(t, conn, expected)521}522func TestProxyListener_readBinary_SecondDeadlineError(t *testing.T) {523	conn := &ConnMock{524		DeadlineErrors: []error{nil, fmt.Errorf("EXPECTED")},525		ReadReplies: []readResponse{526			readResponse{527				Data: []byte{0x0D},528			},529			readResponse{530				Data: []byte{531					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,532					0x51, 0x55, 0x49, 0x54, 0x10,533				},534			},535			readResponse{536				Data: []byte{0x20, 0x00, 0x00, 0x00},537			},538		},539	}540	expected := "Error unsetting deadline on the socket: EXPECTED"541	connectionTestWrapper(t, conn, expected)542}543func TestProxyListener_readBinary_LocalSuccess(t *testing.T) {544	errors := make([]error, 0, 2)545	pl := &ProxyListener{546		listener: &ListenerMock{547			AcceptReplies: []acceptResponse{548				acceptResponse{Conn: &ConnMock{549					RawRemoteAddr: &AddrMock{550						network: "net",551						str:     "1.1.1.1:1",552					},553					ReadReplies: []readResponse{554						readResponse{555							Data: []byte{0x0D},556						},557						readResponse{558							Data: []byte{559								0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,560								0x51, 0x55, 0x49, 0x54, 0x10,561							},562						},563						readResponse{564							Data: []byte{0x20, 0x00, 0x00, 0x00},565						},566						readResponse{567							Data: []byte("OK"),568						},569					},570				}},571			},572		},573		errorChan:  make(chan error),574		acceptChan: make(chan net.Conn),575		ProtocolError: func(err error) {576			errors = append(errors, err)577		},578		ProtocolDeadline: time.Second,579	}580	pl.waitGroup.Add(1)581	go pl.goAcceptRoutine()582	// Check the results.583	if len(errors) != 0 {584		t.Logf("%#v", errors)585		t.Fatalf("No error expected, at least one returned.")586	}587	select {588	case conn := <-pl.acceptChan:589		data := make([]byte, 2)590		if conn.RemoteAddr().String() != "1.1.1.1:1" {591			t.Fatalf(592				"The Addr was not passed through properly: %s",593				conn.RemoteAddr())594		} else if n, err := conn.Read(data); err != nil {595			t.Fatalf("Error reading post-proxy data: %s", err)596		} else if n != 2 {597			t.Fatalf("Unknown read size: %d", n)598		} else if !bytes.Equal(data, []byte("OK")) {599			t.Fatalf("Unexpected response (expected OK): %#v", data)600		}601	case <-time.NewTimer(time.Millisecond * 10).C:602		t.Fatalf("No connection was passed to the channel.")603	}604	// Stop the processor.605	<-pl.errorChan606	pl.Stop()607}608func TestProxyListener_readBinary_TCPIPv4AddressTooLong(t *testing.T) {609	conn := &ConnMock{610		ReadReplies: []readResponse{611			readResponse{612				Data: []byte{0x0D},613			},614			readResponse{615				Data: []byte{616					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,617					0x51, 0x55, 0x49, 0x54, 0x10,618				},619			},620			readResponse{621				Data: []byte{0x21, 0x11, 0x00, 0x00},622			},623		},624	}625	expected := "Invalid address length for a INET proxy (should be 12): 0"626	connectionTestWrapper(t, conn, expected)627}628func TestProxyListener_readBinary_TCPOverIPv4(t *testing.T) {629	errors := make([]error, 0, 2)630	pl := &ProxyListener{631		listener: &ListenerMock{632			AcceptReplies: []acceptResponse{633				acceptResponse{Conn: &ConnMock{634					RawRemoteAddr: &AddrMock{635						network: "net",636						str:     "0.0.0.0:0",637					},638					ReadReplies: []readResponse{639						readResponse{640							Data: []byte{0x0D},641						},642						readResponse{643							Data: []byte{644								0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,645								0x51, 0x55, 0x49, 0x54, 0x10,646							},647						},648						readResponse{649							Data: []byte{0x21, 0x11, 0x00, 0x0C},650						},651						readResponse{652							Data: []byte{0x01, 0x02, 0x03, 0x04},653						},654						readResponse{655							Data: []byte{0x05, 0x06, 0x07, 0x08},656						},657						readResponse{658							Data: []byte{0x09, 0x0A},659						},660						readResponse{661							Data: []byte{0x0B, 0x0C},662						},663						readResponse{664							Data: []byte("OK"),665						},666					},667				}},668			},669		},670		errorChan:  make(chan error),671		acceptChan: make(chan net.Conn),672		ProtocolError: func(err error) {673			errors = append(errors, err)674		},675		ProtocolDeadline: time.Second,676	}677	pl.waitGroup.Add(1)678	go pl.goAcceptRoutine()679	// Check the results.680	if len(errors) != 0 {681		t.Logf("%#v", errors)682		t.Fatalf("No error expected, at least one returned.")683	}684	select {685	case conn := <-pl.acceptChan:686		data := make([]byte, 2)687		if conn.RemoteAddr().String() != "1.2.3.4:2314" {688			t.Fatalf(689				"The Addr was not passed through properly: %s",690				conn.RemoteAddr())691		} else if n, err := conn.Read(data); err != nil {692			t.Fatalf("Error reading post-proxy data: %s", err)693		} else if n != 2 {694			t.Fatalf("Unknown read size: %d", n)695		} else if !bytes.Equal(data, []byte("OK")) {696			t.Fatalf("Unexpected response (expected OK): %#v", data)697		}698	case <-time.NewTimer(time.Millisecond * 10).C:699		t.Fatalf("No connection was passed to the channel.")700	}701	// Stop the processor.702	<-pl.errorChan703	pl.Stop()704}705func TestProxyListener_readBinary_UDPIPv4AddressTooLong(t *testing.T) {706	conn := &ConnMock{707		ReadReplies: []readResponse{708			readResponse{709				Data: []byte{0x0D},710			},711			readResponse{712				Data: []byte{713					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,714					0x51, 0x55, 0x49, 0x54, 0x10,715				},716			},717			readResponse{718				Data: []byte{0x21, 0x12, 0x00, 0x00},719			},720		},721	}722	expected := "Invalid address length for a INET proxy (should be 12): 0"723	connectionTestWrapper(t, conn, expected)724}725func TestProxyListener_readBinary_UDPOverIPv4(t *testing.T) {726	errors := make([]error, 0, 2)727	pl := &ProxyListener{728		listener: &ListenerMock{729			AcceptReplies: []acceptResponse{730				acceptResponse{Conn: &ConnMock{731					RawRemoteAddr: &AddrMock{732						network: "net",733						str:     "0.0.0.0:0",734					},735					ReadReplies: []readResponse{736						readResponse{737							Data: []byte{0x0D},738						},739						readResponse{740							Data: []byte{741								0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,742								0x51, 0x55, 0x49, 0x54, 0x10,743							},744						},745						readResponse{746							Data: []byte{0x21, 0x12, 0x00, 0x0C},747						},748						readResponse{749							Data: []byte{0x01, 0x02, 0x03, 0x04},750						},751						readResponse{752							Data: []byte{0x05, 0x06, 0x07, 0x08},753						},754						readResponse{755							Data: []byte{0x09, 0x0A},756						},757						readResponse{758							Data: []byte{0x0B, 0x0C},759						},760						readResponse{761							Data: []byte("OK"),762						},763					},764				}},765			},766		},767		errorChan:  make(chan error),768		acceptChan: make(chan net.Conn),769		ProtocolError: func(err error) {770			errors = append(errors, err)771		},772		ProtocolDeadline: time.Second,773	}774	pl.waitGroup.Add(1)775	go pl.goAcceptRoutine()776	// Check the results.777	if len(errors) != 0 {778		t.Logf("%#v", errors)779		t.Fatalf("No error expected, at least one returned.")780	}781	select {782	case conn := <-pl.acceptChan:783		data := make([]byte, 2)784		if conn.RemoteAddr().String() != "1.2.3.4:2314" {785			t.Fatalf(786				"The Addr was not passed through properly: %s",787				conn.RemoteAddr())788		} else if n, err := conn.Read(data); err != nil {789			t.Fatalf("Error reading post-proxy data: %s", err)790		} else if n != 2 {791			t.Fatalf("Unknown read size: %d", n)792		} else if !bytes.Equal(data, []byte("OK")) {793			t.Fatalf("Unexpected response (expected OK): %#v", data)794		}795	case <-time.NewTimer(time.Millisecond * 10).C:796		t.Fatalf("No connection was passed to the channel.")797	}798	// Stop the processor.799	<-pl.errorChan800	pl.Stop()801}802func TestProxyListener_readBinary_TCPIPv6AddressTooLong(t *testing.T) {803	conn := &ConnMock{804		ReadReplies: []readResponse{805			readResponse{806				Data: []byte{0x0D},807			},808			readResponse{809				Data: []byte{810					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,811					0x51, 0x55, 0x49, 0x54, 0x10,812				},813			},814			readResponse{815				Data: []byte{0x21, 0x21, 0x00, 0x00},816			},817		},818	}819	expected := "Invalid address length for a INET6 proxy (should be 36): 0"820	connectionTestWrapper(t, conn, expected)821}822func TestProxyListener_readBinary_TCPOverIPv6(t *testing.T) {823	errors := make([]error, 0, 2)824	pl := &ProxyListener{825		listener: &ListenerMock{826			AcceptReplies: []acceptResponse{827				acceptResponse{Conn: &ConnMock{828					RawRemoteAddr: &AddrMock{829						network: "net",830						str:     "0.0.0.0:0",831					},832					ReadReplies: []readResponse{833						readResponse{834							Data: []byte{0x0D},835						},836						readResponse{837							Data: []byte{838								0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,839								0x51, 0x55, 0x49, 0x54, 0x10,840							},841						},842						readResponse{843							Data: []byte{0x21, 0x21, 0x00, 0x24},844						},845						readResponse{846							Data: []byte{847								0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,848								0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,849							},850						},851						readResponse{852							Data: []byte{853								0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,854								0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,855							},856						},857						readResponse{858							Data: []byte{0x09, 0x0A},859						},860						readResponse{861							Data: []byte{0x0B, 0x0C},862						},863						readResponse{864							Data: []byte("OK"),865						},866					},867				}},868			},869		},870		errorChan:  make(chan error),871		acceptChan: make(chan net.Conn),872		ProtocolError: func(err error) {873			errors = append(errors, err)874		},875		ProtocolDeadline: time.Second,876	}877	pl.waitGroup.Add(1)878	go pl.goAcceptRoutine()879	// Check the results.880	if len(errors) != 0 {881		t.Logf("%#v", errors)882		t.Fatalf("No error expected, at least one returned.")883	}884	select {885	case conn := <-pl.acceptChan:886		addrExpected := "[1:203:405:607:809:a0b:c0d:e0f]:2314"887		data := make([]byte, 2)888		if conn.RemoteAddr().String() != addrExpected {889			t.Fatalf(890				"The Addr was not passed through properly: %s",891				conn.RemoteAddr())892		} else if n, err := conn.Read(data); err != nil {893			t.Fatalf("Error reading post-proxy data: %s", err)894		} else if n != 2 {895			t.Fatalf("Unknown read size: %d", n)896		} else if !bytes.Equal(data, []byte("OK")) {897			t.Fatalf("Unexpected response (expected OK): %#v", data)898		}899	case <-time.NewTimer(time.Millisecond * 10).C:900		t.Fatalf("No connection was passed to the channel.")901	}902	// Stop the processor.903	<-pl.errorChan904	pl.Stop()905}906func TestProxyListener_readBinary_UDPIPv6AddressTooLong(t *testing.T) {907	conn := &ConnMock{908		ReadReplies: []readResponse{909			readResponse{910				Data: []byte{0x0D},911			},912			readResponse{913				Data: []byte{914					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,915					0x51, 0x55, 0x49, 0x54, 0x10,916				},917			},918			readResponse{919				Data: []byte{0x21, 0x22, 0x00, 0x00},920			},921		},922	}923	expected := "Invalid address length for a INET6 proxy (should be 36): 0"924	connectionTestWrapper(t, conn, expected)925}926func TestProxyListener_readBinary_UDPOverIPv6(t *testing.T) {927	errors := make([]error, 0, 2)928	pl := &ProxyListener{929		listener: &ListenerMock{930			AcceptReplies: []acceptResponse{931				acceptResponse{Conn: &ConnMock{932					RawRemoteAddr: &AddrMock{933						network: "net",934						str:     "0.0.0.0:0",935					},936					ReadReplies: []readResponse{937						readResponse{938							Data: []byte{0x0D},939						},940						readResponse{941							Data: []byte{942								0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,943								0x51, 0x55, 0x49, 0x54, 0x10,944							},945						},946						readResponse{947							Data: []byte{0x21, 0x22, 0x00, 0x24},948						},949						readResponse{950							Data: []byte{951								0x0F, 0x0E, 0x0D, 0x0C, 0x0B, 0x0A, 0x09, 0x08,952								0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00,953							},954						},955						readResponse{956							Data: []byte{957								0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,958								0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,959							},960						},961						readResponse{962							Data: []byte{0x09, 0x0A},963						},964						readResponse{965							Data: []byte{0x0B, 0x0C},966						},967						readResponse{968							Data: []byte("OK"),969						},970					},971				}},972			},973		},974		errorChan:  make(chan error),975		acceptChan: make(chan net.Conn),976		ProtocolError: func(err error) {977			errors = append(errors, err)978		},979		ProtocolDeadline: time.Second,980	}981	pl.waitGroup.Add(1)982	go pl.goAcceptRoutine()983	// Check the results.984	if len(errors) != 0 {985		t.Logf("%#v", errors)986		t.Fatalf("No error expected, at least one returned.")987	}988	select {989	case conn := <-pl.acceptChan:990		addrExpected := "[f0e:d0c:b0a:908:706:504:302:100]:2314"991		data := make([]byte, 2)992		if conn.RemoteAddr().String() != addrExpected {993			t.Fatalf(994				"The Addr was not passed through properly: %s",995				conn.RemoteAddr())996		} else if n, err := conn.Read(data); err != nil {997			t.Fatalf("Error reading post-proxy data: %s", err)998		} else if n != 2 {999			t.Fatalf("Unknown read size: %d", n)1000		} else if !bytes.Equal(data, []byte("OK")) {1001			t.Fatalf("Unexpected response (expected OK): %#v", data)1002		}1003	case <-time.NewTimer(time.Millisecond * 10).C:1004		t.Fatalf("No connection was passed to the channel.")1005	}1006	// Stop the processor.1007	<-pl.errorChan1008	pl.Stop()1009}1010func TestProxyListener_readBinary_UnspportedCombination(t *testing.T) {1011	conn := &ConnMock{1012		ReadReplies: []readResponse{1013			readResponse{1014				Data: []byte{0x0D},1015			},1016			readResponse{1017				Data: []byte{1018					0x0AD, 0x0D, 0x0A, 0x00, 0x0D, 0x0A,1019					0x51, 0x55, 0x49, 0x54, 0x10,1020				},1021			},1022			readResponse{1023				Data: []byte{0x21, 0x32, 0x00, 0x00},1024			},1025			readResponse{1026				Data: bytes.Repeat([]byte{0}, 36),1027			},1028		},1029	}1030	expected := "Unsupported family/protocol combination."1031	connectionTestWrapper(t, conn, expected)1032}1033func TestProxyListener_Accept_Error(t *testing.T) {1034	p := &ProxyListener{1035		errorChan:  make(chan error, 1),1036		acceptChan: make(chan net.Conn, 1),1037	}1038	p.errorChan <- fmt.Errorf("EXPECTED")1039	conn, err := p.Accept()...readResponse
Using AI Code Generation
1func main() {2    conn := new(conn)3    conn.readResponse()4}5func main() {6    conn := new(conn)7    conn.readResponse()8}9./1.go:7: conn.readResponse undefined (type *conn has no field or method readResponse)10./2.go:7: conn.readResponse undefined (type *conn has no field or method readResponse)11func main() {12    conn := new(conn)13    conn.(*conn).readResponse()14}15func main() {16    conn := new(conn)17    conn.(*conn).readResponse()18}readResponse
Using AI Code Generation
1import (2func main() {3	conn, err := net.Dial("tcp", "localhost:8080")4	if err != nil {5		log.Fatal(err)6	}7	defer conn.Close()8	if err != nil {9		log.Fatal(err)10	}11	err = req.Write(conn)12	if err != nil {13		log.Fatal(err)14	}15	resp, err := http.ReadResponse(bufio.NewReader(conn), req)16	if err != nil {17		log.Fatal(err)18	}19	fmt.Println("Response status:", resp.Status)20	body, err := ioutil.ReadAll(resp.Body)21	if err != nil {22		log.Fatal(err)23	}24	fmt.Println("Response body:", string(body))25}readResponse
Using AI Code Generation
1import (2func main() {3    jar, _ := cookiejar.New(nil)4    client := http.Client{5    }6    resp, _ := client.Do(req)7    fmt.Println(resp.Cookies())8}9[{GOOGAPPUIDreadResponse
Using AI Code Generation
1import (2func main() {3    if err != nil {4        fmt.Println("Error: ", err)5    }6    fmt.Println("Response Status: ", resp.Status)7    fmt.Println("Response Headers: ", resp.Header)8    fmt.Println("Response Body: ", resp.Body)9}10Response Headers:  map[Content-Type:[text/html; charset=UTF-8] Date:[Thu, 11 Feb 2021 13:47:17 GMT] Expires:[-1] P3p:[CP="This is not a P3P policy! See g.co/p3phelp for more info."] Server:[gws] Set-Cookie:[1P_JAR=2021-02-11-13; expires=Sat, 13-Mar-2021 13:47:17 GMT; path=/; domain=.google.com; Secure, NID=204=Z6U5J6Q2m1f5R6jKkH8F7A2gMzRZfJxgKj8d1O3qg3Jy7pZUVdS0eI7ZJ0XZTz1t4v4tj0f0GJfFw4wSfSd8cPjTtX9Tz1i4Q4Dj8LsNtP4e4M; expires=Fri, 11-Aug-2021 13:47:17 GMT; path=/; domain=.google.com; HttpOnly; Secure] Transfer-Encoding:[chunked]]11import (12func main() {13    if err != nil {14        fmt.Println("Error: ", err)15    }16    defer resp.Body.Close()17    body, err := ioutil.ReadAll(resp.Body)18    if err != nil {19        fmt.Println("Error: ", err)20    }21    fmt.Println("Response Body: ", string(body))22}readResponse
Using AI Code Generation
1import (2func main() {3	fmt.Println("Hello, World!")4}5import (6func main() {7	fmt.Println("Hello, World!")8}9import (10func main() {11	fmt.Println("Hello, World!")12}13import (14func main() {15	fmt.Println("Hello, World!")16}17import (18func main() {19	fmt.Println("Hello, World!")20}21import (22func main() {23	fmt.Println("Hello, World!")24}25import (26func main() {27	fmt.Println("Hello, World!")28}29import (30func main() {31	fmt.Println("Hello, World!")32}33import (34func main() {35	fmt.Println("Hello, World!")36}37import (38func main() {39	fmt.Println("Hello, World!")40}Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!
