Source file src/net/textproto/reader.go

Documentation: net/textproto

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

View as plain text