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.URL Server *Server RemoteAddr net.Addr 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 }