Documentation ¶
Index ¶
- Constants
- Variables
- func IsWellKnownDummyHostname(s string) bool
- func ListenAndServe(addr string, host string, handler Handler, meta MetaHandler) error
- func MustFlush(f interface{ ... })
- func NewTextReader(rdr io.Reader) io.Reader
- func NotFound(w ResponseWriter, r *Request)
- func WriteMeta(mw MetaWriter, i ItemType, disp, sel string, meta []MetaEntry) error
- type BinaryResponse
- type Caps
- type CapsSource
- type CapsUpdater
- type Client
- func (c *Client) Binary(ctx context.Context, rq *Request) (*BinaryResponse, error)
- func (c *Client) Dir(ctx context.Context, rq *Request) (*DirResponse, error)
- func (c *Client) Fetch(ctx context.Context, rq *Request) (Response, error)
- func (c *Client) Raw(ctx context.Context, rq *Request) (Response, error)
- func (c *Client) Search(ctx context.Context, rq *Request) (*DirResponse, error)
- func (c *Client) Text(ctx context.Context, rq *Request) (*TextResponse, error)
- func (c *Client) UUEncoded(ctx context.Context, rq *Request) (*UUEncodedResponse, error)
- type DirReader
- type DirResponse
- type DirWriter
- func (dw *DirWriter) Binary(disp, sel string) error
- func (dw *DirWriter) Dir(disp, sel string) error
- func (dw *DirWriter) Dirent(dirent *Dirent) error
- func (dw *DirWriter) Error(disp string) error
- func (dw *DirWriter) Flush() error
- func (dw *DirWriter) Image(disp, sel string) error
- func (dw *DirWriter) Info(disp string) error
- func (dw *DirWriter) MustFlush()
- func (dw *DirWriter) Plus(i ItemType, disp, sel string) error
- func (dw *DirWriter) RemoteSelector(i ItemType, disp, sel string, host string, port int) error
- func (dw *DirWriter) Root(disp string) error
- func (dw *DirWriter) Selector(i ItemType, disp, sel string) error
- func (dw *DirWriter) Text(disp, sel string) error
- func (dw *DirWriter) WWW(disp, url string) error
- type Dirent
- type DirentFlag
- type ErrFactory
- type Error
- type Feature
- type FeatureStatus
- type Handler
- type HandlerFunc
- type ItemType
- type Logger
- type MetaEntry
- type MetaHandler
- type MetaHandlerFunc
- type MetaType
- type MetaValueWriter
- type MetaWriter
- type Mux
- type Param
- type Params
- type PathConfig
- type Recorder
- type Recording
- type Request
- type Response
- type ResponseClass
- type ResponseInfo
- type ResponseWriter
- type Server
- type ServerInfo
- type Status
- type TLSMode
- type TextResponse
- type TextWriter
- type URL
- func (u URL) AsMetaDir(records ...string) URL
- func (u URL) AsMetaItem(records ...string) URL
- func (u URL) CanFetch() bool
- func (u URL) Host() string
- func (u URL) IsAbs() bool
- func (u URL) IsEmpty() bool
- func (u URL) IsMeta() bool
- func (u URL) IsSecure() bool
- func (u URL) MarshalText() ([]byte, error)
- func (u URL) MetaType() MetaType
- func (u URL) Parts() map[string]interface{}
- func (u URL) String() string
- func (u *URL) UnmarshalText(b []byte) error
- type URLVar
- type UUEncodedResponse
- func (br *UUEncodedResponse) Class() ResponseClass
- func (br *UUEncodedResponse) Close() error
- func (br *UUEncodedResponse) File() (string, bool)
- func (br *UUEncodedResponse) Info() *ResponseInfo
- func (br *UUEncodedResponse) Mode() (os.FileMode, bool)
- func (br *UUEncodedResponse) Read(b []byte) (n int, err error)
- func (br *UUEncodedResponse) Reader() io.ReadCloser
Constants ¶
const ( // Reserve NUL as representing 'no item type'. This means we can't ever use it as a // "valid selector", but it really shouldn't be anyway. This seems like it should be // in the spec as it seems extremely unlikely that Gopher servers and/or clients // written in C would even remotely be able to handle this. Even if the spec said // NUL was valid, would anyone bother to support it? NoItemType ItemType = 0 Text ItemType = '0' Dir ItemType = '1' CSOServer ItemType = '2' // https://en.wikipedia.org/wiki/CCSO_Nameserver ItemError ItemType = '3' BinHex ItemType = '4' // Ancient pre OS X Mac format BinaryArchive ItemType = '5' // (zip; rar; 7-Zip; gzip; tar); Client must read until the TCP connection closes. Beware. UUEncoded ItemType = '6' Search ItemType = '7' Telnet ItemType = '8' // Connect to given host at given port. The name to login as at this host is in the selector string. Binary ItemType = '9' // Client must read until the TCP connection closes. Beware. // The information applies to a duplicated server. The information contained within is // a duplicate of the primary server. The primary server is defined as the last // DirEntity that is has a non-plus "Type" field. The client should use the // transaction as defined by the primary server Type field. Duplicate ItemType = '+' GIF ItemType = 'g' Image ItemType = 'I' // Item is some kind of image file. Client gets to decide. // The information applies to a tn3270 based telnet session. Connect to given host at // given port. The name to login as at this host is in the selector string. TN3270 ItemType = 'T' // Not a standard item type, but let's consider this 'well-known'. It makes // sense alongside the Telnet ones, which are very obsolete. // https://github.com/solderpunk/VF-1/blob/master/vf1.py#L281 SSH ItemType = 'S' Calendar = 'c' // Word-processing document (MS Word; OpenOffice.org; WordPerfect); PDF document Doc = 'd' HTML = 'h' Info = 'i' Page = 'p' // e.g. (TeX; LaTeX; PostScript; Rich Text Format) MBOX = 'm' // Electronic mail repository (also known as MBOX) Sound = 's' XML = 'x' Video = ';' MetaError = '-' )
const ( DefaultRequestSizeLimit = 1 << 12 DefaultReadTimeout = 10 * time.Second DefaultReadSelectorTimeout = 5 * time.Second )
const DefaultTimeout = 10 * time.Second
const (
DirentHostOptional = 1 << iota
)
Variables ¶
var ( ErrMetaLeadingPlus = errors.New("gopher: metadata value contains leading '+'") ErrMetaInfoAlreadySent = errors.New("gopher: attempted to send INFO more than once for '!' meta request") ErrMetaInfoNotSent = errors.New("gopher: attempted to send non-info record before INFO") )
var ( ErrBadRequest = errors.New("gopher: bad request") ErrServerClosed = errors.New("gopher: server closed") )
var ErrStatus = errors.New("status")
var UnixPathConfig = PathConfig{ Delimiter: "/", Identity: ".", Parent: "..", ParentDouble: false, EscapeCharacter: '\\', KeepPreDelimiter: false, }
Functions ¶
func IsWellKnownDummyHostname ¶
IsWellKnownDummyHostname compares the hostname against a set of well-known dummy values. Gopher servers use a hotch-potch of values for dummy hostnames.
Dear Gopher server authors: please use 'invalid' (or, somewhat less ideally, 'example') as per RFC2606.
func ListenAndServe ¶
func ListenAndServe(addr string, host string, handler Handler, meta MetaHandler) error
func NotFound ¶
func NotFound(w ResponseWriter, r *Request)
Types ¶
type BinaryResponse ¶
type BinaryResponse struct {
// contains filtered or unexported fields
}
func NewBinaryResponse ¶
func NewBinaryResponse(info *ResponseInfo, rdr io.ReadCloser) *BinaryResponse
func (*BinaryResponse) Class ¶
func (br *BinaryResponse) Class() ResponseClass
func (*BinaryResponse) Close ¶
func (br *BinaryResponse) Close() error
func (*BinaryResponse) Info ¶
func (br *BinaryResponse) Info() *ResponseInfo
func (*BinaryResponse) Reader ¶
func (br *BinaryResponse) Reader() io.ReadCloser
type Caps ¶
type Caps interface { Version() int ExpiresAfter() time.Duration // Return -1 if the Caps don't expire Supports(feature Feature) FeatureStatus PathConfig() (*PathConfig, error) ServerInfo() (*ServerInfo, error) Software() (name, version string) // TLSPort for the server; returns 0 if not present or configured. TLSPort() int // Default text encoding for content types 0 and 1. // If this returns an empty string, UTF-8 is presumed. DefaultEncoding() string }
var DefaultCaps Caps = defaultCaps{}
type CapsSource ¶
type CapsUpdater ¶
type Client ¶
type Client struct { Timeout time.Duration ExtraBinaryTypes [256]bool DisableErrorIntercept bool // Warning: subject to change. Recorder Recorder CapsSource CapsSource TLSClientConfig *tls.Config TLSMode TLSMode DialContext func(ctx context.Context, network, addr string) (net.Conn, error) }
type DirReader ¶
type DirReader struct { Flag DirentFlag // contains filtered or unexported fields }
func NewDirReader ¶
type DirResponse ¶
type DirResponse struct {
// contains filtered or unexported fields
}
func NewDirResponse ¶
func NewDirResponse(info *ResponseInfo, rdr io.ReadCloser) *DirResponse
func (*DirResponse) Class ¶
func (br *DirResponse) Class() ResponseClass
func (*DirResponse) Close ¶
func (br *DirResponse) Close() error
func (*DirResponse) Info ¶
func (br *DirResponse) Info() *ResponseInfo
func (*DirResponse) Next ¶
func (br *DirResponse) Next(dir *Dirent) bool
func (*DirResponse) Reader ¶
func (br *DirResponse) Reader() io.ReadCloser
type DirWriter ¶
type DirWriter struct {
// contains filtered or unexported fields
}
func (*DirWriter) Info ¶
Info writes an 'i' line to the directory. It is safe to ignore the returned error as it will be returned when Flush() is called.
func (*DirWriter) RemoteSelector ¶
type Dirent ¶
type Dirent struct { ItemType ItemType `json:"type"` Display string `json:"display"` Selector string `json:"selector"` Hostname string `json:"host,omitempty"` Port string `json:"port,omitempty"` Plus bool `json:"plus,omitempty"` Raw string `json:"-"` }
func (*Dirent) PopulateURL ¶
type DirentFlag ¶
type DirentFlag int
type Error ¶
func DetectError ¶
func DetectError(data []byte, errFactory ErrFactory) *Error
type Feature ¶
type Feature int
const ( // Server supports those weird ASK forms from Gopher+. // // This lib is unlikely to ever support these until evidence appears of something // actually using them in the wild, which has so far not been forthcoming. FeaturePlusAsk Feature = 1 // Server understands GopherII queries. FeatureII Feature = 2 // Server will respond to GopherIIbis metadata queries. FeatureIIbis Feature = 3 )
type FeatureStatus ¶
type FeatureStatus int
const ( FeatureStatusUnknown FeatureStatus = iota FeatureSupported FeatureUnsupported )
type Handler ¶
type Handler interface {
ServeGopher(ctx context.Context, w ResponseWriter, r *Request)
}
type HandlerFunc ¶
type HandlerFunc func(context.Context, ResponseWriter, *Request)
func (HandlerFunc) ServeGopher ¶
func (fn HandlerFunc) ServeGopher(ctx context.Context, w ResponseWriter, r *Request)
type MetaHandler ¶
type MetaHandler interface {
ServeGopherMeta(ctx context.Context, w MetaWriter, r *Request)
}
type MetaHandlerFunc ¶
type MetaHandlerFunc func(context.Context, MetaWriter, *Request)
func (MetaHandlerFunc) ServeGopherMeta ¶
func (fn MetaHandlerFunc) ServeGopherMeta(ctx context.Context, w MetaWriter, r *Request)
type MetaValueWriter ¶
type MetaValueWriter struct {
// contains filtered or unexported fields
}
func (*MetaValueWriter) WriteLine ¶
func (mvw *MetaValueWriter) WriteLine(s string) (n int, err error)
func (*MetaValueWriter) WriteString ¶
func (mvw *MetaValueWriter) WriteString(s string) (n int, err error)
type MetaWriter ¶
type MetaWriter interface { // The `INFO` record is MANDATORY in every metadata listing. It // contains the same data as the Gopher selector, with a plus sign at // the end, per GopherIIbis style. It MUST always be present, and it // MUST always be the first metadata record present. The `INFO` record // serves to separate metadata listings when more are sent at the same // time. // // If the Request is for a single file's metadata only ('!' rather than // '&'), multiple calls to Info() will result in an error. Info(i ItemType, disp, sel string) // If the Request is invalid, MetaError() should be called once and only // once. No other calls to write Info or Records are valid if MetaError() // has been called. MetaError(code Status, msg string) // Write an entire record with a string value: WriteRecord(record string, value string) (ok bool) // Begin a record and return a writer that can be used to write its value. // If the returned writer is nil, the record is ignored by the request. // Duplicate records may be written. BeginRecord(record string) *MetaValueWriter // Flush any buffered metadata and return any cached error. It is not // necessary to call Flush() directly; Server will call it regardless // at the end of the request. Flush() error }
type Mux ¶
type Mux struct { CatchAllRequiresTrailingSlash bool // contains filtered or unexported fields }
Mux is the 2-hour version of httprouter. Maybe I'll come back and add the 1-week version later, but this is reasonably quick and has most of the features.
Slashes ('/') are always trimmed from patterns and search paths.
Named parameters only match a single path segment:
Pattern: /user/:user
/user/gordon match /user/you match /user/gordon/profile no match /user/ no match
Catch-All parameters ¶
Catch-all parameters and have the form *name, and match everything to the end of the input. Catch-all parameters must be at the end fo the pattern.
Pattern: /src/*filepath
/src match <-- (!) /src/ match /src/somefile.go match /src/subdir/somefile.go match
Leading/Trailing Slashes
Mux strips leading and trailing slashes. If the last segment is a catch all and the previous segment does not match an existing node, the catch-all will receive an empty path.
Patterns: /foo, /foo/*rest
Selector Handler /foo /foo /foo/ /foo/*rest /foo/stuff /foo/*rest
Patterns: /foo/*rest
Selector Handler /foo /foo/*rest /foo/ /foo/*rest /foo/stuff /foo/*rest
func (*Mux) Handle ¶
func (mux *Mux) Handle(pattern string, handler Handler, meta MetaHandler)
Handle a pattern with Handler and/or MetaHandler.
Calling Handle() twice with the same pattern will result in a panic.
Patterns are described in Mux's documentation.
If meta is nil but handler implements MetaHandler, it will be used as the MetaHandler.
func (*Mux) ServeGopher ¶
func (mux *Mux) ServeGopher(ctx context.Context, w ResponseWriter, r *Request)
func (*Mux) ServeGopherMeta ¶
func (mux *Mux) ServeGopherMeta(ctx context.Context, w MetaWriter, r *Request)
type PathConfig ¶
type PathConfig struct { // Refers to how the server separates folders from each other; Unix machines use `/`, // Microsoft machines use `\`, and obsolete Macs use `:` Delimiter string // Refers to the shorthand used by an operating system to mean "this directory"; UNIX // machines use `.`. Identity string // Refers to the shorthand for "the directory immediately above", and is `..` on UNIX // and Microsoft systems. Parent string // Refers to an oddball feature of obsolete Macs: two consecutive path delimiters are // used to refer to the parent directory. For all systems other than pre-OS X // Macintoshes, this should be false. ParentDouble bool // Tells the client the escape character for quoting delimiters when they appear in // selectors; most of the time, this is `\\`. EscapeCharacter byte // Tells the client not to cut everything up to the first path delimiter; most of the // time, this should be `FALSE`. KeepPreDelimiter bool }
type Request ¶
type Request struct { // Server only. When a server accepts an actual connection, this will be set to the // remote address. This field is ignored by the Gopher client. RemoteAddr *net.TCPAddr // Server only. Params is free to be set by your Server's Mux implementation. If you // have requirements that this can't satisfy, use the dreaded context.WithValue() to // add what you need. Params Params // Server only. SelectorPrefix is added to all generated selectors which are internal // to this server. Comes from the Server struct. Useful for things like configurable // sites deployable at different selector bases. SelectorPrefix string // contains filtered or unexported fields }
func NewFormatRequest ¶
func (*Request) Body ¶
func (r *Request) Body() io.ReadCloser
func (*Request) Format ¶
In addition to a selector string, a GopherIIbis-compliant request contains a *format* string, a data flag indicating the presence or absence of a data block, and an OPTIONAL data block.
The reason for the inclusion of the format string is because GopherIIbis allows one selector to point to multiple versions of the same file, in multiple languages.
type Response ¶
type Response interface { Reader() io.ReadCloser Info() *ResponseInfo Class() ResponseClass Close() error }
type ResponseClass ¶
type ResponseClass int
const ( UnknownClass ResponseClass = iota BinaryClass DirClass TextClass )
type ResponseInfo ¶
type ResponseInfo struct { Request *Request // TLS contains information about the TLS connection on which the // response was received. It is nil for unencrypted responses. // The pointer is shared between responses and should not be // modified. TLS *tls.ConnectionState }
func (*ResponseInfo) URL ¶
func (ri *ResponseInfo) URL() URL
type ResponseWriter ¶
type Server ¶
type Server struct { Handler Handler MetaHandler MetaHandler ErrorLog Logger Info *ServerInfo // If false, the server will not intercept request for caps.txt DisableCaps bool // Maximum number of bytes RequestSizeLimit int ReadTimeout time.Duration ReadSelectorTimeout time.Duration TLSConfig *tls.Config // This will be set in the Request so that writers like DirWriter can build prefixed // selectors with zero extra config. SelectorPrefix string // contains filtered or unexported fields }
type ServerInfo ¶
type Status ¶
type Status int
Uses GopherII codes wherever possible: https://tools.ietf.org/html/draft-matavka-gopher-ii-02#section-9.1
Wherever not possible, uses 6xx for client or 7xx for server errors. 6xx and 7xx codes are subject to change outside the GopherII RFC. This is discouraged by the RFC and will be minimised.
const ( OK Status = 0 StatusBadRequest Status = 400 StatusForbidden Status = 403 StatusNotFound Status = 404 StatusRequestTimeout Status = 408 StatusGone Status = 410 StatusInternal Status = 500 StatusNotImplemented Status = 501 StatusGeneralError Status = 600 // Non-specific error code StatusEmpty Status = 601 )
type TLSMode ¶
type TLSMode int
TLSMode describes how the Client will respond in the presence of a URL with a gopher:// scheme. If the gophers:// scheme is used, the TLSMode is always "TLSInsist".
const ( TLSModeDefault TLSMode = iota // The client will always attempt a TLS connection, and if it fails, an // error is returned. TLSInsist // The client will attempt a TLS connection, and if it fails, attempt // a plain-text connection. TLSWithInsecure // The client will not attempt a TLS connection; plain-text only. TLSDisabled )
type TextResponse ¶
type TextResponse struct {
// contains filtered or unexported fields
}
func NewTextResponse ¶
func NewTextResponse(info *ResponseInfo, rdr io.ReadCloser) *TextResponse
func (*TextResponse) Class ¶
func (br *TextResponse) Class() ResponseClass
func (*TextResponse) Close ¶
func (br *TextResponse) Close() error
func (*TextResponse) Info ¶
func (br *TextResponse) Info() *ResponseInfo
func (*TextResponse) Reader ¶
func (br *TextResponse) Reader() io.ReadCloser
type TextWriter ¶
type TextWriter struct {
// contains filtered or unexported fields
}
func NewTextWriter ¶
func NewTextWriter(w io.Writer) *TextWriter
func (*TextWriter) Flush ¶
func (tw *TextWriter) Flush() error
func (*TextWriter) MustFlush ¶
func (tw *TextWriter) MustFlush()
func (*TextWriter) WriteString ¶
func (tw *TextWriter) WriteString(s string) (n int, err error)
type URL ¶
type URL struct { Scheme string Hostname string Port string Root bool // For server requests, this will always be Text ('0') as there is no // way to tell the ItemType from what the client sends: ItemType ItemType Selector string Search string }
URL implements most of the Gopher URL scheme (excluding some of the largely unused Gopher+ stuff).
http://tools.ietf.org/html/rfc4266 https://www.w3.org/Addressing/URL/4_1_Gopher+.html
func MustParseURL ¶
func (URL) AsMetaDir ¶
AsMetaDir returns a new URL with the Search portion set to a request for a directory's metadata.
func (URL) AsMetaItem ¶
AsMetaItem returns a new URL with the Search portion set to a request for an item's metadata.
func (URL) CanFetch ¶
CanFetch returns true if (a best effort guess determines that) it is possible for a client to fetch this URL.
func (URL) IsAbs ¶
IsAbs reports whether the URL is absolute. Absolute means that it has a non-empty scheme.
func (URL) MarshalText ¶
func (*URL) UnmarshalText ¶
type UUEncodedResponse ¶
type UUEncodedResponse struct {
// contains filtered or unexported fields
}
func NewUUEncodedResponse ¶
func NewUUEncodedResponse(info *ResponseInfo, rdr io.ReadCloser) *UUEncodedResponse
func (*UUEncodedResponse) Class ¶
func (br *UUEncodedResponse) Class() ResponseClass
func (*UUEncodedResponse) Close ¶
func (br *UUEncodedResponse) Close() error
func (*UUEncodedResponse) File ¶
func (br *UUEncodedResponse) File() (string, bool)
func (*UUEncodedResponse) Info ¶
func (br *UUEncodedResponse) Info() *ResponseInfo
func (*UUEncodedResponse) Reader ¶
func (br *UUEncodedResponse) Reader() io.ReadCloser