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 }