github.com/geniusesgroup/libgo@v0.0.0-20220713101832-828057a9d3d4/http/request.go (about)

     1  /* For license and copyright information please see LEGAL file in repository */
     2  
     3  package http
     4  
     5  import (
     6  	"io"
     7  	"strings"
     8  
     9  	"../convert"
    10  	"../mediatype"
    11  	"../protocol"
    12  )
    13  
    14  // Request is represent HTTP request protocol structure.
    15  // https://tools.ietf.org/html/rfc2616#section-5
    16  type Request struct {
    17  	method  string
    18  	uri     URI
    19  	version string
    20  
    21  	H header // Exported field to let consumers use other methods that protocol.HTTPHeader
    22  	body
    23  }
    24  
    25  func (r *Request) Init() { r.H.Init() }
    26  func (r *Request) Reset() {
    27  	r.method = ""
    28  	r.uri.Reset()
    29  	r.version = ""
    30  	r.H.Reset()
    31  	r.body.Reset()
    32  }
    33  
    34  func (r *Request) Method() string              { return r.method }
    35  func (r *Request) URI() protocol.HTTPURI       { return &r.uri }
    36  func (r *Request) Version() string             { return r.version }
    37  func (r *Request) SetMethod(method string)     { r.method = method }
    38  func (r *Request) SetVersion(version string)   { r.version = version }
    39  func (r *Request) Header() protocol.HTTPHeader { return &r.H }
    40  
    41  /*
    42  ********** protocol.Codec interface **********
    43   */
    44  
    45  func (r *Request) MediaType() protocol.MediaType       { return mediatype.HTTPRequest }
    46  func (r *Request) CompressType() protocol.CompressType { return nil }
    47  func (r *Request) Len() (ln int) {
    48  	ln = r.LenWithoutBody()
    49  	ln += r.body.Len()
    50  	return
    51  }
    52  
    53  func (r *Request) Decode(reader protocol.Reader) (err protocol.Error) {
    54  	// Make a buffer to hold incoming data.
    55  	var buf = make([]byte, MaxHTTPHeaderSize)
    56  	// Read the incoming connection into the buffer.
    57  	var headerReadLength, goErr = reader.Read(buf)
    58  	if goErr != nil || headerReadLength == 0 {
    59  		// err =
    60  		return
    61  	}
    62  
    63  	buf = buf[:headerReadLength]
    64  	buf, err = r.UnmarshalFrom(buf)
    65  	if err != nil {
    66  		return err
    67  	}
    68  	err = r.body.checkAndSetReaderAsIncomeBody(buf, reader, &r.H)
    69  	return
    70  }
    71  
    72  // Encode write request to given buffer writer.
    73  func (r *Request) Encode(writer protocol.Writer) (err protocol.Error) {
    74  	var _, goErr = r.WriteTo(writer)
    75  	if goErr != nil {
    76  		// err =
    77  	}
    78  	return
    79  }
    80  
    81  // Marshal enecodes whole r *Request data and return httpPacket.
    82  func (r *Request) Marshal() (httpPacket []byte) {
    83  	httpPacket = make([]byte, 0, r.Len())
    84  	httpPacket = r.MarshalTo(httpPacket)
    85  	return
    86  }
    87  
    88  // MarshalTo enecodes whole r *Request data to given httpPacket and return it with new len.
    89  func (r *Request) MarshalTo(httpPacket []byte) []byte {
    90  	httpPacket = append(httpPacket, r.method...)
    91  	httpPacket = append(httpPacket, SP)
    92  	httpPacket = r.uri.MarshalTo(httpPacket)
    93  	httpPacket = append(httpPacket, SP)
    94  	httpPacket = append(httpPacket, r.version...)
    95  	httpPacket = append(httpPacket, CRLF...)
    96  
    97  	httpPacket = r.H.MarshalTo(httpPacket)
    98  	httpPacket = append(httpPacket, CRLF...)
    99  
   100  	httpPacket = r.body.MarshalTo(httpPacket)
   101  	return httpPacket
   102  }
   103  
   104  // Unmarshal parses and decodes data of given httpPacket to r *Request.
   105  // In some bad packet may occur panic, handle panic by recover otherwise app will crash and exit!
   106  func (r *Request) Unmarshal(httpPacket []byte) (err protocol.Error) {
   107  	var maybeBody []byte
   108  	maybeBody, err = r.UnmarshalFrom(httpPacket)
   109  	if err != nil {
   110  		return
   111  	}
   112  	err = r.body.checkAndSetIncomeBody(maybeBody, &r.H)
   113  	return
   114  }
   115  
   116  // Unmarshal parses and decodes data of given httpPacket to r *Request.
   117  // In some bad packet may occur panic, handle panic by recover otherwise app will crash and exit!
   118  func (r *Request) UnmarshalFrom(httpPacket []byte) (maybeBody []byte, err protocol.Error) {
   119  	// By use unsafe pointer here all strings assign in Request will just point to httpPacket slice
   120  	// and no need to alloc lot of new memory locations and copy request line and headers keys & values!
   121  	var s = convert.UnsafeByteSliceToString(httpPacket)
   122  
   123  	// First line: GET /index.html HTTP/1.0
   124  	var index int
   125  	index = strings.IndexByte(s[:methodMaxLength], SP)
   126  	if index == -1 {
   127  		return httpPacket[:], ErrParseMethod
   128  	}
   129  	r.method = s[:index]
   130  	s = s[index+1:]
   131  
   132  	index = r.uri.unmarshalFrom(s)
   133  	s = s[index+1:]
   134  
   135  	index = strings.IndexByte(s[:versionMaxLength], '\r')
   136  	if index == -1 {
   137  		return httpPacket[index:], ErrParseVersion
   138  	}
   139  	r.version = s[:index]
   140  	s = s[index+2:] // +2 due to have "\r\n"
   141  
   142  	// TODO::: check performance below vs make new Int var for bodyStart and add to it in each IndexByte()
   143  	// vs have 4 Int for each index
   144  	index = len(r.method) + len(r.uri.uri) + len(r.version) + 4
   145  
   146  	index += r.H.Unmarshal(s)
   147  
   148  	r.uri.checkHost(&r.H)
   149  
   150  	// By https://tools.ietf.org/html/rfc2616#section-4 very simple http packet must end with CRLF even packet without header or body!
   151  	// So it can be occur panic if very simple request end without any CRLF
   152  	index += 2 // +2 due to have "\r\n" after header end
   153  	return httpPacket[index:], nil
   154  }
   155  
   156  /*
   157  ********** io package interfaces **********
   158   */
   159  
   160  // ReadFrom decodes r *Request data by read from given io.Reader!
   161  // Declare to respect io.ReaderFrom interface!
   162  func (r *Request) ReadFrom(reader io.Reader) (n int64, goErr error) {
   163  	// Make a buffer to hold incoming data.
   164  	var buf = make([]byte, MaxHTTPHeaderSize)
   165  	var headerReadLength int
   166  	var err protocol.Error
   167  
   168  	// Read the incoming connection into the buffer.
   169  	headerReadLength, goErr = reader.Read(buf)
   170  	if goErr != nil || headerReadLength == 0 {
   171  		return
   172  	}
   173  
   174  	buf = buf[:headerReadLength]
   175  	buf, err = r.UnmarshalFrom(buf)
   176  	if err != nil {
   177  		return int64(headerReadLength), err
   178  	}
   179  	err = r.body.checkAndSetReaderAsIncomeBody(buf, reader, &r.H)
   180  	n = int64(headerReadLength)
   181  	return
   182  }
   183  
   184  // WriteTo enecodes r *Request data and write it to given io.Writer!
   185  // Declare to respect io.WriterTo interface!
   186  func (r *Request) WriteTo(writer io.Writer) (n int64, err error) {
   187  	var lenWithoutBody = r.LenWithoutBody()
   188  	var bodyLen = r.body.Len()
   189  	var wholeLen = lenWithoutBody + bodyLen
   190  	// Check if whole request has fewer length than MaxHTTPHeaderSize and Decide to send header and body separately
   191  	if wholeLen > MaxHTTPHeaderSize {
   192  		var httpPacket = make([]byte, 0, lenWithoutBody)
   193  		httpPacket = r.MarshalToWithoutBody(httpPacket)
   194  
   195  		var headerWriteLength int
   196  		headerWriteLength, err = writer.Write(httpPacket)
   197  		if err == nil && r.body.Codec != nil {
   198  			err = r.body.Encode(writer)
   199  		}
   200  
   201  		n = int64(bodyLen + headerWriteLength)
   202  	} else {
   203  		var httpPacket = make([]byte, 0, wholeLen)
   204  		httpPacket = r.MarshalTo(httpPacket)
   205  		var packetWriteLength int
   206  		packetWriteLength, err = writer.Write(httpPacket)
   207  		n = int64(packetWriteLength)
   208  	}
   209  	return
   210  }
   211  
   212  /*
   213  ********** Other methods **********
   214   */
   215  
   216  // MarshalWithoutBody enecodes r *Request data and return httpPacket without body part!
   217  func (r *Request) MarshalWithoutBody() (httpPacket []byte) {
   218  	httpPacket = make([]byte, 0, r.LenWithoutBody())
   219  	httpPacket = r.MarshalToWithoutBody(httpPacket)
   220  	return
   221  }
   222  
   223  // MarshalWithoutBody enecodes r *Request data and return httpPacket without body part!
   224  func (r *Request) MarshalToWithoutBody(httpPacket []byte) []byte {
   225  	httpPacket = append(httpPacket, r.method...)
   226  	httpPacket = append(httpPacket, SP)
   227  	httpPacket = r.uri.MarshalTo(httpPacket)
   228  	httpPacket = append(httpPacket, SP)
   229  	httpPacket = append(httpPacket, r.version...)
   230  	httpPacket = append(httpPacket, CRLF...)
   231  
   232  	httpPacket = r.H.MarshalTo(httpPacket)
   233  	httpPacket = append(httpPacket, CRLF...)
   234  	return httpPacket
   235  }
   236  
   237  // LenWithoutBody return length of request without body length
   238  func (r *Request) LenWithoutBody() (ln int) {
   239  	ln = 6 // 6=1+1+2+2=len(SP)+len(SP)+len(CRLF)+len(CRLF)
   240  	ln += len(r.method)
   241  	ln += r.uri.Len()
   242  	ln += len(r.version)
   243  	ln += r.H.Len()
   244  	return
   245  }