summaryrefslogtreecommitdiff
path: root/gemini/request.go
blob: 248ce67cde18d2a433e3ef57f6469fefed7fc7fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
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
}