go fmt/vet

This commit is contained in:
Adrien Marquès 2018-09-29 14:39:12 +02:00
parent a9986c3123
commit 7fb4241187
9 changed files with 161 additions and 162 deletions

View File

@ -3,6 +3,7 @@ package request
import ( import (
"fmt" "fmt"
) )
// invalid request // invalid request
// - multiple-value if only 1 expected // - multiple-value if only 1 expected
type InvalidRequest struct { type InvalidRequest struct {
@ -23,13 +24,13 @@ func (err IncompleteRequest) Error() string {
return fmt.Sprintf("imcomplete request, '%s' is invalid or missing", err.MissingField) return fmt.Sprintf("imcomplete request, '%s' is invalid or missing", err.MissingField)
} }
// Request has a violated origin policy // Request has a violated origin policy
type InvalidOriginPolicy struct { type InvalidOriginPolicy struct {
Host string Host string
Origin string Origin string
err error err error
} }
func (err InvalidOriginPolicy) Error() string { func (err InvalidOriginPolicy) Error() string {
return fmt.Sprintf("invalid origin policy; (host: '%s' origin: '%s' error: '%s')", err.Host, err.Origin, err.err) return fmt.Sprintf("invalid origin policy; (host: '%s' origin: '%s' error: '%s')", err.Host, err.Origin, err.err)
} }

View File

@ -1,13 +1,14 @@
package request package request
import ( import (
"fmt"
"bytes" "bytes"
"fmt"
"regexp" "regexp"
) )
// httpMethod represents available http methods // httpMethod represents available http methods
type httpMethod byte type httpMethod byte
const ( const (
OPTIONS httpMethod = iota OPTIONS httpMethod = iota
GET GET
@ -17,7 +18,6 @@ const (
DELETE DELETE
) )
// RequestLine represents the HTTP Request line // RequestLine represents the HTTP Request line
// defined in rfc-2616 : https://tools.ietf.org/html/rfc2616#section-5.1 // defined in rfc-2616 : https://tools.ietf.org/html/rfc2616#section-5.1
type RequestLine struct { type RequestLine struct {
@ -26,7 +26,6 @@ type RequestLine struct {
version byte version byte
} }
// parseRequestLine parses the first HTTP request line // parseRequestLine parses the first HTTP request line
func (r *RequestLine) Parse(b []byte) error { func (r *RequestLine) Parse(b []byte) error {
@ -60,35 +59,32 @@ func (r *RequestLine) Parse(b []byte) error {
} }
// GetURI returns the actual URI // GetURI returns the actual URI
func (r RequestLine) GetURI() string { func (r RequestLine) GetURI() string {
return r.uri return r.uri
} }
// extractHttpMethod extracts the HTTP method from a []byte // extractHttpMethod extracts the HTTP method from a []byte
// and checks for errors // and checks for errors
// allowed format: OPTIONS|GET|HEAD|POST|PUT|DELETE // allowed format: OPTIONS|GET|HEAD|POST|PUT|DELETE
func (r *RequestLine) extractHttpMethod(b []byte) error { func (r *RequestLine) extractHttpMethod(b []byte) error {
switch string(b) { switch string(b) {
// case "OPTIONS": r.method = OPTIONS // case "OPTIONS": r.method = OPTIONS
case "GET": r.method = GET case "GET":
// case "HEAD": r.method = HEAD r.method = GET
// case "POST": r.method = POST // case "HEAD": r.method = HEAD
// case "PUT": r.method = PUT // case "POST": r.method = POST
// case "DELETE": r.method = DELETE // case "PUT": r.method = PUT
// case "DELETE": r.method = DELETE
default: default:
return fmt.Errorf("Invalid HTTP method '%s', expected 'GET'", b) return fmt.Errorf("Invalid HTTP method '%s', expected 'GET'", b)
} }
return nil return nil
} }
// extractURI extracts the URI from a []byte and checks for errors // extractURI extracts the URI from a []byte and checks for errors
// allowed format: /([^/]/)*/? // allowed format: /([^/]/)*/?
func (r *RequestLine) extractURI(b []byte) error { func (r *RequestLine) extractURI(b []byte) error {
@ -106,13 +102,12 @@ func (r *RequestLine) extractURI(b []byte) error {
} }
// extractHttpVersion extracts the version and checks for errors // extractHttpVersion extracts the version and checks for errors
// allowed format: [1-9] or [1.9].[0-9] // allowed format: [1-9] or [1.9].[0-9]
func (r *RequestLine) extractHttpVersion(b []byte) error { func (r *RequestLine) extractHttpVersion(b []byte) error {
/* (1) Extract version parts */ /* (1) Extract version parts */
extractor := regexp.MustCompile(`^HTTP/([1-9])(?:\.([0-9]))?$`); extractor := regexp.MustCompile(`^HTTP/([1-9])(?:\.([0-9]))?$`)
if !extractor.Match(b) { if !extractor.Match(b) {
return fmt.Errorf("HTTP version, expected INT or INT.INT, got '%s'", b) return fmt.Errorf("HTTP version, expected INT or INT.INT, got '%s'", b)
@ -120,7 +115,7 @@ func (r *RequestLine) extractHttpVersion(b []byte) error {
/* (2) Extract version number */ /* (2) Extract version number */
matches := extractor.FindSubmatch(b) matches := extractor.FindSubmatch(b)
var version byte = matches[1][0] - '0' var version byte = matches[1][0] - '0'
/* (3) Extract subversion (if exists) */ /* (3) Extract subversion (if exists) */
var subVersion byte = 0 var subVersion byte = 0
@ -129,7 +124,7 @@ func (r *RequestLine) extractHttpVersion(b []byte) error {
} }
/* (4) Store version (x 10 to fit uint8) */ /* (4) Store version (x 10 to fit uint8) */
r.version = version * 10 + subVersion r.version = version*10 + subVersion
return nil return nil
} }

View File

@ -1,10 +1,11 @@
package request package request
import ( import (
"io"
"bytes" "bytes"
"io"
"testing" "testing"
) )
// /* (1) Parse request */ // /* (1) Parse request */
// req, _ := request.Parse(s) // req, _ := request.Parse(s)
@ -22,7 +23,7 @@ import (
// return nil, fmt.Errorf("Upgrade error (HTTP %d)\n", res.GetStatusCode()) // return nil, fmt.Errorf("Upgrade error (HTTP %d)\n", res.GetStatusCode())
// } // }
func TestEOFSocket(t *testing.T){ func TestEOFSocket(t *testing.T) {
socket := new(bytes.Buffer) socket := new(bytes.Buffer)
@ -36,44 +37,44 @@ func TestEOFSocket(t *testing.T){
} }
func TestInvalidRequestLine(t *testing.T){ func TestInvalidRequestLine(t *testing.T) {
socket := new(bytes.Buffer) socket := new(bytes.Buffer)
cases := []struct{ cases := []struct {
Reqline string Reqline string
HasError bool HasError bool
}{ }{
{ "abc", true }, {"abc", true},
{ "a c", true }, {"a c", true},
{ "a c", true }, {"a c", true},
{ "a c", true }, {"a c", true},
{ "a b c", true }, {"a b c", true},
{ "GET invaliduri HTTP/1.1", true }, {"GET invaliduri HTTP/1.1", true},
{ "GET /validuri HTTP/1.1", false }, {"GET /validuri HTTP/1.1", false},
{ "POST /validuri HTTP/1.1", true }, {"POST /validuri HTTP/1.1", true},
{ "PUT /validuri HTTP/1.1", true }, {"PUT /validuri HTTP/1.1", true},
{ "DELETE /validuri HTTP/1.1", true }, {"DELETE /validuri HTTP/1.1", true},
{ "OPTIONS /validuri HTTP/1.1", true }, {"OPTIONS /validuri HTTP/1.1", true},
{ "UNKNOWN /validuri HTTP/1.1", true }, {"UNKNOWN /validuri HTTP/1.1", true},
{ "GET / HTTP", true }, {"GET / HTTP", true},
{ "GET / HTTP/", true }, {"GET / HTTP/", true},
{ "GET / 1.1", true }, {"GET / 1.1", true},
{ "GET / 1", true }, {"GET / 1", true},
{ "GET / HTTP/52", true }, {"GET / HTTP/52", true},
{ "GET / HTTP/1.", true }, {"GET / HTTP/1.", true},
{ "GET / HTTP/.1", true }, {"GET / HTTP/.1", true},
{ "GET / HTTP/1.1", false }, {"GET / HTTP/1.1", false},
{ "GET / HTTP/2", false }, {"GET / HTTP/2", false},
} }
for ti, tc := range cases { for ti, tc := range cases {
socket.Reset() socket.Reset()
socket.Write( []byte(tc.Reqline) ) socket.Write([]byte(tc.Reqline))
socket.Write( []byte("\r\n\r\n") ) socket.Write([]byte("\r\n\r\n"))
_, err := Parse(socket) _, err := Parse(socket)
@ -82,7 +83,7 @@ func TestInvalidRequestLine(t *testing.T){
// no error -> ok // no error -> ok
if err == nil { if err == nil {
continue continue
// error for the end of the request -> ok // error for the end of the request -> ok
} else if _, ok := err.(*IncompleteRequest); ok { } else if _, ok := err.(*IncompleteRequest); ok {
continue continue
} }
@ -96,7 +97,7 @@ func TestInvalidRequestLine(t *testing.T){
continue continue
} }
ir, ok := err.(*InvalidRequest); ir, ok := err.(*InvalidRequest)
// not InvalidRequest err -> error // not InvalidRequest err -> error
if !ok || ir.Field != "Request-Line" { if !ok || ir.Field != "Request-Line" {
@ -108,54 +109,53 @@ func TestInvalidRequestLine(t *testing.T){
} }
func TestInvalidHost(t *testing.T){ func TestInvalidHost(t *testing.T) {
requestLine := []byte( "GET / HTTP/1.1\r\n" ) requestLine := []byte("GET / HTTP/1.1\r\n")
socket := new(bytes.Buffer) socket := new(bytes.Buffer)
cases := []struct{ cases := []struct {
Host string Host string
HasError bool HasError bool
}{ }{
{ "1", true }, {"1", true},
{ "12", true }, {"12", true},
{ "123", true }, {"123", true},
{ "1234", false }, {"1234", false},
{ "singlevalue", false }, {"singlevalue", false},
{ "multi value", true }, {"multi value", true},
{ "singlevalue:1", false }, {"singlevalue:1", false},
{ "singlevalue:", true }, {"singlevalue:", true},
{ "singlevalue:x", true }, {"singlevalue:x", true},
{ "xx:x", true }, {"xx:x", true},
{ ":xxx", true }, {":xxx", true},
{ "xxx:", true }, {"xxx:", true},
{ "a:12", false }, {"a:12", false},
{ "google.com", false }, {"google.com", false},
{ "8.8.8.8", false }, {"8.8.8.8", false},
{ "google.com:8080", false }, {"google.com:8080", false},
{ "8.8.8.8:8080", false }, {"8.8.8.8:8080", false},
} }
for ti, tc := range cases { for ti, tc := range cases {
socket.Reset() socket.Reset()
socket.Write(requestLine) socket.Write(requestLine)
socket.Write( []byte("Host: ") ) socket.Write([]byte("Host: "))
socket.Write( []byte(tc.Host) ) socket.Write([]byte(tc.Host))
socket.Write( []byte("\r\n\r\n") ) socket.Write([]byte("\r\n\r\n"))
_, err := Parse(socket) _, err := Parse(socket)
if !tc.HasError { if !tc.HasError {
// no error -> ok // no error -> ok
if err == nil { if err == nil {
continue continue
// error for the end of the request -> ok // error for the end of the request -> ok
} else if _, ok := err.(*IncompleteRequest); ok { } else if _, ok := err.(*IncompleteRequest); ok {
continue continue
} }
@ -170,7 +170,7 @@ func TestInvalidHost(t *testing.T){
} }
// check if InvalidRequest // check if InvalidRequest
ir, ok := err.(*InvalidRequest); ir, ok := err.(*InvalidRequest)
// not InvalidRequest err -> error // not InvalidRequest err -> error
if ok && ir.Field != "Host" { if ok && ir.Field != "Host" {
@ -180,4 +180,4 @@ func TestInvalidHost(t *testing.T){
} }
} }

View File

@ -1,14 +1,12 @@
package response package response
import ( import (
"crypto/sha1"
"encoding/base64"
"fmt" "fmt"
"io" "io"
"encoding/base64"
"crypto/sha1"
) )
// SetStatusCode sets the status code // SetStatusCode sets the status code
func (r *T) SetStatusCode(sc StatusCode) { func (r *T) SetStatusCode(sc StatusCode) {
r.code = sc r.code = sc
@ -36,11 +34,10 @@ func (r *T) ProcessKey(k []byte) {
digest := sha1.Sum(mix) digest := sha1.Sum(mix)
/* (3) Base64 encode it */ /* (3) Base64 encode it */
r.accept = []byte( base64.StdEncoding.EncodeToString( digest[:sha1.Size] ) ) r.accept = []byte(base64.StdEncoding.EncodeToString(digest[:sha1.Size]))
} }
// Send sends the response through an io.Writer // Send sends the response through an io.Writer
// typically a socket // typically a socket
func (r T) Send(w io.Writer) (int, error) { func (r T) Send(w io.Writer) (int, error) {
@ -75,8 +72,7 @@ func (r T) GetProtocol() []byte {
return r.protocol return r.protocol
} }
// GetStatusCode returns the response status code // GetStatusCode returns the response status code
func (r T) GetStatusCode() StatusCode { func (r T) GetStatusCode() StatusCode {
return r.code return r.code
} }

View File

@ -4,22 +4,28 @@ package response
type StatusCode uint16 type StatusCode uint16
var SWITCHING_PROTOCOLS StatusCode = 101 // handshake success var SWITCHING_PROTOCOLS StatusCode = 101 // handshake success
var BAD_REQUEST StatusCode = 400 // missing/malformed headers var BAD_REQUEST StatusCode = 400 // missing/malformed headers
var FORBIDDEN StatusCode = 403 // invalid origin policy, TLS required var FORBIDDEN StatusCode = 403 // invalid origin policy, TLS required
var UPGRADE_REQUIRED StatusCode = 426 // invalid WS version var UPGRADE_REQUIRED StatusCode = 426 // invalid WS version
var NOT_FOUND StatusCode = 404 // unserved or invalid URI var NOT_FOUND StatusCode = 404 // unserved or invalid URI
var INTERNAL StatusCode = 500 // custom error var INTERNAL StatusCode = 500 // custom error
func (sc StatusCode) Message() string { func (sc StatusCode) Message() string {
switch sc { switch sc {
case SWITCHING_PROTOCOLS: return "Switching Protocols" case SWITCHING_PROTOCOLS:
case BAD_REQUEST: return "Bad Request" return "Switching Protocols"
case FORBIDDEN: return "Forbidden" case BAD_REQUEST:
case UPGRADE_REQUIRED: return "Upgrade Required" return "Bad Request"
case NOT_FOUND: return "Not Found" case FORBIDDEN:
case INTERNAL: return "Internal Server Error" return "Forbidden"
default: case UPGRADE_REQUIRED:
return "Unknown Status Code" return "Upgrade Required"
case NOT_FOUND:
return "Not Found"
case INTERNAL:
return "Internal Server Error"
default:
return "Unknown Status Code"
} }
} }

View File

@ -1,15 +1,15 @@
package response package response
// Constant // Constant
const HttpVersion = "1.1" const HttpVersion = "1.1"
const WSVersion = 13 const WSVersion = 13
var WSSalt []byte = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
var WSSalt []byte = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11")
// T represents an HTTP Upgrade Response // T represents an HTTP Upgrade Response
type T struct { type T struct {
code StatusCode // status code code StatusCode // status code
accept []byte // processed from Sec-WebSocket-Key accept []byte // processed from Sec-WebSocket-Key
protocol []byte // set from Sec-WebSocket-Protocol or none if not received protocol []byte // set from Sec-WebSocket-Protocol or none if not received
} }

View File

@ -1,11 +1,10 @@
package parser package parser
import ( import (
"strings"
"fmt" "fmt"
"strings"
) )
// buildScheme builds a 'basic' scheme // buildScheme builds a 'basic' scheme
// from a pattern string // from a pattern string
func buildScheme(ss []string) (Scheme, error) { func buildScheme(ss []string) (Scheme, error) {
@ -16,42 +15,44 @@ func buildScheme(ss []string) (Scheme, error) {
for _, s := range ss { for _, s := range ss {
/* (2) ignore empty */ /* (2) ignore empty */
if len(s) == 0 { continue } if len(s) == 0 {
continue
}
m := new(matcher) m := new(matcher)
switch s { switch s {
/* (3) Card: 0, N */ /* (3) Card: 0, N */
case "**": case "**":
m.req = false m.req = false
m.mul = true m.mul = true
sch = append(sch, m) sch = append(sch, m)
/* (4) Card: 1, N */ /* (4) Card: 1, N */
case "..": case "..":
m.req = true m.req = true
m.mul = true m.mul = true
sch = append(sch, m) sch = append(sch, m)
/* (5) Card: 0, 1 */ /* (5) Card: 0, 1 */
case "*": case "*":
m.req = false m.req = false
m.mul = false m.mul = false
sch = append(sch, m) sch = append(sch, m)
/* (6) Card: 1 */ /* (6) Card: 1 */
case ".": case ".":
m.req = true m.req = true
m.mul = false m.mul = false
sch = append(sch, m) sch = append(sch, m)
/* (7) Card: 1, literal string */ /* (7) Card: 1, literal string */
default: default:
m.req = true m.req = true
m.mul = false m.mul = false
m.pat = fmt.Sprintf("/%s", s) m.pat = fmt.Sprintf("/%s", s)
sch = append(sch, m) sch = append(sch, m)
} }
@ -60,8 +61,6 @@ func buildScheme(ss []string) (Scheme, error) {
return sch, nil return sch, nil
} }
// optimise optimised the scheme for further parsing // optimise optimised the scheme for further parsing
func (s Scheme) optimise() (Scheme, error) { func (s Scheme) optimise() (Scheme, error) {
@ -74,9 +73,8 @@ func (s Scheme) optimise() (Scheme, error) {
rshift := make(Scheme, 0, maxMatch) rshift := make(Scheme, 0, maxMatch)
rshift = append(rshift, s[0]) rshift = append(rshift, s[0])
/* (2) Iterate over matchers */ /* (2) Iterate over matchers */
for p, i, l := 0, 1, len(s) ; i < l ; i++ { for p, i, l := 0, 1, len(s); i < l; i++ {
pre, cur := s[p], s[i] pre, cur := s[p], s[i]
@ -103,7 +101,6 @@ func (s Scheme) optimise() (Scheme, error) {
} }
// matchString checks the STRING matchers from an URI // matchString checks the STRING matchers from an URI
// it returns a boolean : false when not matching, true eitherway // it returns a boolean : false when not matching, true eitherway
// it returns a cleared uri, without STRING data // it returns a cleared uri, without STRING data
@ -116,18 +113,23 @@ func (s Scheme) matchString(uri string) (string, bool) {
/* (2) Iterate over strings */ /* (2) Iterate over strings */
for _, m := range s { for _, m := range s {
ls := len(m.pat) ls := len(m.pat)
// {1} If not STRING matcher -> ignore // // {1} If not STRING matcher -> ignore //
if ls == 0 { continue } if ls == 0 {
continue
}
// {2} Get offset in URI (else -1) // // {2} Get offset in URI (else -1) //
off := strings.Index(clr, m.pat) off := strings.Index(clr, m.pat)
if off < 0 { return "", false } if off < 0 {
return "", false
}
// {3} Fail on invalid offset range // // {3} Fail on invalid offset range //
if off < minOff { return "", false } if off < minOff {
return "", false
}
// {4} Check for trailing '/' // // {4} Check for trailing '/' //
hasSlash := 0 hasSlash := 0
@ -141,7 +143,7 @@ func (s Scheme) matchString(uri string) (string, bool) {
// {6} Update offset range // // {6} Update offset range //
minOff = len(beg) + 2 - 1 // +2 slash separators minOff = len(beg) + 2 - 1 // +2 slash separators
// -1 because strings begin with 1 slash already // -1 because strings begin with 1 slash already
} }
@ -159,7 +161,6 @@ func (s Scheme) matchString(uri string) (string, bool) {
} }
// matchWildcards check the WILCARDS (non-string) matchers from // matchWildcards check the WILCARDS (non-string) matchers from
// a cleared URI. it returns if the string matches // a cleared URI. it returns if the string matches
// + it sets the matchers buffers for later extraction // + it sets the matchers buffers for later extraction
@ -212,4 +213,4 @@ func (s Scheme) matchWildcards(clear string) bool {
/* (5) Match */ /* (5) Match */
return true return true
} }

View File

@ -6,7 +6,7 @@ import (
) )
// Build builds an URI scheme from a pattern string // Build builds an URI scheme from a pattern string
func Build(s string) (*Scheme, error){ func Build(s string) (*Scheme, error) {
/* (1) Manage '/' at the start */ /* (1) Manage '/' at the start */
if len(s) < 1 || s[0] != '/' { if len(s) < 1 || s[0] != '/' {
@ -19,7 +19,7 @@ func Build(s string) (*Scheme, error){
/* (3) Max exceeded */ /* (3) Max exceeded */
if len(parts)-2 > maxMatch { if len(parts)-2 > maxMatch {
for i, p := range parts { for i, p := range parts {
fmt.Printf("%d: '%s'\n", i, p); fmt.Printf("%d: '%s'\n", i, p)
} }
return nil, fmt.Errorf("URI must not exceed %d slash-separated components, got %d", maxMatch, len(parts)) return nil, fmt.Errorf("URI must not exceed %d slash-separated components, got %d", maxMatch, len(parts))
} }
@ -40,12 +40,13 @@ func Build(s string) (*Scheme, error){
} }
// Match returns if the given URI is matched by the scheme // Match returns if the given URI is matched by the scheme
func (s Scheme) Match(str string) bool { func (s Scheme) Match(str string) bool {
/* (1) Nothing -> match all */ /* (1) Nothing -> match all */
if len(s) == 0 { return true } if len(s) == 0 {
return true
}
/* (2) Check for string match */ /* (2) Check for string match */
clearURI, match := s.matchString(str) clearURI, match := s.matchString(str)
@ -62,7 +63,6 @@ func (s Scheme) Match(str string) bool {
return true return true
} }
// GetMatch returns the indexed match (excluding string matchers) // GetMatch returns the indexed match (excluding string matchers)
func (s Scheme) GetMatch(n uint8) ([]string, error) { func (s Scheme) GetMatch(n uint8) ([]string, error) {
@ -76,7 +76,9 @@ func (s Scheme) GetMatch(n uint8) ([]string, error) {
for _, m := range s { for _, m := range s {
// ignore strings // ignore strings
if len(m.pat) > 0 { continue } if len(m.pat) > 0 {
continue
}
// increment match counter : ni // increment match counter : ni
ni++ ni++
@ -93,9 +95,6 @@ func (s Scheme) GetMatch(n uint8) ([]string, error) {
} }
// GetAllMatch returns all the indexed match (excluding string matchers) // GetAllMatch returns all the indexed match (excluding string matchers)
func (s Scheme) GetAllMatch() [][]string { func (s Scheme) GetAllMatch() [][]string {
@ -104,7 +103,9 @@ func (s Scheme) GetAllMatch() [][]string {
for _, m := range s { for _, m := range s {
// ignore strings // ignore strings
if len(m.pat) > 0 { continue } if len(m.pat) > 0 {
continue
}
match = append(match, m.buf) match = append(match, m.buf)
@ -112,4 +113,4 @@ func (s Scheme) GetAllMatch() [][]string {
return match return match
} }

View File

@ -24,13 +24,12 @@ const maxMatch = 16
// Represents an URI matcher // Represents an URI matcher
type matcher struct { type matcher struct {
pat string // pattern to match (empty if wildcard) pat string // pattern to match (empty if wildcard)
req bool // whether it is required req bool // whether it is required
mul bool // whether multiple matches are allowed mul bool // whether multiple matches are allowed
buf []string // matched content (when matching) buf []string // matched content (when matching)
} }
// Represents an URI scheme // Represents an URI scheme
type Scheme []*matcher type Scheme []*matcher