github.com/cloudwego/hertz@v0.9.3/pkg/protocol/response.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  	"io"
    46  	"net"
    47  	"sync"
    48  
    49  	"github.com/cloudwego/hertz/internal/bytesconv"
    50  	"github.com/cloudwego/hertz/internal/nocopy"
    51  	"github.com/cloudwego/hertz/pkg/common/bytebufferpool"
    52  	"github.com/cloudwego/hertz/pkg/common/compress"
    53  	"github.com/cloudwego/hertz/pkg/common/utils"
    54  	"github.com/cloudwego/hertz/pkg/network"
    55  )
    56  
    57  var (
    58  	responsePool sync.Pool
    59  	// NoResponseBody is an io.ReadCloser with no bytes. Read always returns EOF
    60  	// and Close always returns nil. It can be used in an ingoing client
    61  	// response to explicitly signal that a response has zero bytes.
    62  	NoResponseBody = noBody{}
    63  )
    64  
    65  // Response represents HTTP response.
    66  //
    67  // It is forbidden copying Response instances. Create new instances
    68  // and use CopyTo instead.
    69  //
    70  // Response instance MUST NOT be used from concurrently running goroutines.
    71  type Response struct {
    72  	noCopy nocopy.NoCopy //lint:ignore U1000 until noCopy is used
    73  
    74  	// Response header
    75  	//
    76  	// Copying Header by value is forbidden. Use pointer to Header instead.
    77  	Header ResponseHeader
    78  
    79  	// Flush headers as soon as possible without waiting for first body bytes.
    80  	// Relevant for bodyStream only.
    81  	ImmediateHeaderFlush bool
    82  
    83  	bodyStream      io.Reader
    84  	w               responseBodyWriter
    85  	body            *bytebufferpool.ByteBuffer
    86  	bodyRaw         []byte
    87  	maxKeepBodySize int
    88  
    89  	// Response.Read() skips reading body if set to true.
    90  	// Use it for reading HEAD responses.
    91  	//
    92  	// Response.Write() skips writing body if set to true.
    93  	// Use it for writing HEAD responses.
    94  	SkipBody bool
    95  
    96  	// Remote TCPAddr from concurrently net.Conn
    97  	raddr net.Addr
    98  	// Local TCPAddr from concurrently net.Conn
    99  	laddr net.Addr
   100  
   101  	// If set a hijackWriter, hertz will skip the default header/body writer process.
   102  	hijackWriter network.ExtWriter
   103  }
   104  
   105  func (resp *Response) GetHijackWriter() network.ExtWriter {
   106  	return resp.hijackWriter
   107  }
   108  
   109  func (resp *Response) HijackWriter(writer network.ExtWriter) {
   110  	resp.hijackWriter = writer
   111  }
   112  
   113  type responseBodyWriter struct {
   114  	r *Response
   115  }
   116  
   117  func (w *responseBodyWriter) Write(p []byte) (int, error) {
   118  	w.r.AppendBody(p)
   119  	return len(p), nil
   120  }
   121  
   122  func (resp *Response) MustSkipBody() bool {
   123  	return resp.SkipBody || resp.Header.MustSkipContentLength()
   124  }
   125  
   126  // BodyGunzip returns un-gzipped body data.
   127  //
   128  // This method may be used if the response header contains
   129  // 'Content-Encoding: gzip' for reading un-gzipped body.
   130  // Use Body for reading gzipped response body.
   131  func (resp *Response) BodyGunzip() ([]byte, error) {
   132  	return gunzipData(resp.Body())
   133  }
   134  
   135  // SetConnectionClose sets 'Connection: close' header.
   136  func (resp *Response) SetConnectionClose() {
   137  	resp.Header.SetConnectionClose(true)
   138  }
   139  
   140  // SetBodyString sets response body.
   141  func (resp *Response) SetBodyString(body string) {
   142  	resp.CloseBodyStream()            //nolint:errcheck
   143  	resp.BodyBuffer().SetString(body) //nolint:errcheck
   144  }
   145  
   146  func (resp *Response) ConstructBodyStream(body *bytebufferpool.ByteBuffer, bodyStream io.Reader) {
   147  	resp.body = body
   148  	resp.bodyStream = bodyStream
   149  }
   150  
   151  // BodyWriter returns writer for populating response body.
   152  //
   153  // If used inside RequestHandler, the returned writer must not be used
   154  // after returning from RequestHandler. Use RequestContext.Write
   155  // or SetBodyStreamWriter in this case.
   156  func (resp *Response) BodyWriter() io.Writer {
   157  	resp.w.r = resp
   158  	return &resp.w
   159  }
   160  
   161  // SetStatusCode sets response status code.
   162  func (resp *Response) SetStatusCode(statusCode int) {
   163  	resp.Header.SetStatusCode(statusCode)
   164  }
   165  
   166  func (resp *Response) SetMaxKeepBodySize(n int) {
   167  	resp.maxKeepBodySize = n
   168  }
   169  
   170  func (resp *Response) BodyBytes() []byte {
   171  	if resp.bodyRaw != nil {
   172  		return resp.bodyRaw
   173  	}
   174  	if resp.body == nil {
   175  		return nil
   176  	}
   177  	return resp.body.B
   178  }
   179  
   180  func (resp *Response) HasBodyBytes() bool {
   181  	return len(resp.BodyBytes()) != 0
   182  }
   183  
   184  func (resp *Response) CopyToSkipBody(dst *Response) {
   185  	dst.Reset()
   186  	resp.Header.CopyTo(&dst.Header)
   187  	dst.SkipBody = resp.SkipBody
   188  	dst.raddr = resp.raddr
   189  	dst.laddr = resp.laddr
   190  }
   191  
   192  // IsBodyStream returns true if body is set via SetBodyStream*
   193  func (resp *Response) IsBodyStream() bool {
   194  	return resp.bodyStream != nil
   195  }
   196  
   197  // SetBodyStream sets response body stream and, optionally body size.
   198  //
   199  // If bodySize is >= 0, then the bodyStream must provide exactly bodySize bytes
   200  // before returning io.EOF.
   201  //
   202  // If bodySize < 0, then bodyStream is read until io.EOF.
   203  //
   204  // bodyStream.Close() is called after finishing reading all body data
   205  // if it implements io.Closer.
   206  //
   207  // See also SetBodyStreamWriter.
   208  func (resp *Response) SetBodyStream(bodyStream io.Reader, bodySize int) {
   209  	resp.ResetBody()
   210  	resp.bodyStream = bodyStream
   211  	resp.Header.SetContentLength(bodySize)
   212  }
   213  
   214  // SetBodyStreamNoReset is almost the same as SetBodyStream,
   215  // but it doesn't reset the bodyStream before.
   216  func (resp *Response) SetBodyStreamNoReset(bodyStream io.Reader, bodySize int) {
   217  	resp.bodyStream = bodyStream
   218  	resp.Header.SetContentLength(bodySize)
   219  }
   220  
   221  // BodyE returns response body.
   222  func (resp *Response) BodyE() ([]byte, error) {
   223  	if resp.bodyStream != nil {
   224  		bodyBuf := resp.BodyBuffer()
   225  		bodyBuf.Reset()
   226  		zw := network.NewWriter(bodyBuf)
   227  		_, err := utils.CopyZeroAlloc(zw, resp.bodyStream)
   228  		resp.CloseBodyStream() //nolint:errcheck
   229  		if err != nil {
   230  			return nil, err
   231  		}
   232  	}
   233  	return resp.BodyBytes(), nil
   234  }
   235  
   236  // Body returns response body.
   237  // if get body failed, returns nil.
   238  func (resp *Response) Body() []byte {
   239  	body, _ := resp.BodyE()
   240  	return body
   241  }
   242  
   243  // BodyWriteTo writes response body to w.
   244  func (resp *Response) BodyWriteTo(w io.Writer) error {
   245  	zw := network.NewWriter(w)
   246  	if resp.bodyStream != nil {
   247  		_, err := utils.CopyZeroAlloc(zw, resp.bodyStream)
   248  		resp.CloseBodyStream() //nolint:errcheck
   249  		return err
   250  	}
   251  
   252  	body := resp.BodyBytes()
   253  	zw.WriteBinary(body) //nolint:errcheck
   254  	return zw.Flush()
   255  }
   256  
   257  // CopyTo copies resp contents to dst except of body stream.
   258  func (resp *Response) CopyTo(dst *Response) {
   259  	resp.CopyToSkipBody(dst)
   260  	if resp.bodyRaw != nil {
   261  		dst.bodyRaw = append(dst.bodyRaw[:0], resp.bodyRaw...)
   262  		if dst.body != nil {
   263  			dst.body.Reset()
   264  		}
   265  	} else if resp.body != nil {
   266  		dst.BodyBuffer().Set(resp.body.B)
   267  	} else if dst.body != nil {
   268  		dst.body.Reset()
   269  	}
   270  }
   271  
   272  func SwapResponseBody(a, b *Response) {
   273  	a.body, b.body = b.body, a.body
   274  	a.bodyRaw, b.bodyRaw = b.bodyRaw, a.bodyRaw
   275  	a.bodyStream, b.bodyStream = b.bodyStream, a.bodyStream
   276  }
   277  
   278  // Reset clears response contents.
   279  func (resp *Response) Reset() {
   280  	resp.Header.Reset()
   281  	resp.resetSkipHeader()
   282  	resp.SkipBody = false
   283  	resp.raddr = nil
   284  	resp.laddr = nil
   285  	resp.ImmediateHeaderFlush = false
   286  	resp.hijackWriter = nil
   287  }
   288  
   289  func (resp *Response) resetSkipHeader() {
   290  	resp.ResetBody()
   291  }
   292  
   293  // ResetBody resets response body.
   294  func (resp *Response) ResetBody() {
   295  	resp.bodyRaw = nil
   296  	resp.CloseBodyStream() //nolint:errcheck
   297  	if resp.body != nil {
   298  		if resp.body.Len() <= resp.maxKeepBodySize {
   299  			resp.body.Reset()
   300  			return
   301  		}
   302  		responseBodyPool.Put(resp.body)
   303  		resp.body = nil
   304  	}
   305  }
   306  
   307  // SetBodyRaw sets response body, but without copying it.
   308  //
   309  // From this point onward the body argument must not be changed.
   310  func (resp *Response) SetBodyRaw(body []byte) {
   311  	resp.ResetBody()
   312  	resp.bodyRaw = body
   313  }
   314  
   315  // StatusCode returns response status code.
   316  func (resp *Response) StatusCode() int {
   317  	return resp.Header.StatusCode()
   318  }
   319  
   320  // SetBody sets response body.
   321  //
   322  // It is safe re-using body argument after the function returns.
   323  func (resp *Response) SetBody(body []byte) {
   324  	resp.CloseBodyStream() //nolint:errcheck
   325  	if resp.GetHijackWriter() == nil {
   326  		resp.BodyBuffer().Set(body) //nolint:errcheck
   327  		return
   328  	}
   329  
   330  	// If the hijack writer support .SetBody() api, then use it.
   331  	if setter, ok := resp.GetHijackWriter().(interface {
   332  		SetBody(b []byte)
   333  	}); ok {
   334  		setter.SetBody(body)
   335  		return
   336  	}
   337  
   338  	// Otherwise, call .Write() api instead.
   339  	resp.GetHijackWriter().Write(body) //nolint:errcheck
   340  }
   341  
   342  func (resp *Response) BodyStream() io.Reader {
   343  	if resp.bodyStream == nil {
   344  		resp.bodyStream = NoResponseBody
   345  	}
   346  	return resp.bodyStream
   347  }
   348  
   349  // AppendBody appends p to response body.
   350  //
   351  // It is safe re-using p after the function returns.
   352  func (resp *Response) AppendBody(p []byte) {
   353  	resp.CloseBodyStream() //nolint:errcheck
   354  	if resp.hijackWriter != nil {
   355  		resp.hijackWriter.Write(p) //nolint:errcheck
   356  		return
   357  	}
   358  	resp.BodyBuffer().Write(p) //nolint:errcheck
   359  }
   360  
   361  // AppendBodyString appends s to response body.
   362  func (resp *Response) AppendBodyString(s string) {
   363  	resp.CloseBodyStream() //nolint:errcheck
   364  	if resp.hijackWriter != nil {
   365  		resp.hijackWriter.Write(bytesconv.S2b(s)) //nolint:errcheck
   366  		return
   367  	}
   368  	resp.BodyBuffer().WriteString(s) //nolint:errcheck
   369  }
   370  
   371  // ConnectionClose returns true if 'Connection: close' header is set.
   372  func (resp *Response) ConnectionClose() bool {
   373  	return resp.Header.ConnectionClose()
   374  }
   375  
   376  func (resp *Response) CloseBodyStream() error {
   377  	if resp.bodyStream == nil {
   378  		return nil
   379  	}
   380  	var err error
   381  	if bsc, ok := resp.bodyStream.(io.Closer); ok {
   382  		err = bsc.Close()
   383  	}
   384  	resp.bodyStream = nil
   385  	return err
   386  }
   387  
   388  func (resp *Response) BodyBuffer() *bytebufferpool.ByteBuffer {
   389  	if resp.body == nil {
   390  		resp.body = responseBodyPool.Get()
   391  	}
   392  	resp.bodyRaw = nil
   393  	return resp.body
   394  }
   395  
   396  func gunzipData(p []byte) ([]byte, error) {
   397  	var bb bytebufferpool.ByteBuffer
   398  	_, err := compress.WriteGunzip(&bb, p)
   399  	if err != nil {
   400  		return nil, err
   401  	}
   402  	return bb.B, nil
   403  }
   404  
   405  // RemoteAddr returns the remote network address. The Addr returned is shared
   406  // by all invocations of RemoteAddr, so do not modify it.
   407  func (resp *Response) RemoteAddr() net.Addr {
   408  	return resp.raddr
   409  }
   410  
   411  // LocalAddr returns the local network address. The Addr returned is shared
   412  // by all invocations of LocalAddr, so do not modify it.
   413  func (resp *Response) LocalAddr() net.Addr {
   414  	return resp.laddr
   415  }
   416  
   417  func (resp *Response) ParseNetAddr(conn network.Conn) {
   418  	resp.raddr = conn.RemoteAddr()
   419  	resp.laddr = conn.LocalAddr()
   420  }
   421  
   422  // AcquireResponse returns an empty Response instance from response pool.
   423  //
   424  // The returned Response instance may be passed to ReleaseResponse when it is
   425  // no longer needed. This allows Response recycling, reduces GC pressure
   426  // and usually improves performance.
   427  func AcquireResponse() *Response {
   428  	v := responsePool.Get()
   429  	if v == nil {
   430  		return &Response{}
   431  	}
   432  	return v.(*Response)
   433  }
   434  
   435  // ReleaseResponse return resp acquired via AcquireResponse to response pool.
   436  //
   437  // It is forbidden accessing resp and/or its members after returning
   438  // it to response pool.
   439  func ReleaseResponse(resp *Response) {
   440  	resp.Reset()
   441  	responsePool.Put(resp)
   442  }