func doChunkedResponse(w http.ResponseWriter, resp *http.Response, client *httputil.ClientConn) { wf, ok := w.(writeFlusher) if !ok { http.Error(w, "Error forwarding chunked response body: flush not available", http.StatusInternalServerError) return } w.WriteHeader(resp.StatusCode) up, remaining := client.Hijack() defer up.Close() var err error chunks := bufio.NewScanner(io.MultiReader(remaining, up)) chunks.Split(splitChunks) for chunks.Scan() && err == nil { _, err = wf.Write(chunks.Bytes()) wf.Flush() } if err == nil { err = chunks.Err() } if err != nil { Log.Errorf("Error forwarding chunked response body: %s", err) } }
func (ctx *runContext) connectToRunServer() (*http.Response, net.Conn, error) { if ctx.attachURL == "" { return nil, nil, errgo.New("No attach URL to connect to") } req, err := http.NewRequest("CONNECT", ctx.attachURL, nil) if err != nil { return nil, nil, errgo.Mask(err, errgo.Any) } req.SetBasicAuth("", config.AuthenticatedUser.AuthenticationToken) url, err := url.Parse(ctx.attachURL) if err != nil { return nil, nil, errgo.Mask(err, errgo.Any) } dial, err := net.Dial("tcp", url.Host) if err != nil { return nil, nil, errgo.Mask(err, errgo.Any) } var conn *httputil.ClientConn if url.Scheme == "https" { host := strings.Split(url.Host, ":")[0] config := *config.TlsConfig config.ServerName = host tls_conn := tls.Client(dial, &config) conn = httputil.NewClientConn(tls_conn, nil) } else if url.Scheme == "http" { conn = httputil.NewClientConn(dial, nil) } else { return nil, nil, errgo.Newf("Invalid scheme format %s", url.Scheme) } res, err := conn.Do(req) if err != httputil.ErrPersistEOF && err != nil { if err, ok := err.(*net.OpError); ok { if err.Err.Error() == "record overflow" { return nil, nil, errgo.Newf( "Fail to create a secure connection to Scalingo server\n"+ "The encountered error is: %v (ID: CLI-1001)\n"+ "Your firewall or proxy may block the connection to %s", err, url.Host, ) } } return nil, nil, errgo.Mask(err, errgo.Any) } connection, _ := conn.Hijack() return res, connection, nil }
func hijack(w http.ResponseWriter, client *httputil.ClientConn) (down net.Conn, downBuf *bufio.ReadWriter, up net.Conn, remaining io.Reader, err error) { hj, ok := w.(http.Hijacker) if !ok { err = errors.New("Unable to cast to Hijack") return } down, downBuf, err = hj.Hijack() if err != nil { return } up, remaining = client.Hijack() return }
func (p *Peer) enterLoop(con *httputil.ClientConn) { c, rw := con.Hijack() reader := json.NewDecoder(rw) writer := json.NewEncoder(c) log.Printf("################################################################### Entering peer loop for peer: %s\n", p.Name) for { /* switch { case <-p.stopForward: log.Printf("Peer %s received a stop request\n", p.Name) o := make(chan bool) go func(){ p.stopForward <- true o <- true }() <-o return default: */ execCmd := &ExecuteCommand{} execCmdReply := &ExecuteCommandReply{} err := reader.Decode(execCmd) if err != nil { log.Printf("############## Peer %s Decoding incoming message failed: %v\n", p.Name, err) return } else { log.Printf("############ Peer %s Decoding incoming message success: %v\n", p.Name, execCmd) iface, err := p.server.Do(execCmd) log.Printf("############# Peer %s Executed command. Result: %v, Error: %v\n", p.Name, iface, err) execCmdReply.Error = err out, ok := iface.(*sql.Output) if ok { execCmdReply.Output = *out } } err = writer.Encode(execCmdReply) if err != nil { return } // } } }
func (s *httpService) handle(req *http.Request, sc *httputil.ServerConn, tls, sticky bool) { for { req.Header.Set("X-Request-Start", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)) var backend *httputil.ClientConn var stickyCookie *http.Cookie if sticky { backend, stickyCookie = s.getBackendSticky(req) } else { backend = s.getBackend() } if backend == nil { log.Println("no backend found") fail(sc, req, 503, "Service Unavailable") return } if req.Method != "GET" && req.Method != "POST" && req.Method != "HEAD" && req.Method != "OPTIONS" && req.Method != "PUT" && req.Method != "DELETE" && req.Method != "TRACE" { fail(sc, req, 405, "Method not allowed") return } req.Proto = "HTTP/1.1" req.ProtoMajor = 1 req.ProtoMinor = 1 delete(req.Header, "Te") delete(req.Header, "Transfer-Encoding") if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { // If we aren't the first proxy retain prior // X-Forwarded-For information as a comma+space // separated list and fold multiple headers into one. if prior, ok := req.Header["X-Forwarded-For"]; ok { clientIP = strings.Join(prior, ", ") + ", " + clientIP } req.Header.Set("X-Forwarded-For", clientIP) } if tls { req.Header.Set("X-Forwarded-Proto", "https") } else { req.Header.Set("X-Forwarded-Proto", "http") } // TODO: Set X-Forwarded-Port if err := backend.Write(req); err != nil { log.Println("server write err:", err) return } res, err := backend.Read(req) if res != nil { if stickyCookie != nil { res.Header.Add("Set-Cookie", stickyCookie.String()) } if res.StatusCode == http.StatusSwitchingProtocols { res.Body = nil } if err := sc.Write(req, res); err != nil { if err != io.EOF && err != httputil.ErrPersistEOF { log.Println("client write err:", err) // TODO: log error } return } } if err != nil { if err != io.EOF && err != httputil.ErrPersistEOF { log.Println("server read err:", err) // TODO: log error fail(sc, req, 502, "Bad Gateway") } return } // TODO: Proxy HTTP CONNECT? (example: Go RPC over HTTP) if res.StatusCode == http.StatusSwitchingProtocols { serverW, serverR := backend.Hijack() clientW, clientR := sc.Hijack() defer serverW.Close() done := make(chan struct{}) go func() { serverR.WriteTo(clientW) if cw, ok := clientW.(writeCloser); ok { cw.CloseWrite() } close(done) }() clientR.WriteTo(serverW) serverW.(writeCloser).CloseWrite() <-done return } // close the backend connection, so we don't accidently send to // a closed socket on the backend backend.Close() // TODO: http pipelining req, err = sc.Read() if err != nil { if err != io.EOF && err != httputil.ErrPersistEOF { log.Println("client read err:", err) } return } } }
func (s *httpService) handle(req *http.Request, sc *httputil.ServerConn, tls, sticky bool) (done bool) { req.Header.Set("X-Request-Start", strconv.FormatInt(time.Now().UnixNano()/int64(time.Millisecond), 10)) req.Header.Set("X-Request-Id", random.UUID()) var backend *httputil.ClientConn var stickyCookie *http.Cookie if sticky { backend, stickyCookie = s.getBackendSticky(req) } else { backend = s.getBackend() } if backend == nil { log.Println("no backend found") fail(sc, req, 503, "Service Unavailable") return } defer backend.Close() req.Proto = "HTTP/1.1" req.ProtoMajor = 1 req.ProtoMinor = 1 delete(req.Header, "Te") delete(req.Header, "Transfer-Encoding") if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { // If we aren't the first proxy retain prior // X-Forwarded-For information as a comma+space // separated list and fold multiple headers into one. if prior, ok := req.Header["X-Forwarded-For"]; ok { clientIP = strings.Join(prior, ", ") + ", " + clientIP } req.Header.Set("X-Forwarded-For", clientIP) } if tls { req.Header.Set("X-Forwarded-Proto", "https") } else { req.Header.Set("X-Forwarded-Proto", "http") } // TODO: Set X-Forwarded-Port // Pass the Request-URI verbatim without any modifications req.URL.Opaque = strings.Split(strings.TrimPrefix(req.RequestURI, req.URL.Scheme+":"), "?")[0] if err := backend.Write(req); err != nil { log.Println("server write err:", err) // TODO: return error to client here return true } res, err := backend.Read(req) if res != nil { if stickyCookie != nil { res.Header.Add("Set-Cookie", stickyCookie.String()) } if res.StatusCode == http.StatusSwitchingProtocols { res.Body = nil } if err := sc.Write(req, res); err != nil { if err != io.EOF && err != httputil.ErrPersistEOF { log.Println("client write err:", err) // TODO: log error } return true } } if err != nil { if err != io.EOF && err != httputil.ErrPersistEOF { log.Println("server read err:", err) // TODO: log error fail(sc, req, 502, "Bad Gateway") } return } // TODO: Proxy HTTP CONNECT? (example: Go RPC over HTTP) if res.StatusCode == http.StatusSwitchingProtocols { serverW, serverR := backend.Hijack() clientW, clientR := sc.Hijack() defer serverW.Close() done := make(chan struct{}) go func() { serverR.WriteTo(clientW) if cw, ok := clientW.(writeCloser); ok { cw.CloseWrite() } close(done) }() clientR.WriteTo(serverW) serverW.(writeCloser).CloseWrite() <-done return true } return }