src/pkg/net/http/lex.go - The Go Programming Language

Golang

Source file src/pkg/net/http/lex.go

     1	// Copyright 2009 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 http
     6	
     7	// This file deals with lexical matters of HTTP
     8	
     9	func isSeparator(c byte) bool {
    10		switch c {
    11		case '(', ')', '<', '>', '@', ',', ';', ':', '\\', '"', '/', '[', ']', '?', '=', '{', '}', ' ', '\t':
    12			return true
    13		}
    14		return false
    15	}
    16	
    17	func isCtl(c byte) bool { return (0 <= c && c <= 31) || c == 127 }
    18	
    19	func isChar(c byte) bool { return 0 <= c && c <= 127 }
    20	
    21	func isAnyText(c byte) bool { return !isCtl(c) }
    22	
    23	func isQdText(c byte) bool { return isAnyText(c) && c != '"' }
    24	
    25	func isToken(c byte) bool { return isChar(c) && !isCtl(c) && !isSeparator(c) }
    26	
    27	// Valid escaped sequences are not specified in RFC 2616, so for now, we assume
    28	// that they coincide with the common sense ones used by GO. Malformed
    29	// characters should probably not be treated as errors by a robust (forgiving)
    30	// parser, so we replace them with the '?' character.
    31	func httpUnquotePair(b byte) byte {
    32		// skip the first byte, which should always be '\'
    33		switch b {
    34		case 'a':
    35			return '\a'
    36		case 'b':
    37			return '\b'
    38		case 'f':
    39			return '\f'
    40		case 'n':
    41			return '\n'
    42		case 'r':
    43			return '\r'
    44		case 't':
    45			return '\t'
    46		case 'v':
    47			return '\v'
    48		case '\\':
    49			return '\\'
    50		case '\'':
    51			return '\''
    52		case '"':
    53			return '"'
    54		}
    55		return '?'
    56	}
    57	
    58	// raw must begin with a valid quoted string. Only the first quoted string is
    59	// parsed and is unquoted in result. eaten is the number of bytes parsed, or -1
    60	// upon failure.
    61	func httpUnquote(raw []byte) (eaten int, result string) {
    62		buf := make([]byte, len(raw))
    63		if raw[0] != '"' {
    64			return -1, ""
    65		}
    66		eaten = 1
    67		j := 0 // # of bytes written in buf
    68		for i := 1; i < len(raw); i++ {
    69			switch b := raw[i]; b {
    70			case '"':
    71				eaten++
    72				buf = buf[0:j]
    73				return i + 1, string(buf)
    74			case '\\':
    75				if len(raw) < i+2 {
    76					return -1, ""
    77				}
    78				buf[j] = httpUnquotePair(raw[i+1])
    79				eaten += 2
    80				j++
    81				i++
    82			default:
    83				if isQdText(b) {
    84					buf[j] = b
    85				} else {
    86					buf[j] = '?'
    87				}
    88				eaten++
    89				j++
    90			}
    91		}
    92		return -1, ""
    93	}
    94	
    95	// This is a best effort parse, so errors are not returned, instead not all of
    96	// the input string might be parsed. result is always non-nil.
    97	func httpSplitFieldValue(fv string) (eaten int, result []string) {
    98		result = make([]string, 0, len(fv))
    99		raw := []byte(fv)
   100		i := 0
   101		chunk := ""
   102		for i < len(raw) {
   103			b := raw[i]
   104			switch {
   105			case b == '"':
   106				eaten, unq := httpUnquote(raw[i:len(raw)])
   107				if eaten < 0 {
   108					return i, result
   109				} else {
   110					i += eaten
   111					chunk += unq
   112				}
   113			case isSeparator(b):
   114				if chunk != "" {
   115					result = result[0 : len(result)+1]
   116					result[len(result)-1] = chunk
   117					chunk = ""
   118				}
   119				i++
   120			case isToken(b):
   121				chunk += string(b)
   122				i++
   123			case b == '\n' || b == '\r':
   124				i++
   125			default:
   126				chunk += "?"
   127				i++
   128			}
   129		}
   130		if chunk != "" {
   131			result = result[0 : len(result)+1]
   132			result[len(result)-1] = chunk
   133			chunk = ""
   134		}
   135		return i, result
   136	}