golang如何将http请求流转到gin( 二 )

比较关键的几行代码是第31行和第61行,他们做的事情分别是接收到请求并解析请求数据,使用新的goroutines处理该请求 。接着我们需要看看golang具体是如何处理接收到的请求
// Serve a new connection.func (c *conn) serve(ctx context.Context) {c.remoteAddr = c.rwc.RemoteAddr().String()ctx = context.WithValue(ctx, LocalAddrContextKey, c.rwc.LocalAddr())defer func() {if err := recover(); err != nil && err != ErrAbortHandler {const size = 64 << 10buf := make([]byte, size)buf = buf[:runtime.Stack(buf, false)]c.server.logf("http: panic serving %v: %vn%s", c.remoteAddr, err, buf)}if !c.hijacked() {c.close()c.setState(c.rwc, StateClosed, runHooks)}}()if tlsConn, ok := c.rwc.(*tls.Conn); ok {if d := c.server.ReadTimeout; d > 0 {c.rwc.SetReadDeadline(time.Now().Add(d))}if d := c.server.WriteTimeout; d > 0 {c.rwc.SetWriteDeadline(time.Now().Add(d))}if err := tlsConn.HandshakeContext(ctx); err != nil {// If the handshake failed due to the client not speaking// TLS, assume they're speaking plaintext HTTP and write a// 400 response on the TLS conn's underlying net.Conn.if re, ok := err.(tls.RecordHeaderError); ok && re.Conn != nil && tlsRecordHeaderLooksLikeHTTP(re.RecordHeader) {io.WriteString(re.Conn, "HTTP/1.0 400 Bad RequestrnrnClient sent an HTTP request to an HTTPS server.n")re.Conn.Close()return}c.server.logf("http: TLS handshake error from %s: %v", c.rwc.RemoteAddr(), err)return}c.tlsState = new(tls.ConnectionState)*c.tlsState = tlsConn.ConnectionState()if proto := c.tlsState.NegotiatedProtocol; validNextProto(proto) {if fn := c.server.TLSNextProto[proto]; fn != nil {h := initALPNRequest{ctx, tlsConn, serverHandler{c.server}}// Mark freshly created HTTP/2 as active and prevent any server state hooks// from being run on these connections. This prevents closeIdleConns from// closing such connections. See issue https://golang.org/issue/39776.c.setState(c.rwc, StateActive, skipHooks)fn(c.server, tlsConn, h)}return}}// HTTP/1.x from here on.ctx, cancelCtx := context.WithCancel(ctx)c.cancelCtx = cancelCtxdefer cancelCtx()c.r = &connReader{conn: c}c.bufr = newBufioReader(c.r)c.bufw = newBufioWriterSize(checkConnErrorWriter{c}, 4<<10)for {w, err := c.readRequest(ctx)if c.r.remain != c.server.initialReadLimitSize() {// If we read any bytes off the wire, we're active.c.setState(c.rwc, StateActive, runHooks)}if err != nil {const errorHeaders = "rnContent-Type: text/plain; charset=utf-8rnConnection: closernrn"switch {case err == errTooLarge:// Their HTTP client may or may not be// able to read this if we're// responding to them and hanging up// while they're still writing their// request. Undefined behavior.const publicErr = "431 Request Header Fields Too Large"fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)c.closeWriteAndWait()returncase isUnsupportedTEError(err):// Respond as per RFC 7230 Section 3.3.1 which says,//A server that receives a request message with a//transfer coding it does not understand SHOULD//respond with 501 (Unimplemented).code := StatusNotImplemented// We purposefully aren't echoing back the transfer-encoding's value,// so as to mitigate the risk of cross side scripting by an attacker.fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s%sUnsupported transfer encoding", code, StatusText(code), errorHeaders)returncase isCommonNetReadError(err):return // don't replydefault:if v, ok := err.(statusError); ok {fmt.Fprintf(c.rwc, "HTTP/1.1 %d %s: %s%s%d %s: %s", v.code, StatusText(v.code), v.text, errorHeaders, v.code, StatusText(v.code), v.text)return}publicErr := "400 Bad Request"fmt.Fprintf(c.rwc, "HTTP/1.1 "+publicErr+errorHeaders+publicErr)return}}// Expect 100 Continue supportreq := w.reqif req.expectsContinue() {if req.ProtoAtLeast(1, 1) && req.ContentLength != 0 {// Wrap the Body reader with one that replies on the connectionreq.Body = &expectContinueReader{readCloser: req.Body, resp: w}w.canWriteContinue.setTrue()}} else if req.Header.get("Expect") != "" {w.sendExpectationFailed()return}c.curReq.Store(w)if requestBodyRemains(req.Body) {registerOnHitEOF(req.Body, w.conn.r.startBackgroundRead)} else {w.conn.r.startBackgroundRead()}// HTTP cannot have multiple simultaneous active requests.[*]// Until the server replies to this request, it can't read another,// so we might as well run the handler in this goroutine.// [*] Not strictly true: HTTP pipelining. We could let them all process// in parallel even if their responses need to be serialized.// But we're not going to implement HTTP pipelining because it// was never deployed in the wild and the answer is HTTP/2.serverHandler{c.server}.ServeHTTP(w, w.req)w.cancelCtx()if c.hijacked() {return}w.finishRequest()if !w.shouldReuseConnection() {if w.requestBodyLimitHit || w.closedRequestBodyEarly() {c.closeWriteAndWait()}return}c.setState(c.rwc, StateIdle, runHooks)c.curReq.Store((*response)(nil))if !w.conn.server.doKeepAlives() {// We're in shutdown mode. We might've replied// to the user without "Connection: close" and// they might think they can send another// request, but such is life with HTTP/1.1.return}if d := c.server.idleTimeout(); d != 0 {c.rwc.SetReadDeadline(time.Now().Add(d))if _, err := c.bufr.Peek(4); err != nil {return}}c.rwc.SetReadDeadline(time.Time{})}}


推荐阅读