💾 Archived View for source.community › ckaznocha › gemini › raw › main › url.go captured on 2021-12-17 at 13:26:06.
-=-=-=-=-=-=-
package gemini import ( "fmt" "net/url" "unicode/utf8" ) // URI represents a Gemini URI. // // Resources hosted via Gemini are identified using URIs with the scheme // "gemini". This scheme is syntactically compatible with the generic URI // syntax defined in RFC 3986, but does not support all components of the // generic syntax. In particular, the authority component is allowed and // required, but its userinfo subcomponent is NOT allowed. The host // subcomponent is required. The port subcomponent is optional, with a default // value of 1965. The path, query and fragment components are allowed and have // no special meanings beyond those defined by the generic syntax. Spaces in // gemini URIs should be encoded as %20, not +. type URI struct { url *url.URL Host string Port string Path string Fragment string // Query is the decoded query section. The original query is stored in // RawQuery. Query string // RawQuery is the original query section as received by the server. Use // this in the event you need to parse a query section into a url.Values. RawQuery string } // ParseRequestURI parses a raw URI string into a Gemini URI. It returns an error if // the URI is invalid. func ParseRequestURI(rawURI string) (*URI, error) { if !utf8.ValidString(rawURI) { return nil, fmt.Errorf("%w: request URI must be valid utf-8", ErrMalformedURI) } uri, err := url.ParseRequestURI(rawURI) if err != nil { return nil, fmt.Errorf("%w: %s", ErrMalformedURI, err) } if !uri.IsAbs() { return nil, fmt.Errorf("%w: request URI cannot be relative", ErrMalformedURI) } if uri.User != nil { return nil, fmt.Errorf("%w: URI cannot have a user", ErrMalformedURI) } if uri.Host == "" { return nil, fmt.Errorf("%w: URI must have a host", ErrMalformedURI) } query, err := url.PathUnescape(uri.RawQuery) if err != nil { return nil, fmt.Errorf("%w: URI has a malformed query section: %s", ErrMalformedURI, err) } return &URI{ Host: uri.Hostname(), Port: uri.Port(), Path: uri.Path, Fragment: uri.Fragment, Query: query, RawQuery: uri.RawQuery, url: uri, }, nil } func (u *URI) String() string { if u.url == nil { u.url = &url.URL{ Scheme: "gemini", Host: u.Host, Path: u.Path, RawQuery: u.RawQuery, Fragment: u.Fragment, } } return u.url.String() }