github.com/cloudwego/hertz@v0.9.3/pkg/protocol/request.go (about)

     1  /*
     2   * Copyright 2022 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   * The MIT License (MIT)
    17   *
    18   * Copyright (c) 2015-present Aliaksandr Valialkin, VertaMedia, Kirill Danshin, Erik Dubbelboer, FastHTTP Authors
    19   *
    20   * Permission is hereby granted, free of charge, to any person obtaining a copy
    21   * of this software and associated documentation files (the "Software"), to deal
    22   * in the Software without restriction, including without limitation the rights
    23   * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    24   * copies of the Software, and to permit persons to whom the Software is
    25   * furnished to do so, subject to the following conditions:
    26   *
    27   * The above copyright notice and this permission notice shall be included in
    28   * all copies or substantial portions of the Software.
    29   *
    30   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    31   * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    32   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    33   * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    34   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    35   * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    36   * THE SOFTWARE.
    37   *
    38   * This file may have been modified by CloudWeGo authors. All CloudWeGo
    39   * Modifications are Copyright 2022 CloudWeGo Authors.
    40   */
    41  
    42  package protocol
    43  
    44  import (
    45  	"bytes"
    46  	"compress/gzip"
    47  	"encoding/base64"
    48  	"fmt"
    49  	"io"
    50  	"mime/multipart"
    51  	"net/url"
    52  	"strings"
    53  	"sync"
    54  
    55  	"github.com/cloudwego/hertz/internal/bytesconv"
    56  	"github.com/cloudwego/hertz/internal/bytestr"
    57  	"github.com/cloudwego/hertz/internal/nocopy"
    58  	"github.com/cloudwego/hertz/pkg/common/bytebufferpool"
    59  	"github.com/cloudwego/hertz/pkg/common/compress"
    60  	"github.com/cloudwego/hertz/pkg/common/config"
    61  	"github.com/cloudwego/hertz/pkg/common/errors"
    62  	"github.com/cloudwego/hertz/pkg/common/utils"
    63  	"github.com/cloudwego/hertz/pkg/network"
    64  	"github.com/cloudwego/hertz/pkg/protocol/consts"
    65  )
    66  
    67  var (
    68  	ErrMissingFile = errors.NewPublic("http: no such file")
    69  
    70  	responseBodyPool bytebufferpool.Pool
    71  	requestBodyPool  bytebufferpool.Pool
    72  
    73  	requestPool sync.Pool
    74  )
    75  
    76  // NoBody is an io.ReadCloser with no bytes. Read always returns EOF
    77  // and Close always returns nil. It can be used in an outgoing client
    78  // request to explicitly signal that a request has zero bytes.
    79  var NoBody = noBody{}
    80  
    81  type noBody struct{}
    82  
    83  func (noBody) Read([]byte) (int, error) { return 0, io.EOF }
    84  func (noBody) Close() error             { return nil }
    85  
    86  type Request struct {
    87  	noCopy nocopy.NoCopy //lint:ignore U1000 until noCopy is used
    88  
    89  	Header RequestHeader
    90  
    91  	uri      URI
    92  	postArgs Args
    93  
    94  	bodyStream      io.Reader
    95  	w               requestBodyWriter
    96  	body            *bytebufferpool.ByteBuffer
    97  	bodyRaw         []byte
    98  	maxKeepBodySize int
    99  
   100  	multipartForm         *multipart.Form
   101  	multipartFormBoundary string
   102  
   103  	// Group bool members in order to reduce Request object size.
   104  	parsedURI      bool
   105  	parsedPostArgs bool
   106  
   107  	isTLS bool
   108  
   109  	multipartFiles  []*File
   110  	multipartFields []*MultipartField
   111  
   112  	// Request level options, service discovery options etc.
   113  	options *config.RequestOptions
   114  }
   115  
   116  type requestBodyWriter struct {
   117  	r *Request
   118  }
   119  
   120  // File struct represent file information for multipart request
   121  type File struct {
   122  	Name      string
   123  	ParamName string
   124  	io.Reader
   125  }
   126  
   127  // MultipartField struct represent custom data part for multipart request
   128  type MultipartField struct {
   129  	Param       string
   130  	FileName    string
   131  	ContentType string
   132  	io.Reader
   133  }
   134  
   135  func (w *requestBodyWriter) Write(p []byte) (int, error) {
   136  	w.r.AppendBody(p)
   137  	return len(p), nil
   138  }
   139  
   140  func (req *Request) Options() *config.RequestOptions {
   141  	if req.options == nil {
   142  		req.options = config.NewRequestOptions(nil)
   143  	}
   144  	return req.options
   145  }
   146  
   147  // AppendBody appends p to request body.
   148  //
   149  // It is safe re-using p after the function returns.
   150  func (req *Request) AppendBody(p []byte) {
   151  	req.RemoveMultipartFormFiles()
   152  	req.CloseBodyStream()     //nolint:errcheck
   153  	req.BodyBuffer().Write(p) //nolint:errcheck
   154  }
   155  
   156  func (req *Request) BodyBuffer() *bytebufferpool.ByteBuffer {
   157  	if req.body == nil {
   158  		req.body = requestBodyPool.Get()
   159  	}
   160  	req.bodyRaw = nil
   161  	return req.body
   162  }
   163  
   164  // MayContinue returns true if the request contains
   165  // 'Expect: 100-continue' header.
   166  //
   167  // The caller must do one of the following actions if MayContinue returns true:
   168  //
   169  //   - Either send StatusExpectationFailed response if request headers don't
   170  //     satisfy the caller.
   171  //   - Or send StatusContinue response before reading request body
   172  //     with ContinueReadBody.
   173  //   - Or close the connection.
   174  func (req *Request) MayContinue() bool {
   175  	return bytes.Equal(req.Header.peek(bytestr.StrExpect), bytestr.Str100Continue)
   176  }
   177  
   178  // Scheme returns the scheme of the request.
   179  // uri will be parsed in ServeHTTP(before user's process), so that there is no need for uri nil-check.
   180  func (req *Request) Scheme() []byte {
   181  	return req.uri.Scheme()
   182  }
   183  
   184  // For keepalive connection reuse.
   185  // It is roughly the same as ResetSkipHeader, except that the connection related fields are removed:
   186  // - req.isTLS
   187  func (req *Request) resetSkipHeaderAndConn() {
   188  	req.ResetBody()
   189  	req.uri.Reset()
   190  	req.parsedURI = false
   191  	req.parsedPostArgs = false
   192  	req.postArgs.Reset()
   193  }
   194  
   195  func (req *Request) ResetSkipHeader() {
   196  	req.resetSkipHeaderAndConn()
   197  	req.isTLS = false
   198  }
   199  
   200  func SwapRequestBody(a, b *Request) {
   201  	a.body, b.body = b.body, a.body
   202  	a.bodyRaw, b.bodyRaw = b.bodyRaw, a.bodyRaw
   203  	a.bodyStream, b.bodyStream = b.bodyStream, a.bodyStream
   204  	a.multipartFields, b.multipartFields = b.multipartFields, a.multipartFields
   205  	a.multipartFiles, b.multipartFiles = b.multipartFiles, a.multipartFiles
   206  }
   207  
   208  // Reset clears request contents.
   209  func (req *Request) Reset() {
   210  	req.Header.Reset()
   211  	req.ResetSkipHeader()
   212  	req.CloseBodyStream()
   213  
   214  	req.options = nil
   215  }
   216  
   217  func (req *Request) IsURIParsed() bool {
   218  	return req.parsedURI
   219  }
   220  
   221  func (req *Request) PostArgString() []byte {
   222  	return req.postArgs.QueryString()
   223  }
   224  
   225  // MultipartForm returns request's multipart form.
   226  //
   227  // Returns errors.ErrNoMultipartForm if request's Content-Type
   228  // isn't 'multipart/form-data'.
   229  //
   230  // RemoveMultipartFormFiles must be called after returned multipart form
   231  // is processed.
   232  func (req *Request) MultipartForm() (*multipart.Form, error) {
   233  	if req.multipartForm != nil {
   234  		return req.multipartForm, nil
   235  	}
   236  	req.multipartFormBoundary = string(req.Header.MultipartFormBoundary())
   237  	if len(req.multipartFormBoundary) == 0 {
   238  		return nil, errors.ErrNoMultipartForm
   239  	}
   240  
   241  	ce := req.Header.peek(bytestr.StrContentEncoding)
   242  	var err error
   243  	var f *multipart.Form
   244  
   245  	if !req.IsBodyStream() {
   246  		body := req.BodyBytes()
   247  		if bytes.Equal(ce, bytestr.StrGzip) {
   248  			// Do not care about memory usage here.
   249  			var err error
   250  			if body, err = compress.AppendGunzipBytes(nil, body); err != nil {
   251  				return nil, fmt.Errorf("cannot gunzip request body: %s", err)
   252  			}
   253  		} else if len(ce) > 0 {
   254  			return nil, fmt.Errorf("unsupported Content-Encoding: %q", ce)
   255  		}
   256  		f, err = ReadMultipartForm(bytes.NewReader(body), req.multipartFormBoundary, len(body), len(body))
   257  	} else {
   258  		bodyStream := req.bodyStream
   259  		if req.Header.contentLength > 0 {
   260  			bodyStream = io.LimitReader(bodyStream, int64(req.Header.contentLength))
   261  		}
   262  		if bytes.Equal(ce, bytestr.StrGzip) {
   263  			// Do not care about memory usage here.
   264  			if bodyStream, err = gzip.NewReader(bodyStream); err != nil {
   265  				return nil, fmt.Errorf("cannot gunzip request body: %w", err)
   266  			}
   267  		} else if len(ce) > 0 {
   268  			return nil, fmt.Errorf("unsupported Content-Encoding: %q", ce)
   269  		}
   270  
   271  		mr := multipart.NewReader(bodyStream, req.multipartFormBoundary)
   272  
   273  		f, err = mr.ReadForm(8 * 1024)
   274  	}
   275  
   276  	if err != nil {
   277  		return nil, err
   278  	}
   279  	req.multipartForm = f
   280  	return f, nil
   281  }
   282  
   283  // AppendBodyString appends s to request body.
   284  func (req *Request) AppendBodyString(s string) {
   285  	req.RemoveMultipartFormFiles()
   286  	req.CloseBodyStream()           //nolint:errcheck
   287  	req.BodyBuffer().WriteString(s) //nolint:errcheck
   288  }
   289  
   290  // SetRequestURI sets RequestURI.
   291  func (req *Request) SetRequestURI(requestURI string) {
   292  	req.Header.SetRequestURI(requestURI)
   293  	req.parsedURI = false
   294  }
   295  
   296  func (req *Request) SetMaxKeepBodySize(n int) {
   297  	req.maxKeepBodySize = n
   298  }
   299  
   300  // RequestURI returns the RequestURI for the given request.
   301  func (req *Request) RequestURI() []byte {
   302  	return req.Header.RequestURI()
   303  }
   304  
   305  // FormFile returns the first file for the provided form key.
   306  func (req *Request) FormFile(name string) (*multipart.FileHeader, error) {
   307  	mf, err := req.MultipartForm()
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  	if mf.File == nil {
   312  		return nil, err
   313  	}
   314  	fhh := mf.File[name]
   315  	if fhh == nil {
   316  		return nil, ErrMissingFile
   317  	}
   318  	return fhh[0], nil
   319  }
   320  
   321  // SetHost sets host for the request.
   322  func (req *Request) SetHost(host string) {
   323  	req.URI().SetHost(host)
   324  }
   325  
   326  // Host returns the host for the given request.
   327  func (req *Request) Host() []byte {
   328  	return req.URI().Host()
   329  }
   330  
   331  // SetIsTLS is used by TLS server to mark whether the request is a TLS request.
   332  // Client shouldn't use this method but should depend on the uri.scheme instead.
   333  func (req *Request) SetIsTLS(isTLS bool) {
   334  	req.isTLS = isTLS
   335  }
   336  
   337  // SwapBody swaps request body with the given body and returns
   338  // the previous request body.
   339  //
   340  // It is forbidden to use the body passed to SwapBody after
   341  // the function returns.
   342  func (req *Request) SwapBody(body []byte) []byte {
   343  	bb := req.BodyBuffer()
   344  	zw := network.NewWriter(bb)
   345  
   346  	if req.IsBodyStream() {
   347  		bb.Reset()
   348  		_, err := utils.CopyZeroAlloc(zw, req.bodyStream)
   349  		req.CloseBodyStream() //nolint:errcheck
   350  		if err != nil {
   351  			bb.Reset()
   352  			bb.SetString(err.Error())
   353  		}
   354  	}
   355  
   356  	req.bodyRaw = nil
   357  
   358  	oldBody := bb.B
   359  	bb.B = body
   360  	return oldBody
   361  }
   362  
   363  // CopyTo copies req contents to dst except of body stream.
   364  func (req *Request) CopyTo(dst *Request) {
   365  	req.CopyToSkipBody(dst)
   366  	if req.bodyRaw != nil {
   367  		dst.bodyRaw = append(dst.bodyRaw[:0], req.bodyRaw...)
   368  		if dst.body != nil {
   369  			dst.body.Reset()
   370  		}
   371  	} else if req.body != nil {
   372  		dst.BodyBuffer().Set(req.body.B)
   373  	} else if dst.body != nil {
   374  		dst.body.Reset()
   375  	}
   376  }
   377  
   378  func (req *Request) CopyToSkipBody(dst *Request) {
   379  	dst.Reset()
   380  	req.Header.CopyTo(&dst.Header)
   381  
   382  	req.uri.CopyTo(&dst.uri)
   383  	dst.parsedURI = req.parsedURI
   384  
   385  	req.postArgs.CopyTo(&dst.postArgs)
   386  	dst.parsedPostArgs = req.parsedPostArgs
   387  	dst.isTLS = req.isTLS
   388  
   389  	if req.options != nil {
   390  		dst.options = &config.RequestOptions{}
   391  		req.options.CopyTo(dst.options)
   392  	}
   393  
   394  	// do not copy multipartForm - it will be automatically
   395  	// re-created on the first call to MultipartForm.
   396  }
   397  
   398  func (req *Request) BodyBytes() []byte {
   399  	if req.bodyRaw != nil {
   400  		return req.bodyRaw
   401  	}
   402  	if req.body == nil {
   403  		return nil
   404  	}
   405  	return req.body.B
   406  }
   407  
   408  // ResetBody resets request body.
   409  func (req *Request) ResetBody() {
   410  	req.bodyRaw = nil
   411  	req.RemoveMultipartFormFiles()
   412  	req.CloseBodyStream() //nolint:errcheck
   413  	if req.body != nil {
   414  		if req.body.Len() <= req.maxKeepBodySize {
   415  			req.body.Reset()
   416  			return
   417  		}
   418  		requestBodyPool.Put(req.body)
   419  		req.body = nil
   420  	}
   421  }
   422  
   423  // SetBodyRaw sets request body, but without copying it.
   424  //
   425  // From this point onward the body argument must not be changed.
   426  func (req *Request) SetBodyRaw(body []byte) {
   427  	req.ResetBody()
   428  	req.bodyRaw = body
   429  }
   430  
   431  // SetMultipartFormBoundary will set the multipart form boundary for the request.
   432  func (req *Request) SetMultipartFormBoundary(b string) {
   433  	req.multipartFormBoundary = b
   434  }
   435  
   436  func (req *Request) MultipartFormBoundary() string {
   437  	return req.multipartFormBoundary
   438  }
   439  
   440  // SetBody sets request body.
   441  //
   442  // It is safe re-using body argument after the function returns.
   443  func (req *Request) SetBody(body []byte) {
   444  	req.RemoveMultipartFormFiles()
   445  	req.CloseBodyStream() //nolint:errcheck
   446  	req.BodyBuffer().Set(body)
   447  }
   448  
   449  // SetBodyString sets request body.
   450  func (req *Request) SetBodyString(body string) {
   451  	req.RemoveMultipartFormFiles()
   452  	req.CloseBodyStream() //nolint:errcheck
   453  	req.BodyBuffer().SetString(body)
   454  }
   455  
   456  // SetQueryString sets query string.
   457  func (req *Request) SetQueryString(queryString string) {
   458  	req.URI().SetQueryString(queryString)
   459  }
   460  
   461  // SetFormData sets x-www-form-urlencoded params
   462  func (req *Request) SetFormData(data map[string]string) {
   463  	for k, v := range data {
   464  		req.postArgs.Add(k, v)
   465  	}
   466  	req.parsedPostArgs = true
   467  	req.Header.SetContentTypeBytes(bytestr.StrPostArgsContentType)
   468  }
   469  
   470  // SetFormDataFromValues sets x-www-form-urlencoded params from url values.
   471  func (req *Request) SetFormDataFromValues(data url.Values) {
   472  	for k, v := range data {
   473  		for _, kv := range v {
   474  			req.postArgs.Add(k, kv)
   475  		}
   476  	}
   477  	req.parsedPostArgs = true
   478  	req.Header.SetContentTypeBytes(bytestr.StrPostArgsContentType)
   479  }
   480  
   481  // SetFile sets single file field name and its path for multipart upload.
   482  func (req *Request) SetFile(param, filePath string) {
   483  	req.multipartFiles = append(req.multipartFiles, &File{
   484  		Name:      filePath,
   485  		ParamName: param,
   486  	})
   487  }
   488  
   489  // SetFiles sets multiple file field name and its path for multipart upload.
   490  func (req *Request) SetFiles(files map[string]string) {
   491  	for f, fp := range files {
   492  		req.multipartFiles = append(req.multipartFiles, &File{
   493  			Name:      fp,
   494  			ParamName: f,
   495  		})
   496  	}
   497  }
   498  
   499  // SetFileReader sets single file using io.Reader for multipart upload.
   500  func (req *Request) SetFileReader(param, fileName string, reader io.Reader) {
   501  	req.multipartFiles = append(req.multipartFiles, &File{
   502  		Name:      fileName,
   503  		ParamName: param,
   504  		Reader:    reader,
   505  	})
   506  }
   507  
   508  // SetMultipartFormData method allows simple form data to be attached to the request as `multipart:form-data`
   509  func (req *Request) SetMultipartFormData(data map[string]string) {
   510  	for k, v := range data {
   511  		req.SetMultipartField(k, "", "", strings.NewReader(v))
   512  	}
   513  }
   514  
   515  func (req *Request) MultipartFiles() []*File {
   516  	return req.multipartFiles
   517  }
   518  
   519  // SetMultipartField sets custom data using io.Reader for multipart upload.
   520  func (req *Request) SetMultipartField(param, fileName, contentType string, reader io.Reader) {
   521  	req.multipartFields = append(req.multipartFields, &MultipartField{
   522  		Param:       param,
   523  		FileName:    fileName,
   524  		ContentType: contentType,
   525  		Reader:      reader,
   526  	})
   527  }
   528  
   529  // SetMultipartFields sets multiple data fields using io.Reader for multipart upload.
   530  func (req *Request) SetMultipartFields(fields ...*MultipartField) {
   531  	req.multipartFields = append(req.multipartFields, fields...)
   532  }
   533  
   534  func (req *Request) MultipartFields() []*MultipartField {
   535  	return req.multipartFields
   536  }
   537  
   538  // SetBasicAuth sets the basic authentication header in the current HTTP request.
   539  func (req *Request) SetBasicAuth(username, password string) {
   540  	encodeStr := base64.StdEncoding.EncodeToString([]byte(username + ":" + password))
   541  	req.SetHeader(consts.HeaderAuthorization, "Basic "+encodeStr)
   542  }
   543  
   544  // BasicAuth can return the username and password in the request's Authorization
   545  // header, if the request uses the HTTP Basic Authorization.
   546  func (req *Request) BasicAuth() (username, password string, ok bool) {
   547  	// Using Peek to reduce the cost for type transfer.
   548  	auth := req.Header.Peek(consts.HeaderAuthorization)
   549  	if auth == nil {
   550  		return
   551  	}
   552  
   553  	return parseBasicAuth(auth)
   554  }
   555  
   556  var prefix = []byte{'B', 'a', 's', 'i', 'c', ' '}
   557  
   558  // parseBasicAuth can parse an HTTP Basic Authorization string encrypted by base64.
   559  // Example: "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" returns ("Aladdin", "open sesame", true).
   560  func parseBasicAuth(auth []byte) (username, password string, ok bool) {
   561  	if len(auth) < len(prefix) || !bytes.EqualFold(auth[:len(prefix)], prefix) {
   562  		return
   563  	}
   564  
   565  	decodeLen := base64.StdEncoding.DecodedLen(len(auth[len(prefix):]))
   566  	// base64.StdEncoding.Decode(dst,rsc []byte) will return less than DecodedLen(len(src)))
   567  	decodeData := make([]byte, decodeLen)
   568  	num, err := base64.StdEncoding.Decode(decodeData, auth[len(prefix):])
   569  	if err != nil {
   570  		return
   571  	}
   572  
   573  	cs := bytesconv.B2s(decodeData[:num])
   574  	s := strings.IndexByte(cs, ':')
   575  
   576  	if s < 0 {
   577  		return
   578  	}
   579  
   580  	return cs[:s], cs[s+1:], true
   581  }
   582  
   583  // SetAuthToken sets the auth token header(Default Scheme: Bearer) in the current HTTP request. Header example:
   584  //
   585  //	Authorization: Bearer <auth-token-value-comes-here>
   586  func (req *Request) SetAuthToken(token string) {
   587  	req.SetHeader(consts.HeaderAuthorization, "Bearer "+token)
   588  }
   589  
   590  // SetAuthSchemeToken sets the auth token scheme type in the HTTP request. For Example:
   591  //
   592  //	Authorization: <auth-scheme-value-set-here> <auth-token-value>
   593  func (req *Request) SetAuthSchemeToken(scheme, token string) {
   594  	req.SetHeader(consts.HeaderAuthorization, scheme+" "+token)
   595  }
   596  
   597  // SetHeader sets a single header field and its value in the current request.
   598  func (req *Request) SetHeader(header, value string) {
   599  	req.Header.Set(header, value)
   600  }
   601  
   602  // SetHeaders sets multiple header field and its value in the current request.
   603  func (req *Request) SetHeaders(headers map[string]string) {
   604  	for h, v := range headers {
   605  		req.Header.Set(h, v)
   606  	}
   607  }
   608  
   609  // SetCookie appends a single cookie in the current request instance.
   610  func (req *Request) SetCookie(key, value string) {
   611  	req.Header.SetCookie(key, value)
   612  }
   613  
   614  // SetCookies sets an array of cookies in the current request instance.
   615  func (req *Request) SetCookies(hc map[string]string) {
   616  	for k, v := range hc {
   617  		req.Header.SetCookie(k, v)
   618  	}
   619  }
   620  
   621  // SetMethod sets http method for this request.
   622  func (req *Request) SetMethod(method string) {
   623  	req.Header.SetMethod(method)
   624  }
   625  
   626  func (req *Request) OnlyMultipartForm() bool {
   627  	return req.multipartForm != nil && (req.body == nil || len(req.body.B) == 0)
   628  }
   629  
   630  func (req *Request) HasMultipartForm() bool {
   631  	return req.multipartForm != nil
   632  }
   633  
   634  // IsBodyStream returns true if body is set via SetBodyStream*
   635  func (req *Request) IsBodyStream() bool {
   636  	return req.bodyStream != nil && req.bodyStream != NoBody
   637  }
   638  
   639  func (req *Request) BodyStream() io.Reader {
   640  	if req.bodyStream == nil {
   641  		req.bodyStream = NoBody
   642  	}
   643  	return req.bodyStream
   644  }
   645  
   646  // SetBodyStream sets request body stream and, optionally body size.
   647  //
   648  // If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
   649  // before returning io.EOF.
   650  //
   651  // If bodySize < 0, then bodyStream is read until io.EOF.
   652  //
   653  // bodyStream.Close() is called after finishing reading all body data
   654  // if it implements io.Closer.
   655  //
   656  // Note that GET and HEAD requests cannot have body.
   657  //
   658  // See also SetBodyStreamWriter.
   659  func (req *Request) SetBodyStream(bodyStream io.Reader, bodySize int) {
   660  	req.ResetBody()
   661  	req.bodyStream = bodyStream
   662  	req.Header.SetContentLength(bodySize)
   663  }
   664  
   665  func (req *Request) ConstructBodyStream(body *bytebufferpool.ByteBuffer, bodyStream io.Reader) {
   666  	req.body = body
   667  	req.bodyStream = bodyStream
   668  }
   669  
   670  // BodyWriter returns writer for populating request body.
   671  func (req *Request) BodyWriter() io.Writer {
   672  	req.w.r = req
   673  	return &req.w
   674  }
   675  
   676  // PostArgs returns POST arguments.
   677  func (req *Request) PostArgs() *Args {
   678  	req.parsePostArgs()
   679  	return &req.postArgs
   680  }
   681  
   682  func (req *Request) parsePostArgs() {
   683  	if req.parsedPostArgs {
   684  		return
   685  	}
   686  	req.parsedPostArgs = true
   687  
   688  	if !bytes.HasPrefix(req.Header.ContentType(), bytestr.StrPostArgsContentType) {
   689  		return
   690  	}
   691  	req.postArgs.ParseBytes(req.Body())
   692  }
   693  
   694  // BodyE returns request body.
   695  func (req *Request) BodyE() ([]byte, error) {
   696  	if req.bodyRaw != nil {
   697  		return req.bodyRaw, nil
   698  	}
   699  	if req.IsBodyStream() {
   700  		bodyBuf := req.BodyBuffer()
   701  		bodyBuf.Reset()
   702  		zw := network.NewWriter(bodyBuf)
   703  		_, err := utils.CopyZeroAlloc(zw, req.bodyStream)
   704  		req.CloseBodyStream() //nolint:errcheck
   705  		if err != nil {
   706  			return nil, err
   707  		}
   708  		return req.BodyBytes(), nil
   709  	}
   710  	if req.OnlyMultipartForm() {
   711  		body, err := MarshalMultipartForm(req.multipartForm, req.multipartFormBoundary)
   712  		if err != nil {
   713  			return nil, err
   714  		}
   715  		return body, nil
   716  	}
   717  	return req.BodyBytes(), nil
   718  }
   719  
   720  // Body returns request body.
   721  // if get body failed, returns nil.
   722  func (req *Request) Body() []byte {
   723  	body, _ := req.BodyE()
   724  	return body
   725  }
   726  
   727  // BodyWriteTo writes request body to w.
   728  func (req *Request) BodyWriteTo(w io.Writer) error {
   729  	if req.IsBodyStream() {
   730  		zw := network.NewWriter(w)
   731  		_, err := utils.CopyZeroAlloc(zw, req.bodyStream)
   732  		req.CloseBodyStream() //nolint:errcheck
   733  		return err
   734  	}
   735  	if req.OnlyMultipartForm() {
   736  		return WriteMultipartForm(w, req.multipartForm, req.multipartFormBoundary)
   737  	}
   738  	_, err := w.Write(req.BodyBytes())
   739  	return err
   740  }
   741  
   742  func (req *Request) CloseBodyStream() error {
   743  	if req.bodyStream == nil {
   744  		return nil
   745  	}
   746  
   747  	var err error
   748  	if bsc, ok := req.bodyStream.(io.Closer); ok {
   749  		err = bsc.Close()
   750  	}
   751  	req.bodyStream = nil
   752  	return err
   753  }
   754  
   755  // URI returns request URI
   756  func (req *Request) URI() *URI {
   757  	req.ParseURI()
   758  	return &req.uri
   759  }
   760  
   761  func (req *Request) ParseURI() {
   762  	if req.parsedURI {
   763  		return
   764  	}
   765  	req.parsedURI = true
   766  
   767  	req.uri.parse(req.Header.Host(), req.Header.RequestURI(), req.isTLS)
   768  }
   769  
   770  // RemoveMultipartFormFiles removes multipart/form-data temporary files
   771  // associated with the request.
   772  func (req *Request) RemoveMultipartFormFiles() {
   773  	if req.multipartForm != nil {
   774  		// Do not check for error, since these files may be deleted or moved
   775  		// to new places by user code.
   776  		req.multipartForm.RemoveAll() //nolint:errcheck
   777  		req.multipartForm = nil
   778  	}
   779  	req.multipartFormBoundary = ""
   780  	req.multipartFiles = nil
   781  	req.multipartFields = nil
   782  }
   783  
   784  func AddMultipartFormField(w *multipart.Writer, mf *MultipartField) error {
   785  	partWriter, err := w.CreatePart(CreateMultipartHeader(mf.Param, mf.FileName, mf.ContentType))
   786  	if err != nil {
   787  		return err
   788  	}
   789  
   790  	_, err = io.Copy(partWriter, mf.Reader)
   791  	return err
   792  }
   793  
   794  // Method returns request method
   795  func (req *Request) Method() []byte {
   796  	return req.Header.Method()
   797  }
   798  
   799  // Path returns request path
   800  func (req *Request) Path() []byte {
   801  	return req.URI().Path()
   802  }
   803  
   804  // QueryString returns request query
   805  func (req *Request) QueryString() []byte {
   806  	return req.URI().QueryString()
   807  }
   808  
   809  // SetOptions is used to set request options.
   810  // These options can be used to do something in middlewares such as service discovery.
   811  func (req *Request) SetOptions(opts ...config.RequestOption) {
   812  	req.Options().Apply(opts)
   813  }
   814  
   815  // ConnectionClose returns true if 'Connection: close' header is set.
   816  func (req *Request) ConnectionClose() bool {
   817  	return req.Header.ConnectionClose()
   818  }
   819  
   820  // SetConnectionClose sets 'Connection: close' header.
   821  func (req *Request) SetConnectionClose() {
   822  	req.Header.SetConnectionClose(true)
   823  }
   824  
   825  func (req *Request) ResetWithoutConn() {
   826  	req.Header.Reset()
   827  	req.resetSkipHeaderAndConn()
   828  	req.CloseBodyStream()
   829  
   830  	req.options = nil
   831  }
   832  
   833  // AcquireRequest returns an empty Request instance from request pool.
   834  //
   835  // The returned Request instance may be passed to ReleaseRequest when it is
   836  // no longer needed. This allows Request recycling, reduces GC pressure
   837  // and usually improves performance.
   838  func AcquireRequest() *Request {
   839  	v := requestPool.Get()
   840  	if v == nil {
   841  		return &Request{}
   842  	}
   843  	return v.(*Request)
   844  }
   845  
   846  // ReleaseRequest returns req acquired via AcquireRequest to request pool.
   847  //
   848  // It is forbidden accessing req and/or its members after returning
   849  // it to request pool.
   850  func ReleaseRequest(req *Request) {
   851  	req.Reset()
   852  	requestPool.Put(req)
   853  }
   854  
   855  // NewRequest makes a new Request given a method, URL, and
   856  // optional body.
   857  //
   858  // # Method's default value is GET
   859  //
   860  // Url must contain fully qualified uri, i.e. with scheme and host,
   861  // and http is assumed if scheme is omitted.
   862  //
   863  // Protocol version is always HTTP/1.1
   864  //
   865  // NewRequest just uses for unit-testing. Use AcquireRequest() in other cases.
   866  func NewRequest(method, url string, body io.Reader) *Request {
   867  	if method == "" {
   868  		method = consts.MethodGet
   869  	}
   870  
   871  	req := new(Request)
   872  	req.SetRequestURI(url)
   873  	req.SetIsTLS(bytes.HasPrefix(bytesconv.S2b(url), bytestr.StrHTTPS))
   874  	req.ParseURI()
   875  	req.SetMethod(method)
   876  	req.Header.SetHost(string(req.URI().Host()))
   877  	req.Header.SetRequestURIBytes(req.URI().RequestURI())
   878  
   879  	if !req.Header.IgnoreBody() {
   880  		req.SetBodyStream(body, -1)
   881  		switch v := req.BodyStream().(type) {
   882  		case *bytes.Buffer:
   883  			req.Header.SetContentLength(v.Len())
   884  		case *bytes.Reader:
   885  			req.Header.SetContentLength(v.Len())
   886  		case *strings.Reader:
   887  			req.Header.SetContentLength(v.Len())
   888  		default:
   889  		}
   890  	}
   891  
   892  	return req
   893  }