diff --git a/cmd/gwstester/tester.go b/cmd/gwstester/tester.go index 49aa1dc..3f30860 100644 --- a/cmd/gwstester/tester.go +++ b/cmd/gwstester/tester.go @@ -43,13 +43,23 @@ func manageClient(sock net.Conn) { for { - req, err := request.Build(sock) + /* (1) Parse request */ + req, errRq := request.Parse(sock) + if errRq != nil { fmt.Printf("Request parsing error: %s\n", errRq) } + fmt.Printf("%v\n", req) + + /* (2) Build response */ + res := req.BuildResponse() + + /* (3) Write into socket */ + written, err := res.Send(sock) if err != nil { - fmt.Printf("STATUS CODE: %d %s\n", req.StatusCode(), req.StatusCode().Explicit()) - panic(err) + fmt.Printf("WRITE ERROR: %s\n", err); + return } - fmt.Printf("%v\n", req) + fmt.Printf("Written %d bytes\n", written) + break; } diff --git a/http/upgrade/request/public.go b/http/upgrade/request/public.go index 973f956..89a8654 100644 --- a/http/upgrade/request/public.go +++ b/http/upgrade/request/public.go @@ -9,7 +9,7 @@ import ( // Parse builds an upgrade HTTP request // from a reader (typically bufio.NewRead of the socket) -func Build(r io.Reader) (request *T, err error) { +func Parse(r io.Reader) (request *T, err error) { req := new(T) req.code = 500 @@ -75,3 +75,24 @@ func (r T) String() string{ func (r T) StatusCode() response.StatusCode { return r.code } + + + +// BuildResponse builds a response.T from the request +func (r *T) BuildResponse() *response.T{ + + inst := new(response.T) + + /* (1) Copy code */ + inst.SetStatusCode(r.code) + + /* (2) Set Protocol */ + if len(r.protocols) > 0 { + inst.SetProtocol(r.protocols[0]) + } + + /* (4) Process key */ + inst.ProcessKey(r.key) + + return inst +} \ No newline at end of file diff --git a/http/upgrade/response/public.go b/http/upgrade/response/public.go new file mode 100644 index 0000000..e64518d --- /dev/null +++ b/http/upgrade/response/public.go @@ -0,0 +1,62 @@ +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) { + + /* (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.Explicit()) + + /* (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-Accept: %s\r\nSec-WebSocket-Version: %d\r\n%s", r.accept, WSVersion, optionalProtocol) + + /* (3) Build all */ + raw := []byte(fmt.Sprintf("%s%s\r\n", responseLine, headers)) + + /* (4) Write */ + fmt.Printf("Upgrade Response\n----------------\n%s----------------\n", raw) + written, err := w.Write(raw) + + return written, err + +} \ No newline at end of file diff --git a/http/upgrade/response/types.go b/http/upgrade/response/types.go index 9349bb0..735b549 100644 --- a/http/upgrade/response/types.go +++ b/http/upgrade/response/types.go @@ -1,9 +1,15 @@ package response +// Constant +const HttpVersion = "1.1" +const WSVersion = 13 +var WSSalt []byte = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + // T represents an HTTP Upgrade Response type T struct { - code StatusCode // status code - accept []byte // processed from Sec-WebSocket-Key - protocol []byte // set from Sec-WebSocket-Protocol or none if not received + code StatusCode // status code + accept []byte // processed from Sec-WebSocket-Key + protocol []byte // set from Sec-WebSocket-Protocol or none if not received + } \ No newline at end of file