github.com/gramework/gramework@v1.8.1-0.20231027140105-82555c9057f5/adaptor.go (about) 1 package gramework 2 3 import ( 4 "io" 5 "net/http" 6 "net/url" 7 ) 8 9 type ( 10 netHTTPBody struct { 11 b []byte 12 } 13 14 netHTTPResponseWriter struct { 15 statusCode int 16 h http.Header 17 body []byte 18 } 19 ) 20 21 // NewGrameHandlerFunc wraps net/http handler func to gramework 22 // request handler, so it can be passed to gramework router. 23 // 24 // While this function may be used for easy switching from net/http to gramework, 25 // it has the following drawbacks comparing to using manually written gramework 26 // request handler: 27 // 28 // * A lot of useful functionality provided by fasthttp is missing 29 // from net/http handler. 30 // * net/http -> fasthttp handler conversion has some overhead, 31 // so the returned handler will be always slower than manually written 32 // fasthttp handler. 33 // 34 // So it is advisable using this function only for quick net/http -> fasthttp 35 // switching. Then manually convert net/http handlers to fasthttp handlers 36 // according to https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp . 37 // 38 // This adaptor is a fork of https://github.com/valyala/fasthttp/tree/master/fasthttpadaptor 39 // We're embedding it because we don't want additional allocation, but we need exactly gramework 40 // request handler, not fasthttp request handler. 41 // The package provides helper functions for converting net/http 42 // request handlers to fasthttp request handlers. 43 // See the original license in /3rd-Party Licenses/fasthttp 44 func NewGrameHandlerFunc(h http.HandlerFunc) RequestHandler { 45 return NewGrameHandler(h) 46 } 47 48 // NewGrameHandler wraps net/http handler to fasthttp request handler, 49 // so it can be passed to fasthttp server. 50 // 51 // While this function may be used for easy switching from net/http to fasthttp, 52 // it has the following drawbacks comparing to using manually written fasthttp 53 // request handler: 54 // 55 // * A lot of useful functionality provided by fasthttp is missing 56 // from net/http handler. 57 // * net/http -> fasthttp handler conversion has some overhead, 58 // so the returned handler will be always slower than manually written 59 // fasthttp handler. 60 // 61 // So it is advisable using this function only for quick net/http -> fasthttp 62 // switching. Then manually convert net/http handlers to fasthttp handlers 63 // according to https://github.com/valyala/fasthttp#switching-from-nethttp-to-fasthttp . 64 // 65 // This adaptor is a fork of https://github.com/valyala/fasthttp/tree/master/fasthttpadaptor 66 // We're embedding it because we don't want additional allocation, but we need exactly gramework 67 // request handler, not fasthttp request handler. 68 // The package provides helper functions for converting net/http 69 // request handlers to fasthttp request handlers. 70 // See the original license in /3rd-Party Licenses/fasthttp 71 func NewGrameHandler(h http.Handler) RequestHandler { 72 return func(ctx *Context) { 73 var r http.Request 74 75 body := ctx.PostBody() 76 r.Method = string(ctx.Method()) 77 r.Proto = "HTTP/1.1" 78 r.ProtoMajor = 1 79 r.ProtoMinor = 1 80 r.RequestURI = string(ctx.RequestURI()) 81 r.ContentLength = int64(len(body)) 82 r.Host = string(ctx.Host()) 83 r.RemoteAddr = ctx.RemoteAddr().String() 84 85 hdr := make(http.Header) 86 ctx.Request.Header.VisitAll(func(k, v []byte) { 87 sk := string(k) 88 sv := string(v) 89 switch sk { 90 case "Transfer-Encoding": 91 r.TransferEncoding = append(r.TransferEncoding, sv) 92 default: 93 hdr.Set(sk, sv) 94 } 95 }) 96 r.Header = hdr 97 r.Body = &netHTTPBody{body} 98 rURL, err := url.ParseRequestURI(r.RequestURI) 99 if err != nil { 100 ctx.Logger.Errorf("cannot parse requestURI %q: %s", r.RequestURI, err) 101 ctx.Err500("Internal Server Error") 102 return 103 } 104 r.URL = rURL 105 106 var w netHTTPResponseWriter 107 h.ServeHTTP(&w, &r) 108 109 ctx.SetStatusCode(w.StatusCode()) 110 for k, vv := range w.Header() { 111 for _, v := range vv { 112 ctx.Response.Header.Set(k, v) 113 } 114 } 115 _, e := ctx.Write(w.body) 116 _ = e // handled separately, but got a false-positive linter check 117 } 118 } 119 120 func (r *netHTTPBody) Read(p []byte) (int, error) { 121 if len(r.b) == 0 { 122 return 0, io.EOF 123 } 124 n := copy(p, r.b) 125 r.b = r.b[n:] 126 return n, nil 127 } 128 129 func (r *netHTTPBody) Close() error { 130 r.b = r.b[:0] 131 return nil 132 } 133 134 func (w *netHTTPResponseWriter) StatusCode() int { 135 if w.statusCode == 0 { 136 return http.StatusOK 137 } 138 return w.statusCode 139 } 140 141 func (w *netHTTPResponseWriter) Header() http.Header { 142 if w.h == nil { 143 w.h = make(http.Header) 144 } 145 return w.h 146 } 147 148 func (w *netHTTPResponseWriter) WriteHeader(statusCode int) { 149 w.statusCode = statusCode 150 } 151 152 func (w *netHTTPResponseWriter) Write(p []byte) (int, error) { 153 w.body = append(w.body, p...) 154 return len(p), nil 155 }