Browse Source

Response 'peeking' rewrite, auth cache for Digest pending

Eugene Fryntov 10 năm trước cách đây
mục cha
commit
8987c81d71

+ 14 - 15
psiphon/upstreamproxy/transport_proxy_auth.go

@@ -30,6 +30,8 @@ import (
 	"strings"
 	"strings"
 )
 )
 
 
+const HTTP_STAT_LINE_LENGTH = 12
+
 // ProxyAuthTransport provides support for proxy authentication when doing plain HTTP
 // ProxyAuthTransport provides support for proxy authentication when doing plain HTTP
 // by tapping into HTTP conversation and adding authentication headers to the requests
 // by tapping into HTTP conversation and adding authentication headers to the requests
 // when requested by server
 // when requested by server
@@ -92,13 +94,11 @@ type transportConn struct {
 	requestInterceptor io.Writer
 	requestInterceptor io.Writer
 	reqDone            chan struct{}
 	reqDone            chan struct{}
 	errChannel         chan error
 	errChannel         chan error
-	// a buffered Reader from the raw net.Conn so we could Peek at the data
-	// without advancing the 'read' pointer
-	connReader *bufio.Reader
 	// last written request holder
 	// last written request holder
 	lastRequest   *http.Request
 	lastRequest   *http.Request
 	authenticator HttpAuthenticator
 	authenticator HttpAuthenticator
 	authState     HttpAuthState
 	authState     HttpAuthState
+	authCache     string
 	transport     *ProxyAuthTransport
 	transport     *ProxyAuthTransport
 }
 }
 
 
@@ -107,7 +107,6 @@ func newTransportConn(c net.Conn, tr *ProxyAuthTransport) *transportConn {
 		Conn:       c,
 		Conn:       c,
 		reqDone:    make(chan struct{}),
 		reqDone:    make(chan struct{}),
 		errChannel: make(chan error),
 		errChannel: make(chan error),
-		connReader: bufio.NewReader(c),
 		transport:  tr,
 		transport:  tr,
 	}
 	}
 	// Intercept outgoing request as it is written out to server and store it
 	// Intercept outgoing request as it is written out to server and store it
@@ -115,10 +114,11 @@ func newTransportConn(c net.Conn, tr *ProxyAuthTransport) *transportConn {
 	//NOTE that pipelining is currently not supported
 	//NOTE that pipelining is currently not supported
 	pr, pw := io.Pipe()
 	pr, pw := io.Pipe()
 	tc.requestInterceptor = pw
 	tc.requestInterceptor = pw
+	requestReader := bufio.NewReader(pr)
 	go func() {
 	go func() {
 	requestInterceptLoop:
 	requestInterceptLoop:
 		for {
 		for {
-			req, err := http.ReadRequest(bufio.NewReader(pr))
+			req, err := http.ReadRequest(requestReader)
 			if err != nil {
 			if err != nil {
 				tc.Conn.Close()
 				tc.Conn.Close()
 				pr.Close()
 				pr.Close()
@@ -139,20 +139,21 @@ func newTransportConn(c net.Conn, tr *ProxyAuthTransport) *transportConn {
 
 
 // Read peeks into the new response and checks if the proxy requests authentication
 // Read peeks into the new response and checks if the proxy requests authentication
 // If so, the last intercepted request is authenticated against the response
 // If so, the last intercepted request is authenticated against the response
-// authentication challenge and replayed
-func (tc *transportConn) Read(p []byte) (int, error) {
-	peeked, err := tc.connReader.Peek(12)
-	if err != nil {
-		return 0, err
+func (tc *transportConn) Read(p []byte) (n int, err error) {
+	n, err = tc.Conn.Read(p)
+	if n < HTTP_STAT_LINE_LENGTH {
+		return
 	}
 	}
-	line := string(peeked)
 	select {
 	select {
 	case _ = <-tc.reqDone:
 	case _ = <-tc.reqDone:
+		line := string(p[:HTTP_STAT_LINE_LENGTH])
 		//This is a new response
 		//This is a new response
 		//Let's see if proxy requests authentication
 		//Let's see if proxy requests authentication
 		f := strings.SplitN(line, " ", 2)
 		f := strings.SplitN(line, " ", 2)
+		readBufferReader := bytes.NewReader(p)
+		responseReader := io.MultiReader(readBufferReader, tc.Conn)
 		if (f[0] == "HTTP/1.0" || f[0] == "HTTP/1.1") && f[1] == "407" {
 		if (f[0] == "HTTP/1.0" || f[0] == "HTTP/1.1") && f[1] == "407" {
-			resp, err := http.ReadResponse(tc.connReader, nil)
+			resp, err := http.ReadResponse(bufio.NewReader(responseReader), nil)
 			if err != nil {
 			if err != nil {
 				return 0, err
 				return 0, err
 			}
 			}
@@ -178,7 +179,6 @@ func (tc *transportConn) Read(p []byte) (int, error) {
 				if err != nil {
 				if err != nil {
 					return 0, err
 					return 0, err
 				}
 				}
-				tc.connReader = bufio.NewReader(tc.Conn)
 			}
 			}
 
 
 			// Authenticate and replay the request
 			// Authenticate and replay the request
@@ -193,8 +193,7 @@ func (tc *transportConn) Read(p []byte) (int, error) {
 		return 0, err
 		return 0, err
 	default:
 	default:
 	}
 	}
-	n, err := tc.connReader.Read(p)
-	return n, err
+	return
 }
 }
 
 
 func (tc *transportConn) Write(p []byte) (n int, err error) {
 func (tc *transportConn) Write(p []byte) (n int, err error) {