1 // Copyright 2013 The Gorilla WebSocket 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.
17 var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
19 func computeAcceptKey(challengeKey string) string {
21 h.Write([]byte(challengeKey))
23 return base64.StdEncoding.EncodeToString(h.Sum(nil))
26 func generateChallengeKey() (string, error) {
28 if _, err := io.ReadFull(rand.Reader, p); err != nil {
31 return base64.StdEncoding.EncodeToString(p), nil
34 // Token octets per RFC 2616.
35 var isTokenOctet = [256]bool{
115 // skipSpace returns a slice of the string s with all leading RFC 2616 linear
116 // whitespace removed.
117 func skipSpace(s string) (rest string) {
119 for ; i < len(s); i++ {
120 if b := s[i]; b != ' ' && b != '\t' {
127 // nextToken returns the leading RFC 2616 token of s and the string following
129 func nextToken(s string) (token, rest string) {
131 for ; i < len(s); i++ {
132 if !isTokenOctet[s[i]] {
139 // nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
140 // and the string following the token or quoted string.
141 func nextTokenOrQuoted(s string) (value string, rest string) {
142 if !strings.HasPrefix(s, "\"") {
146 for i := 0; i < len(s); i++ {
149 return s[:i], s[i+1:]
151 p := make([]byte, len(s)-1)
154 for i = i + 1; i < len(s); i++ {
164 return string(p[:j]), s[i+1:]
176 // equalASCIIFold returns true if s is equal to t with ASCII case folding as
177 // defined in RFC 4790.
178 func equalASCIIFold(s, t string) bool {
179 for s != "" && t != "" {
180 sr, size := utf8.DecodeRuneInString(s)
182 tr, size := utf8.DecodeRuneInString(t)
187 if 'A' <= sr && sr <= 'Z' {
190 if 'A' <= tr && tr <= 'Z' {
200 // tokenListContainsValue returns true if the 1#token header with the given
201 // name contains a token equal to value with ASCII case folding.
202 func tokenListContainsValue(header http.Header, name string, value string) bool {
204 for _, s := range header[name] {
207 t, s = nextToken(skipSpace(s))
212 if s != "" && s[0] != ',' {
215 if equalASCIIFold(t, value) {
227 // parseExtensions parses WebSocket extensions from a header.
228 func parseExtensions(header http.Header) []map[string]string {
231 // Sec-WebSocket-Extensions = extension-list
232 // extension-list = 1#extension
233 // extension = extension-token *( ";" extension-param )
234 // extension-token = registered-token
235 // registered-token = token
236 // extension-param = token [ "=" (token | quoted-string) ]
237 // ;When using the quoted-string syntax variant, the value
238 // ;after quoted-string unescaping MUST conform to the
241 var result []map[string]string
243 for _, s := range header["Sec-Websocket-Extensions"] {
246 t, s = nextToken(skipSpace(s))
250 ext := map[string]string{"": t}
253 if !strings.HasPrefix(s, ";") {
257 k, s = nextToken(skipSpace(s[1:]))
263 if strings.HasPrefix(s, "=") {
264 v, s = nextTokenOrQuoted(skipSpace(s[1:]))
267 if s != "" && s[0] != ',' && s[0] != ';' {
272 if s != "" && s[0] != ',' {
275 result = append(result, ext)