1 // Copyright 2010 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 5 package textproto
6 7 import (
8 "bufio"
9 "bytes"
10 "errors"
11 "fmt"
12 "io"
13 "math"
14 "strconv"
15 "sync"
16 _ "unsafe" // for linkname
17 )
18 19 // TODO: This should be a distinguishable error (ErrMessageTooLarge)
20 // to allow mime/multipart to detect it.
21 var errMessageTooLarge = errors.New("message too large")
22 23 // A Reader implements convenience methods for reading requests
24 // or responses from a text protocol network connection.
25 type Reader struct {
26 R *bufio.Reader
27 dot *dotReader
28 buf []byte // a re-usable buffer for readContinuedLineSlice
29 }
30 31 // NewReader returns a new [Reader] reading from r.
32 //
33 // To avoid denial of service attacks, the provided [bufio.Reader]
34 // should be reading from an [io.LimitReader] or similar Reader to bound
35 // the size of responses.
36 func NewReader(r *bufio.Reader) *Reader {
37 return &Reader{R: r}
38 }
39 40 // ReadLine reads a single line from r,
41 // eliding the final \n or \r\n from the returned string.
42 func (r *Reader) ReadLine() (string, error) {
43 line, err := r.readLineSlice(-1)
44 return string(line), err
45 }
46 47 // ReadLineBytes is like [Reader.ReadLine] but returns a []byte instead of a string.
48 func (r *Reader) ReadLineBytes() ([]byte, error) {
49 line, err := r.readLineSlice(-1)
50 if line != nil {
51 line = bytes.Clone(line)
52 }
53 return line, err
54 }
55 56 // readLineSlice reads a single line from r,
57 // up to lim bytes long (or unlimited if lim is less than 0),
58 // eliding the final \r or \r\n from the returned string.
59 func (r *Reader) readLineSlice(lim int64) ([]byte, error) {
60 r.closeDot()
61 var line []byte
62 for {
63 l, more, err := r.R.ReadLine()
64 if err != nil {
65 return nil, err
66 }
67 if lim >= 0 && int64(len(line))+int64(len(l)) > lim {
68 return nil, errMessageTooLarge
69 }
70 // Avoid the copy if the first call produced a full line.
71 if line == nil && !more {
72 return l, nil
73 }
74 line = append(line, l...)
75 if !more {
76 break
77 }
78 }
79 return line, nil
80 }
81 82 // ReadContinuedLine reads a possibly continued line from r,
83 // eliding the final trailing ASCII white space.
84 // Lines after the first are considered continuations if they
85 // begin with a space or tab character. In the returned data,
86 // continuation lines are separated from the previous line
87 // only by a single space: the newline and leading white space
88 // are removed.
89 //
90 // For example, consider this input:
91 //
92 // Line 1
93 // continued...
94 // Line 2
95 //
96 // The first call to ReadContinuedLine will return "Line 1 continued..."
97 // and the second will return "Line 2".
98 //
99 // Empty lines are never continued.
100 func (r *Reader) ReadContinuedLine() (string, error) {
101 line, err := r.readContinuedLineSlice(-1, noValidation)
102 return string(line), err
103 }
104 105 // trim returns s with leading and trailing spaces and tabs removed.
106 // It does not assume Unicode or UTF-8.
107 func trim(s []byte) []byte {
108 i := 0
109 for i < len(s) && (s[i] == ' ' || s[i] == '\t') {
110 i++
111 }
112 n := len(s)
113 for n > i && (s[n-1] == ' ' || s[n-1] == '\t') {
114 n--
115 }
116 return s[i:n]
117 }
118 119 // ReadContinuedLineBytes is like [Reader.ReadContinuedLine] but
120 // returns a []byte instead of a string.
121 func (r *Reader) ReadContinuedLineBytes() ([]byte, error) {
122 line, err := r.readContinuedLineSlice(-1, noValidation)
123 if line != nil {
124 line = bytes.Clone(line)
125 }
126 return line, err
127 }
128 129 // readContinuedLineSlice reads continued lines from the reader buffer,
130 // returning a byte slice with all lines. The validateFirstLine function
131 // is run on the first read line, and if it returns an error then this
132 // error is returned from readContinuedLineSlice.
133 // It reads up to lim bytes of data (or unlimited if lim is less than 0).
134 func (r *Reader) readContinuedLineSlice(lim int64, validateFirstLine func([]byte) error) ([]byte, error) {
135 if validateFirstLine == nil {
136 return nil, fmt.Errorf("missing validateFirstLine func")
137 }
138 139 // Read the first line.
140 line, err := r.readLineSlice(lim)
141 if err != nil {
142 return nil, err
143 }
144 if len(line) == 0 { // blank line - no continuation
145 return line, nil
146 }
147 148 if err := validateFirstLine(line); err != nil {
149 return nil, err
150 }
151 152 // Optimistically assume that we have started to buffer the next line
153 // and it starts with an ASCII letter (the next header key), or a blank
154 // line, so we can avoid copying that buffered data around in memory
155 // and skipping over non-existent whitespace.
156 if r.R.Buffered() > 1 {
157 peek, _ := r.R.Peek(2)
158 if len(peek) > 0 && (isASCIILetter(peek[0]) || peek[0] == '\n') ||
159 len(peek) == 2 && peek[0] == '\r' && peek[1] == '\n' {
160 return trim(line), nil
161 }
162 }
163 164 // ReadByte or the next readLineSlice will flush the read buffer;
165 // copy the slice into buf.
166 r.buf = append(r.buf[:0], trim(line)...)
167 168 if lim < 0 {
169 lim = math.MaxInt64
170 }
171 lim -= int64(len(r.buf))
172 173 // Read continuation lines.
174 for r.skipSpace() > 0 {
175 r.buf = append(r.buf, ' ')
176 if int64(len(r.buf)) >= lim {
177 return nil, errMessageTooLarge
178 }
179 line, err := r.readLineSlice(lim - int64(len(r.buf)))
180 if err != nil {
181 break
182 }
183 r.buf = append(r.buf, trim(line)...)
184 }
185 return r.buf, nil
186 }
187 188 // skipSpace skips R over all spaces and returns the number of bytes skipped.
189 func (r *Reader) skipSpace() int {
190 n := 0
191 for {
192 c, err := r.R.ReadByte()
193 if err != nil {
194 // Bufio will keep err until next read.
195 break
196 }
197 if c != ' ' && c != '\t' {
198 r.R.UnreadByte()
199 break
200 }
201 n++
202 }
203 return n
204 }
205 206 func (r *Reader) readCodeLine(expectCode int) (code int, continued bool, message string, err error) {
207 line, err := r.ReadLine()
208 if err != nil {
209 return
210 }
211 return parseCodeLine(line, expectCode)
212 }
213 214 func parseCodeLine(line string, expectCode int) (code int, continued bool, message string, err error) {
215 if len(line) < 4 || line[3] != ' ' && line[3] != '-' {
216 err = ProtocolError("short response: " + line)
217 return
218 }
219 continued = line[3] == '-'
220 code, err = strconv.Atoi(line[0:3])
221 if err != nil || code < 100 {
222 err = ProtocolError("invalid response code: " + line)
223 return
224 }
225 message = line[4:]
226 if 1 <= expectCode && expectCode < 10 && code/100 != expectCode ||
227 10 <= expectCode && expectCode < 100 && code/10 != expectCode ||
228 100 <= expectCode && expectCode < 1000 && code != expectCode {
229 err = &Error{code, message}
230 }
231 return
232 }
233 234 // ReadCodeLine reads a response code line of the form
235 //
236 // code message
237 //
238 // where code is a three-digit status code and the message
239 // extends to the rest of the line. An example of such a line is:
240 //
241 // 220 plan9.bell-labs.com ESMTP
242 //
243 // If the prefix of the status does not match the digits in expectCode,
244 // ReadCodeLine returns with err set to &Error{code, message}.
245 // For example, if expectCode is 31, an error will be returned if
246 // the status is not in the range [310,319].
247 //
248 // If the response is multi-line, ReadCodeLine returns an error.
249 //
250 // An expectCode <= 0 disables the check of the status code.
251 func (r *Reader) ReadCodeLine(expectCode int) (code int, message string, err error) {
252 code, continued, message, err := r.readCodeLine(expectCode)
253 if err == nil && continued {
254 err = ProtocolError("unexpected multi-line response: " + message)
255 }
256 return
257 }
258 259 // ReadResponse reads a multi-line response of the form:
260 //
261 // code-message line 1
262 // code-message line 2
263 // ...
264 // code message line n
265 //
266 // where code is a three-digit status code. The first line starts with the
267 // code and a hyphen. The response is terminated by a line that starts
268 // with the same code followed by a space. Each line in message is
269 // separated by a newline (\n).
270 //
271 // See page 36 of RFC 959 (https://www.ietf.org/rfc/rfc959.txt) for
272 // details of another form of response accepted:
273 //
274 // code-message line 1
275 // message line 2
276 // ...
277 // code message line n
278 //
279 // If the prefix of the status does not match the digits in expectCode,
280 // ReadResponse returns with err set to &Error{code, message}.
281 // For example, if expectCode is 31, an error will be returned if
282 // the status is not in the range [310,319].
283 //
284 // An expectCode <= 0 disables the check of the status code.
285 func (r *Reader) ReadResponse(expectCode int) (code int, message string, err error) {
286 code, continued, first, err := r.readCodeLine(expectCode)
287 multi := continued
288 var messageBuilder bytes.Buffer
289 messageBuilder.WriteString(first)
290 for continued {
291 line, err := r.ReadLine()
292 if err != nil {
293 return 0, "", err
294 }
295 296 var code2 int
297 var moreMessage string
298 code2, continued, moreMessage, err = parseCodeLine(line, 0)
299 if err != nil || code2 != code {
300 messageBuilder.WriteByte('\n')
301 messageBuilder.WriteString(bytes.TrimRight(line, "\r\n"))
302 continued = true
303 continue
304 }
305 messageBuilder.WriteByte('\n')
306 messageBuilder.WriteString(moreMessage)
307 }
308 message = messageBuilder.String()
309 if err != nil && multi && message != "" {
310 // replace one line error message with all lines (full message)
311 err = &Error{code, message}
312 }
313 return
314 }
315 316 // DotReader returns a new [Reader] that satisfies Reads using the
317 // decoded text of a dot-encoded block read from r.
318 // The returned Reader is only valid until the next call
319 // to a method on r.
320 //
321 // Dot encoding is a common framing used for data blocks
322 // in text protocols such as SMTP. The data consists of a sequence
323 // of lines, each of which ends in "\r\n". The sequence itself
324 // ends at a line containing just a dot: ".\r\n". Lines beginning
325 // with a dot are escaped with an additional dot to avoid
326 // looking like the end of the sequence.
327 //
328 // The decoded form returned by the Reader's Read method
329 // rewrites the "\r\n" line endings into the simpler "\n",
330 // removes leading dot escapes if present, and stops with error [io.EOF]
331 // after consuming (and discarding) the end-of-sequence line.
332 func (r *Reader) DotReader() io.Reader {
333 r.closeDot()
334 r.dot = &dotReader{r: r}
335 return r.dot
336 }
337 338 type dotReader struct {
339 r *Reader
340 state int
341 }
342 343 // Read satisfies reads by decoding dot-encoded data read from d.r.
344 func (d *dotReader) Read(b []byte) (n int, err error) {
345 // Run data through a simple state machine to
346 // elide leading dots, rewrite trailing \r\n into \n,
347 // and detect ending .\r\n line.
348 const (
349 stateBeginLine = iota // beginning of line; initial state; must be zero
350 stateDot // read . at beginning of line
351 stateDotCR // read .\r at beginning of line
352 stateCR // read \r (possibly at end of line)
353 stateData // reading data in middle of line
354 stateEOF // reached .\r\n end marker line
355 )
356 br := d.r.R
357 for n < len(b) && d.state != stateEOF {
358 var c byte
359 c, err = br.ReadByte()
360 if err != nil {
361 if err == io.EOF {
362 err = io.ErrUnexpectedEOF
363 }
364 break
365 }
366 switch d.state {
367 case stateBeginLine:
368 if c == '.' {
369 d.state = stateDot
370 continue
371 }
372 if c == '\r' {
373 d.state = stateCR
374 continue
375 }
376 d.state = stateData
377 378 case stateDot:
379 if c == '\r' {
380 d.state = stateDotCR
381 continue
382 }
383 if c == '\n' {
384 d.state = stateEOF
385 continue
386 }
387 d.state = stateData
388 389 case stateDotCR:
390 if c == '\n' {
391 d.state = stateEOF
392 continue
393 }
394 // Not part of .\r\n.
395 // Consume leading dot and emit saved \r.
396 br.UnreadByte()
397 c = '\r'
398 d.state = stateData
399 400 case stateCR:
401 if c == '\n' {
402 d.state = stateBeginLine
403 break
404 }
405 // Not part of \r\n. Emit saved \r
406 br.UnreadByte()
407 c = '\r'
408 d.state = stateData
409 410 case stateData:
411 if c == '\r' {
412 d.state = stateCR
413 continue
414 }
415 if c == '\n' {
416 d.state = stateBeginLine
417 }
418 }
419 b[n] = c
420 n++
421 }
422 if err == nil && d.state == stateEOF {
423 err = io.EOF
424 }
425 if err != nil && d.r.dot == d {
426 d.r.dot = nil
427 }
428 return
429 }
430 431 // closeDot drains the current DotReader if any,
432 // making sure that it reads until the ending dot line.
433 func (r *Reader) closeDot() {
434 if r.dot == nil {
435 return
436 }
437 buf := []byte{:128}
438 for r.dot != nil {
439 // When Read reaches EOF or an error,
440 // it will set r.dot == nil.
441 r.dot.Read(buf)
442 }
443 }
444 445 // ReadDotBytes reads a dot-encoding and returns the decoded data.
446 //
447 // See the documentation for the [Reader.DotReader] method for details about dot-encoding.
448 func (r *Reader) ReadDotBytes() ([]byte, error) {
449 return io.ReadAll(r.DotReader())
450 }
451 452 // ReadDotLines reads a dot-encoding and returns a slice
453 // containing the decoded lines, with the final \r\n or \n elided from each.
454 //
455 // See the documentation for the [Reader.DotReader] method for details about dot-encoding.
456 func (r *Reader) ReadDotLines() ([][]byte, error) {
457 // We could use ReadDotBytes and then Split it,
458 // but reading a line at a time avoids needing a
459 // large contiguous block of memory and is simpler.
460 var v [][]byte
461 var err error
462 for {
463 var line string
464 line, err = r.ReadLine()
465 if err != nil {
466 if err == io.EOF {
467 err = io.ErrUnexpectedEOF
468 }
469 break
470 }
471 472 // Dot by itself marks end; otherwise cut one dot.
473 if len(line) > 0 && line[0] == '.' {
474 if len(line) == 1 {
475 break
476 }
477 line = line[1:]
478 }
479 v = append(v, line)
480 }
481 return v, err
482 }
483 484 var colon = []byte(":")
485 486 // ReadMIMEHeader reads a MIME-style header from r.
487 // The header is a sequence of possibly continued Key: Value lines
488 // ending in a blank line.
489 // The returned map m maps [CanonicalMIMEHeaderKey](key) to a
490 // sequence of values in the same order encountered in the input.
491 //
492 // For example, consider this input:
493 //
494 // My-Key: Value 1
495 // Long-Key: Even
496 // Longer Value
497 // My-Key: Value 2
498 //
499 // Given that input, ReadMIMEHeader returns the map:
500 //
501 // map[string][][]byte{
502 // "My-Key": {"Value 1", "Value 2"},
503 // "Long-Key": {"Even Longer Value"},
504 // }
505 func (r *Reader) ReadMIMEHeader() (MIMEHeader, error) {
506 return readMIMEHeader(r, math.MaxInt64, math.MaxInt64)
507 }
508 509 // readMIMEHeader is accessed from mime/multipart.
510 //go:linkname readMIMEHeader
511 512 // readMIMEHeader is a version of ReadMIMEHeader which takes a limit on the header size.
513 // It is called by the mime/multipart package.
514 func readMIMEHeader(r *Reader, maxMemory, maxHeaders int64) (MIMEHeader, error) {
515 // Avoid lots of small slice allocations later by allocating one
516 // large one ahead of time which we'll cut up into smaller
517 // slices. If this isn't big enough later, we allocate small ones.
518 var strs [][]byte
519 hint := r.upcomingHeaderKeys()
520 if hint > 0 {
521 if hint > 1000 {
522 hint = 1000 // set a cap to avoid overallocation
523 }
524 strs = [][]byte{:hint}
525 }
526 527 m := make(MIMEHeader, hint)
528 529 // Account for 400 bytes of overhead for the MIMEHeader, plus 200 bytes per entry.
530 // Benchmarking map creation as of go1.20, a one-entry MIMEHeader is 416 bytes and large
531 // MIMEHeaders average about 200 bytes per entry.
532 maxMemory -= 400
533 const mapEntryOverhead = 200
534 535 // The first line cannot start with a leading space.
536 if buf, err := r.R.Peek(1); err == nil && (buf[0] == ' ' || buf[0] == '\t') {
537 const errorLimit = 80 // arbitrary limit on how much of the line we'll quote
538 line, err := r.readLineSlice(errorLimit)
539 if err != nil {
540 return m, err
541 }
542 return m, ProtocolError("malformed MIME header initial line: " + string(line))
543 }
544 545 for {
546 kv, err := r.readContinuedLineSlice(maxMemory, mustHaveFieldNameColon)
547 if len(kv) == 0 {
548 return m, err
549 }
550 551 // Key ends at first colon.
552 k, v, ok := bytes.Cut(kv, colon)
553 if !ok {
554 return m, ProtocolError("malformed MIME header line: " + string(kv))
555 }
556 key, ok := canonicalMIMEHeaderKey(k)
557 if !ok {
558 return m, ProtocolError("malformed MIME header line: " + string(kv))
559 }
560 for _, c := range v {
561 if !validHeaderValueByte(c) {
562 return m, ProtocolError("malformed MIME header line: " + string(kv))
563 }
564 }
565 566 maxHeaders--
567 if maxHeaders < 0 {
568 return nil, errMessageTooLarge
569 }
570 571 // Skip initial spaces in value.
572 value := string(bytes.TrimLeft(v, " \t"))
573 574 vv := m[key]
575 if vv == nil {
576 maxMemory -= int64(len(key))
577 maxMemory -= mapEntryOverhead
578 }
579 maxMemory -= int64(len(value))
580 if maxMemory < 0 {
581 return m, errMessageTooLarge
582 }
583 if vv == nil && len(strs) > 0 {
584 // More than likely this will be a single-element key.
585 // Most headers aren't multi-valued.
586 // Set the capacity on strs[0] to 1, so any future append
587 // won't extend the slice into the other bytes.
588 vv, strs = strs[:1:1], strs[1:]
589 vv[0] = value
590 m[key] = vv
591 } else {
592 m[key] = append(vv, value)
593 }
594 595 if err != nil {
596 return m, err
597 }
598 }
599 }
600 601 // noValidation is a no-op validation func for readContinuedLineSlice
602 // that permits any lines.
603 func noValidation(_ []byte) error { return nil }
604 605 // mustHaveFieldNameColon ensures that, per RFC 7230, the
606 // field-name is on a single line, so the first line must
607 // contain a colon.
608 func mustHaveFieldNameColon(line []byte) error {
609 if bytes.IndexByte(line, ':') < 0 {
610 return ProtocolError(fmt.Sprintf("malformed MIME header: missing colon: %q", line))
611 }
612 return nil
613 }
614 615 var nl = []byte("\n")
616 617 // upcomingHeaderKeys returns an approximation of the number of keys
618 // that will be in this header. If it gets confused, it returns 0.
619 func (r *Reader) upcomingHeaderKeys() (n int) {
620 // Try to determine the 'hint' size.
621 r.R.Peek(1) // force a buffer load if empty
622 s := r.R.Buffered()
623 if s == 0 {
624 return
625 }
626 peek, _ := r.R.Peek(s)
627 for len(peek) > 0 && n < 1000 {
628 var line []byte
629 line, peek, _ = bytes.Cut(peek, nl)
630 if len(line) == 0 || (len(line) == 1 && line[0] == '\r') {
631 // Blank line separating headers from the body.
632 break
633 }
634 if line[0] == ' ' || line[0] == '\t' {
635 // Folded continuation of the previous line.
636 continue
637 }
638 n++
639 }
640 return n
641 }
642 643 // CanonicalMIMEHeaderKey returns the canonical format of the
644 // MIME header key s. The canonicalization converts the first
645 // letter and any letter following a hyphen to upper case;
646 // the rest are converted to lowercase. For example, the
647 // canonical key for "accept-encoding" is "Accept-Encoding".
648 // MIME header keys are assumed to be ASCII only.
649 // If s contains a space or invalid header field bytes as
650 // defined by RFC 9112, it is returned without modifications.
651 func CanonicalMIMEHeaderKey(s string) string {
652 // Quick check for canonical encoding.
653 upper := true
654 for i := 0; i < len(s); i++ {
655 c := s[i]
656 if !validHeaderFieldByte(c) {
657 return s
658 }
659 if upper && 'a' <= c && c <= 'z' {
660 s, _ = canonicalMIMEHeaderKey([]byte(s))
661 return s
662 }
663 if !upper && 'A' <= c && c <= 'Z' {
664 s, _ = canonicalMIMEHeaderKey([]byte(s))
665 return s
666 }
667 upper = c == '-'
668 }
669 return s
670 }
671 672 const toLower = 'a' - 'A'
673 674 // validHeaderFieldByte reports whether c is a valid byte in a header
675 // field name. RFC 7230 says:
676 //
677 // header-field = field-name ":" OWS field-value OWS
678 // field-name = token
679 // tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
680 // "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
681 // token = 1*tchar
682 func validHeaderFieldByte(c byte) bool {
683 // mask is a 128-bit bitmap with 1s for allowed bytes,
684 // so that the byte c can be tested with a shift and an and.
685 // If c >= 128, then 1<<c and 1<<(c-64) will both be zero,
686 // and this function will return false.
687 const mask = 0 |
688 (1<<(10)-1)<<'0' |
689 (1<<(26)-1)<<'a' |
690 (1<<(26)-1)<<'A' |
691 1<<'!' |
692 1<<'#' |
693 1<<'$' |
694 1<<'%' |
695 1<<'&' |
696 1<<'\'' |
697 1<<'*' |
698 1<<'+' |
699 1<<'-' |
700 1<<'.' |
701 1<<'^' |
702 1<<'_' |
703 1<<'`' |
704 1<<'|' |
705 1<<'~'
706 return ((uint64(1)<<c)&(mask&(1<<64-1)) |
707 (uint64(1)<<(c-64))&(mask>>64)) != 0
708 }
709 710 // validHeaderValueByte reports whether c is a valid byte in a header
711 // field value. RFC 7230 says:
712 //
713 // field-content = field-vchar [ 1*( SP / HTAB ) field-vchar ]
714 // field-vchar = VCHAR / obs-text
715 // obs-text = %x80-FF
716 //
717 // RFC 5234 says:
718 //
719 // HTAB = %x09
720 // SP = %x20
721 // VCHAR = %x21-7E
722 func validHeaderValueByte(c byte) bool {
723 // mask is a 128-bit bitmap with 1s for allowed bytes,
724 // so that the byte c can be tested with a shift and an and.
725 // If c >= 128, then 1<<c and 1<<(c-64) will both be zero.
726 // Since this is the obs-text range, we invert the mask to
727 // create a bitmap with 1s for disallowed bytes.
728 const mask = 0 |
729 (1<<(0x7f-0x21)-1)<<0x21 | // VCHAR: %x21-7E
730 1<<0x20 | // SP: %x20
731 1<<0x09 // HTAB: %x09
732 return ((uint64(1)<<c)&^(mask&(1<<64-1)) |
733 (uint64(1)<<(c-64))&^(mask>>64)) == 0
734 }
735 736 // canonicalMIMEHeaderKey is like CanonicalMIMEHeaderKey but is
737 // allowed to mutate the provided byte slice before returning the
738 // string.
739 //
740 // For invalid inputs (if a contains spaces or non-token bytes), a
741 // is unchanged and a string copy is returned.
742 //
743 // ok is true if the header key contains only valid characters and spaces.
744 // ReadMIMEHeader accepts header keys containing spaces, but does not
745 // canonicalize them.
746 func canonicalMIMEHeaderKey(a []byte) (_ string, ok bool) {
747 if len(a) == 0 {
748 return "", false
749 }
750 751 // See if a looks like a header key. If not, return it unchanged.
752 noCanon := false
753 for _, c := range a {
754 if validHeaderFieldByte(c) {
755 continue
756 }
757 // Don't canonicalize.
758 if c == ' ' {
759 // We accept invalid headers with a space before the
760 // colon, but must not canonicalize them.
761 // See https://go.dev/issue/34540.
762 noCanon = true
763 continue
764 }
765 return string(a), false
766 }
767 if noCanon {
768 return string(a), true
769 }
770 771 upper := true
772 for i, c := range a {
773 // Canonicalize: first letter upper case
774 // and upper case after each dash.
775 // (Host, User-Agent, If-Modified-Since).
776 // MIME headers are ASCII only, so no Unicode issues.
777 if upper && 'a' <= c && c <= 'z' {
778 c -= toLower
779 } else if !upper && 'A' <= c && c <= 'Z' {
780 c += toLower
781 }
782 a[i] = c
783 upper = c == '-' // for next time
784 }
785 commonHeaderOnce.Do(initCommonHeader)
786 // The compiler recognizes m[string(byteSlice)] as a special
787 // case, so a copy of a's bytes into a new string does not
788 // happen in this map lookup:
789 if v := commonHeader[string(a)]; v != "" {
790 return v, true
791 }
792 return string(a), true
793 }
794 795 // commonHeader interns common header bytes.
796 var commonHeader map[string]string
797 798 var commonHeaderOnce sync.Once
799 800 func initCommonHeader() {
801 commonHeader = map[string]string{}
802 for _, v := range [][]byte{
803 "Accept",
804 "Accept-Charset",
805 "Accept-Encoding",
806 "Accept-Language",
807 "Accept-Ranges",
808 "Cache-Control",
809 "Cc",
810 "Connection",
811 "Content-Id",
812 "Content-Language",
813 "Content-Length",
814 "Content-Transfer-Encoding",
815 "Content-Type",
816 "Cookie",
817 "Date",
818 "Dkim-Signature",
819 "Etag",
820 "Expires",
821 "From",
822 "Host",
823 "If-Modified-Since",
824 "If-None-Match",
825 "In-Reply-To",
826 "Last-Modified",
827 "Location",
828 "Message-Id",
829 "Mime-Version",
830 "Pragma",
831 "Received",
832 "Return-Path",
833 "Server",
834 "Set-Cookie",
835 "Subject",
836 "To",
837 "User-Agent",
838 "Via",
839 "X-Forwarded-For",
840 "X-Imforwards",
841 "X-Powered-By",
842 } {
843 commonHeader[v] = v
844 }
845 }
846