MCPcopy
hub / github.com/monasticacademy/httptap / proxyHTTPScheme

Function proxyHTTPScheme

http.go:185–302  ·  view source on GitHub ↗

Service an incoming HTTP connection on conn by sending a request out to the world through dst. If the URL in the request does not contain a scheme, use the specified scheme for the proxied request.

(dst http.RoundTripper, conn net.Conn, outgoingScheme string)

Source from the content-addressed store, hash-verified

183// Service an incoming HTTP connection on conn by sending a request out to the world through dst.
184// If the URL in the request does not contain a scheme, use the specified scheme for the proxied request.
185func proxyHTTPScheme(dst http.RoundTripper, conn net.Conn, outgoingScheme string) {
186 defer handlePanic()
187 defer conn.Close()
188
189 verbosef("intercepted a connection to %v", conn.LocalAddr())
190
191 // wrap the connection with a byte counter
192 counts := countBytesConn{Conn: conn}
193 conn = &counts
194
195 // read the HTTP request (TODO: support HTTP/2 using golang.org/x/net/http2)
196 req, err := http.ReadRequest(bufio.NewReader(conn))
197 if err != nil {
198 errorf("error reading http request over tls server conn: %v, aborting", err)
199 return
200 }
201 defer req.Body.Close()
202
203 verbosef("decoded an HTTP request for %v sent to %v", req.URL, conn.LocalAddr())
204
205 // the request may contain a relative URL but we need an absolute URL for call to RoundTrip
206 if req.URL.Host == "" {
207 req.URL.Host = req.Host
208 if req.URL.Host == "" {
209 req.URL.Host = conn.LocalAddr().String()
210 }
211 }
212 if req.URL.Scheme == "" {
213 req.URL.Scheme = outgoingScheme
214 }
215
216 // add the IP to which we intercepted packets as a context variable
217 req = req.WithContext(context.WithValue(req.Context(), dialToContextKey, conn.LocalAddr().String()))
218
219 // capture the request body into memory for inspection later
220 var reqbody bytes.Buffer
221 req.Body = TeeReadCloser(req.Body, &reqbody)
222
223 // it seems that harlog assumes that request.GetBody will be non-nil whenever request.Body is non-nil
224 req.GetBody = func() (io.ReadCloser, error) { return req.Body, nil }
225
226 // do roundtrip to the actual server in the world -- we use RoundTrip here because
227 // we do not want to follow redirects or accumulate our own cookies
228 resp, err := dst.RoundTrip(req)
229 if err != nil {
230 // error here means the server hostname could not be resolved, or a TCP connection could not be made,
231 // or TLS could not be negotiated, or something like that
232 errbody := []byte(err.Error())
233 resp = &http.Response{
234 Proto: "HTTP/1.1",
235 ProtoMajor: 1,
236 ProtoMinor: 1,
237 Status: http.StatusText(http.StatusBadGateway),
238 StatusCode: http.StatusBadGateway,
239 Header: make(http.Header),
240 ContentLength: int64(len(errbody)),
241 Body: io.NopCloser(bytes.NewReader(errbody)),
242 }

Callers 2

proxyHTTPSFunction · 0.85
proxyHTTPFunction · 0.85

Calls 12

handlePanicFunction · 0.85
decodeContentFunction · 0.85
notifyHTTPFunction · 0.85
RoundTripMethod · 0.80
verbosefFunction · 0.70
errorfFunction · 0.70
TeeReadCloserFunction · 0.70
LocalAddrMethod · 0.65
WriteMethod · 0.65
CloseMethod · 0.45
StringMethod · 0.45
ErrorMethod · 0.45

Tested by

no test coverage detected