ws/internal/http/upgrade/response/public.go

79 lines
1.7 KiB
Go

package response
import (
"crypto/sha1"
"encoding/base64"
"fmt"
"io"
)
// 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\r\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", 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
}