MCPcopy
hub / github.com/cortesi/devd / ServeHTTPContext

Method ServeHTTPContext

reverseproxy/reverseproxy.go:120–193  ·  view source on GitHub ↗

ServeHTTPContext serves HTTP with a context

(
	ctx context.Context, rw http.ResponseWriter, req *http.Request,
)

Source from the content-addressed store, hash-verified

118
119// ServeHTTPContext serves HTTP with a context
120func (p *ReverseProxy) ServeHTTPContext(
121 ctx context.Context, rw http.ResponseWriter, req *http.Request,
122) {
123 log := termlog.FromContext(ctx)
124 transport := p.Transport
125 if transport == nil {
126 transport = http.DefaultTransport
127 }
128
129 outreq := new(http.Request)
130 *outreq = *req // includes shallow copies of maps, but okay
131
132 p.Director(outreq)
133 outreq.Proto = "HTTP/1.1"
134 outreq.ProtoMajor = 1
135 outreq.ProtoMinor = 1
136 outreq.Close = false
137
138 // Remove hop-by-hop headers to the backend. Especially
139 // important is "Connection" because we want a persistent
140 // connection, regardless of what the client sent to us. This
141 // is modifying the same underlying map from req (shallow
142 // copied above) so we only copy it if necessary.
143 copiedHeaders := false
144 for _, h := range hopHeaders {
145 if outreq.Header.Get(h) != "" {
146 if !copiedHeaders {
147 outreq.Header = make(http.Header)
148 copyHeader(outreq.Header, req.Header)
149 copiedHeaders = true
150 }
151 outreq.Header.Del(h)
152 }
153 }
154
155 if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil {
156 // If we aren't the first proxy retain prior
157 // X-Forwarded-For information as a comma+space
158 // separated list and fold multiple headers into one.
159 if prior, ok := outreq.Header["X-Forwarded-For"]; ok {
160 clientIP = strings.Join(prior, ", ") + ", " + clientIP
161 }
162 outreq.Header.Set("X-Forwarded-For", clientIP)
163 }
164
165 res, err := transport.RoundTrip(outreq)
166 if err != nil {
167 log.Shout("reverse proxy error: %v", err)
168 rw.WriteHeader(http.StatusInternalServerError)
169 return
170 }
171 defer res.Body.Close()
172 if req.ContentLength > 0 {
173 log.Say(fmt.Sprintf("%s uploaded", humanize.Bytes(uint64(req.ContentLength))))
174 }
175
176 inject, err := p.Inject.Sniff(res.Body, res.Header.Get("Content-Type"))
177 if err != nil {

Callers 1

ServeHTTPMethod · 0.95

Calls 8

copyResponseMethod · 0.95
copyHeaderFunction · 0.85
WriteHeaderMethod · 0.80
SniffMethod · 0.80
HeaderMethod · 0.80
FoundMethod · 0.65
ExtraMethod · 0.65
CloseMethod · 0.45

Tested by

no test coverage detected