MCPcopy
hub / github.com/connectrpc/connect-go / ServeHTTP

Method ServeHTTP

handler.go:259–338  ·  view source on GitHub ↗

ServeHTTP implements [http.Handler].

(responseWriter http.ResponseWriter, request *http.Request)

Source from the content-addressed store, hash-verified

257
258// ServeHTTP implements [http.Handler].
259func (h *Handler) ServeHTTP(responseWriter http.ResponseWriter, request *http.Request) {
260 // We don't need to defer functions to close the request body or read to
261 // EOF: the stream we construct later on already does that, and we only
262 // return early when dealing with misbehaving clients. In those cases, it's
263 // okay if we can't re-use the connection.
264 isBidi := (h.spec.StreamType & StreamTypeBidi) == StreamTypeBidi
265 if isBidi && request.ProtoMajor < 2 {
266 // Clients coded to expect full-duplex connections may hang if they've
267 // mistakenly negotiated HTTP/1.1. To unblock them, we must close the
268 // underlying TCP connection.
269 responseWriter.Header().Set("Connection", "close")
270 responseWriter.WriteHeader(http.StatusHTTPVersionNotSupported)
271 return
272 }
273
274 protocolHandlers := h.protocolHandlers[request.Method]
275 if len(protocolHandlers) == 0 {
276 responseWriter.Header().Set("Allow", h.allowMethod)
277 responseWriter.WriteHeader(http.StatusMethodNotAllowed)
278 return
279 }
280
281 contentType := canonicalizeContentType(getHeaderCanonical(request.Header, headerContentType))
282
283 // Find our implementation of the RPC protocol in use.
284 var protocolHandler protocolHandler
285 for _, handler := range protocolHandlers {
286 if handler.CanHandlePayload(request, contentType) {
287 protocolHandler = handler
288 break
289 }
290 }
291 if protocolHandler == nil {
292 responseWriter.Header().Set("Accept-Post", h.acceptPost)
293 responseWriter.WriteHeader(http.StatusUnsupportedMediaType)
294 return
295 }
296
297 if request.Method == http.MethodGet {
298 // A body must not be present.
299 hasBody := request.ContentLength > 0
300 if request.ContentLength < 0 {
301 // No content-length header.
302 // Test if body is empty by trying to read a single byte.
303 var b [1]byte
304 n, _ := request.Body.Read(b[:])
305 hasBody = n > 0
306 }
307 if hasBody {
308 responseWriter.WriteHeader(http.StatusUnsupportedMediaType)
309 return
310 }
311 _ = request.Body.Close()
312 }
313
314 // Establish a stream and serve the RPC.
315 setHeaderCanonical(request.Header, headerContentType, contentType)
316 setHeaderCanonical(request.Header, headerHost, request.Host)

Callers 15

NewAuthenticatedHandlerFunction · 0.80
TestGetNoContentHeadersFunction · 0.80
TestServerFunction · 0.80
NewCollideServiceHandlerFunction · 0.80
NewPingServiceHandlerFunction · 0.80
NewCollideServiceHandlerFunction · 0.80
NewPingServiceHandlerFunction · 0.80
NewTestServiceHandlerFunction · 0.80
NewTestServiceHandlerFunction · 0.80

Calls 10

SetTimeoutMethod · 0.95
NewConnMethod · 0.95
canonicalizeContentTypeFunction · 0.85
getHeaderCanonicalFunction · 0.85
setHeaderCanonicalFunction · 0.85
HeaderMethod · 0.65
CanHandlePayloadMethod · 0.65
CloseMethod · 0.65
WriteHeaderMethod · 0.45
ReadMethod · 0.45

Tested by 6

NewAuthenticatedHandlerFunction · 0.64
TestGetNoContentHeadersFunction · 0.64
TestServerFunction · 0.64