github.com/GeniusesGroup/libgo@v0.0.0-20220929090155-5ff932cb408e/http/body.go (about)

     1  /* For license and copyright information please see the LEGAL file in the code repository */
     2  
     3  package http
     4  
     5  import (
     6  	"io"
     7  
     8  	"github.com/GeniusesGroup/libgo/compress/raw"
     9  	"github.com/GeniusesGroup/libgo/protocol"
    10  )
    11  
    12  // body is represent HTTP body.
    13  // Due to many performance impact, MediaType() method of body not return any true data. use header ContentType() method instead. This can be change if ...
    14  // https://datatracker.ietf.org/doc/html/rfc2616#section-4.3
    15  type body struct {
    16  	protocol.Codec
    17  }
    18  
    19  func (b *body) Init()   {}
    20  func (b *body) Reinit() { b.Codec = nil }
    21  func (b *body) Deinit() {}
    22  
    23  func (b *body) Body() protocol.Codec         { return b }
    24  func (b *body) SetBody(codec protocol.Codec) { b.Codec = codec }
    25  
    26  //libgo:impl protocol.Codec
    27  func (b *body) Len() int {
    28  	if b.Codec != nil {
    29  		return b.Codec.Len()
    30  	}
    31  	return 0
    32  }
    33  func (b *body) MediaType() protocol.MediaType {
    34  	if b.Codec != nil {
    35  		return b.Codec.MediaType()
    36  	}
    37  	return nil
    38  }
    39  func (b *body) CompressType() protocol.CompressType {
    40  	if b.Codec != nil {
    41  		return b.Codec.CompressType()
    42  	}
    43  	return nil
    44  }
    45  func (b *body) Decode(source protocol.Codec) (n int, err protocol.Error) {
    46  	if b.Codec != nil {
    47  		n, err = b.Codec.Decode(source)
    48  	}
    49  	return
    50  }
    51  func (b *body) Encode(destination protocol.Codec) (n int, err protocol.Error) {
    52  	if b.Codec != nil {
    53  		n, err = b.Codec.Encode(destination)
    54  	}
    55  	return
    56  }
    57  func (b *body) Marshal() (data []byte, err protocol.Error) {
    58  	if b.Codec != nil {
    59  		data, err = b.Codec.Marshal()
    60  	}
    61  	return
    62  }
    63  func (b *body) MarshalTo(data []byte) (added []byte, err protocol.Error) {
    64  	if b.Codec != nil {
    65  		return b.Codec.MarshalTo(data)
    66  	}
    67  	return data, nil
    68  }
    69  func (b *body) Unmarshal(data []byte) (n int, err protocol.Error) {
    70  	if b.Codec != nil {
    71  		n, err = b.Codec.Unmarshal(data)
    72  	}
    73  	return
    74  }
    75  func (b *body) UnmarshalFrom(data []byte) (remaining []byte, err protocol.Error) {
    76  	if b.Codec != nil {
    77  		return b.Codec.UnmarshalFrom(data)
    78  	}
    79  	return
    80  }
    81  
    82  // ReadFrom decodes r *Request data by read from given io.Reader
    83  //
    84  //libgo:impl io.ReaderFrom
    85  func (b *body) ReadFrom(reader io.Reader) (n int64, goErr error) {
    86  
    87  	return
    88  }
    89  
    90  // WriteTo encodes r(*Request) data and write it to given io.Writer
    91  //
    92  //libgo:impl io.WriterTo
    93  func (b *body) WriteTo(writer io.Writer) (n int64, err error) {
    94  
    95  	return
    96  }
    97  
    98  /*
    99  ********** local methods **********
   100   */
   101  
   102  func (b *body) checkAndSetCodecAsIncomeBody(maybeBody []byte, c protocol.Codec, h *header) (err protocol.Error) {
   103  	var transferEncoding, _ = h.TransferEncoding()
   104  	switch transferEncoding {
   105  	case "":
   106  		var contentLength = h.ContentLength()
   107  		var maybeBodyLength = len(maybeBody)
   108  		if maybeBodyLength == int(contentLength) {
   109  			b.setReadedIncomeBody(maybeBody, h)
   110  		} else {
   111  			// TODO::: allow this situation that peer send some part of body with header??
   112  			// Header length maybe other than stream income data length e.g. send body in multiple TCP.PSH flag set.
   113  			if maybeBodyLength > 0 {
   114  				var bodySlice = make([]byte, maybeBodyLength, contentLength)
   115  				copy(bodySlice, maybeBody)
   116  				for {
   117  					bodySlice, err = c.MarshalTo(bodySlice)
   118  					if err != nil || len(bodySlice) == int(contentLength) {
   119  						break
   120  					}
   121  				}
   122  				b.setReadedIncomeBody(bodySlice, h)
   123  			} else {
   124  				b.setCodecAsIncomeBody(c, h)
   125  			}
   126  		}
   127  	case HeaderValueChunked:
   128  		// TODO:::
   129  	default:
   130  		// Like nginx, due to security, we only support a single Transfer-Encoding header field, and
   131  		// only if set to "chunked".
   132  		// err =
   133  	}
   134  	return
   135  }
   136  
   137  func (b *body) checkAndSetReaderAsIncomeBody(maybeBody []byte, reader protocol.Reader, h *header) (err protocol.Error) {
   138  	var transferEncoding, _ = h.TransferEncoding()
   139  	switch transferEncoding {
   140  	case "":
   141  		var contentLength = h.ContentLength()
   142  		var maybeBodyLength = len(maybeBody)
   143  		if maybeBodyLength == int(contentLength) {
   144  			b.setReadedIncomeBody(maybeBody, h)
   145  		} else {
   146  			// Header length maybe other than stream income data length e.g. send body in multiple TCP.PSH flag set.
   147  			if maybeBodyLength > 0 {
   148  				var bodyReadLength int
   149  				var goErr error
   150  				var bodySlice = make([]byte, contentLength)
   151  				bodyReadLength, goErr = reader.Read(bodySlice[maybeBodyLength:])
   152  				if goErr != nil {
   153  					// err =
   154  					return
   155  				}
   156  				if bodyReadLength+maybeBodyLength != int(contentLength) {
   157  					// err =
   158  					return
   159  				}
   160  				copy(bodySlice, maybeBody)
   161  				b.setReadedIncomeBody(bodySlice, h)
   162  			} else {
   163  				b.setReaderAsIncomeBody(reader, h, contentLength)
   164  			}
   165  		}
   166  	case HeaderValueChunked:
   167  		// TODO:::
   168  	default:
   169  		// Like nginx, due to security, we only support a single Transfer-Encoding header field, and
   170  		// only if set to "chunked".
   171  		// err =
   172  	}
   173  	return
   174  }
   175  
   176  // Call this method just if body marshaled with first line and headers.
   177  func (b *body) checkAndSetIncomeBody(maybeBody []byte, h *header) (err protocol.Error) {
   178  	var maybeBodyLength = len(maybeBody)
   179  	if maybeBodyLength > 0 {
   180  		var contentLength = h.ContentLength()
   181  		if maybeBodyLength == int(contentLength) {
   182  			b.setReadedIncomeBody(maybeBody, h)
   183  		} else {
   184  			// err =
   185  		}
   186  	}
   187  	return
   188  }
   189  
   190  func (b *body) setCodecAsIncomeBody(c protocol.Codec, h *header) (err protocol.Error) {
   191  	var contentEncoding, _ = h.ContentEncoding()
   192  	if contentEncoding == "" {
   193  		b.Codec = c
   194  		return
   195  	}
   196  
   197  	var compressType protocol.CompressType
   198  	compressType, err = protocol.OS.GetCompressTypeByContentEncoding(contentEncoding)
   199  	if err != nil {
   200  		return
   201  	}
   202  	b.Codec, err = compressType.Decompress(c)
   203  	return
   204  }
   205  
   206  func (b *body) setReaderAsIncomeBody(reader protocol.Reader, h *header, contentLength uint64) (err protocol.Error) {
   207  	var contentEncoding, _ = h.ContentEncoding()
   208  	if contentEncoding == "" {
   209  		b.Codec, err = raw.RAW.DecompressFromReader(reader, int(contentLength))
   210  		return
   211  	}
   212  
   213  	var compressType protocol.CompressType
   214  	compressType, err = protocol.OS.GetCompressTypeByContentEncoding(contentEncoding)
   215  	if err != nil {
   216  		return
   217  	}
   218  	b.Codec, err = compressType.DecompressFromReader(reader, int(contentLength))
   219  	return
   220  }
   221  
   222  func (b *body) setReadedIncomeBody(body []byte, h *header) (err protocol.Error) {
   223  	var contentEncoding, _ = h.ContentEncoding()
   224  	if contentEncoding == "" {
   225  		b.Codec, err = raw.RAW.DecompressFromSlice(body)
   226  		return
   227  	}
   228  
   229  	var compressType protocol.CompressType
   230  	compressType, err = protocol.OS.GetCompressTypeByContentEncoding(contentEncoding)
   231  	if err != nil {
   232  		return
   233  	}
   234  	b.Codec, err = compressType.DecompressFromSlice(body)
   235  	return
   236  }