blob: 933281be0bd643a7d69ec2835bec77f1754d5c9e (
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
|
package gemini
import (
"bufio"
"crypto/tls"
"errors"
"io"
"net"
"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 is the specific URL being fetched by the request.
*url.URL
// Server is the server which received the request.
//
// This is only populated in gemini servers.
// It is unused on the client end.
Server *Server
// RemoteAddr is the address of the other side of the connection.
//
// This will be the server address for clients, or the connecting
// client's address in servers.
//
// Be aware though that proxies (and reverse proxies) can confuse this.
RemoteAddr net.Addr
// TLSState contains information about the TLS encryption over the connection.
//
// This includes peer certificates and version information.
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
}
|