github.com/aacfactory/fns@v1.2.86-0.20240310083819-80d667fc0a17/transports/standard/convert.go (about) 1 /* 2 * Copyright 2023 Wang Min Xiang 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 * 16 */ 17 18 package standard 19 20 import ( 21 "bytes" 22 "github.com/aacfactory/errors" 23 "github.com/aacfactory/fns/commons/bytex" 24 "github.com/aacfactory/fns/transports" 25 "io" 26 "net/http" 27 "net/url" 28 ) 29 30 func ConvertHttpHandlerFunc(h http.HandlerFunc) transports.Handler { 31 return ConvertHttpHandler(h) 32 } 33 34 func ConvertHttpHandler(h http.Handler) transports.Handler { 35 return transports.HandlerFunc(func(writer transports.ResponseWriter, request transports.Request) { 36 var r http.Request 37 if err := ConvertRequest(request, &r, true); err != nil { 38 writer.Failed(errors.Warning("fns: convert to http.Request failed").WithCause(err)) 39 return 40 } 41 w := netHTTPResponseWriter{w: writer} 42 h.ServeHTTP(&w, r.WithContext(request)) 43 writer.SetStatus(w.StatusCode()) 44 haveContentType := false 45 for k, vv := range w.Header() { 46 if k == bytex.ToString(transports.ContentTypeHeaderName) { 47 haveContentType = true 48 } 49 50 for _, v := range vv { 51 writer.Header().Add(bytex.FromString(k), bytex.FromString(v)) 52 } 53 } 54 if !haveContentType { 55 l := 512 56 b := writer.Body() 57 if len(b) < 512 { 58 l = len(b) 59 } 60 writer.Header().Set(transports.ContentTypeHeaderName, bytex.FromString(http.DetectContentType(b[:l]))) 61 } 62 }) 63 } 64 65 func ConvertRequest(ctx transports.Request, r *http.Request, forServer bool) error { 66 body, bodyErr := ctx.Body() 67 if bodyErr != nil { 68 return bodyErr 69 } 70 strRequestURI := bytex.ToString(ctx.RequestURI()) 71 72 rURL, err := url.ParseRequestURI(strRequestURI) 73 if err != nil { 74 return err 75 } 76 77 r.Method = bytex.ToString(ctx.Method()) 78 r.Proto = bytex.ToString(ctx.Proto()) 79 if r.Proto == "HTTP/2" { 80 r.ProtoMajor = 2 81 } else { 82 r.ProtoMajor = 1 83 } 84 r.ProtoMinor = 1 85 r.ContentLength = int64(len(body)) 86 r.RemoteAddr = bytex.ToString(ctx.RemoteAddr()) 87 r.Host = bytex.ToString(ctx.Host()) 88 r.TLS = ctx.TLSConnectionState() 89 r.Body = io.NopCloser(bytes.NewReader(body)) 90 r.URL = rURL 91 92 if forServer { 93 r.RequestURI = strRequestURI 94 } 95 96 if r.Header == nil { 97 r.Header = make(http.Header) 98 } else if len(r.Header) > 0 { 99 for k := range r.Header { 100 delete(r.Header, k) 101 } 102 } 103 104 ctx.Header().Foreach(func(k []byte, vv [][]byte) { 105 sk := bytex.ToString(k) 106 for _, v := range vv { 107 sv := bytex.ToString(v) 108 switch sk { 109 case "Transfer-Encoding": 110 r.TransferEncoding = append(r.TransferEncoding, sv) 111 default: 112 r.Header.Add(sk, sv) 113 } 114 } 115 }) 116 117 return nil 118 } 119 120 type netHTTPResponseWriter struct { 121 statusCode int 122 h http.Header 123 w io.Writer 124 } 125 126 func (w *netHTTPResponseWriter) StatusCode() int { 127 if w.statusCode == 0 { 128 return http.StatusOK 129 } 130 return w.statusCode 131 } 132 133 func (w *netHTTPResponseWriter) Header() http.Header { 134 if w.h == nil { 135 w.h = make(http.Header) 136 } 137 return w.h 138 } 139 140 func (w *netHTTPResponseWriter) WriteHeader(statusCode int) { 141 w.statusCode = statusCode 142 } 143 144 func (w *netHTTPResponseWriter) Write(p []byte) (int, error) { 145 return w.w.Write(p) 146 } 147 148 func (w *netHTTPResponseWriter) Flush() {}