func (s *HttpServer) forwardRequest(req *http.Request) { last := s.Base.Chain.lastNode if last == nil { return } cc, err := s.Base.Chain.GetConn() if err != nil { glog.V(LWARNING).Infof("[http] %s -> %s : %s", s.conn.RemoteAddr(), last.Addr, err) b := []byte("HTTP/1.1 503 Service unavailable\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n") glog.V(LDEBUG).Infof("[http] %s <- %s\n%s", s.conn.RemoteAddr(), last.Addr, string(b)) s.conn.Write(b) return } defer cc.Close() if last.User != nil { req.Header.Set("Proxy-Authorization", "Basic "+base64.StdEncoding.EncodeToString([]byte(last.User.String()))) } cc.SetWriteDeadline(time.Now().Add(WriteTimeout)) if err = req.WriteProxy(cc); err != nil { glog.V(LWARNING).Infof("[http] %s -> %s : %s", s.conn.RemoteAddr(), req.Host, err) return } cc.SetWriteDeadline(time.Time{}) glog.V(LINFO).Infof("[http] %s <-> %s", s.conn.RemoteAddr(), req.Host) s.Base.transport(s.conn, cc) glog.V(LINFO).Infof("[http] %s >-< %s", s.conn.RemoteAddr(), req.Host) return }
func doRequest(req *http.Request) (*http.Response, error) { if proxyURL != nil { c, err := dial(proxyURL.Host) if err != nil { log.Println(err) return nil, err } defer c.Close() setBasicAuth(req) if err := req.WriteProxy(c); err != nil { log.Println(err) return nil, err } /* b, err := ioutil.ReadAll(c) if err != nil { log.Println(err) return nil, err } */ return http.ReadResponse(bufio.NewReader(c), req) } return http.DefaultClient.Do(req) }
func (handler *SogouProxyHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) { proxyConn := mustDialSogou(handler) timestamp := fmt.Sprintf("%08x", time.Now().Unix()) request.Header.Add("X-Sogou-Timestamp", timestamp) tag := fmt.Sprintf("%08x", sogouTagHash(timestamp+request.Host+"SogouExplorerProxy")) request.Header.Add("X-Sogou-Tag", tag) request.Header.Add("X-Sogou-Auth", "58C41A7C258CAB58167E110BB5DEF7AF/4.1.3.8107/md5") request.WriteProxy(proxyConn) hj, ok := writer.(http.Hijacker) if !ok { log.Println("ERROR: ", "webserver doesn't support hijacking", http.StatusInternalServerError) http.Error(writer, "webserver doesn't support hijacking", http.StatusInternalServerError) return } clientConn, _, err := hj.Hijack() if err != nil { log.Println("ERROR: ", err, http.StatusInternalServerError) http.Error(writer, err.Error(), http.StatusInternalServerError) return } proxyBufReader := bufio.NewReader(proxyConn) response, err := http.ReadResponse(proxyBufReader, request) if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) return } if request.Method == "CONNECT" { response.Body.Close() } else { defer response.Body.Close() } log.Printf("%s %s %s\n<- %s\n", request.RemoteAddr, request.Method, request.RequestURI, response.Status) response.Write(clientConn) if request.Method == "CONNECT" && response.StatusCode == http.StatusOK { go copyAndClose(proxyConn, clientConn) go copyAndClose(clientConn, proxyBufReader) } else { clientConn.Close() proxyConn.Close() } }
func (h *ProxyHTTPHandler) doConnect(w http.ResponseWriter, r *http.Request) { var ( clientConn net.Conn serverConn net.Conn err error ) hj, ok := w.(http.Hijacker) if !ok { http.Error(w, "", http.StatusInternalServerError) return } clientConn, _, err = hj.Hijack() if err != nil { http.Error(w, "", http.StatusInternalServerError) return } removeProxyHeaders(r) pacConn, err := h.pac.PacConn(r.URL) if err != nil { http.Error(w, "", http.StatusBadGateway) return } if pacConn != nil { serverConn, err = pacConn.Dial() if err != nil { http.Error(w, "", http.StatusBadGateway) return } defer serverConn.Close() r.WriteProxy(serverConn) } else { serverConn, err = net.Dial("tcp", r.URL.Host) if err != nil { http.Error(w, "", http.StatusBadGateway) return } defer serverConn.Close() clientConn.Write([]byte("HTTP/1.0 200 OK\r\n\r\n")) } defer clientConn.Close() defer serverConn.Close() go io.Copy(clientConn, serverConn) io.Copy(serverConn, clientConn) }
func (conn *ForwardConnection) writeHttpRequest(req *http.Request) error { var err error index := 0 for { if conn.manager.overProxy { err = req.WriteProxy(conn.forward_conn) } else { err = req.Write(conn.forward_conn) } if nil != err { log.Printf("Resend request since error:%v occured.\n", err) conn.Close() conn.initForwardConn(req.Host, strings.EqualFold(req.Method, "Connect")) } else { return nil } index++ if index == 2 { return err } } return nil }
func (client *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { r.Header.Add("Proxy-Authenticate", client.psw) c, err := net.Dial("tcp", client.remote_addr) if err != nil { //should not print log.Println(GetColorError(err)) return } defer c.Close() if tc, ok := c.(*net.TCPConn); ok { if tc.SetReadBuffer(4096*32) != nil { log.Println(GetColorError(err)) return } if tc.SetKeepAlive(true) != nil { log.Println(GetColorError(err)) return } if tc.SetKeepAlivePeriod(1*time.Minute) != nil { log.Println(GetColorError(err)) return } } conn := NewRecord(tls.Client(c, &tls.Config{InsecureSkipVerify: true}), client.lock, &client.upload, &client.download) //Send the requset to own proxy server read := bufio.NewReader(conn) if err = r.WriteProxy(conn); err != nil { log.Println(GetColorError(err)) atomic.AddUint64(&client.errCounter, 1) return } if r.Method == "CONNECT" { //send the https request resp, err := http.ReadResponse(read, r) if err != nil { log.Println(GetColorError(err)) return } defer resp.Body.Close() if resp.StatusCode != 200 { return } hij, ok := w.(http.Hijacker) if !ok { log.Println("httpserver does not support hijacking") return } proxyClient, _, e := hij.Hijack() if e != nil { log.Println("Cannot hijack connection " + e.Error()) return } //write the 200 ok to the client proxyClient.Write([]byte("HTTP/1.1 200 OK\r\n\r\n")) //connect keep the connect alive go copyAndClose(proxyClient, read) copyAndClose(conn, proxyClient) return } //read the response resp, err := http.ReadResponse(read, r) if err != nil { log.Println(GetColorError(err)) atomic.AddUint64(&client.errCounter, 1) return } defer resp.Body.Close() copyHeaders(w.Header(), resp.Header) w.WriteHeader(resp.StatusCode) io.Copy(w, resp.Body) }
func handleHttpRequest(req *http.Request, conn net.Conn, arg Args) { if glog.V(LDEBUG) { dump, err := httputil.DumpRequest(req, false) if err != nil { glog.Infoln(err) } else { glog.Infoln(string(dump)) } } glog.V(LINFO).Infoln("[http] CONNECT", req.Host) var username, password string if arg.User != nil { username = arg.User.Username() password, _ = arg.User.Password() } u, p, _ := basicAuth(req.Header.Get("Proxy-Authorization")) req.Header.Del("Proxy-Authorization") if (username != "" && u != username) || (password != "" && p != password) { resp := "HTTP/1.1 407 Proxy Authentication Required\r\n" + "Proxy-Authenticate: Basic realm=\"gost\"\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n" if _, err := conn.Write([]byte(resp)); err != nil { glog.V(LWARNING).Infoln(err) } glog.V(LDEBUG).Infoln(resp) glog.V(LWARNING).Infoln("http: proxy authentication required") return } c, err := Connect(req.Host) if err != nil { glog.V(LWARNING).Infoln("[http] CONNECT", req.Host, err) b := []byte("HTTP/1.1 503 Service unavailable\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n") glog.V(LDEBUG).Infoln(string(b)) conn.Write(b) return } defer c.Close() if req.Method == "CONNECT" { b := []byte("HTTP/1.1 200 Connection established\r\n" + "Proxy-Agent: gost/" + Version + "\r\n\r\n") glog.V(LDEBUG).Infoln(string(b)) if _, err := conn.Write(b); err != nil { glog.V(LWARNING).Infoln(err) return } } else { if len(forwardArgs) > 0 { err = req.WriteProxy(c) } else { err = req.Write(c) } if err != nil { glog.V(LWARNING).Infoln(err) return } } glog.V(LINFO).Infoln("[http] CONNECT", req.Host, "OK") Transport(conn, c) }
func LHttpRequest(L *lua.LState, r *http.Request) *lua.LTable { t := L.NewTable() t.RawSetString("body", LReadCloser(L, r.Body)) t.RawSetString("close", lua.LBool(r.Close)) t.RawSetString("content_length", lua.LNumber(r.ContentLength)) t.RawSetString("header", LHttpHeader(L, r.Header)) t.RawSetString("host", lua.LString(r.Host)) t.RawSetString("method", lua.LString(r.Method)) t.RawSetString("proto", lua.LString(r.Proto)) t.RawSetString("proto_major", lua.LNumber(r.ProtoMajor)) t.RawSetString("proto_minor", lua.LNumber(r.ProtoMinor)) t.RawSetString("remote_addr", lua.LString(r.RemoteAddr)) t.RawSetString("request_uri", lua.LString(r.RequestURI)) t.RawSetString("trailer", LHttpHeader(L, r.Trailer)) t.RawSetString("tls", lua.LNil) // Cancel <-chan struct{} // not applicable to server per net/http docs // how to make lazy? func or...? t.RawSetString("transfer_encoding", LStringSlice(L, r.TransferEncoding)) // this could be much better t.RawSetString("url", lua.LString(r.URL.String())) L.SetFuncs(t, map[string]lua.LGFunction{ // AddCookie(c *Cookie) // BasicAuth() (username, password string, ok bool) // Cookie(name string) (*Cookie, error) // Cookies() []*Cookie // FormFile(key string) (multipart.File, *multipart.FileHeader, error) // FormValue(key string) string // MultipartReader() (*multipart.Reader, error) // ParseForm() error // ParseMultipartForm(maxMemory int64) error // PostFormValue(key string) string // ProtoAtLeast(major, minor int) bool // Referer() string // SetBasicAuth(username, password string) "user_agent": func(L *lua.LState) int { L.Push(lua.LString(r.UserAgent())) return 1 }, // Write(w io.Writer) error "write": func(L *lua.LState) int { o := L.CheckAny(1) w, ok := o.(io.Writer) if !ok { L.Push(lua.LString("not a writer")) return 1 } err := r.Write(w) if err == nil { L.Push(lua.LNil) } else { L.Push(lua.LString(err.Error())) } return 1 }, // WriteProxy(w io.Writer) error "write_proxy": func(L *lua.LState) int { o := L.CheckAny(1) w, ok := o.(io.Writer) if !ok { L.Push(lua.LString("not a writer")) return 1 } err := r.WriteProxy(w) if err == nil { L.Push(lua.LNil) } else { L.Push(lua.LString(err.Error())) } return 1 }, }) return t }
func handle(con net.Conn, out string) { defer con.Close() laddr := con.LocalAddr().(*net.TCPAddr) var outs []string for _, o := range strings.Fields(out) { outs = append(outs, getHostPort(o)) } if len(outs) == 0 && laddr.Port == 443 { for _, name := range []string{"HTTPS_PROXY", "https_proxy"} { if value := os.Getenv(name); len(value) > 0 { if o := getHostPort(value); len(o) > 0 { outs = append(outs, o) } } } } if len(outs) == 0 { for _, name := range []string{"HTTP_PROXY", "http_proxy"} { if value := os.Getenv(name); len(value) > 0 { if o := getHostPort(value); len(o) > 0 { outs = append(outs, o) } } } } var v4addrs []string var v6addrs []string for _, out := range outs { if host, port, err := net.SplitHostPort(out); err != nil { log.Print("proxy config %v error %v", out, err) } else if ips, err := net.LookupIP(host); err == nil { for _, ip := range ips { if ip.To4() != nil { v4addrs = append(v4addrs, net.JoinHostPort(ip.String(), port)) } else { v6addrs = append(v6addrs, net.JoinHostPort(ip.String(), port)) } } } else { log.Print(laddr, err) } } var addrs []string if laddr.IP.To4() != nil { addrs = append(v4addrs, v6addrs...) } else { addrs = append(v6addrs, v4addrs...) } switch laddr.Port { case 80: rcon := bufio.NewReader(TimedIo{con}) getRequest := func() *http.Request { req, err := http.ReadRequest(rcon) if err != nil { if err == io.EOF { // pass } else if e, ok := err.(net.Error); ok && e.Timeout() { // pass } else { log.Print(laddr, fmt.Errorf("http.ReadRequest %v", err)) } return nil } // using Opaque and RawQuery is stable if len(req.URL.Scheme) == 0 { req.URL.Scheme = "http" if len(req.URL.Host) == 0 { req.URL.Host = req.Host } if len(req.URL.Host) == 0 { req.URL.Host = laddr.IP.String() } } return req } var req *http.Request for _, addr := range addrs { if err := func() error { var conOut net.Conn var rconOut *bufio.Reader for { if req == nil { req = getRequest() } if req == nil { return nil } if conOut == nil { var e1 error conOut, e1 = net.DialTimeout("tcp", addr, 2*time.Second) if e1 != nil { return e1 } rconOut = bufio.NewReader(TimedIo{conOut}) defer conOut.Close() } if err := req.WriteProxy(conOut); err != nil { return err } else if res, err := http.ReadResponse(rconOut, req); err != nil { return err } else { sent := make(chan bool) go func() { io.Copy(TimedIo{conOut}, req.Body) close(sent) }() res.Write(con) _ = <-sent if "keep-alive" != req.Header.Get("Connection") || "keep-alive" != res.Header.Get("Connection") { return nil } req = nil } } return nil }(); err != nil { log.Print(laddr, err) } else { return } } case 443: // tried here to use hostname from SSL ClientHello entry, // but wild clients did not support it. // like github.com/elazarl/goproxy // using github.com/inconshreveable/go-vhost req := &http.Request{ Method: "CONNECT", Host: con.LocalAddr().String(), URL: &url.URL{}, } for _, addr := range addrs { if err := func() error { conOut, err := net.DialTimeout("tcp", addr, 2*time.Second) if err != nil { return err } defer conOut.Close() if err := req.WriteProxy(conOut); err != nil { return err } else if res, err := http.ReadResponse(bufio.NewReader(TimedIo{conOut}), req); err != nil { return err } else if res.StatusCode != 200 { return fmt.Errorf("proxy error %v", res) } else { sent := make(chan bool) go func() { io.Copy(TimedIo{conOut}, TimedIo{con}) close(sent) }() io.Copy(TimedIo{con}, res.Body) _ = <-sent return nil } }(); err != nil { log.Print(laddr, err) } else { return } } } log.Printf("handle faild for %v %v", laddr, addrs) }