From ff05d62013906f3086b452bfeda3e0d5b9b7a541 Mon Sep 17 00:00:00 2001 From: tjpcc Date: Mon, 9 Jan 2023 16:40:24 -0700 Subject: Initial commit. some basics: - minimal README - some TODOs - server and request handler framework - contribs: file serving, request logging - server examples - CI setup --- gemini/request.go | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 gemini/request.go (limited to 'gemini/request.go') 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 +} -- cgit v1.2.3