diff options
Diffstat (limited to 'gemini/request.go')
-rw-r--r-- | gemini/request.go | 50 |
1 files changed, 50 insertions, 0 deletions
diff --git a/gemini/request.go b/gemini/request.go new file mode 100644 index 0000000..248ce67 --- /dev/null +++ b/gemini/request.go @@ -0,0 +1,50 @@ +package gemini + +import ( + "bufio" + "crypto/tls" + "errors" + "io" + "net/url" +) + +// InvalidRequestLineEnding indicates that a gemini request didn't end with "\r\n". +var InvalidRequestLineEnding = errors.New("invalid request line ending") + +// Request represents a request over the gemini protocol. +type Request struct { + *url.URL + + TLSState *tls.ConnectionState +} + +// ParseRequest parses a single gemini request from a reader. +func ParseRequest(rdr io.Reader) (*Request, error) { + line, err := bufio.NewReader(rdr).ReadString('\n') + if err != io.EOF && err != nil { + return nil, err + } + + if len(line) < 2 || line[len(line)-2:] != "\r\n" { + return nil, InvalidRequestLineEnding + } + + u, err := url.Parse(line[:len(line)-2]) + if err != nil { + return nil, err + } + + if u.Scheme == "" { + u.Scheme = "gemini" + } + + return &Request{URL: u}, nil +} + +// UnescapedQuery performs %XX unescaping on the URL query segment. +// +// Like URL.Query(), it silently drops malformed %-encoded sequences. +func (req Request) UnescapedQuery() string { + unescaped, _ := url.QueryUnescape(req.RawQuery) + return unescaped +} |