1 | package fasthttp
|
---|
2 |
|
---|
3 | import (
|
---|
4 | "bufio"
|
---|
5 | "bytes"
|
---|
6 | "compress/gzip"
|
---|
7 | "encoding/base64"
|
---|
8 | "errors"
|
---|
9 | "fmt"
|
---|
10 | "io"
|
---|
11 | "mime/multipart"
|
---|
12 | "net"
|
---|
13 | "os"
|
---|
14 | "sync"
|
---|
15 | "time"
|
---|
16 |
|
---|
17 | "github.com/valyala/bytebufferpool"
|
---|
18 | )
|
---|
19 |
|
---|
20 | var (
|
---|
21 | requestBodyPoolSizeLimit = -1
|
---|
22 | responseBodyPoolSizeLimit = -1
|
---|
23 | )
|
---|
24 |
|
---|
25 | // SetBodySizePoolLimit set the max body size for bodies to be returned to the pool.
|
---|
26 | // If the body size is larger it will be released instead of put back into the pool for reuse.
|
---|
27 | func SetBodySizePoolLimit(reqBodyLimit, respBodyLimit int) {
|
---|
28 | requestBodyPoolSizeLimit = reqBodyLimit
|
---|
29 | responseBodyPoolSizeLimit = respBodyLimit
|
---|
30 | }
|
---|
31 |
|
---|
32 | // Request represents HTTP request.
|
---|
33 | //
|
---|
34 | // It is forbidden copying Request instances. Create new instances
|
---|
35 | // and use CopyTo instead.
|
---|
36 | //
|
---|
37 | // Request instance MUST NOT be used from concurrently running goroutines.
|
---|
38 | type Request struct {
|
---|
39 | noCopy noCopy //nolint:unused,structcheck
|
---|
40 |
|
---|
41 | // Request header
|
---|
42 | //
|
---|
43 | // Copying Header by value is forbidden. Use pointer to Header instead.
|
---|
44 | Header RequestHeader
|
---|
45 |
|
---|
46 | uri URI
|
---|
47 | postArgs Args
|
---|
48 |
|
---|
49 | bodyStream io.Reader
|
---|
50 | w requestBodyWriter
|
---|
51 | body *bytebufferpool.ByteBuffer
|
---|
52 | bodyRaw []byte
|
---|
53 |
|
---|
54 | multipartForm *multipart.Form
|
---|
55 | multipartFormBoundary string
|
---|
56 | secureErrorLogMessage bool
|
---|
57 |
|
---|
58 | // Group bool members in order to reduce Request object size.
|
---|
59 | parsedURI bool
|
---|
60 | parsedPostArgs bool
|
---|
61 |
|
---|
62 | keepBodyBuffer bool
|
---|
63 |
|
---|
64 | // Used by Server to indicate the request was received on a HTTPS endpoint.
|
---|
65 | // Client/HostClient shouldn't use this field but should depend on the uri.scheme instead.
|
---|
66 | isTLS bool
|
---|
67 |
|
---|
68 | // Request timeout. Usually set by DoDeadline or DoTimeout
|
---|
69 | // if <= 0, means not set
|
---|
70 | timeout time.Duration
|
---|
71 |
|
---|
72 | // Use Host header (request.Header.SetHost) instead of the host from SetRequestURI, SetHost, or URI().SetHost
|
---|
73 | UseHostHeader bool
|
---|
74 | }
|
---|
75 |
|
---|
76 | // Response represents HTTP response.
|
---|
77 | //
|
---|
78 | // It is forbidden copying Response instances. Create new instances
|
---|
79 | // and use CopyTo instead.
|
---|
80 | //
|
---|
81 | // Response instance MUST NOT be used from concurrently running goroutines.
|
---|
82 | type Response struct {
|
---|
83 | noCopy noCopy //nolint:unused,structcheck
|
---|
84 |
|
---|
85 | // Response header
|
---|
86 | //
|
---|
87 | // Copying Header by value is forbidden. Use pointer to Header instead.
|
---|
88 | Header ResponseHeader
|
---|
89 |
|
---|
90 | // Flush headers as soon as possible without waiting for first body bytes.
|
---|
91 | // Relevant for bodyStream only.
|
---|
92 | ImmediateHeaderFlush bool
|
---|
93 |
|
---|
94 | bodyStream io.Reader
|
---|
95 | w responseBodyWriter
|
---|
96 | body *bytebufferpool.ByteBuffer
|
---|
97 | bodyRaw []byte
|
---|
98 |
|
---|
99 | // Response.Read() skips reading body if set to true.
|
---|
100 | // Use it for reading HEAD responses.
|
---|
101 | //
|
---|
102 | // Response.Write() skips writing body if set to true.
|
---|
103 | // Use it for writing HEAD responses.
|
---|
104 | SkipBody bool
|
---|
105 |
|
---|
106 | keepBodyBuffer bool
|
---|
107 | secureErrorLogMessage bool
|
---|
108 |
|
---|
109 | // Remote TCPAddr from concurrently net.Conn
|
---|
110 | raddr net.Addr
|
---|
111 | // Local TCPAddr from concurrently net.Conn
|
---|
112 | laddr net.Addr
|
---|
113 | }
|
---|
114 |
|
---|
115 | // SetHost sets host for the request.
|
---|
116 | func (req *Request) SetHost(host string) {
|
---|
117 | req.URI().SetHost(host)
|
---|
118 | }
|
---|
119 |
|
---|
120 | // SetHostBytes sets host for the request.
|
---|
121 | func (req *Request) SetHostBytes(host []byte) {
|
---|
122 | req.URI().SetHostBytes(host)
|
---|
123 | }
|
---|
124 |
|
---|
125 | // Host returns the host for the given request.
|
---|
126 | func (req *Request) Host() []byte {
|
---|
127 | return req.URI().Host()
|
---|
128 | }
|
---|
129 |
|
---|
130 | // SetRequestURI sets RequestURI.
|
---|
131 | func (req *Request) SetRequestURI(requestURI string) {
|
---|
132 | req.Header.SetRequestURI(requestURI)
|
---|
133 | req.parsedURI = false
|
---|
134 | }
|
---|
135 |
|
---|
136 | // SetRequestURIBytes sets RequestURI.
|
---|
137 | func (req *Request) SetRequestURIBytes(requestURI []byte) {
|
---|
138 | req.Header.SetRequestURIBytes(requestURI)
|
---|
139 | req.parsedURI = false
|
---|
140 | }
|
---|
141 |
|
---|
142 | // RequestURI returns request's URI.
|
---|
143 | func (req *Request) RequestURI() []byte {
|
---|
144 | if req.parsedURI {
|
---|
145 | requestURI := req.uri.RequestURI()
|
---|
146 | req.SetRequestURIBytes(requestURI)
|
---|
147 | }
|
---|
148 | return req.Header.RequestURI()
|
---|
149 | }
|
---|
150 |
|
---|
151 | // StatusCode returns response status code.
|
---|
152 | func (resp *Response) StatusCode() int {
|
---|
153 | return resp.Header.StatusCode()
|
---|
154 | }
|
---|
155 |
|
---|
156 | // SetStatusCode sets response status code.
|
---|
157 | func (resp *Response) SetStatusCode(statusCode int) {
|
---|
158 | resp.Header.SetStatusCode(statusCode)
|
---|
159 | }
|
---|
160 |
|
---|
161 | // ConnectionClose returns true if 'Connection: close' header is set.
|
---|
162 | func (resp *Response) ConnectionClose() bool {
|
---|
163 | return resp.Header.ConnectionClose()
|
---|
164 | }
|
---|
165 |
|
---|
166 | // SetConnectionClose sets 'Connection: close' header.
|
---|
167 | func (resp *Response) SetConnectionClose() {
|
---|
168 | resp.Header.SetConnectionClose()
|
---|
169 | }
|
---|
170 |
|
---|
171 | // ConnectionClose returns true if 'Connection: close' header is set.
|
---|
172 | func (req *Request) ConnectionClose() bool {
|
---|
173 | return req.Header.ConnectionClose()
|
---|
174 | }
|
---|
175 |
|
---|
176 | // SetConnectionClose sets 'Connection: close' header.
|
---|
177 | func (req *Request) SetConnectionClose() {
|
---|
178 | req.Header.SetConnectionClose()
|
---|
179 | }
|
---|
180 |
|
---|
181 | // SendFile registers file on the given path to be used as response body
|
---|
182 | // when Write is called.
|
---|
183 | //
|
---|
184 | // Note that SendFile doesn't set Content-Type, so set it yourself
|
---|
185 | // with Header.SetContentType.
|
---|
186 | func (resp *Response) SendFile(path string) error {
|
---|
187 | f, err := os.Open(path)
|
---|
188 | if err != nil {
|
---|
189 | return err
|
---|
190 | }
|
---|
191 | fileInfo, err := f.Stat()
|
---|
192 | if err != nil {
|
---|
193 | f.Close()
|
---|
194 | return err
|
---|
195 | }
|
---|
196 | size64 := fileInfo.Size()
|
---|
197 | size := int(size64)
|
---|
198 | if int64(size) != size64 {
|
---|
199 | size = -1
|
---|
200 | }
|
---|
201 |
|
---|
202 | resp.Header.SetLastModified(fileInfo.ModTime())
|
---|
203 | resp.SetBodyStream(f, size)
|
---|
204 | return nil
|
---|
205 | }
|
---|
206 |
|
---|
207 | // SetBodyStream sets request body stream and, optionally body size.
|
---|
208 | //
|
---|
209 | // If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
|
---|
210 | // before returning io.EOF.
|
---|
211 | //
|
---|
212 | // If bodySize < 0, then bodyStream is read until io.EOF.
|
---|
213 | //
|
---|
214 | // bodyStream.Close() is called after finishing reading all body data
|
---|
215 | // if it implements io.Closer.
|
---|
216 | //
|
---|
217 | // Note that GET and HEAD requests cannot have body.
|
---|
218 | //
|
---|
219 | // See also SetBodyStreamWriter.
|
---|
220 | func (req *Request) SetBodyStream(bodyStream io.Reader, bodySize int) {
|
---|
221 | req.ResetBody()
|
---|
222 | req.bodyStream = bodyStream
|
---|
223 | req.Header.SetContentLength(bodySize)
|
---|
224 | }
|
---|
225 |
|
---|
226 | // SetBodyStream sets response body stream and, optionally body size.
|
---|
227 | //
|
---|
228 | // If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
|
---|
229 | // before returning io.EOF.
|
---|
230 | //
|
---|
231 | // If bodySize < 0, then bodyStream is read until io.EOF.
|
---|
232 | //
|
---|
233 | // bodyStream.Close() is called after finishing reading all body data
|
---|
234 | // if it implements io.Closer.
|
---|
235 | //
|
---|
236 | // See also SetBodyStreamWriter.
|
---|
237 | func (resp *Response) SetBodyStream(bodyStream io.Reader, bodySize int) {
|
---|
238 | resp.ResetBody()
|
---|
239 | resp.bodyStream = bodyStream
|
---|
240 | resp.Header.SetContentLength(bodySize)
|
---|
241 | }
|
---|
242 |
|
---|
243 | // IsBodyStream returns true if body is set via SetBodyStream*
|
---|
244 | func (req *Request) IsBodyStream() bool {
|
---|
245 | return req.bodyStream != nil
|
---|
246 | }
|
---|
247 |
|
---|
248 | // IsBodyStream returns true if body is set via SetBodyStream*
|
---|
249 | func (resp *Response) IsBodyStream() bool {
|
---|
250 | return resp.bodyStream != nil
|
---|
251 | }
|
---|
252 |
|
---|
253 | // SetBodyStreamWriter registers the given sw for populating request body.
|
---|
254 | //
|
---|
255 | // This function may be used in the following cases:
|
---|
256 | //
|
---|
257 | // * if request body is too big (more than 10MB).
|
---|
258 | // * if request body is streamed from slow external sources.
|
---|
259 | // * if request body must be streamed to the server in chunks
|
---|
260 | // (aka `http client push` or `chunked transfer-encoding`).
|
---|
261 | //
|
---|
262 | // Note that GET and HEAD requests cannot have body.
|
---|
263 | //
|
---|
264 | /// See also SetBodyStream.
|
---|
265 | func (req *Request) SetBodyStreamWriter(sw StreamWriter) {
|
---|
266 | sr := NewStreamReader(sw)
|
---|
267 | req.SetBodyStream(sr, -1)
|
---|
268 | }
|
---|
269 |
|
---|
270 | // SetBodyStreamWriter registers the given sw for populating response body.
|
---|
271 | //
|
---|
272 | // This function may be used in the following cases:
|
---|
273 | //
|
---|
274 | // * if response body is too big (more than 10MB).
|
---|
275 | // * if response body is streamed from slow external sources.
|
---|
276 | // * if response body must be streamed to the client in chunks
|
---|
277 | // (aka `http server push` or `chunked transfer-encoding`).
|
---|
278 | //
|
---|
279 | // See also SetBodyStream.
|
---|
280 | func (resp *Response) SetBodyStreamWriter(sw StreamWriter) {
|
---|
281 | sr := NewStreamReader(sw)
|
---|
282 | resp.SetBodyStream(sr, -1)
|
---|
283 | }
|
---|
284 |
|
---|
285 | // BodyWriter returns writer for populating response body.
|
---|
286 | //
|
---|
287 | // If used inside RequestHandler, the returned writer must not be used
|
---|
288 | // after returning from RequestHandler. Use RequestCtx.Write
|
---|
289 | // or SetBodyStreamWriter in this case.
|
---|
290 | func (resp *Response) BodyWriter() io.Writer {
|
---|
291 | resp.w.r = resp
|
---|
292 | return &resp.w
|
---|
293 | }
|
---|
294 |
|
---|
295 | // BodyWriter returns writer for populating request body.
|
---|
296 | func (req *Request) BodyWriter() io.Writer {
|
---|
297 | req.w.r = req
|
---|
298 | return &req.w
|
---|
299 | }
|
---|
300 |
|
---|
301 | type responseBodyWriter struct {
|
---|
302 | r *Response
|
---|
303 | }
|
---|
304 |
|
---|
305 | func (w *responseBodyWriter) Write(p []byte) (int, error) {
|
---|
306 | w.r.AppendBody(p)
|
---|
307 | return len(p), nil
|
---|
308 | }
|
---|
309 |
|
---|
310 | type requestBodyWriter struct {
|
---|
311 | r *Request
|
---|
312 | }
|
---|
313 |
|
---|
314 | func (w *requestBodyWriter) Write(p []byte) (int, error) {
|
---|
315 | w.r.AppendBody(p)
|
---|
316 | return len(p), nil
|
---|
317 | }
|
---|
318 |
|
---|
319 | func (resp *Response) parseNetConn(conn net.Conn) {
|
---|
320 | resp.raddr = conn.RemoteAddr()
|
---|
321 | resp.laddr = conn.LocalAddr()
|
---|
322 | }
|
---|
323 |
|
---|
324 | // RemoteAddr returns the remote network address. The Addr returned is shared
|
---|
325 | // by all invocations of RemoteAddr, so do not modify it.
|
---|
326 | func (resp *Response) RemoteAddr() net.Addr {
|
---|
327 | return resp.raddr
|
---|
328 | }
|
---|
329 |
|
---|
330 | // LocalAddr returns the local network address. The Addr returned is shared
|
---|
331 | // by all invocations of LocalAddr, so do not modify it.
|
---|
332 | func (resp *Response) LocalAddr() net.Addr {
|
---|
333 | return resp.laddr
|
---|
334 | }
|
---|
335 |
|
---|
336 | // Body returns response body.
|
---|
337 | //
|
---|
338 | // The returned value is valid until the response is released,
|
---|
339 | // either though ReleaseResponse or your request handler returning.
|
---|
340 | // Do not store references to returned value. Make copies instead.
|
---|
341 | func (resp *Response) Body() []byte {
|
---|
342 | if resp.bodyStream != nil {
|
---|
343 | bodyBuf := resp.bodyBuffer()
|
---|
344 | bodyBuf.Reset()
|
---|
345 | _, err := copyZeroAlloc(bodyBuf, resp.bodyStream)
|
---|
346 | resp.closeBodyStream() //nolint:errcheck
|
---|
347 | if err != nil {
|
---|
348 | bodyBuf.SetString(err.Error())
|
---|
349 | }
|
---|
350 | }
|
---|
351 | return resp.bodyBytes()
|
---|
352 | }
|
---|
353 |
|
---|
354 | func (resp *Response) bodyBytes() []byte {
|
---|
355 | if resp.bodyRaw != nil {
|
---|
356 | return resp.bodyRaw
|
---|
357 | }
|
---|
358 | if resp.body == nil {
|
---|
359 | return nil
|
---|
360 | }
|
---|
361 | return resp.body.B
|
---|
362 | }
|
---|
363 |
|
---|
364 | func (req *Request) bodyBytes() []byte {
|
---|
365 | if req.bodyRaw != nil {
|
---|
366 | return req.bodyRaw
|
---|
367 | }
|
---|
368 | if req.bodyStream != nil {
|
---|
369 | bodyBuf := req.bodyBuffer()
|
---|
370 | bodyBuf.Reset()
|
---|
371 | _, err := copyZeroAlloc(bodyBuf, req.bodyStream)
|
---|
372 | req.closeBodyStream() //nolint:errcheck
|
---|
373 | if err != nil {
|
---|
374 | bodyBuf.SetString(err.Error())
|
---|
375 | }
|
---|
376 | }
|
---|
377 | if req.body == nil {
|
---|
378 | return nil
|
---|
379 | }
|
---|
380 | return req.body.B
|
---|
381 | }
|
---|
382 |
|
---|
383 | func (resp *Response) bodyBuffer() *bytebufferpool.ByteBuffer {
|
---|
384 | if resp.body == nil {
|
---|
385 | resp.body = responseBodyPool.Get()
|
---|
386 | }
|
---|
387 | resp.bodyRaw = nil
|
---|
388 | return resp.body
|
---|
389 | }
|
---|
390 |
|
---|
391 | func (req *Request) bodyBuffer() *bytebufferpool.ByteBuffer {
|
---|
392 | if req.body == nil {
|
---|
393 | req.body = requestBodyPool.Get()
|
---|
394 | }
|
---|
395 | req.bodyRaw = nil
|
---|
396 | return req.body
|
---|
397 | }
|
---|
398 |
|
---|
399 | var (
|
---|
400 | responseBodyPool bytebufferpool.Pool
|
---|
401 | requestBodyPool bytebufferpool.Pool
|
---|
402 | )
|
---|
403 |
|
---|
404 | // BodyGunzip returns un-gzipped body data.
|
---|
405 | //
|
---|
406 | // This method may be used if the request header contains
|
---|
407 | // 'Content-Encoding: gzip' for reading un-gzipped body.
|
---|
408 | // Use Body for reading gzipped request body.
|
---|
409 | func (req *Request) BodyGunzip() ([]byte, error) {
|
---|
410 | return gunzipData(req.Body())
|
---|
411 | }
|
---|
412 |
|
---|
413 | // BodyGunzip returns un-gzipped body data.
|
---|
414 | //
|
---|
415 | // This method may be used if the response header contains
|
---|
416 | // 'Content-Encoding: gzip' for reading un-gzipped body.
|
---|
417 | // Use Body for reading gzipped response body.
|
---|
418 | func (resp *Response) BodyGunzip() ([]byte, error) {
|
---|
419 | return gunzipData(resp.Body())
|
---|
420 | }
|
---|
421 |
|
---|
422 | func gunzipData(p []byte) ([]byte, error) {
|
---|
423 | var bb bytebufferpool.ByteBuffer
|
---|
424 | _, err := WriteGunzip(&bb, p)
|
---|
425 | if err != nil {
|
---|
426 | return nil, err
|
---|
427 | }
|
---|
428 | return bb.B, nil
|
---|
429 | }
|
---|
430 |
|
---|
431 | // BodyUnbrotli returns un-brotlied body data.
|
---|
432 | //
|
---|
433 | // This method may be used if the request header contains
|
---|
434 | // 'Content-Encoding: br' for reading un-brotlied body.
|
---|
435 | // Use Body for reading brotlied request body.
|
---|
436 | func (req *Request) BodyUnbrotli() ([]byte, error) {
|
---|
437 | return unBrotliData(req.Body())
|
---|
438 | }
|
---|
439 |
|
---|
440 | // BodyUnbrotli returns un-brotlied body data.
|
---|
441 | //
|
---|
442 | // This method may be used if the response header contains
|
---|
443 | // 'Content-Encoding: br' for reading un-brotlied body.
|
---|
444 | // Use Body for reading brotlied response body.
|
---|
445 | func (resp *Response) BodyUnbrotli() ([]byte, error) {
|
---|
446 | return unBrotliData(resp.Body())
|
---|
447 | }
|
---|
448 |
|
---|
449 | func unBrotliData(p []byte) ([]byte, error) {
|
---|
450 | var bb bytebufferpool.ByteBuffer
|
---|
451 | _, err := WriteUnbrotli(&bb, p)
|
---|
452 | if err != nil {
|
---|
453 | return nil, err
|
---|
454 | }
|
---|
455 | return bb.B, nil
|
---|
456 | }
|
---|
457 |
|
---|
458 | // BodyInflate returns inflated body data.
|
---|
459 | //
|
---|
460 | // This method may be used if the response header contains
|
---|
461 | // 'Content-Encoding: deflate' for reading inflated request body.
|
---|
462 | // Use Body for reading deflated request body.
|
---|
463 | func (req *Request) BodyInflate() ([]byte, error) {
|
---|
464 | return inflateData(req.Body())
|
---|
465 | }
|
---|
466 |
|
---|
467 | // BodyInflate returns inflated body data.
|
---|
468 | //
|
---|
469 | // This method may be used if the response header contains
|
---|
470 | // 'Content-Encoding: deflate' for reading inflated response body.
|
---|
471 | // Use Body for reading deflated response body.
|
---|
472 | func (resp *Response) BodyInflate() ([]byte, error) {
|
---|
473 | return inflateData(resp.Body())
|
---|
474 | }
|
---|
475 |
|
---|
476 | func (ctx *RequestCtx) RequestBodyStream() io.Reader {
|
---|
477 | return ctx.Request.bodyStream
|
---|
478 | }
|
---|
479 |
|
---|
480 | func inflateData(p []byte) ([]byte, error) {
|
---|
481 | var bb bytebufferpool.ByteBuffer
|
---|
482 | _, err := WriteInflate(&bb, p)
|
---|
483 | if err != nil {
|
---|
484 | return nil, err
|
---|
485 | }
|
---|
486 | return bb.B, nil
|
---|
487 | }
|
---|
488 |
|
---|
489 | // BodyWriteTo writes request body to w.
|
---|
490 | func (req *Request) BodyWriteTo(w io.Writer) error {
|
---|
491 | if req.bodyStream != nil {
|
---|
492 | _, err := copyZeroAlloc(w, req.bodyStream)
|
---|
493 | req.closeBodyStream() //nolint:errcheck
|
---|
494 | return err
|
---|
495 | }
|
---|
496 | if req.onlyMultipartForm() {
|
---|
497 | return WriteMultipartForm(w, req.multipartForm, req.multipartFormBoundary)
|
---|
498 | }
|
---|
499 | _, err := w.Write(req.bodyBytes())
|
---|
500 | return err
|
---|
501 | }
|
---|
502 |
|
---|
503 | // BodyWriteTo writes response body to w.
|
---|
504 | func (resp *Response) BodyWriteTo(w io.Writer) error {
|
---|
505 | if resp.bodyStream != nil {
|
---|
506 | _, err := copyZeroAlloc(w, resp.bodyStream)
|
---|
507 | resp.closeBodyStream() //nolint:errcheck
|
---|
508 | return err
|
---|
509 | }
|
---|
510 | _, err := w.Write(resp.bodyBytes())
|
---|
511 | return err
|
---|
512 | }
|
---|
513 |
|
---|
514 | // AppendBody appends p to response body.
|
---|
515 | //
|
---|
516 | // It is safe re-using p after the function returns.
|
---|
517 | func (resp *Response) AppendBody(p []byte) {
|
---|
518 | resp.closeBodyStream() //nolint:errcheck
|
---|
519 | resp.bodyBuffer().Write(p) //nolint:errcheck
|
---|
520 | }
|
---|
521 |
|
---|
522 | // AppendBodyString appends s to response body.
|
---|
523 | func (resp *Response) AppendBodyString(s string) {
|
---|
524 | resp.closeBodyStream() //nolint:errcheck
|
---|
525 | resp.bodyBuffer().WriteString(s) //nolint:errcheck
|
---|
526 | }
|
---|
527 |
|
---|
528 | // SetBody sets response body.
|
---|
529 | //
|
---|
530 | // It is safe re-using body argument after the function returns.
|
---|
531 | func (resp *Response) SetBody(body []byte) {
|
---|
532 | resp.closeBodyStream() //nolint:errcheck
|
---|
533 | bodyBuf := resp.bodyBuffer()
|
---|
534 | bodyBuf.Reset()
|
---|
535 | bodyBuf.Write(body) //nolint:errcheck
|
---|
536 | }
|
---|
537 |
|
---|
538 | // SetBodyString sets response body.
|
---|
539 | func (resp *Response) SetBodyString(body string) {
|
---|
540 | resp.closeBodyStream() //nolint:errcheck
|
---|
541 | bodyBuf := resp.bodyBuffer()
|
---|
542 | bodyBuf.Reset()
|
---|
543 | bodyBuf.WriteString(body) //nolint:errcheck
|
---|
544 | }
|
---|
545 |
|
---|
546 | // ResetBody resets response body.
|
---|
547 | func (resp *Response) ResetBody() {
|
---|
548 | resp.bodyRaw = nil
|
---|
549 | resp.closeBodyStream() //nolint:errcheck
|
---|
550 | if resp.body != nil {
|
---|
551 | if resp.keepBodyBuffer {
|
---|
552 | resp.body.Reset()
|
---|
553 | } else {
|
---|
554 | responseBodyPool.Put(resp.body)
|
---|
555 | resp.body = nil
|
---|
556 | }
|
---|
557 | }
|
---|
558 | }
|
---|
559 |
|
---|
560 | // SetBodyRaw sets response body, but without copying it.
|
---|
561 | //
|
---|
562 | // From this point onward the body argument must not be changed.
|
---|
563 | func (resp *Response) SetBodyRaw(body []byte) {
|
---|
564 | resp.ResetBody()
|
---|
565 | resp.bodyRaw = body
|
---|
566 | }
|
---|
567 |
|
---|
568 | // SetBodyRaw sets response body, but without copying it.
|
---|
569 | //
|
---|
570 | // From this point onward the body argument must not be changed.
|
---|
571 | func (req *Request) SetBodyRaw(body []byte) {
|
---|
572 | req.ResetBody()
|
---|
573 | req.bodyRaw = body
|
---|
574 | }
|
---|
575 |
|
---|
576 | // ReleaseBody retires the response body if it is greater than "size" bytes.
|
---|
577 | //
|
---|
578 | // This permits GC to reclaim the large buffer. If used, must be before
|
---|
579 | // ReleaseResponse.
|
---|
580 | //
|
---|
581 | // Use this method only if you really understand how it works.
|
---|
582 | // The majority of workloads don't need this method.
|
---|
583 | func (resp *Response) ReleaseBody(size int) {
|
---|
584 | resp.bodyRaw = nil
|
---|
585 | if cap(resp.body.B) > size {
|
---|
586 | resp.closeBodyStream() //nolint:errcheck
|
---|
587 | resp.body = nil
|
---|
588 | }
|
---|
589 | }
|
---|
590 |
|
---|
591 | // ReleaseBody retires the request body if it is greater than "size" bytes.
|
---|
592 | //
|
---|
593 | // This permits GC to reclaim the large buffer. If used, must be before
|
---|
594 | // ReleaseRequest.
|
---|
595 | //
|
---|
596 | // Use this method only if you really understand how it works.
|
---|
597 | // The majority of workloads don't need this method.
|
---|
598 | func (req *Request) ReleaseBody(size int) {
|
---|
599 | req.bodyRaw = nil
|
---|
600 | if cap(req.body.B) > size {
|
---|
601 | req.closeBodyStream() //nolint:errcheck
|
---|
602 | req.body = nil
|
---|
603 | }
|
---|
604 | }
|
---|
605 |
|
---|
606 | // SwapBody swaps response body with the given body and returns
|
---|
607 | // the previous response body.
|
---|
608 | //
|
---|
609 | // It is forbidden to use the body passed to SwapBody after
|
---|
610 | // the function returns.
|
---|
611 | func (resp *Response) SwapBody(body []byte) []byte {
|
---|
612 | bb := resp.bodyBuffer()
|
---|
613 |
|
---|
614 | if resp.bodyStream != nil {
|
---|
615 | bb.Reset()
|
---|
616 | _, err := copyZeroAlloc(bb, resp.bodyStream)
|
---|
617 | resp.closeBodyStream() //nolint:errcheck
|
---|
618 | if err != nil {
|
---|
619 | bb.Reset()
|
---|
620 | bb.SetString(err.Error())
|
---|
621 | }
|
---|
622 | }
|
---|
623 |
|
---|
624 | resp.bodyRaw = nil
|
---|
625 |
|
---|
626 | oldBody := bb.B
|
---|
627 | bb.B = body
|
---|
628 | return oldBody
|
---|
629 | }
|
---|
630 |
|
---|
631 | // SwapBody swaps request body with the given body and returns
|
---|
632 | // the previous request body.
|
---|
633 | //
|
---|
634 | // It is forbidden to use the body passed to SwapBody after
|
---|
635 | // the function returns.
|
---|
636 | func (req *Request) SwapBody(body []byte) []byte {
|
---|
637 | bb := req.bodyBuffer()
|
---|
638 |
|
---|
639 | if req.bodyStream != nil {
|
---|
640 | bb.Reset()
|
---|
641 | _, err := copyZeroAlloc(bb, req.bodyStream)
|
---|
642 | req.closeBodyStream() //nolint:errcheck
|
---|
643 | if err != nil {
|
---|
644 | bb.Reset()
|
---|
645 | bb.SetString(err.Error())
|
---|
646 | }
|
---|
647 | }
|
---|
648 |
|
---|
649 | req.bodyRaw = nil
|
---|
650 |
|
---|
651 | oldBody := bb.B
|
---|
652 | bb.B = body
|
---|
653 | return oldBody
|
---|
654 | }
|
---|
655 |
|
---|
656 | // Body returns request body.
|
---|
657 | //
|
---|
658 | // The returned value is valid until the request is released,
|
---|
659 | // either though ReleaseRequest or your request handler returning.
|
---|
660 | // Do not store references to returned value. Make copies instead.
|
---|
661 | func (req *Request) Body() []byte {
|
---|
662 | if req.bodyRaw != nil {
|
---|
663 | return req.bodyRaw
|
---|
664 | } else if req.onlyMultipartForm() {
|
---|
665 | body, err := marshalMultipartForm(req.multipartForm, req.multipartFormBoundary)
|
---|
666 | if err != nil {
|
---|
667 | return []byte(err.Error())
|
---|
668 | }
|
---|
669 | return body
|
---|
670 | }
|
---|
671 | return req.bodyBytes()
|
---|
672 | }
|
---|
673 |
|
---|
674 | // AppendBody appends p to request body.
|
---|
675 | //
|
---|
676 | // It is safe re-using p after the function returns.
|
---|
677 | func (req *Request) AppendBody(p []byte) {
|
---|
678 | req.RemoveMultipartFormFiles()
|
---|
679 | req.closeBodyStream() //nolint:errcheck
|
---|
680 | req.bodyBuffer().Write(p) //nolint:errcheck
|
---|
681 | }
|
---|
682 |
|
---|
683 | // AppendBodyString appends s to request body.
|
---|
684 | func (req *Request) AppendBodyString(s string) {
|
---|
685 | req.RemoveMultipartFormFiles()
|
---|
686 | req.closeBodyStream() //nolint:errcheck
|
---|
687 | req.bodyBuffer().WriteString(s) //nolint:errcheck
|
---|
688 | }
|
---|
689 |
|
---|
690 | // SetBody sets request body.
|
---|
691 | //
|
---|
692 | // It is safe re-using body argument after the function returns.
|
---|
693 | func (req *Request) SetBody(body []byte) {
|
---|
694 | req.RemoveMultipartFormFiles()
|
---|
695 | req.closeBodyStream() //nolint:errcheck
|
---|
696 | req.bodyBuffer().Set(body)
|
---|
697 | }
|
---|
698 |
|
---|
699 | // SetBodyString sets request body.
|
---|
700 | func (req *Request) SetBodyString(body string) {
|
---|
701 | req.RemoveMultipartFormFiles()
|
---|
702 | req.closeBodyStream() //nolint:errcheck
|
---|
703 | req.bodyBuffer().SetString(body)
|
---|
704 | }
|
---|
705 |
|
---|
706 | // ResetBody resets request body.
|
---|
707 | func (req *Request) ResetBody() {
|
---|
708 | req.bodyRaw = nil
|
---|
709 | req.RemoveMultipartFormFiles()
|
---|
710 | req.closeBodyStream() //nolint:errcheck
|
---|
711 | if req.body != nil {
|
---|
712 | if req.keepBodyBuffer {
|
---|
713 | req.body.Reset()
|
---|
714 | } else {
|
---|
715 | requestBodyPool.Put(req.body)
|
---|
716 | req.body = nil
|
---|
717 | }
|
---|
718 | }
|
---|
719 | }
|
---|
720 |
|
---|
721 | // CopyTo copies req contents to dst except of body stream.
|
---|
722 | func (req *Request) CopyTo(dst *Request) {
|
---|
723 | req.copyToSkipBody(dst)
|
---|
724 | if req.bodyRaw != nil {
|
---|
725 | dst.bodyRaw = req.bodyRaw
|
---|
726 | if dst.body != nil {
|
---|
727 | dst.body.Reset()
|
---|
728 | }
|
---|
729 | } else if req.body != nil {
|
---|
730 | dst.bodyBuffer().Set(req.body.B)
|
---|
731 | } else if dst.body != nil {
|
---|
732 | dst.body.Reset()
|
---|
733 | }
|
---|
734 | }
|
---|
735 |
|
---|
736 | func (req *Request) copyToSkipBody(dst *Request) {
|
---|
737 | dst.Reset()
|
---|
738 | req.Header.CopyTo(&dst.Header)
|
---|
739 |
|
---|
740 | req.uri.CopyTo(&dst.uri)
|
---|
741 | dst.parsedURI = req.parsedURI
|
---|
742 |
|
---|
743 | req.postArgs.CopyTo(&dst.postArgs)
|
---|
744 | dst.parsedPostArgs = req.parsedPostArgs
|
---|
745 | dst.isTLS = req.isTLS
|
---|
746 |
|
---|
747 | dst.UseHostHeader = req.UseHostHeader
|
---|
748 |
|
---|
749 | // do not copy multipartForm - it will be automatically
|
---|
750 | // re-created on the first call to MultipartForm.
|
---|
751 | }
|
---|
752 |
|
---|
753 | // CopyTo copies resp contents to dst except of body stream.
|
---|
754 | func (resp *Response) CopyTo(dst *Response) {
|
---|
755 | resp.copyToSkipBody(dst)
|
---|
756 | if resp.bodyRaw != nil {
|
---|
757 | dst.bodyRaw = resp.bodyRaw
|
---|
758 | if dst.body != nil {
|
---|
759 | dst.body.Reset()
|
---|
760 | }
|
---|
761 | } else if resp.body != nil {
|
---|
762 | dst.bodyBuffer().Set(resp.body.B)
|
---|
763 | } else if dst.body != nil {
|
---|
764 | dst.body.Reset()
|
---|
765 | }
|
---|
766 | }
|
---|
767 |
|
---|
768 | func (resp *Response) copyToSkipBody(dst *Response) {
|
---|
769 | dst.Reset()
|
---|
770 | resp.Header.CopyTo(&dst.Header)
|
---|
771 | dst.SkipBody = resp.SkipBody
|
---|
772 | dst.raddr = resp.raddr
|
---|
773 | dst.laddr = resp.laddr
|
---|
774 | }
|
---|
775 |
|
---|
776 | func swapRequestBody(a, b *Request) {
|
---|
777 | a.body, b.body = b.body, a.body
|
---|
778 | a.bodyRaw, b.bodyRaw = b.bodyRaw, a.bodyRaw
|
---|
779 | a.bodyStream, b.bodyStream = b.bodyStream, a.bodyStream
|
---|
780 | }
|
---|
781 |
|
---|
782 | func swapResponseBody(a, b *Response) {
|
---|
783 | a.body, b.body = b.body, a.body
|
---|
784 | a.bodyRaw, b.bodyRaw = b.bodyRaw, a.bodyRaw
|
---|
785 | a.bodyStream, b.bodyStream = b.bodyStream, a.bodyStream
|
---|
786 | }
|
---|
787 |
|
---|
788 | // URI returns request URI
|
---|
789 | func (req *Request) URI() *URI {
|
---|
790 | req.parseURI() //nolint:errcheck
|
---|
791 | return &req.uri
|
---|
792 | }
|
---|
793 |
|
---|
794 | // SetURI initializes request URI
|
---|
795 | // Use this method if a single URI may be reused across multiple requests.
|
---|
796 | // Otherwise, you can just use SetRequestURI() and it will be parsed as new URI.
|
---|
797 | // The URI is copied and can be safely modified later.
|
---|
798 | func (req *Request) SetURI(newUri *URI) {
|
---|
799 | if newUri != nil {
|
---|
800 | newUri.CopyTo(&req.uri)
|
---|
801 | req.parsedURI = true
|
---|
802 | return
|
---|
803 | }
|
---|
804 | req.uri.Reset()
|
---|
805 | req.parsedURI = false
|
---|
806 | }
|
---|
807 |
|
---|
808 | func (req *Request) parseURI() error {
|
---|
809 | if req.parsedURI {
|
---|
810 | return nil
|
---|
811 | }
|
---|
812 | req.parsedURI = true
|
---|
813 |
|
---|
814 | return req.uri.parse(req.Header.Host(), req.Header.RequestURI(), req.isTLS)
|
---|
815 | }
|
---|
816 |
|
---|
817 | // PostArgs returns POST arguments.
|
---|
818 | func (req *Request) PostArgs() *Args {
|
---|
819 | req.parsePostArgs()
|
---|
820 | return &req.postArgs
|
---|
821 | }
|
---|
822 |
|
---|
823 | func (req *Request) parsePostArgs() {
|
---|
824 | if req.parsedPostArgs {
|
---|
825 | return
|
---|
826 | }
|
---|
827 | req.parsedPostArgs = true
|
---|
828 |
|
---|
829 | if !bytes.HasPrefix(req.Header.ContentType(), strPostArgsContentType) {
|
---|
830 | return
|
---|
831 | }
|
---|
832 | req.postArgs.ParseBytes(req.bodyBytes())
|
---|
833 | }
|
---|
834 |
|
---|
835 | // ErrNoMultipartForm means that the request's Content-Type
|
---|
836 | // isn't 'multipart/form-data'.
|
---|
837 | var ErrNoMultipartForm = errors.New("request has no multipart/form-data Content-Type")
|
---|
838 |
|
---|
839 | // MultipartForm returns requests's multipart form.
|
---|
840 | //
|
---|
841 | // Returns ErrNoMultipartForm if request's Content-Type
|
---|
842 | // isn't 'multipart/form-data'.
|
---|
843 | //
|
---|
844 | // RemoveMultipartFormFiles must be called after returned multipart form
|
---|
845 | // is processed.
|
---|
846 | func (req *Request) MultipartForm() (*multipart.Form, error) {
|
---|
847 | if req.multipartForm != nil {
|
---|
848 | return req.multipartForm, nil
|
---|
849 | }
|
---|
850 |
|
---|
851 | req.multipartFormBoundary = string(req.Header.MultipartFormBoundary())
|
---|
852 | if len(req.multipartFormBoundary) == 0 {
|
---|
853 | return nil, ErrNoMultipartForm
|
---|
854 | }
|
---|
855 |
|
---|
856 | var err error
|
---|
857 | ce := req.Header.peek(strContentEncoding)
|
---|
858 |
|
---|
859 | if req.bodyStream != nil {
|
---|
860 | bodyStream := req.bodyStream
|
---|
861 | if bytes.Equal(ce, strGzip) {
|
---|
862 | // Do not care about memory usage here.
|
---|
863 | if bodyStream, err = gzip.NewReader(bodyStream); err != nil {
|
---|
864 | return nil, fmt.Errorf("cannot gunzip request body: %w", err)
|
---|
865 | }
|
---|
866 | } else if len(ce) > 0 {
|
---|
867 | return nil, fmt.Errorf("unsupported Content-Encoding: %q", ce)
|
---|
868 | }
|
---|
869 |
|
---|
870 | mr := multipart.NewReader(bodyStream, req.multipartFormBoundary)
|
---|
871 | req.multipartForm, err = mr.ReadForm(8 * 1024)
|
---|
872 | if err != nil {
|
---|
873 | return nil, fmt.Errorf("cannot read multipart/form-data body: %w", err)
|
---|
874 | }
|
---|
875 | } else {
|
---|
876 | body := req.bodyBytes()
|
---|
877 | if bytes.Equal(ce, strGzip) {
|
---|
878 | // Do not care about memory usage here.
|
---|
879 | if body, err = AppendGunzipBytes(nil, body); err != nil {
|
---|
880 | return nil, fmt.Errorf("cannot gunzip request body: %w", err)
|
---|
881 | }
|
---|
882 | } else if len(ce) > 0 {
|
---|
883 | return nil, fmt.Errorf("unsupported Content-Encoding: %q", ce)
|
---|
884 | }
|
---|
885 |
|
---|
886 | req.multipartForm, err = readMultipartForm(bytes.NewReader(body), req.multipartFormBoundary, len(body), len(body))
|
---|
887 | if err != nil {
|
---|
888 | return nil, err
|
---|
889 | }
|
---|
890 | }
|
---|
891 |
|
---|
892 | return req.multipartForm, nil
|
---|
893 | }
|
---|
894 |
|
---|
895 | func marshalMultipartForm(f *multipart.Form, boundary string) ([]byte, error) {
|
---|
896 | var buf bytebufferpool.ByteBuffer
|
---|
897 | if err := WriteMultipartForm(&buf, f, boundary); err != nil {
|
---|
898 | return nil, err
|
---|
899 | }
|
---|
900 | return buf.B, nil
|
---|
901 | }
|
---|
902 |
|
---|
903 | // WriteMultipartForm writes the given multipart form f with the given
|
---|
904 | // boundary to w.
|
---|
905 | func WriteMultipartForm(w io.Writer, f *multipart.Form, boundary string) error {
|
---|
906 | // Do not care about memory allocations here, since multipart
|
---|
907 | // form processing is slow.
|
---|
908 | if len(boundary) == 0 {
|
---|
909 | panic("BUG: form boundary cannot be empty")
|
---|
910 | }
|
---|
911 |
|
---|
912 | mw := multipart.NewWriter(w)
|
---|
913 | if err := mw.SetBoundary(boundary); err != nil {
|
---|
914 | return fmt.Errorf("cannot use form boundary %q: %w", boundary, err)
|
---|
915 | }
|
---|
916 |
|
---|
917 | // marshal values
|
---|
918 | for k, vv := range f.Value {
|
---|
919 | for _, v := range vv {
|
---|
920 | if err := mw.WriteField(k, v); err != nil {
|
---|
921 | return fmt.Errorf("cannot write form field %q value %q: %w", k, v, err)
|
---|
922 | }
|
---|
923 | }
|
---|
924 | }
|
---|
925 |
|
---|
926 | // marshal files
|
---|
927 | for k, fvv := range f.File {
|
---|
928 | for _, fv := range fvv {
|
---|
929 | vw, err := mw.CreatePart(fv.Header)
|
---|
930 | if err != nil {
|
---|
931 | return fmt.Errorf("cannot create form file %q (%q): %w", k, fv.Filename, err)
|
---|
932 | }
|
---|
933 | fh, err := fv.Open()
|
---|
934 | if err != nil {
|
---|
935 | return fmt.Errorf("cannot open form file %q (%q): %s", k, fv.Filename, err)
|
---|
936 | }
|
---|
937 | if _, err = copyZeroAlloc(vw, fh); err != nil {
|
---|
938 | return fmt.Errorf("error when copying form file %q (%q): %w", k, fv.Filename, err)
|
---|
939 | }
|
---|
940 | if err = fh.Close(); err != nil {
|
---|
941 | return fmt.Errorf("cannot close form file %q (%q): %w", k, fv.Filename, err)
|
---|
942 | }
|
---|
943 | }
|
---|
944 | }
|
---|
945 |
|
---|
946 | if err := mw.Close(); err != nil {
|
---|
947 | return fmt.Errorf("error when closing multipart form writer: %w", err)
|
---|
948 | }
|
---|
949 |
|
---|
950 | return nil
|
---|
951 | }
|
---|
952 |
|
---|
953 | func readMultipartForm(r io.Reader, boundary string, size, maxInMemoryFileSize int) (*multipart.Form, error) {
|
---|
954 | // Do not care about memory allocations here, since they are tiny
|
---|
955 | // compared to multipart data (aka multi-MB files) usually sent
|
---|
956 | // in multipart/form-data requests.
|
---|
957 |
|
---|
958 | if size <= 0 {
|
---|
959 | return nil, fmt.Errorf("form size must be greater than 0. Given %d", size)
|
---|
960 | }
|
---|
961 | lr := io.LimitReader(r, int64(size))
|
---|
962 | mr := multipart.NewReader(lr, boundary)
|
---|
963 | f, err := mr.ReadForm(int64(maxInMemoryFileSize))
|
---|
964 | if err != nil {
|
---|
965 | return nil, fmt.Errorf("cannot read multipart/form-data body: %w", err)
|
---|
966 | }
|
---|
967 | return f, nil
|
---|
968 | }
|
---|
969 |
|
---|
970 | // Reset clears request contents.
|
---|
971 | func (req *Request) Reset() {
|
---|
972 | if requestBodyPoolSizeLimit >= 0 && req.body != nil {
|
---|
973 | req.ReleaseBody(requestBodyPoolSizeLimit)
|
---|
974 | }
|
---|
975 | req.Header.Reset()
|
---|
976 | req.resetSkipHeader()
|
---|
977 | req.timeout = 0
|
---|
978 | req.UseHostHeader = false
|
---|
979 | }
|
---|
980 |
|
---|
981 | func (req *Request) resetSkipHeader() {
|
---|
982 | req.ResetBody()
|
---|
983 | req.uri.Reset()
|
---|
984 | req.parsedURI = false
|
---|
985 | req.postArgs.Reset()
|
---|
986 | req.parsedPostArgs = false
|
---|
987 | req.isTLS = false
|
---|
988 | }
|
---|
989 |
|
---|
990 | // RemoveMultipartFormFiles removes multipart/form-data temporary files
|
---|
991 | // associated with the request.
|
---|
992 | func (req *Request) RemoveMultipartFormFiles() {
|
---|
993 | if req.multipartForm != nil {
|
---|
994 | // Do not check for error, since these files may be deleted or moved
|
---|
995 | // to new places by user code.
|
---|
996 | req.multipartForm.RemoveAll() //nolint:errcheck
|
---|
997 | req.multipartForm = nil
|
---|
998 | }
|
---|
999 | req.multipartFormBoundary = ""
|
---|
1000 | }
|
---|
1001 |
|
---|
1002 | // Reset clears response contents.
|
---|
1003 | func (resp *Response) Reset() {
|
---|
1004 | if responseBodyPoolSizeLimit >= 0 && resp.body != nil {
|
---|
1005 | resp.ReleaseBody(responseBodyPoolSizeLimit)
|
---|
1006 | }
|
---|
1007 | resp.Header.Reset()
|
---|
1008 | resp.resetSkipHeader()
|
---|
1009 | resp.SkipBody = false
|
---|
1010 | resp.raddr = nil
|
---|
1011 | resp.laddr = nil
|
---|
1012 | resp.ImmediateHeaderFlush = false
|
---|
1013 | }
|
---|
1014 |
|
---|
1015 | func (resp *Response) resetSkipHeader() {
|
---|
1016 | resp.ResetBody()
|
---|
1017 | }
|
---|
1018 |
|
---|
1019 | // Read reads request (including body) from the given r.
|
---|
1020 | //
|
---|
1021 | // RemoveMultipartFormFiles or Reset must be called after
|
---|
1022 | // reading multipart/form-data request in order to delete temporarily
|
---|
1023 | // uploaded files.
|
---|
1024 | //
|
---|
1025 | // If MayContinue returns true, the caller must:
|
---|
1026 | //
|
---|
1027 | // - Either send StatusExpectationFailed response if request headers don't
|
---|
1028 | // satisfy the caller.
|
---|
1029 | // - Or send StatusContinue response before reading request body
|
---|
1030 | // with ContinueReadBody.
|
---|
1031 | // - Or close the connection.
|
---|
1032 | //
|
---|
1033 | // io.EOF is returned if r is closed before reading the first header byte.
|
---|
1034 | func (req *Request) Read(r *bufio.Reader) error {
|
---|
1035 | return req.ReadLimitBody(r, 0)
|
---|
1036 | }
|
---|
1037 |
|
---|
1038 | const defaultMaxInMemoryFileSize = 16 * 1024 * 1024
|
---|
1039 |
|
---|
1040 | // ErrGetOnly is returned when server expects only GET requests,
|
---|
1041 | // but some other type of request came (Server.GetOnly option is true).
|
---|
1042 | var ErrGetOnly = errors.New("non-GET request received")
|
---|
1043 |
|
---|
1044 | // ReadLimitBody reads request from the given r, limiting the body size.
|
---|
1045 | //
|
---|
1046 | // If maxBodySize > 0 and the body size exceeds maxBodySize,
|
---|
1047 | // then ErrBodyTooLarge is returned.
|
---|
1048 | //
|
---|
1049 | // RemoveMultipartFormFiles or Reset must be called after
|
---|
1050 | // reading multipart/form-data request in order to delete temporarily
|
---|
1051 | // uploaded files.
|
---|
1052 | //
|
---|
1053 | // If MayContinue returns true, the caller must:
|
---|
1054 | //
|
---|
1055 | // - Either send StatusExpectationFailed response if request headers don't
|
---|
1056 | // satisfy the caller.
|
---|
1057 | // - Or send StatusContinue response before reading request body
|
---|
1058 | // with ContinueReadBody.
|
---|
1059 | // - Or close the connection.
|
---|
1060 | //
|
---|
1061 | // io.EOF is returned if r is closed before reading the first header byte.
|
---|
1062 | func (req *Request) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
|
---|
1063 | req.resetSkipHeader()
|
---|
1064 | if err := req.Header.Read(r); err != nil {
|
---|
1065 | return err
|
---|
1066 | }
|
---|
1067 |
|
---|
1068 | return req.readLimitBody(r, maxBodySize, false, true)
|
---|
1069 | }
|
---|
1070 |
|
---|
1071 | func (req *Request) readLimitBody(r *bufio.Reader, maxBodySize int, getOnly bool, preParseMultipartForm bool) error {
|
---|
1072 | // Do not reset the request here - the caller must reset it before
|
---|
1073 | // calling this method.
|
---|
1074 |
|
---|
1075 | if getOnly && !req.Header.IsGet() {
|
---|
1076 | return ErrGetOnly
|
---|
1077 | }
|
---|
1078 |
|
---|
1079 | if req.MayContinue() {
|
---|
1080 | // 'Expect: 100-continue' header found. Let the caller deciding
|
---|
1081 | // whether to read request body or
|
---|
1082 | // to return StatusExpectationFailed.
|
---|
1083 | return nil
|
---|
1084 | }
|
---|
1085 |
|
---|
1086 | return req.ContinueReadBody(r, maxBodySize, preParseMultipartForm)
|
---|
1087 | }
|
---|
1088 |
|
---|
1089 | func (req *Request) readBodyStream(r *bufio.Reader, maxBodySize int, getOnly bool, preParseMultipartForm bool) error {
|
---|
1090 | // Do not reset the request here - the caller must reset it before
|
---|
1091 | // calling this method.
|
---|
1092 |
|
---|
1093 | if getOnly && !req.Header.IsGet() {
|
---|
1094 | return ErrGetOnly
|
---|
1095 | }
|
---|
1096 |
|
---|
1097 | if req.MayContinue() {
|
---|
1098 | // 'Expect: 100-continue' header found. Let the caller deciding
|
---|
1099 | // whether to read request body or
|
---|
1100 | // to return StatusExpectationFailed.
|
---|
1101 | return nil
|
---|
1102 | }
|
---|
1103 |
|
---|
1104 | return req.ContinueReadBodyStream(r, maxBodySize, preParseMultipartForm)
|
---|
1105 | }
|
---|
1106 |
|
---|
1107 | // MayContinue returns true if the request contains
|
---|
1108 | // 'Expect: 100-continue' header.
|
---|
1109 | //
|
---|
1110 | // The caller must do one of the following actions if MayContinue returns true:
|
---|
1111 | //
|
---|
1112 | // - Either send StatusExpectationFailed response if request headers don't
|
---|
1113 | // satisfy the caller.
|
---|
1114 | // - Or send StatusContinue response before reading request body
|
---|
1115 | // with ContinueReadBody.
|
---|
1116 | // - Or close the connection.
|
---|
1117 | func (req *Request) MayContinue() bool {
|
---|
1118 | return bytes.Equal(req.Header.peek(strExpect), str100Continue)
|
---|
1119 | }
|
---|
1120 |
|
---|
1121 | // ContinueReadBody reads request body if request header contains
|
---|
1122 | // 'Expect: 100-continue'.
|
---|
1123 | //
|
---|
1124 | // The caller must send StatusContinue response before calling this method.
|
---|
1125 | //
|
---|
1126 | // If maxBodySize > 0 and the body size exceeds maxBodySize,
|
---|
1127 | // then ErrBodyTooLarge is returned.
|
---|
1128 | func (req *Request) ContinueReadBody(r *bufio.Reader, maxBodySize int, preParseMultipartForm ...bool) error {
|
---|
1129 | var err error
|
---|
1130 | contentLength := req.Header.realContentLength()
|
---|
1131 | if contentLength > 0 {
|
---|
1132 | if maxBodySize > 0 && contentLength > maxBodySize {
|
---|
1133 | return ErrBodyTooLarge
|
---|
1134 | }
|
---|
1135 |
|
---|
1136 | if len(preParseMultipartForm) == 0 || preParseMultipartForm[0] {
|
---|
1137 | // Pre-read multipart form data of known length.
|
---|
1138 | // This way we limit memory usage for large file uploads, since their contents
|
---|
1139 | // is streamed into temporary files if file size exceeds defaultMaxInMemoryFileSize.
|
---|
1140 | req.multipartFormBoundary = string(req.Header.MultipartFormBoundary())
|
---|
1141 | if len(req.multipartFormBoundary) > 0 && len(req.Header.peek(strContentEncoding)) == 0 {
|
---|
1142 | req.multipartForm, err = readMultipartForm(r, req.multipartFormBoundary, contentLength, defaultMaxInMemoryFileSize)
|
---|
1143 | if err != nil {
|
---|
1144 | req.Reset()
|
---|
1145 | }
|
---|
1146 | return err
|
---|
1147 | }
|
---|
1148 | }
|
---|
1149 | }
|
---|
1150 |
|
---|
1151 | if contentLength == -2 {
|
---|
1152 | // identity body has no sense for http requests, since
|
---|
1153 | // the end of body is determined by connection close.
|
---|
1154 | // So just ignore request body for requests without
|
---|
1155 | // 'Content-Length' and 'Transfer-Encoding' headers.
|
---|
1156 | // refer to https://tools.ietf.org/html/rfc7230#section-3.3.2
|
---|
1157 | if !req.Header.ignoreBody() {
|
---|
1158 | req.Header.SetContentLength(0)
|
---|
1159 | }
|
---|
1160 | return nil
|
---|
1161 | }
|
---|
1162 |
|
---|
1163 | if err = req.ReadBody(r, contentLength, maxBodySize); err != nil {
|
---|
1164 | return err
|
---|
1165 | }
|
---|
1166 |
|
---|
1167 | if req.Header.ContentLength() == -1 {
|
---|
1168 | err = req.Header.ReadTrailer(r)
|
---|
1169 | if err != nil && err != io.EOF {
|
---|
1170 | return err
|
---|
1171 | }
|
---|
1172 | }
|
---|
1173 | return nil
|
---|
1174 | }
|
---|
1175 |
|
---|
1176 | // ReadBody reads request body from the given r, limiting the body size.
|
---|
1177 | //
|
---|
1178 | // If maxBodySize > 0 and the body size exceeds maxBodySize,
|
---|
1179 | // then ErrBodyTooLarge is returned.
|
---|
1180 | func (req *Request) ReadBody(r *bufio.Reader, contentLength int, maxBodySize int) (err error) {
|
---|
1181 | bodyBuf := req.bodyBuffer()
|
---|
1182 | bodyBuf.Reset()
|
---|
1183 |
|
---|
1184 | if contentLength >= 0 {
|
---|
1185 | bodyBuf.B, err = readBody(r, contentLength, maxBodySize, bodyBuf.B)
|
---|
1186 |
|
---|
1187 | } else if contentLength == -1 {
|
---|
1188 | bodyBuf.B, err = readBodyChunked(r, maxBodySize, bodyBuf.B)
|
---|
1189 |
|
---|
1190 | } else {
|
---|
1191 | bodyBuf.B, err = readBodyIdentity(r, maxBodySize, bodyBuf.B)
|
---|
1192 | req.Header.SetContentLength(len(bodyBuf.B))
|
---|
1193 | }
|
---|
1194 |
|
---|
1195 | if err != nil {
|
---|
1196 | req.Reset()
|
---|
1197 | return err
|
---|
1198 | }
|
---|
1199 | return nil
|
---|
1200 | }
|
---|
1201 |
|
---|
1202 | // ContinueReadBodyStream reads request body if request header contains
|
---|
1203 | // 'Expect: 100-continue'.
|
---|
1204 | //
|
---|
1205 | // The caller must send StatusContinue response before calling this method.
|
---|
1206 | //
|
---|
1207 | // If maxBodySize > 0 and the body size exceeds maxBodySize,
|
---|
1208 | // then ErrBodyTooLarge is returned.
|
---|
1209 | func (req *Request) ContinueReadBodyStream(r *bufio.Reader, maxBodySize int, preParseMultipartForm ...bool) error {
|
---|
1210 | var err error
|
---|
1211 | contentLength := req.Header.realContentLength()
|
---|
1212 | if contentLength > 0 {
|
---|
1213 | if len(preParseMultipartForm) == 0 || preParseMultipartForm[0] {
|
---|
1214 | // Pre-read multipart form data of known length.
|
---|
1215 | // This way we limit memory usage for large file uploads, since their contents
|
---|
1216 | // is streamed into temporary files if file size exceeds defaultMaxInMemoryFileSize.
|
---|
1217 | req.multipartFormBoundary = b2s(req.Header.MultipartFormBoundary())
|
---|
1218 | if len(req.multipartFormBoundary) > 0 && len(req.Header.peek(strContentEncoding)) == 0 {
|
---|
1219 | req.multipartForm, err = readMultipartForm(r, req.multipartFormBoundary, contentLength, defaultMaxInMemoryFileSize)
|
---|
1220 | if err != nil {
|
---|
1221 | req.Reset()
|
---|
1222 | }
|
---|
1223 | return err
|
---|
1224 | }
|
---|
1225 | }
|
---|
1226 | }
|
---|
1227 |
|
---|
1228 | if contentLength == -2 {
|
---|
1229 | // identity body has no sense for http requests, since
|
---|
1230 | // the end of body is determined by connection close.
|
---|
1231 | // So just ignore request body for requests without
|
---|
1232 | // 'Content-Length' and 'Transfer-Encoding' headers.
|
---|
1233 | req.Header.SetContentLength(0)
|
---|
1234 | return nil
|
---|
1235 | }
|
---|
1236 |
|
---|
1237 | bodyBuf := req.bodyBuffer()
|
---|
1238 | bodyBuf.Reset()
|
---|
1239 | bodyBuf.B, err = readBodyWithStreaming(r, contentLength, maxBodySize, bodyBuf.B)
|
---|
1240 | if err != nil {
|
---|
1241 | if err == ErrBodyTooLarge {
|
---|
1242 | req.Header.SetContentLength(contentLength)
|
---|
1243 | req.body = bodyBuf
|
---|
1244 | req.bodyStream = acquireRequestStream(bodyBuf, r, &req.Header)
|
---|
1245 | return nil
|
---|
1246 | }
|
---|
1247 | if err == errChunkedStream {
|
---|
1248 | req.body = bodyBuf
|
---|
1249 | req.bodyStream = acquireRequestStream(bodyBuf, r, &req.Header)
|
---|
1250 | return nil
|
---|
1251 | }
|
---|
1252 | req.Reset()
|
---|
1253 | return err
|
---|
1254 | }
|
---|
1255 |
|
---|
1256 | req.body = bodyBuf
|
---|
1257 | req.bodyStream = acquireRequestStream(bodyBuf, r, &req.Header)
|
---|
1258 | req.Header.SetContentLength(contentLength)
|
---|
1259 | return nil
|
---|
1260 | }
|
---|
1261 |
|
---|
1262 | // Read reads response (including body) from the given r.
|
---|
1263 | //
|
---|
1264 | // io.EOF is returned if r is closed before reading the first header byte.
|
---|
1265 | func (resp *Response) Read(r *bufio.Reader) error {
|
---|
1266 | return resp.ReadLimitBody(r, 0)
|
---|
1267 | }
|
---|
1268 |
|
---|
1269 | // ReadLimitBody reads response headers from the given r,
|
---|
1270 | // then reads the body using the ReadBody function and limiting the body size.
|
---|
1271 | //
|
---|
1272 | // If resp.SkipBody is true then it skips reading the response body.
|
---|
1273 | //
|
---|
1274 | // If maxBodySize > 0 and the body size exceeds maxBodySize,
|
---|
1275 | // then ErrBodyTooLarge is returned.
|
---|
1276 | //
|
---|
1277 | // io.EOF is returned if r is closed before reading the first header byte.
|
---|
1278 | func (resp *Response) ReadLimitBody(r *bufio.Reader, maxBodySize int) error {
|
---|
1279 | resp.resetSkipHeader()
|
---|
1280 | err := resp.Header.Read(r)
|
---|
1281 | if err != nil {
|
---|
1282 | return err
|
---|
1283 | }
|
---|
1284 | if resp.Header.StatusCode() == StatusContinue {
|
---|
1285 | // Read the next response according to http://www.w3.org/Protocols/rfc2616/rfc2616-sec8.html .
|
---|
1286 | if err = resp.Header.Read(r); err != nil {
|
---|
1287 | return err
|
---|
1288 | }
|
---|
1289 | }
|
---|
1290 |
|
---|
1291 | if !resp.mustSkipBody() {
|
---|
1292 | err = resp.ReadBody(r, maxBodySize)
|
---|
1293 | if err != nil {
|
---|
1294 | return err
|
---|
1295 | }
|
---|
1296 | }
|
---|
1297 |
|
---|
1298 | if resp.Header.ContentLength() == -1 {
|
---|
1299 | err = resp.Header.ReadTrailer(r)
|
---|
1300 | if err != nil && err != io.EOF {
|
---|
1301 | return err
|
---|
1302 | }
|
---|
1303 | }
|
---|
1304 | return nil
|
---|
1305 | }
|
---|
1306 |
|
---|
1307 | // ReadBody reads response body from the given r, limiting the body size.
|
---|
1308 | //
|
---|
1309 | // If maxBodySize > 0 and the body size exceeds maxBodySize,
|
---|
1310 | // then ErrBodyTooLarge is returned.
|
---|
1311 | func (resp *Response) ReadBody(r *bufio.Reader, maxBodySize int) (err error) {
|
---|
1312 | bodyBuf := resp.bodyBuffer()
|
---|
1313 | bodyBuf.Reset()
|
---|
1314 |
|
---|
1315 | contentLength := resp.Header.ContentLength()
|
---|
1316 | if contentLength >= 0 {
|
---|
1317 | bodyBuf.B, err = readBody(r, contentLength, maxBodySize, bodyBuf.B)
|
---|
1318 |
|
---|
1319 | } else if contentLength == -1 {
|
---|
1320 | bodyBuf.B, err = readBodyChunked(r, maxBodySize, bodyBuf.B)
|
---|
1321 |
|
---|
1322 | } else {
|
---|
1323 | bodyBuf.B, err = readBodyIdentity(r, maxBodySize, bodyBuf.B)
|
---|
1324 | resp.Header.SetContentLength(len(bodyBuf.B))
|
---|
1325 | }
|
---|
1326 | return err
|
---|
1327 | }
|
---|
1328 |
|
---|
1329 | func (resp *Response) mustSkipBody() bool {
|
---|
1330 | return resp.SkipBody || resp.Header.mustSkipContentLength()
|
---|
1331 | }
|
---|
1332 |
|
---|
1333 | var errRequestHostRequired = errors.New("missing required Host header in request")
|
---|
1334 |
|
---|
1335 | // WriteTo writes request to w. It implements io.WriterTo.
|
---|
1336 | func (req *Request) WriteTo(w io.Writer) (int64, error) {
|
---|
1337 | return writeBufio(req, w)
|
---|
1338 | }
|
---|
1339 |
|
---|
1340 | // WriteTo writes response to w. It implements io.WriterTo.
|
---|
1341 | func (resp *Response) WriteTo(w io.Writer) (int64, error) {
|
---|
1342 | return writeBufio(resp, w)
|
---|
1343 | }
|
---|
1344 |
|
---|
1345 | func writeBufio(hw httpWriter, w io.Writer) (int64, error) {
|
---|
1346 | sw := acquireStatsWriter(w)
|
---|
1347 | bw := acquireBufioWriter(sw)
|
---|
1348 | err1 := hw.Write(bw)
|
---|
1349 | err2 := bw.Flush()
|
---|
1350 | releaseBufioWriter(bw)
|
---|
1351 | n := sw.bytesWritten
|
---|
1352 | releaseStatsWriter(sw)
|
---|
1353 |
|
---|
1354 | err := err1
|
---|
1355 | if err == nil {
|
---|
1356 | err = err2
|
---|
1357 | }
|
---|
1358 | return n, err
|
---|
1359 | }
|
---|
1360 |
|
---|
1361 | type statsWriter struct {
|
---|
1362 | w io.Writer
|
---|
1363 | bytesWritten int64
|
---|
1364 | }
|
---|
1365 |
|
---|
1366 | func (w *statsWriter) Write(p []byte) (int, error) {
|
---|
1367 | n, err := w.w.Write(p)
|
---|
1368 | w.bytesWritten += int64(n)
|
---|
1369 | return n, err
|
---|
1370 | }
|
---|
1371 |
|
---|
1372 | func acquireStatsWriter(w io.Writer) *statsWriter {
|
---|
1373 | v := statsWriterPool.Get()
|
---|
1374 | if v == nil {
|
---|
1375 | return &statsWriter{
|
---|
1376 | w: w,
|
---|
1377 | }
|
---|
1378 | }
|
---|
1379 | sw := v.(*statsWriter)
|
---|
1380 | sw.w = w
|
---|
1381 | return sw
|
---|
1382 | }
|
---|
1383 |
|
---|
1384 | func releaseStatsWriter(sw *statsWriter) {
|
---|
1385 | sw.w = nil
|
---|
1386 | sw.bytesWritten = 0
|
---|
1387 | statsWriterPool.Put(sw)
|
---|
1388 | }
|
---|
1389 |
|
---|
1390 | var statsWriterPool sync.Pool
|
---|
1391 |
|
---|
1392 | func acquireBufioWriter(w io.Writer) *bufio.Writer {
|
---|
1393 | v := bufioWriterPool.Get()
|
---|
1394 | if v == nil {
|
---|
1395 | return bufio.NewWriter(w)
|
---|
1396 | }
|
---|
1397 | bw := v.(*bufio.Writer)
|
---|
1398 | bw.Reset(w)
|
---|
1399 | return bw
|
---|
1400 | }
|
---|
1401 |
|
---|
1402 | func releaseBufioWriter(bw *bufio.Writer) {
|
---|
1403 | bufioWriterPool.Put(bw)
|
---|
1404 | }
|
---|
1405 |
|
---|
1406 | var bufioWriterPool sync.Pool
|
---|
1407 |
|
---|
1408 | func (req *Request) onlyMultipartForm() bool {
|
---|
1409 | return req.multipartForm != nil && (req.body == nil || len(req.body.B) == 0)
|
---|
1410 | }
|
---|
1411 |
|
---|
1412 | // Write writes request to w.
|
---|
1413 | //
|
---|
1414 | // Write doesn't flush request to w for performance reasons.
|
---|
1415 | //
|
---|
1416 | // See also WriteTo.
|
---|
1417 | func (req *Request) Write(w *bufio.Writer) error {
|
---|
1418 | if len(req.Header.Host()) == 0 || req.parsedURI {
|
---|
1419 | uri := req.URI()
|
---|
1420 | host := uri.Host()
|
---|
1421 | if len(req.Header.Host()) == 0 {
|
---|
1422 | if len(host) == 0 {
|
---|
1423 | return errRequestHostRequired
|
---|
1424 | } else {
|
---|
1425 | req.Header.SetHostBytes(host)
|
---|
1426 | }
|
---|
1427 | } else if !req.UseHostHeader {
|
---|
1428 | req.Header.SetHostBytes(host)
|
---|
1429 | }
|
---|
1430 | req.Header.SetRequestURIBytes(uri.RequestURI())
|
---|
1431 |
|
---|
1432 | if len(uri.username) > 0 {
|
---|
1433 | // RequestHeader.SetBytesKV only uses RequestHeader.bufKV.key
|
---|
1434 | // So we are free to use RequestHeader.bufKV.value as a scratch pad for
|
---|
1435 | // the base64 encoding.
|
---|
1436 | nl := len(uri.username) + len(uri.password) + 1
|
---|
1437 | nb := nl + len(strBasicSpace)
|
---|
1438 | tl := nb + base64.StdEncoding.EncodedLen(nl)
|
---|
1439 | if tl > cap(req.Header.bufKV.value) {
|
---|
1440 | req.Header.bufKV.value = make([]byte, 0, tl)
|
---|
1441 | }
|
---|
1442 | buf := req.Header.bufKV.value[:0]
|
---|
1443 | buf = append(buf, uri.username...)
|
---|
1444 | buf = append(buf, strColon...)
|
---|
1445 | buf = append(buf, uri.password...)
|
---|
1446 | buf = append(buf, strBasicSpace...)
|
---|
1447 | base64.StdEncoding.Encode(buf[nb:tl], buf[:nl])
|
---|
1448 | req.Header.SetBytesKV(strAuthorization, buf[nl:tl])
|
---|
1449 | }
|
---|
1450 | }
|
---|
1451 |
|
---|
1452 | if req.bodyStream != nil {
|
---|
1453 | return req.writeBodyStream(w)
|
---|
1454 | }
|
---|
1455 |
|
---|
1456 | body := req.bodyBytes()
|
---|
1457 | var err error
|
---|
1458 | if req.onlyMultipartForm() {
|
---|
1459 | body, err = marshalMultipartForm(req.multipartForm, req.multipartFormBoundary)
|
---|
1460 | if err != nil {
|
---|
1461 | return fmt.Errorf("error when marshaling multipart form: %w", err)
|
---|
1462 | }
|
---|
1463 | req.Header.SetMultipartFormBoundary(req.multipartFormBoundary)
|
---|
1464 | }
|
---|
1465 |
|
---|
1466 | hasBody := false
|
---|
1467 | if len(body) == 0 {
|
---|
1468 | body = req.postArgs.QueryString()
|
---|
1469 | }
|
---|
1470 | if len(body) != 0 || !req.Header.ignoreBody() {
|
---|
1471 | hasBody = true
|
---|
1472 | req.Header.SetContentLength(len(body))
|
---|
1473 | }
|
---|
1474 | if err = req.Header.Write(w); err != nil {
|
---|
1475 | return err
|
---|
1476 | }
|
---|
1477 | if hasBody {
|
---|
1478 | _, err = w.Write(body)
|
---|
1479 | } else if len(body) > 0 {
|
---|
1480 | if req.secureErrorLogMessage {
|
---|
1481 | return fmt.Errorf("non-zero body for non-POST request")
|
---|
1482 | }
|
---|
1483 | return fmt.Errorf("non-zero body for non-POST request. body=%q", body)
|
---|
1484 | }
|
---|
1485 | return err
|
---|
1486 | }
|
---|
1487 |
|
---|
1488 | // WriteGzip writes response with gzipped body to w.
|
---|
1489 | //
|
---|
1490 | // The method gzips response body and sets 'Content-Encoding: gzip'
|
---|
1491 | // header before writing response to w.
|
---|
1492 | //
|
---|
1493 | // WriteGzip doesn't flush response to w for performance reasons.
|
---|
1494 | func (resp *Response) WriteGzip(w *bufio.Writer) error {
|
---|
1495 | return resp.WriteGzipLevel(w, CompressDefaultCompression)
|
---|
1496 | }
|
---|
1497 |
|
---|
1498 | // WriteGzipLevel writes response with gzipped body to w.
|
---|
1499 | //
|
---|
1500 | // Level is the desired compression level:
|
---|
1501 | //
|
---|
1502 | // * CompressNoCompression
|
---|
1503 | // * CompressBestSpeed
|
---|
1504 | // * CompressBestCompression
|
---|
1505 | // * CompressDefaultCompression
|
---|
1506 | // * CompressHuffmanOnly
|
---|
1507 | //
|
---|
1508 | // The method gzips response body and sets 'Content-Encoding: gzip'
|
---|
1509 | // header before writing response to w.
|
---|
1510 | //
|
---|
1511 | // WriteGzipLevel doesn't flush response to w for performance reasons.
|
---|
1512 | func (resp *Response) WriteGzipLevel(w *bufio.Writer, level int) error {
|
---|
1513 | if err := resp.gzipBody(level); err != nil {
|
---|
1514 | return err
|
---|
1515 | }
|
---|
1516 | return resp.Write(w)
|
---|
1517 | }
|
---|
1518 |
|
---|
1519 | // WriteDeflate writes response with deflated body to w.
|
---|
1520 | //
|
---|
1521 | // The method deflates response body and sets 'Content-Encoding: deflate'
|
---|
1522 | // header before writing response to w.
|
---|
1523 | //
|
---|
1524 | // WriteDeflate doesn't flush response to w for performance reasons.
|
---|
1525 | func (resp *Response) WriteDeflate(w *bufio.Writer) error {
|
---|
1526 | return resp.WriteDeflateLevel(w, CompressDefaultCompression)
|
---|
1527 | }
|
---|
1528 |
|
---|
1529 | // WriteDeflateLevel writes response with deflated body to w.
|
---|
1530 | //
|
---|
1531 | // Level is the desired compression level:
|
---|
1532 | //
|
---|
1533 | // * CompressNoCompression
|
---|
1534 | // * CompressBestSpeed
|
---|
1535 | // * CompressBestCompression
|
---|
1536 | // * CompressDefaultCompression
|
---|
1537 | // * CompressHuffmanOnly
|
---|
1538 | //
|
---|
1539 | // The method deflates response body and sets 'Content-Encoding: deflate'
|
---|
1540 | // header before writing response to w.
|
---|
1541 | //
|
---|
1542 | // WriteDeflateLevel doesn't flush response to w for performance reasons.
|
---|
1543 | func (resp *Response) WriteDeflateLevel(w *bufio.Writer, level int) error {
|
---|
1544 | if err := resp.deflateBody(level); err != nil {
|
---|
1545 | return err
|
---|
1546 | }
|
---|
1547 | return resp.Write(w)
|
---|
1548 | }
|
---|
1549 |
|
---|
1550 | func (resp *Response) brotliBody(level int) error {
|
---|
1551 | if len(resp.Header.peek(strContentEncoding)) > 0 {
|
---|
1552 | // It looks like the body is already compressed.
|
---|
1553 | // Do not compress it again.
|
---|
1554 | return nil
|
---|
1555 | }
|
---|
1556 |
|
---|
1557 | if !resp.Header.isCompressibleContentType() {
|
---|
1558 | // The content-type cannot be compressed.
|
---|
1559 | return nil
|
---|
1560 | }
|
---|
1561 |
|
---|
1562 | if resp.bodyStream != nil {
|
---|
1563 | // Reset Content-Length to -1, since it is impossible
|
---|
1564 | // to determine body size beforehand of streamed compression.
|
---|
1565 | // For https://github.com/valyala/fasthttp/issues/176 .
|
---|
1566 | resp.Header.SetContentLength(-1)
|
---|
1567 |
|
---|
1568 | // Do not care about memory allocations here, since brotli is slow
|
---|
1569 | // and allocates a lot of memory by itself.
|
---|
1570 | bs := resp.bodyStream
|
---|
1571 | resp.bodyStream = NewStreamReader(func(sw *bufio.Writer) {
|
---|
1572 | zw := acquireStacklessBrotliWriter(sw, level)
|
---|
1573 | fw := &flushWriter{
|
---|
1574 | wf: zw,
|
---|
1575 | bw: sw,
|
---|
1576 | }
|
---|
1577 | copyZeroAlloc(fw, bs) //nolint:errcheck
|
---|
1578 | releaseStacklessBrotliWriter(zw, level)
|
---|
1579 | if bsc, ok := bs.(io.Closer); ok {
|
---|
1580 | bsc.Close()
|
---|
1581 | }
|
---|
1582 | })
|
---|
1583 | } else {
|
---|
1584 | bodyBytes := resp.bodyBytes()
|
---|
1585 | if len(bodyBytes) < minCompressLen {
|
---|
1586 | // There is no sense in spending CPU time on small body compression,
|
---|
1587 | // since there is a very high probability that the compressed
|
---|
1588 | // body size will be bigger than the original body size.
|
---|
1589 | return nil
|
---|
1590 | }
|
---|
1591 | w := responseBodyPool.Get()
|
---|
1592 | w.B = AppendBrotliBytesLevel(w.B, bodyBytes, level)
|
---|
1593 |
|
---|
1594 | // Hack: swap resp.body with w.
|
---|
1595 | if resp.body != nil {
|
---|
1596 | responseBodyPool.Put(resp.body)
|
---|
1597 | }
|
---|
1598 | resp.body = w
|
---|
1599 | resp.bodyRaw = nil
|
---|
1600 | }
|
---|
1601 | resp.Header.SetCanonical(strContentEncoding, strBr)
|
---|
1602 | return nil
|
---|
1603 | }
|
---|
1604 |
|
---|
1605 | func (resp *Response) gzipBody(level int) error {
|
---|
1606 | if len(resp.Header.peek(strContentEncoding)) > 0 {
|
---|
1607 | // It looks like the body is already compressed.
|
---|
1608 | // Do not compress it again.
|
---|
1609 | return nil
|
---|
1610 | }
|
---|
1611 |
|
---|
1612 | if !resp.Header.isCompressibleContentType() {
|
---|
1613 | // The content-type cannot be compressed.
|
---|
1614 | return nil
|
---|
1615 | }
|
---|
1616 |
|
---|
1617 | if resp.bodyStream != nil {
|
---|
1618 | // Reset Content-Length to -1, since it is impossible
|
---|
1619 | // to determine body size beforehand of streamed compression.
|
---|
1620 | // For https://github.com/valyala/fasthttp/issues/176 .
|
---|
1621 | resp.Header.SetContentLength(-1)
|
---|
1622 |
|
---|
1623 | // Do not care about memory allocations here, since gzip is slow
|
---|
1624 | // and allocates a lot of memory by itself.
|
---|
1625 | bs := resp.bodyStream
|
---|
1626 | resp.bodyStream = NewStreamReader(func(sw *bufio.Writer) {
|
---|
1627 | zw := acquireStacklessGzipWriter(sw, level)
|
---|
1628 | fw := &flushWriter{
|
---|
1629 | wf: zw,
|
---|
1630 | bw: sw,
|
---|
1631 | }
|
---|
1632 | copyZeroAlloc(fw, bs) //nolint:errcheck
|
---|
1633 | releaseStacklessGzipWriter(zw, level)
|
---|
1634 | if bsc, ok := bs.(io.Closer); ok {
|
---|
1635 | bsc.Close()
|
---|
1636 | }
|
---|
1637 | })
|
---|
1638 | } else {
|
---|
1639 | bodyBytes := resp.bodyBytes()
|
---|
1640 | if len(bodyBytes) < minCompressLen {
|
---|
1641 | // There is no sense in spending CPU time on small body compression,
|
---|
1642 | // since there is a very high probability that the compressed
|
---|
1643 | // body size will be bigger than the original body size.
|
---|
1644 | return nil
|
---|
1645 | }
|
---|
1646 | w := responseBodyPool.Get()
|
---|
1647 | w.B = AppendGzipBytesLevel(w.B, bodyBytes, level)
|
---|
1648 |
|
---|
1649 | // Hack: swap resp.body with w.
|
---|
1650 | if resp.body != nil {
|
---|
1651 | responseBodyPool.Put(resp.body)
|
---|
1652 | }
|
---|
1653 | resp.body = w
|
---|
1654 | resp.bodyRaw = nil
|
---|
1655 | }
|
---|
1656 | resp.Header.SetCanonical(strContentEncoding, strGzip)
|
---|
1657 | return nil
|
---|
1658 | }
|
---|
1659 |
|
---|
1660 | func (resp *Response) deflateBody(level int) error {
|
---|
1661 | if len(resp.Header.peek(strContentEncoding)) > 0 {
|
---|
1662 | // It looks like the body is already compressed.
|
---|
1663 | // Do not compress it again.
|
---|
1664 | return nil
|
---|
1665 | }
|
---|
1666 |
|
---|
1667 | if !resp.Header.isCompressibleContentType() {
|
---|
1668 | // The content-type cannot be compressed.
|
---|
1669 | return nil
|
---|
1670 | }
|
---|
1671 |
|
---|
1672 | if resp.bodyStream != nil {
|
---|
1673 | // Reset Content-Length to -1, since it is impossible
|
---|
1674 | // to determine body size beforehand of streamed compression.
|
---|
1675 | // For https://github.com/valyala/fasthttp/issues/176 .
|
---|
1676 | resp.Header.SetContentLength(-1)
|
---|
1677 |
|
---|
1678 | // Do not care about memory allocations here, since flate is slow
|
---|
1679 | // and allocates a lot of memory by itself.
|
---|
1680 | bs := resp.bodyStream
|
---|
1681 | resp.bodyStream = NewStreamReader(func(sw *bufio.Writer) {
|
---|
1682 | zw := acquireStacklessDeflateWriter(sw, level)
|
---|
1683 | fw := &flushWriter{
|
---|
1684 | wf: zw,
|
---|
1685 | bw: sw,
|
---|
1686 | }
|
---|
1687 | copyZeroAlloc(fw, bs) //nolint:errcheck
|
---|
1688 | releaseStacklessDeflateWriter(zw, level)
|
---|
1689 | if bsc, ok := bs.(io.Closer); ok {
|
---|
1690 | bsc.Close()
|
---|
1691 | }
|
---|
1692 | })
|
---|
1693 | } else {
|
---|
1694 | bodyBytes := resp.bodyBytes()
|
---|
1695 | if len(bodyBytes) < minCompressLen {
|
---|
1696 | // There is no sense in spending CPU time on small body compression,
|
---|
1697 | // since there is a very high probability that the compressed
|
---|
1698 | // body size will be bigger than the original body size.
|
---|
1699 | return nil
|
---|
1700 | }
|
---|
1701 | w := responseBodyPool.Get()
|
---|
1702 | w.B = AppendDeflateBytesLevel(w.B, bodyBytes, level)
|
---|
1703 |
|
---|
1704 | // Hack: swap resp.body with w.
|
---|
1705 | if resp.body != nil {
|
---|
1706 | responseBodyPool.Put(resp.body)
|
---|
1707 | }
|
---|
1708 | resp.body = w
|
---|
1709 | resp.bodyRaw = nil
|
---|
1710 | }
|
---|
1711 | resp.Header.SetCanonical(strContentEncoding, strDeflate)
|
---|
1712 | return nil
|
---|
1713 | }
|
---|
1714 |
|
---|
1715 | // Bodies with sizes smaller than minCompressLen aren't compressed at all
|
---|
1716 | const minCompressLen = 200
|
---|
1717 |
|
---|
1718 | type writeFlusher interface {
|
---|
1719 | io.Writer
|
---|
1720 | Flush() error
|
---|
1721 | }
|
---|
1722 |
|
---|
1723 | type flushWriter struct {
|
---|
1724 | wf writeFlusher
|
---|
1725 | bw *bufio.Writer
|
---|
1726 | }
|
---|
1727 |
|
---|
1728 | func (w *flushWriter) Write(p []byte) (int, error) {
|
---|
1729 | n, err := w.wf.Write(p)
|
---|
1730 | if err != nil {
|
---|
1731 | return 0, err
|
---|
1732 | }
|
---|
1733 | if err = w.wf.Flush(); err != nil {
|
---|
1734 | return 0, err
|
---|
1735 | }
|
---|
1736 | if err = w.bw.Flush(); err != nil {
|
---|
1737 | return 0, err
|
---|
1738 | }
|
---|
1739 | return n, nil
|
---|
1740 | }
|
---|
1741 |
|
---|
1742 | // Write writes response to w.
|
---|
1743 | //
|
---|
1744 | // Write doesn't flush response to w for performance reasons.
|
---|
1745 | //
|
---|
1746 | // See also WriteTo.
|
---|
1747 | func (resp *Response) Write(w *bufio.Writer) error {
|
---|
1748 | sendBody := !resp.mustSkipBody()
|
---|
1749 |
|
---|
1750 | if resp.bodyStream != nil {
|
---|
1751 | return resp.writeBodyStream(w, sendBody)
|
---|
1752 | }
|
---|
1753 |
|
---|
1754 | body := resp.bodyBytes()
|
---|
1755 | bodyLen := len(body)
|
---|
1756 | if sendBody || bodyLen > 0 {
|
---|
1757 | resp.Header.SetContentLength(bodyLen)
|
---|
1758 | }
|
---|
1759 | if err := resp.Header.Write(w); err != nil {
|
---|
1760 | return err
|
---|
1761 | }
|
---|
1762 | if sendBody {
|
---|
1763 | if _, err := w.Write(body); err != nil {
|
---|
1764 | return err
|
---|
1765 | }
|
---|
1766 | }
|
---|
1767 | return nil
|
---|
1768 | }
|
---|
1769 |
|
---|
1770 | func (req *Request) writeBodyStream(w *bufio.Writer) error {
|
---|
1771 | var err error
|
---|
1772 |
|
---|
1773 | contentLength := req.Header.ContentLength()
|
---|
1774 | if contentLength < 0 {
|
---|
1775 | lrSize := limitedReaderSize(req.bodyStream)
|
---|
1776 | if lrSize >= 0 {
|
---|
1777 | contentLength = int(lrSize)
|
---|
1778 | if int64(contentLength) != lrSize {
|
---|
1779 | contentLength = -1
|
---|
1780 | }
|
---|
1781 | if contentLength >= 0 {
|
---|
1782 | req.Header.SetContentLength(contentLength)
|
---|
1783 | }
|
---|
1784 | }
|
---|
1785 | }
|
---|
1786 | if contentLength >= 0 {
|
---|
1787 | if err = req.Header.Write(w); err == nil {
|
---|
1788 | err = writeBodyFixedSize(w, req.bodyStream, int64(contentLength))
|
---|
1789 | }
|
---|
1790 | } else {
|
---|
1791 | req.Header.SetContentLength(-1)
|
---|
1792 | err = req.Header.Write(w)
|
---|
1793 | if err == nil {
|
---|
1794 | err = writeBodyChunked(w, req.bodyStream)
|
---|
1795 | }
|
---|
1796 | if err == nil {
|
---|
1797 | err = req.Header.writeTrailer(w)
|
---|
1798 | }
|
---|
1799 | }
|
---|
1800 | err1 := req.closeBodyStream()
|
---|
1801 | if err == nil {
|
---|
1802 | err = err1
|
---|
1803 | }
|
---|
1804 | return err
|
---|
1805 | }
|
---|
1806 |
|
---|
1807 | // ErrBodyStreamWritePanic is returned when panic happens during writing body stream.
|
---|
1808 | type ErrBodyStreamWritePanic struct {
|
---|
1809 | error
|
---|
1810 | }
|
---|
1811 |
|
---|
1812 | func (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) (err error) {
|
---|
1813 | defer func() {
|
---|
1814 | if r := recover(); r != nil {
|
---|
1815 | err = &ErrBodyStreamWritePanic{
|
---|
1816 | error: fmt.Errorf("panic while writing body stream: %+v", r),
|
---|
1817 | }
|
---|
1818 | }
|
---|
1819 | }()
|
---|
1820 |
|
---|
1821 | contentLength := resp.Header.ContentLength()
|
---|
1822 | if contentLength < 0 {
|
---|
1823 | lrSize := limitedReaderSize(resp.bodyStream)
|
---|
1824 | if lrSize >= 0 {
|
---|
1825 | contentLength = int(lrSize)
|
---|
1826 | if int64(contentLength) != lrSize {
|
---|
1827 | contentLength = -1
|
---|
1828 | }
|
---|
1829 | if contentLength >= 0 {
|
---|
1830 | resp.Header.SetContentLength(contentLength)
|
---|
1831 | }
|
---|
1832 | }
|
---|
1833 | }
|
---|
1834 | if contentLength >= 0 {
|
---|
1835 | if err = resp.Header.Write(w); err == nil {
|
---|
1836 | if resp.ImmediateHeaderFlush {
|
---|
1837 | err = w.Flush()
|
---|
1838 | }
|
---|
1839 | if err == nil && sendBody {
|
---|
1840 | err = writeBodyFixedSize(w, resp.bodyStream, int64(contentLength))
|
---|
1841 | }
|
---|
1842 | }
|
---|
1843 | } else {
|
---|
1844 | resp.Header.SetContentLength(-1)
|
---|
1845 | if err = resp.Header.Write(w); err == nil {
|
---|
1846 | if resp.ImmediateHeaderFlush {
|
---|
1847 | err = w.Flush()
|
---|
1848 | }
|
---|
1849 | if err == nil && sendBody {
|
---|
1850 | err = writeBodyChunked(w, resp.bodyStream)
|
---|
1851 | }
|
---|
1852 | if err == nil {
|
---|
1853 | err = resp.Header.writeTrailer(w)
|
---|
1854 | }
|
---|
1855 | }
|
---|
1856 | }
|
---|
1857 | err1 := resp.closeBodyStream()
|
---|
1858 | if err == nil {
|
---|
1859 | err = err1
|
---|
1860 | }
|
---|
1861 | return err
|
---|
1862 | }
|
---|
1863 |
|
---|
1864 | func (req *Request) closeBodyStream() error {
|
---|
1865 | if req.bodyStream == nil {
|
---|
1866 | return nil
|
---|
1867 | }
|
---|
1868 | var err error
|
---|
1869 | if bsc, ok := req.bodyStream.(io.Closer); ok {
|
---|
1870 | err = bsc.Close()
|
---|
1871 | }
|
---|
1872 | req.bodyStream = nil
|
---|
1873 | return err
|
---|
1874 | }
|
---|
1875 |
|
---|
1876 | func (resp *Response) closeBodyStream() error {
|
---|
1877 | if resp.bodyStream == nil {
|
---|
1878 | return nil
|
---|
1879 | }
|
---|
1880 | var err error
|
---|
1881 | if bsc, ok := resp.bodyStream.(io.Closer); ok {
|
---|
1882 | err = bsc.Close()
|
---|
1883 | }
|
---|
1884 | resp.bodyStream = nil
|
---|
1885 | return err
|
---|
1886 | }
|
---|
1887 |
|
---|
1888 | // String returns request representation.
|
---|
1889 | //
|
---|
1890 | // Returns error message instead of request representation on error.
|
---|
1891 | //
|
---|
1892 | // Use Write instead of String for performance-critical code.
|
---|
1893 | func (req *Request) String() string {
|
---|
1894 | return getHTTPString(req)
|
---|
1895 | }
|
---|
1896 |
|
---|
1897 | // String returns response representation.
|
---|
1898 | //
|
---|
1899 | // Returns error message instead of response representation on error.
|
---|
1900 | //
|
---|
1901 | // Use Write instead of String for performance-critical code.
|
---|
1902 | func (resp *Response) String() string {
|
---|
1903 | return getHTTPString(resp)
|
---|
1904 | }
|
---|
1905 |
|
---|
1906 | func getHTTPString(hw httpWriter) string {
|
---|
1907 | w := bytebufferpool.Get()
|
---|
1908 | bw := bufio.NewWriter(w)
|
---|
1909 | if err := hw.Write(bw); err != nil {
|
---|
1910 | return err.Error()
|
---|
1911 | }
|
---|
1912 | if err := bw.Flush(); err != nil {
|
---|
1913 | return err.Error()
|
---|
1914 | }
|
---|
1915 | s := string(w.B)
|
---|
1916 | bytebufferpool.Put(w)
|
---|
1917 | return s
|
---|
1918 | }
|
---|
1919 |
|
---|
1920 | type httpWriter interface {
|
---|
1921 | Write(w *bufio.Writer) error
|
---|
1922 | }
|
---|
1923 |
|
---|
1924 | func writeBodyChunked(w *bufio.Writer, r io.Reader) error {
|
---|
1925 | vbuf := copyBufPool.Get()
|
---|
1926 | buf := vbuf.([]byte)
|
---|
1927 |
|
---|
1928 | var err error
|
---|
1929 | var n int
|
---|
1930 | for {
|
---|
1931 | n, err = r.Read(buf)
|
---|
1932 | if n == 0 {
|
---|
1933 | if err == nil {
|
---|
1934 | panic("BUG: io.Reader returned 0, nil")
|
---|
1935 | }
|
---|
1936 | if err == io.EOF {
|
---|
1937 | if err = writeChunk(w, buf[:0]); err != nil {
|
---|
1938 | break
|
---|
1939 | }
|
---|
1940 | err = nil
|
---|
1941 | }
|
---|
1942 | break
|
---|
1943 | }
|
---|
1944 | if err = writeChunk(w, buf[:n]); err != nil {
|
---|
1945 | break
|
---|
1946 | }
|
---|
1947 | }
|
---|
1948 |
|
---|
1949 | copyBufPool.Put(vbuf)
|
---|
1950 | return err
|
---|
1951 | }
|
---|
1952 |
|
---|
1953 | func limitedReaderSize(r io.Reader) int64 {
|
---|
1954 | lr, ok := r.(*io.LimitedReader)
|
---|
1955 | if !ok {
|
---|
1956 | return -1
|
---|
1957 | }
|
---|
1958 | return lr.N
|
---|
1959 | }
|
---|
1960 |
|
---|
1961 | func writeBodyFixedSize(w *bufio.Writer, r io.Reader, size int64) error {
|
---|
1962 | if size > maxSmallFileSize {
|
---|
1963 | // w buffer must be empty for triggering
|
---|
1964 | // sendfile path in bufio.Writer.ReadFrom.
|
---|
1965 | if err := w.Flush(); err != nil {
|
---|
1966 | return err
|
---|
1967 | }
|
---|
1968 | }
|
---|
1969 |
|
---|
1970 | n, err := copyZeroAlloc(w, r)
|
---|
1971 |
|
---|
1972 | if n != size && err == nil {
|
---|
1973 | err = fmt.Errorf("copied %d bytes from body stream instead of %d bytes", n, size)
|
---|
1974 | }
|
---|
1975 | return err
|
---|
1976 | }
|
---|
1977 |
|
---|
1978 | func copyZeroAlloc(w io.Writer, r io.Reader) (int64, error) {
|
---|
1979 | vbuf := copyBufPool.Get()
|
---|
1980 | buf := vbuf.([]byte)
|
---|
1981 | n, err := io.CopyBuffer(w, r, buf)
|
---|
1982 | copyBufPool.Put(vbuf)
|
---|
1983 | return n, err
|
---|
1984 | }
|
---|
1985 |
|
---|
1986 | var copyBufPool = sync.Pool{
|
---|
1987 | New: func() interface{} {
|
---|
1988 | return make([]byte, 4096)
|
---|
1989 | },
|
---|
1990 | }
|
---|
1991 |
|
---|
1992 | func writeChunk(w *bufio.Writer, b []byte) error {
|
---|
1993 | n := len(b)
|
---|
1994 | if err := writeHexInt(w, n); err != nil {
|
---|
1995 | return err
|
---|
1996 | }
|
---|
1997 | if _, err := w.Write(strCRLF); err != nil {
|
---|
1998 | return err
|
---|
1999 | }
|
---|
2000 | if _, err := w.Write(b); err != nil {
|
---|
2001 | return err
|
---|
2002 | }
|
---|
2003 | // If is end chunk, write CRLF after writing trailer
|
---|
2004 | if n > 0 {
|
---|
2005 | if _, err := w.Write(strCRLF); err != nil {
|
---|
2006 | return err
|
---|
2007 | }
|
---|
2008 | }
|
---|
2009 | return w.Flush()
|
---|
2010 | }
|
---|
2011 |
|
---|
2012 | // ErrBodyTooLarge is returned if either request or response body exceeds
|
---|
2013 | // the given limit.
|
---|
2014 | var ErrBodyTooLarge = errors.New("body size exceeds the given limit")
|
---|
2015 |
|
---|
2016 | func readBody(r *bufio.Reader, contentLength int, maxBodySize int, dst []byte) ([]byte, error) {
|
---|
2017 | if maxBodySize > 0 && contentLength > maxBodySize {
|
---|
2018 | return dst, ErrBodyTooLarge
|
---|
2019 | }
|
---|
2020 | return appendBodyFixedSize(r, dst, contentLength)
|
---|
2021 | }
|
---|
2022 |
|
---|
2023 | var errChunkedStream = errors.New("chunked stream")
|
---|
2024 |
|
---|
2025 | func readBodyWithStreaming(r *bufio.Reader, contentLength int, maxBodySize int, dst []byte) (b []byte, err error) {
|
---|
2026 | if contentLength == -1 {
|
---|
2027 | // handled in requestStream.Read()
|
---|
2028 | return b, errChunkedStream
|
---|
2029 | }
|
---|
2030 |
|
---|
2031 | dst = dst[:0]
|
---|
2032 |
|
---|
2033 | readN := maxBodySize
|
---|
2034 | if readN > contentLength {
|
---|
2035 | readN = contentLength
|
---|
2036 | }
|
---|
2037 | if readN > 8*1024 {
|
---|
2038 | readN = 8 * 1024
|
---|
2039 | }
|
---|
2040 |
|
---|
2041 | if contentLength >= 0 && maxBodySize >= contentLength {
|
---|
2042 | b, err = appendBodyFixedSize(r, dst, readN)
|
---|
2043 | } else {
|
---|
2044 | b, err = readBodyIdentity(r, readN, dst)
|
---|
2045 | }
|
---|
2046 |
|
---|
2047 | if err != nil {
|
---|
2048 | return b, err
|
---|
2049 | }
|
---|
2050 | if contentLength > maxBodySize {
|
---|
2051 | return b, ErrBodyTooLarge
|
---|
2052 | }
|
---|
2053 | return b, nil
|
---|
2054 | }
|
---|
2055 |
|
---|
2056 | func readBodyIdentity(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, error) {
|
---|
2057 | dst = dst[:cap(dst)]
|
---|
2058 | if len(dst) == 0 {
|
---|
2059 | dst = make([]byte, 1024)
|
---|
2060 | }
|
---|
2061 | offset := 0
|
---|
2062 | for {
|
---|
2063 | nn, err := r.Read(dst[offset:])
|
---|
2064 | if nn <= 0 {
|
---|
2065 | if err != nil {
|
---|
2066 | if err == io.EOF {
|
---|
2067 | return dst[:offset], nil
|
---|
2068 | }
|
---|
2069 | return dst[:offset], err
|
---|
2070 | }
|
---|
2071 | panic(fmt.Sprintf("BUG: bufio.Read() returned (%d, nil)", nn))
|
---|
2072 | }
|
---|
2073 | offset += nn
|
---|
2074 | if maxBodySize > 0 && offset > maxBodySize {
|
---|
2075 | return dst[:offset], ErrBodyTooLarge
|
---|
2076 | }
|
---|
2077 | if len(dst) == offset {
|
---|
2078 | n := round2(2 * offset)
|
---|
2079 | if maxBodySize > 0 && n > maxBodySize {
|
---|
2080 | n = maxBodySize + 1
|
---|
2081 | }
|
---|
2082 | b := make([]byte, n)
|
---|
2083 | copy(b, dst)
|
---|
2084 | dst = b
|
---|
2085 | }
|
---|
2086 | }
|
---|
2087 | }
|
---|
2088 |
|
---|
2089 | func appendBodyFixedSize(r *bufio.Reader, dst []byte, n int) ([]byte, error) {
|
---|
2090 | if n == 0 {
|
---|
2091 | return dst, nil
|
---|
2092 | }
|
---|
2093 |
|
---|
2094 | offset := len(dst)
|
---|
2095 | dstLen := offset + n
|
---|
2096 | if cap(dst) < dstLen {
|
---|
2097 | b := make([]byte, round2(dstLen))
|
---|
2098 | copy(b, dst)
|
---|
2099 | dst = b
|
---|
2100 | }
|
---|
2101 | dst = dst[:dstLen]
|
---|
2102 |
|
---|
2103 | for {
|
---|
2104 | nn, err := r.Read(dst[offset:])
|
---|
2105 | if nn <= 0 {
|
---|
2106 | if err != nil {
|
---|
2107 | if err == io.EOF {
|
---|
2108 | err = io.ErrUnexpectedEOF
|
---|
2109 | }
|
---|
2110 | return dst[:offset], err
|
---|
2111 | }
|
---|
2112 | panic(fmt.Sprintf("BUG: bufio.Read() returned (%d, nil)", nn))
|
---|
2113 | }
|
---|
2114 | offset += nn
|
---|
2115 | if offset == dstLen {
|
---|
2116 | return dst, nil
|
---|
2117 | }
|
---|
2118 | }
|
---|
2119 | }
|
---|
2120 |
|
---|
2121 | // ErrBrokenChunk is returned when server receives a broken chunked body (Transfer-Encoding: chunked).
|
---|
2122 | type ErrBrokenChunk struct {
|
---|
2123 | error
|
---|
2124 | }
|
---|
2125 |
|
---|
2126 | func readBodyChunked(r *bufio.Reader, maxBodySize int, dst []byte) ([]byte, error) {
|
---|
2127 | if len(dst) > 0 {
|
---|
2128 | panic("BUG: expected zero-length buffer")
|
---|
2129 | }
|
---|
2130 |
|
---|
2131 | strCRLFLen := len(strCRLF)
|
---|
2132 | for {
|
---|
2133 | chunkSize, err := parseChunkSize(r)
|
---|
2134 | if err != nil {
|
---|
2135 | return dst, err
|
---|
2136 | }
|
---|
2137 | if chunkSize == 0 {
|
---|
2138 | return dst, err
|
---|
2139 | }
|
---|
2140 | if maxBodySize > 0 && len(dst)+chunkSize > maxBodySize {
|
---|
2141 | return dst, ErrBodyTooLarge
|
---|
2142 | }
|
---|
2143 | dst, err = appendBodyFixedSize(r, dst, chunkSize+strCRLFLen)
|
---|
2144 | if err != nil {
|
---|
2145 | return dst, err
|
---|
2146 | }
|
---|
2147 | if !bytes.Equal(dst[len(dst)-strCRLFLen:], strCRLF) {
|
---|
2148 | return dst, ErrBrokenChunk{
|
---|
2149 | error: fmt.Errorf("cannot find crlf at the end of chunk"),
|
---|
2150 | }
|
---|
2151 | }
|
---|
2152 | dst = dst[:len(dst)-strCRLFLen]
|
---|
2153 | }
|
---|
2154 | }
|
---|
2155 |
|
---|
2156 | func parseChunkSize(r *bufio.Reader) (int, error) {
|
---|
2157 | n, err := readHexInt(r)
|
---|
2158 | if err != nil {
|
---|
2159 | return -1, err
|
---|
2160 | }
|
---|
2161 | for {
|
---|
2162 | c, err := r.ReadByte()
|
---|
2163 | if err != nil {
|
---|
2164 | return -1, ErrBrokenChunk{
|
---|
2165 | error: fmt.Errorf("cannot read '\r' char at the end of chunk size: %s", err),
|
---|
2166 | }
|
---|
2167 | }
|
---|
2168 | // Skip chunk extension after chunk size.
|
---|
2169 | // Add support later if anyone needs it.
|
---|
2170 | if c != '\r' {
|
---|
2171 | continue
|
---|
2172 | }
|
---|
2173 | if err := r.UnreadByte(); err != nil {
|
---|
2174 | return -1, ErrBrokenChunk{
|
---|
2175 | error: fmt.Errorf("cannot unread '\r' char at the end of chunk size: %w", err),
|
---|
2176 | }
|
---|
2177 | }
|
---|
2178 | break
|
---|
2179 | }
|
---|
2180 | err = readCrLf(r)
|
---|
2181 | if err != nil {
|
---|
2182 | return -1, err
|
---|
2183 | }
|
---|
2184 | return n, nil
|
---|
2185 | }
|
---|
2186 |
|
---|
2187 | func readCrLf(r *bufio.Reader) error {
|
---|
2188 | for _, exp := range []byte{'\r', '\n'} {
|
---|
2189 | c, err := r.ReadByte()
|
---|
2190 | if err != nil {
|
---|
2191 | return ErrBrokenChunk{
|
---|
2192 | error: fmt.Errorf("cannot read %q char at the end of chunk size: %w", exp, err),
|
---|
2193 | }
|
---|
2194 | }
|
---|
2195 | if c != exp {
|
---|
2196 | return ErrBrokenChunk{
|
---|
2197 | error: fmt.Errorf("unexpected char %q at the end of chunk size. Expected %q", c, exp),
|
---|
2198 | }
|
---|
2199 | }
|
---|
2200 | }
|
---|
2201 | return nil
|
---|
2202 | }
|
---|
2203 |
|
---|
2204 | func round2(n int) int {
|
---|
2205 | if n <= 0 {
|
---|
2206 | return 0
|
---|
2207 | }
|
---|
2208 |
|
---|
2209 | x := uint32(n - 1)
|
---|
2210 | x |= x >> 1
|
---|
2211 | x |= x >> 2
|
---|
2212 | x |= x >> 4
|
---|
2213 | x |= x >> 8
|
---|
2214 | x |= x >> 16
|
---|
2215 |
|
---|
2216 | return int(x + 1)
|
---|
2217 | }
|
---|