readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. It is called by the mime/multipart package.
(maxMemory, maxHeaders int64)
| 229 | // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size. |
| 230 | // It is called by the mime/multipart package. |
| 231 | func (r *textprotoReader) readMIMEHeader(maxMemory, maxHeaders int64) (textproto.MIMEHeader, error) { |
| 232 | // Avoid lots of small slice allocations later by allocating one |
| 233 | // large one ahead of time which we'll cut up into smaller |
| 234 | // slices. If this isn't big enough later, we allocate small ones. |
| 235 | var strs []string |
| 236 | hint := r.upcomingHeaderKeys() |
| 237 | if hint > 0 { |
| 238 | if hint > 1000 { |
| 239 | hint = 1000 // set a cap to avoid overallocation |
| 240 | } |
| 241 | strs = make([]string, hint) |
| 242 | } |
| 243 | |
| 244 | m := make(textproto.MIMEHeader, hint) |
| 245 | |
| 246 | // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry. |
| 247 | // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large |
| 248 | // MIMEHeaders average about 200 bytes per entry. |
| 249 | maxMemory -= 400 |
| 250 | const mapEntryOverhead = 200 |
| 251 | |
| 252 | // The first line cannot start with a leading space. |
| 253 | if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') { |
| 254 | const errorLimit = 80 // arbitrary limit on how much of the line we'll quote |
| 255 | line, err := r.readLineSlice(errorLimit) |
| 256 | if err != nil { |
| 257 | return m, err |
| 258 | } |
| 259 | return m, protocolError("malformed MIME header initial line: " + string(line)) |
| 260 | } |
| 261 | |
| 262 | for { |
| 263 | kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon) |
| 264 | if len(kv) == 0 { |
| 265 | return m, err |
| 266 | } |
| 267 | |
| 268 | // Key ends at first colon. |
| 269 | k, v, ok := bytes.Cut(kv, colon) |
| 270 | if !ok { |
| 271 | return m, protocolError("malformed MIME header line: " + string(kv)) |
| 272 | } |
| 273 | key, ok := canonicalMIMEHeaderKey(k) |
| 274 | if !ok { |
| 275 | return m, protocolError("malformed MIME header line: " + string(kv)) |
| 276 | } |
| 277 | for _, c := range v { |
| 278 | if !validHeaderValueByte(c) { |
| 279 | return m, protocolError("malformed MIME header line: " + string(kv)) |
| 280 | } |
| 281 | } |
| 282 | |
| 283 | maxHeaders-- |
| 284 | if maxHeaders < 0 { |
| 285 | return nil, errMessageTooLarge |
| 286 | } |
| 287 | |
| 288 | // Skip initial spaces in value. |
no test coverage detected