ws/internal/http/upgrade/request_line.go

95 lines
2.1 KiB
Go
Raw Normal View History

package upgrade
import (
"bytes"
"fmt"
"regexp"
)
// RequestLine represents the HTTP Request line
// defined in rfc-2616 : https://tools.ietf.org/html/rfc2616#section-5.1
type RequestLine struct {
uri string
version byte
}
// Read an HTTP request line from a byte array
//
// implements io.Reader
func (rl *RequestLine) Read(b []byte) (int, error) {
var read = len(b)
// split by spaces
parts := bytes.Split(b, []byte(" "))
if len(parts) != 3 {
return read, fmt.Errorf("expected 3 space-separated elements, got %d elements", len(parts))
}
err := rl.extractHttpMethod(parts[0])
if err != nil {
return read, err
}
err = rl.extractURI(parts[1])
if err != nil {
return read, err
}
err = rl.extractHttpVersion(parts[2])
if err != nil {
return read, err
}
return read, nil
}
// URI of the request line
func (rl RequestLine) URI() string {
return rl.uri
}
// extractHttpMethod extracts the HTTP method from a []byte
// and checks for errors
// allowed format: OPTIONS|GET|HEAD|POST|PUT|DELETE
func (rl *RequestLine) extractHttpMethod(b []byte) error {
if string(b) != "GET" {
return fmt.Errorf("invalid HTTP method '%s', expected 'GET'", b)
}
return nil
}
// extractURI extracts the URI from a []byte and checks for errors
// allowed format: /([^/]/)*/?
func (rl *RequestLine) extractURI(b []byte) error {
checker := regexp.MustCompile("^(?:/[^/]+)*/?$")
if !checker.Match(b) {
return fmt.Errorf("invalid URI, expected an absolute path, got '%s'", b)
}
rl.uri = string(b)
return nil
}
// extractHttpVersion extracts the version and checks for errors
// allowed format: [1-9] or [1.9].[0-9]
func (rl *RequestLine) extractHttpVersion(b []byte) error {
extractor := regexp.MustCompile(`^HTTP/([1-9])(?:\.([0-9]))?$`)
if !extractor.Match(b) {
return fmt.Errorf("invalid HTTP version, expected INT or INT.INT, got '%s'", b)
}
matches := extractor.FindSubmatch(b)
var version byte = matches[1][0] - '0'
var subversion byte = 0
if len(matches[2]) > 0 {
subversion = matches[2][0] - '0'
}
rl.version = version*10 + subversion
return nil
}