github.com/Kolosok86/http@v0.1.2/textproto/reader.go (about)

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