29 return "", err |
29 return "", err |
30 } |
30 } |
31 return base64.StdEncoding.EncodeToString(p), nil |
31 return base64.StdEncoding.EncodeToString(p), nil |
32 } |
32 } |
33 |
33 |
34 // Octet types from RFC 2616. |
34 // Token octets per RFC 2616. |
35 var octetTypes [256]byte |
35 var isTokenOctet = [256]bool{ |
36 |
36 '!': true, |
37 const ( |
37 '#': true, |
38 isTokenOctet = 1 << iota |
38 '$': true, |
39 isSpaceOctet |
39 '%': true, |
40 ) |
40 '&': true, |
41 |
41 '\'': true, |
42 func init() { |
42 '*': true, |
43 // From RFC 2616 |
43 '+': true, |
44 // |
44 '-': true, |
45 // OCTET = <any 8-bit sequence of data> |
45 '.': true, |
46 // CHAR = <any US-ASCII character (octets 0 - 127)> |
46 '0': true, |
47 // CTL = <any US-ASCII control character (octets 0 - 31) and DEL (127)> |
47 '1': true, |
48 // CR = <US-ASCII CR, carriage return (13)> |
48 '2': true, |
49 // LF = <US-ASCII LF, linefeed (10)> |
49 '3': true, |
50 // SP = <US-ASCII SP, space (32)> |
50 '4': true, |
51 // HT = <US-ASCII HT, horizontal-tab (9)> |
51 '5': true, |
52 // <"> = <US-ASCII double-quote mark (34)> |
52 '6': true, |
53 // CRLF = CR LF |
53 '7': true, |
54 // LWS = [CRLF] 1*( SP | HT ) |
54 '8': true, |
55 // TEXT = <any OCTET except CTLs, but including LWS> |
55 '9': true, |
56 // separators = "(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\" | <"> |
56 'A': true, |
57 // | "/" | "[" | "]" | "?" | "=" | "{" | "}" | SP | HT |
57 'B': true, |
58 // token = 1*<any CHAR except CTLs or separators> |
58 'C': true, |
59 // qdtext = <any TEXT except <">> |
59 'D': true, |
60 |
60 'E': true, |
61 for c := 0; c < 256; c++ { |
61 'F': true, |
62 var t byte |
62 'G': true, |
63 isCtl := c <= 31 || c == 127 |
63 'H': true, |
64 isChar := 0 <= c && c <= 127 |
64 'I': true, |
65 isSeparator := strings.IndexRune(" \t\"(),/:;<=>?@[]\\{}", rune(c)) >= 0 |
65 'J': true, |
66 if strings.IndexRune(" \t\r\n", rune(c)) >= 0 { |
66 'K': true, |
67 t |= isSpaceOctet |
67 'L': true, |
68 } |
68 'M': true, |
69 if isChar && !isCtl && !isSeparator { |
69 'N': true, |
70 t |= isTokenOctet |
70 'O': true, |
71 } |
71 'P': true, |
72 octetTypes[c] = t |
72 'Q': true, |
73 } |
73 'R': true, |
74 } |
74 'S': true, |
75 |
75 'T': true, |
|
76 'U': true, |
|
77 'W': true, |
|
78 'V': true, |
|
79 'X': true, |
|
80 'Y': true, |
|
81 'Z': true, |
|
82 '^': true, |
|
83 '_': true, |
|
84 '`': true, |
|
85 'a': true, |
|
86 'b': true, |
|
87 'c': true, |
|
88 'd': true, |
|
89 'e': true, |
|
90 'f': true, |
|
91 'g': true, |
|
92 'h': true, |
|
93 'i': true, |
|
94 'j': true, |
|
95 'k': true, |
|
96 'l': true, |
|
97 'm': true, |
|
98 'n': true, |
|
99 'o': true, |
|
100 'p': true, |
|
101 'q': true, |
|
102 'r': true, |
|
103 's': true, |
|
104 't': true, |
|
105 'u': true, |
|
106 'v': true, |
|
107 'w': true, |
|
108 'x': true, |
|
109 'y': true, |
|
110 'z': true, |
|
111 '|': true, |
|
112 '~': true, |
|
113 } |
|
114 |
|
115 // skipSpace returns a slice of the string s with all leading RFC 2616 linear |
|
116 // whitespace removed. |
76 func skipSpace(s string) (rest string) { |
117 func skipSpace(s string) (rest string) { |
77 i := 0 |
118 i := 0 |
78 for ; i < len(s); i++ { |
119 for ; i < len(s); i++ { |
79 if octetTypes[s[i]]&isSpaceOctet == 0 { |
120 if b := s[i]; b != ' ' && b != '\t' { |
80 break |
121 break |
81 } |
122 } |
82 } |
123 } |
83 return s[i:] |
124 return s[i:] |
84 } |
125 } |
85 |
126 |
|
127 // nextToken returns the leading RFC 2616 token of s and the string following |
|
128 // the token. |
86 func nextToken(s string) (token, rest string) { |
129 func nextToken(s string) (token, rest string) { |
87 i := 0 |
130 i := 0 |
88 for ; i < len(s); i++ { |
131 for ; i < len(s); i++ { |
89 if octetTypes[s[i]]&isTokenOctet == 0 { |
132 if !isTokenOctet[s[i]] { |
90 break |
133 break |
91 } |
134 } |
92 } |
135 } |
93 return s[:i], s[i:] |
136 return s[:i], s[i:] |
94 } |
137 } |
95 |
138 |
|
139 // nextTokenOrQuoted returns the leading token or quoted string per RFC 2616 |
|
140 // and the string following the token or quoted string. |
96 func nextTokenOrQuoted(s string) (value string, rest string) { |
141 func nextTokenOrQuoted(s string) (value string, rest string) { |
97 if !strings.HasPrefix(s, "\"") { |
142 if !strings.HasPrefix(s, "\"") { |
98 return nextToken(s) |
143 return nextToken(s) |
99 } |
144 } |
100 s = s[1:] |
145 s = s[1:] |
126 } |
171 } |
127 } |
172 } |
128 return "", "" |
173 return "", "" |
129 } |
174 } |
130 |
175 |
131 // equalASCIIFold returns true if s is equal to t with ASCII case folding. |
176 // equalASCIIFold returns true if s is equal to t with ASCII case folding as |
|
177 // defined in RFC 4790. |
132 func equalASCIIFold(s, t string) bool { |
178 func equalASCIIFold(s, t string) bool { |
133 for s != "" && t != "" { |
179 for s != "" && t != "" { |
134 sr, size := utf8.DecodeRuneInString(s) |
180 sr, size := utf8.DecodeRuneInString(s) |
135 s = s[size:] |
181 s = s[size:] |
136 tr, size := utf8.DecodeRuneInString(t) |
182 tr, size := utf8.DecodeRuneInString(t) |