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