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 }