summaryrefslogtreecommitdiff
path: root/gemini/request.go
diff options
context:
space:
mode:
authortjpcc <tjp@ctrl-c.club>2023-01-09 16:40:24 -0700
committertjpcc <tjp@ctrl-c.club>2023-01-09 16:40:24 -0700
commitff05d62013906f3086b452bfeda3e0d5b9b7a541 (patch)
tree3be29de0b1bc7c273041c6d89b71ca447c940556 /gemini/request.go
Initial commit.
some basics: - minimal README - some TODOs - server and request handler framework - contribs: file serving, request logging - server examples - CI setup
Diffstat (limited to 'gemini/request.go')
-rw-r--r--gemini/request.go50
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
+}