// Hijack implements the http.Hijacker interface to allow a HTTP handler to
// take over the connection.
// See https://golang.org/pkg/net/http/#Hijacker
180482
func (rw *responseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return rw.ResponseWriter.(http.Hijacker).Hijack()
}
553960
func MakeHTTPHandler(handlerFunc httpAPIFunc) http.HandlerFunc {
	// Create a closure and return an anonymous function
	return func(w http.ResponseWriter, r *http.Request) {
		// Call the handler
		resp, err := handlerFunc(w, r, mux.Vars(r))
		if err != nil {
			// Log error
			log.Errorf("Handler for %s %s returned error: %s", r.Method, r.URL, err)

			if resp == nil {
				// Send HTTP response
				http.Error(w, err.Error(), http.StatusInternalServerError)
			} else {
				// Send HTTP response as Json
				content, err := json.Marshal(resp)
				if err != nil {
					http.Error(w, err.Error(), http.StatusInternalServerError)
					return
				}

				w.WriteHeader(http.StatusInternalServerError)
				w.Write(content)
			}
		} else {
			// Send HTTP response as Json
			err = writeJSON(w, http.StatusOK, resp)
			if err != nil {
				http.Error(w, err.Error(), http.StatusInternalServerError)
				return
			}
		}
	}
}
52412
func (p *Printer) Hijack(cb func(ctx *Ctx)) *Printer {
	p.mu.Lock()
	defer p.mu.Unlock()

	if p.hijack == nil {
		p.hijack = cb
		return p
	}

	oldCb := p.hijack
	newCb := cb

	// return the first failure
	p.hijack = func(ctx *Ctx) {
		oldCb(ctx)
		if ctx.continueToNext {
			newCb(ctx)
		}
	}

	return p
}
800161
func (h *HTTPBin) Handler() http.Handler {
	mux := http.NewServeMux()

	mux.HandleFunc("/", methods(h.Index, "GET"))
	mux.HandleFunc("/forms/post", methods(h.FormsPost, "GET"))
	mux.HandleFunc("/encoding/utf8", methods(h.UTF8, "GET"))

	mux.HandleFunc("/get", methods(h.Get, "GET"))
	mux.HandleFunc("/post", methods(h.RequestWithBody, "POST"))
	mux.HandleFunc("/put", methods(h.RequestWithBody, "PUT"))
	mux.HandleFunc("/patch", methods(h.RequestWithBody, "PATCH"))
	mux.HandleFunc("/delete", methods(h.RequestWithBody, "DELETE"))

	mux.HandleFunc("/ip", h.IP)
	mux.HandleFunc("/user-agent", h.UserAgent)
	mux.HandleFunc("/headers", h.Headers)
	mux.HandleFunc("/response-headers", h.ResponseHeaders)

	mux.HandleFunc("/status/", h.Status)

	mux.HandleFunc("/redirect/", h.Redirect)
	mux.HandleFunc("/relative-redirect/", h.RelativeRedirect)
	mux.HandleFunc("/absolute-redirect/", h.AbsoluteRedirect)
	mux.HandleFunc("/redirect-to", h.RedirectTo)

	mux.HandleFunc("/cookies", h.Cookies)
	mux.HandleFunc("/cookies/set", h.SetCookies)
	mux.HandleFunc("/cookies/delete", h.DeleteCookies)

	mux.HandleFunc("/basic-auth/", h.BasicAuth)
	mux.HandleFunc("/hidden-basic-auth/", h.HiddenBasicAuth)
	mux.HandleFunc("/digest-auth/", h.DigestAuth)

	mux.HandleFunc("/deflate", h.Deflate)
	mux.HandleFunc("/gzip", h.Gzip)

	mux.HandleFunc("/stream/", h.Stream)
	mux.HandleFunc("/delay/", h.Delay)
	mux.HandleFunc("/drip", h.Drip)

	mux.HandleFunc("/range/", h.Range)
	mux.HandleFunc("/bytes/", h.Bytes)
	mux.HandleFunc("/stream-bytes/", h.StreamBytes)

	mux.HandleFunc("/html", h.HTML)
	mux.HandleFunc("/robots.txt", h.Robots)
	mux.HandleFunc("/deny", h.Deny)

	mux.HandleFunc("/cache", h.Cache)
	mux.HandleFunc("/cache/", h.CacheControl)
	mux.HandleFunc("/etag/", h.ETag)

	mux.HandleFunc("/links/", h.Links)

	mux.HandleFunc("/image", h.ImageAccept)
	mux.HandleFunc("/image/", h.Image)
	mux.HandleFunc("/xml", h.XML)

	// existing httpbin endpoints that we do not support
	mux.HandleFunc("/brotli", notImplementedHandler)

	// Make sure our ServeMux doesn't "helpfully" redirect these invalid
	// endpoints by adding a trailing slash. See the ServeMux docs for more
	// info: https://golang.org/pkg/net/http/#ServeMux
	mux.HandleFunc("/absolute-redirect", http.NotFound)
	mux.HandleFunc("/basic-auth", http.NotFound)
	mux.HandleFunc("/delay", http.NotFound)
	mux.HandleFunc("/digest-auth", http.NotFound)
	mux.HandleFunc("/hidden-basic-auth", http.NotFound)
	mux.HandleFunc("/redirect", http.NotFound)
	mux.HandleFunc("/relative-redirect", http.NotFound)
	mux.HandleFunc("/status", http.NotFound)
	mux.HandleFunc("/stream", http.NotFound)
	mux.HandleFunc("/bytes", http.NotFound)
	mux.HandleFunc("/stream-bytes", http.NotFound)
	mux.HandleFunc("/links", http.NotFound)

	// Apply global middleware
	var handler http.Handler
	handler = mux
	handler = limitRequestSize(h.MaxBodySize, handler)
	handler = preflight(handler)
	handler = autohead(handler)
	if h.Observer != nil {
		handler = observe(h.Observer, handler)
	}

	return handler
}
986078
func (rww *ResponseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if hj, ok := rww.ResponseWriter.(http.Hijacker); ok {
		return hj.Hijack()
	}
	return nil, nil, NonHijackerError{Underlying: rww.ResponseWriter}
}
615817
func (u Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	if hijacker, ok := w.(http.Hijacker); ok {
		if !u.DisableDirect && r.Method == "PRI" && r.URL.Path == "*" && r.Proto == "HTTP/2.0" {
			body := "SM\r\n\r\n"
			con, rw, err := hijacker.Hijack()
			defer con.Close()
			if err != nil {
				log.Printf("Hijack failed %v", err)
			} else if n, err := io.MultiReader(r.Body, rw).Read([]byte(body)); n != len(body) {
				log.Printf("%d %v", n, err)
			} else {
				wrap := io.MultiReader(bytes.NewBuffer([]byte(http2.ClientPreface)), rw)
				nc := &conn{
					Conn:   con,
					Writer: rw.Writer,
					Reader: wrap,
				}
				h2c := &http2.Server{}
				h2c.ServeConn(nc, &http2.ServeConnOpts{Handler: u.Handler})
				return
			}
			http.Error(w, "Server could not handle the request.", http.StatusMethodNotAllowed)
			return
		}
		if initReq := InitH2c(r); initReq != nil {
			fsz := uint32(1 << 14) // RFC default
			for _, s := range initReq.Settings {
				if s.ID == http2.SettingMaxFrameSize && s.Val != 0 {
					fsz = s.Val
				}
			}
			onError := func(e error) {
				log.Print(e)
				http.Error(w, "Error in upgrading initial request", http.StatusInternalServerError)
			}

			h2req := bytes.NewBuffer([]byte(http2.ClientPreface))
			fr := http2.NewFramer(h2req, nil)

			if err := fr.WriteSettings(initReq.Settings...); err != nil {
				onError(err)
				return
			}

			hdr := initReq.HeaderBlock
			if uint32(len(hdr)) <= fsz {
				if err := fr.WriteHeaders(http2.HeadersFrameParam{
					StreamID:      1,
					BlockFragment: hdr,
					EndHeaders:    true,
				}); err != nil {
					onError(err)
					return
				}
			} else {
				if err := fr.WriteHeaders(http2.HeadersFrameParam{
					StreamID:      1,
					BlockFragment: hdr[:fsz],
				}); err != nil {
					onError(err)
					return
				}
				hdr = hdr[fsz:]
				for len(hdr) > 0 {
					if uint32(len(hdr)) > fsz {
						if err := fr.WriteContinuation(1, false, hdr[:fsz]); err != nil {
							onError(err)
							return
						}
						hdr = hdr[fsz:]
					} else {
						if err := fr.WriteContinuation(1, true, hdr); err != nil {
							onError(err)
							return
						}
						hdr = nil
					}
				}
			}

			con, rw, err := hijacker.Hijack()
			// Note: It seems rw is a wrapper for con.
			// r.Body.Read still looks working unless rw.Read call.
			defer con.Close()
			if err != nil {
				onError(err)
				rw.Flush()
				return
			}

			rw.Write([]byte(
				"HTTP/1.1 101 Switching Protocols\r\n" +
					"Connection: upgrade\r\n" +
					"Upgrade: h2c\r\n" +
					"\r\n"))

			h2req2 := &h2cInitReqBody{
				Framer:    fr,
				Buffer:    h2req,
				Body:      r.Body,
				FrameSize: fsz,
			}
			nc := &conn{
				Conn:      con,
				Writer:    rw.Writer,
				Reader:    io.MultiReader(h2req2, vacuumPreface{rw}, rw),
				vacuumAck: true, // because we sent HTTP2-Settings payload
			}
			h2c := &http2.Server{}
			for _, s := range initReq.Settings {
				switch s.ID {
				case http2.SettingMaxConcurrentStreams:
					h2c.MaxConcurrentStreams = s.Val
				case http2.SettingMaxFrameSize:
					h2c.MaxReadFrameSize = s.Val
				default:
					// just ignore
				}
			}
			h2c.ServeConn(nc, &http2.ServeConnOpts{Handler: u.Handler})
			return
		}
	}
	if u.Handler != nil {
		u.Handler.ServeHTTP(w, r)
	} else {
		http.DefaultServeMux.ServeHTTP(w, r)
	}
	return
}
236630
func (b *BufferWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if hi, ok := b.W.(http.Hijacker); ok {
		return hi.Hijack()
	}
	log.Debugf("Upstream ResponseWriter of type %v does not implement http.Hijacker. Returning dummy channel.", reflect.TypeOf(b.W))
	return nil, nil, fmt.Errorf("the response writer that was wrapped in this proxy, does not implement http.Hijacker. It is of type: %v", reflect.TypeOf(b.W))
}
325725
func (rww *responseWriterWrapper) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	if hj, ok := rww.w.(http.Hijacker); ok {
		return hj.Hijack()
	}
	return nil, nil, httpserver.NonHijackerError{Underlying: rww.w}
}
813033
func (c Chain) Handler(xh HandlerC) http.Handler {
	ctx := context.Background()
	return c.HandlerCtx(ctx, xh)
}
205909
func (rl *respLogger) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	rl.hijacked = true
	return rl.w.(http.Hijacker).Hijack()
}
654950
func (r *responseRecorderWithoutCloseNotify) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	return r.responseWriter.(http.Hijacker).Hijack()
}
729082
func (cli *Client) postHijacked(ctx context.Context, path string, query url.Values, body interface{}, headers map[string][]string) (types.HijackedResponse, error) {
	bodyEncoded, err := encodeData(body)
	if err != nil {
		return types.HijackedResponse{}, err
	}

	apiPath := cli.getAPIPath(ctx, path, query)
	req, err := http.NewRequest("POST", apiPath, bodyEncoded)
	if err != nil {
		return types.HijackedResponse{}, err
	}
	req = cli.addHeaders(req, headers)

	conn, err := cli.setupHijackConn(ctx, req, "tcp")
	if err != nil {
		return types.HijackedResponse{}, err
	}

	return types.HijackedResponse{Conn: conn, Reader: bufio.NewReader(conn)}, err
}
382552
func (client *Client) Handler(h http.Handler) http.Handler {
	if h == nil {
		h = http.DefaultServeMux
	}
	fn := func(w http.ResponseWriter, r *http.Request) {
		defer func() {
			if err := recover(); err != nil {
				client.Notify(newError(err, 2), Params(r.Form), getCGIData(r), *r.URL)
				panic(err)
			}
		}()
		h.ServeHTTP(w, r)
	}
	return http.HandlerFunc(fn)
}
590187
func (r *hijackRecorder) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	rw := bufio.NewReadWriter(bufio.NewReader(r.conn), bufio.NewWriter(r.conn))
	return r.conn, rw, nil
}
86159
func (h *handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
	// Skip compression if the client doesn't accept gzip encoding.
	if !strings.Contains(r.Header.Get(headerAcceptEncoding), encodingGzip) {
		h.next.ServeHTTP(w, r)
		return
	}

	// Skip compression if client attempt WebSocket connection
	if len(r.Header.Get(headerSecWebSocketKey)) > 0 {
		h.next.ServeHTTP(w, r)
		return
	}

	// Create new gzip Writer. Skip compression if an invalid compression
	// level was set.
	gz, err := gzip.NewWriterLevel(w, h.compressionLevel)
	if err != nil {
		h.next.ServeHTTP(w, r)
		return
	}
	defer gz.Close()

	// Set the appropriate gzip headers.
	headers := w.Header()
	headers.Set(headerContentEncoding, encodingGzip)
	headers.Set(headerVary, headerAcceptEncoding)

	grw := gzipResponseWriter{
		gz,
		w,
	}

	// Call the h.next.ServeHTTP handler supplying the gzipResponseWriter instead of
	// the original.
	h.next.ServeHTTP(grw, r)

}
255618
func (r *hijackRecorder) WriteHeader(code int) {
	resp := http.Response{StatusCode: code, Header: r.Header()}
	_ = resp.Write(r.conn)
}
194735
func (h *HijackedResponse) CloseWrite() error {
	if conn, ok := h.Conn.(CloseWriter); ok {
		return conn.CloseWrite()
	}
	return nil
}