// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package websocket

import (
	
	
	
	
	
	
	
)

var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")

func computeAcceptKey( string) string {
	 := sha1.New()
	.Write([]byte())
	.Write(keyGUID)
	return base64.StdEncoding.EncodeToString(.Sum(nil))
}

func generateChallengeKey() (string, error) {
	 := make([]byte, 16)
	if ,  := io.ReadFull(rand.Reader, );  != nil {
		return "", 
	}
	return base64.StdEncoding.EncodeToString(), nil
}

// Token octets per RFC 2616.
var isTokenOctet = [256]bool{
	'!':  true,
	'#':  true,
	'$':  true,
	'%':  true,
	'&':  true,
	'\'': true,
	'*':  true,
	'+':  true,
	'-':  true,
	'.':  true,
	'0':  true,
	'1':  true,
	'2':  true,
	'3':  true,
	'4':  true,
	'5':  true,
	'6':  true,
	'7':  true,
	'8':  true,
	'9':  true,
	'A':  true,
	'B':  true,
	'C':  true,
	'D':  true,
	'E':  true,
	'F':  true,
	'G':  true,
	'H':  true,
	'I':  true,
	'J':  true,
	'K':  true,
	'L':  true,
	'M':  true,
	'N':  true,
	'O':  true,
	'P':  true,
	'Q':  true,
	'R':  true,
	'S':  true,
	'T':  true,
	'U':  true,
	'W':  true,
	'V':  true,
	'X':  true,
	'Y':  true,
	'Z':  true,
	'^':  true,
	'_':  true,
	'`':  true,
	'a':  true,
	'b':  true,
	'c':  true,
	'd':  true,
	'e':  true,
	'f':  true,
	'g':  true,
	'h':  true,
	'i':  true,
	'j':  true,
	'k':  true,
	'l':  true,
	'm':  true,
	'n':  true,
	'o':  true,
	'p':  true,
	'q':  true,
	'r':  true,
	's':  true,
	't':  true,
	'u':  true,
	'v':  true,
	'w':  true,
	'x':  true,
	'y':  true,
	'z':  true,
	'|':  true,
	'~':  true,
}

// skipSpace returns a slice of the string s with all leading RFC 2616 linear
// whitespace removed.
func skipSpace( string) ( string) {
	 := 0
	for ;  < len(); ++ {
		if  := [];  != ' ' &&  != '\t' {
			break
		}
	}
	return [:]
}

// nextToken returns the leading RFC 2616 token of s and the string following
// the token.
func nextToken( string) (,  string) {
	 := 0
	for ;  < len(); ++ {
		if !isTokenOctet[[]] {
			break
		}
	}
	return [:], [:]
}

// nextTokenOrQuoted returns the leading token or quoted string per RFC 2616
// and the string following the token or quoted string.
func nextTokenOrQuoted( string) ( string,  string) {
	if !strings.HasPrefix(, "\"") {
		return nextToken()
	}
	 = [1:]
	for  := 0;  < len(); ++ {
		switch [] {
		case '"':
			return [:], [+1:]
		case '\\':
			 := make([]byte, len()-1)
			 := copy(, [:])
			 := true
			for  =  + 1;  < len(); ++ {
				 := []
				switch {
				case :
					 = false
					[] = 
					++
				case  == '\\':
					 = true
				case  == '"':
					return string([:]), [+1:]
				default:
					[] = 
					++
				}
			}
			return "", ""
		}
	}
	return "", ""
}

// equalASCIIFold returns true if s is equal to t with ASCII case folding as
// defined in RFC 4790.
func equalASCIIFold(,  string) bool {
	for  != "" &&  != "" {
		,  := utf8.DecodeRuneInString()
		 = [:]
		,  := utf8.DecodeRuneInString()
		 = [:]
		if  ==  {
			continue
		}
		if 'A' <=  &&  <= 'Z' {
			 =  + 'a' - 'A'
		}
		if 'A' <=  &&  <= 'Z' {
			 =  + 'a' - 'A'
		}
		if  !=  {
			return false
		}
	}
	return  == 
}

// tokenListContainsValue returns true if the 1#token header with the given
// name contains a token equal to value with ASCII case folding.
func tokenListContainsValue( http.Header,  string,  string) bool {
:
	for ,  := range [] {
		for {
			var  string
			,  = nextToken(skipSpace())
			if  == "" {
				continue 
			}
			 = skipSpace()
			if  != "" && [0] != ',' {
				continue 
			}
			if equalASCIIFold(, ) {
				return true
			}
			if  == "" {
				continue 
			}
			 = [1:]
		}
	}
	return false
}

// parseExtensions parses WebSocket extensions from a header.
func parseExtensions( http.Header) []map[string]string {
	// From RFC 6455:
	//
	//  Sec-WebSocket-Extensions = extension-list
	//  extension-list = 1#extension
	//  extension = extension-token *( ";" extension-param )
	//  extension-token = registered-token
	//  registered-token = token
	//  extension-param = token [ "=" (token | quoted-string) ]
	//     ;When using the quoted-string syntax variant, the value
	//     ;after quoted-string unescaping MUST conform to the
	//     ;'token' ABNF.

	var  []map[string]string
:
	for ,  := range ["Sec-Websocket-Extensions"] {
		for {
			var  string
			,  = nextToken(skipSpace())
			if  == "" {
				continue 
			}
			 := map[string]string{"": }
			for {
				 = skipSpace()
				if !strings.HasPrefix(, ";") {
					break
				}
				var  string
				,  = nextToken(skipSpace([1:]))
				if  == "" {
					continue 
				}
				 = skipSpace()
				var  string
				if strings.HasPrefix(, "=") {
					,  = nextTokenOrQuoted(skipSpace([1:]))
					 = skipSpace()
				}
				if  != "" && [0] != ',' && [0] != ';' {
					continue 
				}
				[] = 
			}
			if  != "" && [0] != ',' {
				continue 
			}
			 = append(, )
			if  == "" {
				continue 
			}
			 = [1:]
		}
	}
	return 
}

// isValidChallengeKey checks if the argument meets RFC6455 specification.
func isValidChallengeKey( string) bool {
	// From RFC6455:
	//
	// A |Sec-WebSocket-Key| header field with a base64-encoded (see
	// Section 4 of [RFC4648]) value that, when decoded, is 16 bytes in
	// length.

	if  == "" {
		return false
	}
	,  := base64.StdEncoding.DecodeString()
	return  == nil && len() == 16
}