github.com/cloudwego/kitex@v0.9.0/pkg/generic/descriptor/http.go (about) 1 /* 2 * Copyright 2021 CloudWeGo Authors 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 package descriptor 18 19 import ( 20 "errors" 21 "net/http" 22 "net/url" 23 24 "github.com/bytedance/sonic/ast" 25 dhttp "github.com/cloudwego/dynamicgo/http" 26 27 "github.com/cloudwego/kitex/pkg/utils" 28 ) 29 30 // MIMEType ... 31 type MIMEType string 32 33 const ( 34 MIMEApplicationJson = "application/json" 35 MIMEApplicationProtobuf = "application/x-protobuf" 36 ) 37 38 var ( 39 _ dhttp.RequestGetter = &HTTPRequest{} 40 _ dhttp.ResponseSetter = &HTTPResponse{} 41 ) 42 43 // HTTPRequest ... 44 type HTTPRequest struct { 45 Params *Params // path params 46 Request *http.Request 47 RawBody []byte 48 Body map[string]interface{} 49 GeneralBody interface{} // body of other representation, used with ContentType 50 ContentType MIMEType 51 cookies map[string]string 52 query url.Values 53 bodyMap *ast.Node 54 } 55 56 // GetHeader implements http.RequestGetter of dynamicgo 57 func (req *HTTPRequest) GetHeader(key string) string { 58 return req.Request.Header.Get(key) 59 } 60 61 // GetCookie implements http.RequestGetter of dynamicgo 62 func (req *HTTPRequest) GetCookie(key string) string { 63 if req.cookies == nil { 64 req.cookies = map[string]string{} 65 for _, cookie := range req.Request.Cookies() { 66 req.cookies[cookie.Name] = cookie.Value 67 } 68 } 69 return req.cookies[key] 70 } 71 72 // GetQuery implements http.RequestGetter of dynamicgo 73 func (req *HTTPRequest) GetQuery(key string) string { 74 if req.Request.URL == nil { 75 return "" 76 } 77 if req.query == nil { 78 req.query = req.Request.URL.Query() 79 } 80 return req.query.Get(key) 81 } 82 83 // GetBody implements http.RequestGetter of dynamicgo 84 func (req *HTTPRequest) GetBody() []byte { 85 return req.RawBody 86 } 87 88 // GetMethod implements http.RequestGetter of dynamicgo 89 func (req *HTTPRequest) GetMethod() string { 90 return req.Request.Method 91 } 92 93 // GetPath implements http.RequestGetter of dynamicgo 94 func (req *HTTPRequest) GetPath() string { 95 if req.Request.URL == nil { 96 return "" 97 } 98 return req.Request.URL.Path 99 } 100 101 // GetHost implements http.RequestGetter of dynamicgo 102 func (req *HTTPRequest) GetHost() string { 103 return req.Request.Host 104 } 105 106 // GetParam implements http.RequestGetter of dynamicgo 107 func (req *HTTPRequest) GetParam(key string) string { 108 return req.Params.ByName(key) 109 } 110 111 // GetMapBody implements http.RequestGetter of dynamicgo 112 func (req *HTTPRequest) GetMapBody(key string) string { 113 if err := req.initializeBodyMap(); err != nil { 114 return "" 115 } 116 117 v := req.bodyMap.Get(key) 118 if v.Check() != nil { 119 return "" 120 } 121 if _, err := v.Raw(); err != nil { 122 return "" 123 } 124 j, err := v.String() 125 if err != nil { 126 return "" 127 } 128 return j 129 } 130 131 // GetPostForm implements http.RequestGetter of dynamicgo 132 func (req *HTTPRequest) GetPostForm(key string) string { 133 return req.Request.PostFormValue(key) 134 } 135 136 // GetUri implements http.RequestGetter of dynamicgo 137 func (req *HTTPRequest) GetUri() string { 138 if req.Request.URL == nil { 139 return "" 140 } 141 return req.Request.URL.String() 142 } 143 144 func (req *HTTPRequest) initializeBodyMap() error { 145 if req.bodyMap == nil { 146 if len(req.RawBody) == 0 { 147 return errors.New("the length of RawBody is 0") 148 } 149 body := req.RawBody 150 s := utils.SliceByteToString(body) 151 node := ast.NewRaw(s) 152 req.bodyMap = &node 153 } 154 return nil 155 } 156 157 // HTTPResponse ... 158 type HTTPResponse struct { 159 Header http.Header 160 StatusCode int32 161 RawBody []byte // this field is set only when generic.UseRawBodyForHTTPResp(true) is set 162 Body map[string]interface{} 163 GeneralBody interface{} // body of other representation, used with ContentType 164 ContentType MIMEType 165 Renderer Renderer 166 } 167 168 // NewHTTPResponse HTTP response for JSON body 169 func NewHTTPResponse() *HTTPResponse { 170 return &HTTPResponse{ 171 Header: http.Header{}, 172 ContentType: MIMEApplicationJson, 173 Body: map[string]interface{}{}, 174 Renderer: JsonRenderer{}, 175 } 176 } 177 178 // SetStatusCode implements http.ResponseSetter of dynamicgo 179 func (resp *HTTPResponse) SetStatusCode(code int) error { 180 resp.StatusCode = int32(code) 181 return nil 182 } 183 184 // SetHeader implements http.ResponseSetter of dynamicgo 185 func (resp *HTTPResponse) SetHeader(key, val string) error { 186 resp.Header.Set(key, val) 187 return nil 188 } 189 190 // SetCookie implements http.ResponseSetter of dynamicgo 191 func (resp *HTTPResponse) SetCookie(key, val string) error { 192 // kitex generic call does not care about Cookie 193 return nil 194 } 195 196 // SetRawBody implements http.ResponseSetter of dynamicgo 197 func (resp *HTTPResponse) SetRawBody(body []byte) error { 198 resp.RawBody = body 199 return nil 200 } 201 202 func NewHTTPPbResponse(initBody interface{}) *HTTPResponse { 203 return &HTTPResponse{ 204 Header: http.Header{}, 205 ContentType: MIMEApplicationProtobuf, 206 GeneralBody: initBody, 207 Renderer: PbRenderer{}, 208 } 209 } 210 211 // NewGeneralHTTPResponse init response with given MIMEType and body 212 func NewGeneralHTTPResponse(contentType MIMEType, initBody interface{}, renderer Renderer) *HTTPResponse { 213 return &HTTPResponse{ 214 Header: http.Header{}, 215 ContentType: contentType, 216 GeneralBody: initBody, 217 Renderer: renderer, 218 } 219 } 220 221 // Write to ResponseWriter 222 func (resp *HTTPResponse) Write(w http.ResponseWriter) error { 223 w.WriteHeader(int(resp.StatusCode)) 224 for k := range resp.Header { 225 w.Header().Set(k, resp.Header.Get(k)) 226 } 227 228 resp.Renderer.WriteContentType(w) 229 230 if resp.Body != nil { 231 return resp.Renderer.Render(w, resp.Body) 232 } 233 234 return resp.Renderer.Render(w, resp.GeneralBody) 235 } 236 237 // Param in request path 238 type Param struct { 239 Key string 240 Value string 241 } 242 243 // Params and recyclable 244 type Params struct { 245 params []Param 246 recycle func(*Params) 247 recycled bool 248 } 249 250 // Recycle the Params 251 func (ps *Params) Recycle() { 252 if ps.recycled { 253 return 254 } 255 ps.recycled = true 256 ps.recycle(ps) 257 } 258 259 // ByName search Param by given name 260 func (ps *Params) ByName(name string) string { 261 for _, p := range ps.params { 262 if p.Key == name { 263 return p.Value 264 } 265 } 266 return "" 267 }