82 lines
1.7 KiB
Go
82 lines
1.7 KiB
Go
package response
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"encoding/base64"
|
|
"crypto/sha1"
|
|
)
|
|
|
|
|
|
|
|
// SetStatusCode sets the status code
|
|
func (r *T) SetStatusCode(sc StatusCode) {
|
|
r.code = sc
|
|
}
|
|
|
|
// SetProtocols sets the protocols
|
|
func (r *T) SetProtocol(p []byte) {
|
|
r.protocol = p
|
|
}
|
|
|
|
// ProcessKey processes the accept token according
|
|
// to the rfc from the Sec-WebSocket-Key
|
|
func (r *T) ProcessKey(k []byte) {
|
|
|
|
// do nothing for empty key
|
|
if k == nil || len(k) == 0 {
|
|
r.accept = nil
|
|
return
|
|
}
|
|
|
|
/* (1) Concat with constant salt */
|
|
mix := append(k, WSSalt...)
|
|
|
|
/* (2) Hash with sha1 algorithm */
|
|
digest := sha1.Sum(mix)
|
|
|
|
/* (3) Base64 encode it */
|
|
r.accept = []byte( base64.StdEncoding.EncodeToString( digest[:sha1.Size] ) )
|
|
|
|
}
|
|
|
|
|
|
// Send sends the response through an io.Writer
|
|
// typically a socket
|
|
func (r T) Send(w io.Writer) (int, error) {
|
|
|
|
/* (1) Build response line */
|
|
responseLine := fmt.Sprintf("HTTP/%s %d %s\r\n", HttpVersion, r.code, r.code.Message())
|
|
|
|
/* (2) Build headers */
|
|
optionalProtocol := ""
|
|
if len(r.protocol) > 0 {
|
|
optionalProtocol = fmt.Sprintf("Sec-WebSocket-Protocol: %s\r\n", r.protocol)
|
|
}
|
|
|
|
headers := fmt.Sprintf("Upgrade: websocket\t\nConnection: Upgrade\r\nSec-WebSocket-Version: %d\r\n%s", WSVersion, optionalProtocol)
|
|
if r.accept != nil {
|
|
headers = fmt.Sprintf("%sSec-WebSocket-Accept: %s\r\n", headers, r.accept)
|
|
}
|
|
headers = fmt.Sprintf("%s\r\n", headers)
|
|
|
|
/* (3) Build all */
|
|
raw := []byte(fmt.Sprintf("%s%s\r\n", responseLine, headers))
|
|
|
|
/* (4) Write */
|
|
written, err := w.Write(raw)
|
|
|
|
return written, err
|
|
|
|
}
|
|
|
|
// GetProtocol returns the choosen protocol if set, else nil
|
|
func (r T) GetProtocol() []byte {
|
|
return r.protocol
|
|
}
|
|
|
|
|
|
// GetStatusCode returns the response status code
|
|
func (r T) GetStatusCode() StatusCode {
|
|
return r.code
|
|
} |