README

Gopher protocol library for Golang

Build Status CodeCov Go Report Card GoDoc Sourcegraph

This is a standards compliant Gopher library for the Go programming language implementing the RFC 1436 specification. The library includes both client and server handling and examples of each.

Installation

$ go get within.website/gopher

Usage

import "within.website/gopher"

Example

Client
package main

import (
	"fmt"

	"within.website/gopher"
)

func main() {
	res, _ := gopher.Get("gopher://gopher.floodgap.com/")
	bytes, _ = res.Dir.ToText()
	fmt.Println(string(bytes))
}
Server
package main

import (
	"log"

	"within.website/gopher"
)

func hello(w gopher.ResponseWriter, r *gopher.Request) {
	w.WriteInfo("Hello World!")
}

func main() {
	gopher.HandleFunc("/hello", hello)
	log.Fatal(gopher.ListenAndServe("localhost:70", nil))
}

Related projects:

  • gopherproxy gopherproxy is Gopher to HTTP proxy that uses go-gopher for all of its core functionality.

  • gopherclient gopherclient is a cross-platform QT/QML GUI Gopher Client using the gopherproxy library as its backend.

License

MIT

Documentation

Overview

    Package gopher provides an implementation of the Gopher protocol (RFC 1436)

    Much of the API is similar in design to the net/http package of the standard library. To build custom Gopher servers implement handler functions or the `Handler{}` interface. Implementing a client is as simple as calling `gopher.Get(uri)` and passing in a `uri` such as `"gopher://gopher.floodgap.com/"`.

    Example (Client)
    Output:
    
    
    Example (Fileserver)
    Output:
    
    
    Example (Server)
    Output:
    
    

    Index

    Examples

    Constants

    View Source
    const (
    	FILE        = ItemType('0') // Item is a file
    	DIRECTORY   = ItemType('1') // Item is a directory
    	PHONEBOOK   = ItemType('2') // Item is a CSO phone-book server
    	ERROR       = ItemType('3') // Error
    	BINHEX      = ItemType('4') // Item is a BinHexed Macintosh file.
    	DOSARCHIVE  = ItemType('5') // Item is DOS binary archive of some sort. (*)
    	UUENCODED   = ItemType('6') // Item is a UNIX uuencoded file.
    	INDEXSEARCH = ItemType('7') // Item is an Index-Search server.
    	TELNET      = ItemType('8') // Item points to a text-based telnet session.
    	BINARY      = ItemType('9') // Item is a binary file! (*)
    
    	REDUNDANT = ItemType('+') // Item is a redundant server
    	TN3270    = ItemType('T') // Item points to a text-based tn3270 session.
    	GIF       = ItemType('g') // Item is a GIF format graphics file.
    	IMAGE     = ItemType('I') // Item is some kind of image file.
    
    	// non-standard
    	INFO  = ItemType('i') // Item is an informational message
    	HTML  = ItemType('h') // Item is a HTML document
    	AUDIO = ItemType('s') // Item is an Audio file
    	PNG   = ItemType('p') // Item is a PNG Image
    	DOC   = ItemType('d') // Item is a Document
    )

      Item Types

      View Source
      const (
      	// END represents the terminator used in directory responses
      	END = byte('.')
      
      	// TAB is the delimiter used to separate item response parts
      	TAB = byte('\t')
      
      	// CRLF is the delimiter used per line of response item
      	CRLF = "\r\n"
      
      	// DEFAULT is the default item type
      	DEFAULT = BINARY
      )

      Variables

      View Source
      var (
      	// ServerContextKey is a context key. It can be used in Gopher
      	// handlers with context.WithValue to access the server that
      	// started the handler. The associated value will be of type *Server.
      	ServerContextKey = &contextKey{"gopher-server"}
      
      	// LocalAddrContextKey is a context key. It can be used in
      	// Gopher handlers with context.WithValue to access the address
      	// the local address the connection arrived on.
      	// The associated value will be of type net.Addr.
      	LocalAddrContextKey = &contextKey{"local-addr"}
      )
      View Source
      var DefaultServeMux = &defaultServeMux

        DefaultServeMux is the default ServeMux used by Serve.

        View Source
        var FileExtensions = map[string]ItemType{
        	".txt":  FILE,
        	".gif":  GIF,
        	".jpg":  IMAGE,
        	".jpeg": IMAGE,
        	".png":  IMAGE,
        	".html": HTML,
        	".ogg":  AUDIO,
        	".mp3":  AUDIO,
        	".wav":  AUDIO,
        	".mod":  AUDIO,
        	".it":   AUDIO,
        	".xm":   AUDIO,
        	".mid":  AUDIO,
        	".vgm":  AUDIO,
        	".s":    FILE,
        	".c":    FILE,
        	".py":   FILE,
        	".h":    FILE,
        	".md":   FILE,
        	".go":   FILE,
        	".fs":   FILE,
        }

          FileExtensions defines a mapping of known file extensions to gopher types

          View Source
          var MimeTypes = map[string]ItemType{
          	"text/html": HTML,
          	"text/*":    FILE,
          
          	"image/gif": GIF,
          	"image/*":   IMAGE,
          
          	"audio/*": AUDIO,
          
          	"application/x-tar":  DOSARCHIVE,
          	"application/x-gtar": DOSARCHIVE,
          
          	"application/x-xz":    DOSARCHIVE,
          	"application/x-zip":   DOSARCHIVE,
          	"application/x-gzip":  DOSARCHIVE,
          	"application/x-bzip2": DOSARCHIVE,
          }

            MimeTypes defines a mapping of known mimetypes to gopher types

            Functions

            func Error

            func Error(w ResponseWriter, error string)

              Error replies to the request with the specified error message. It does not otherwise end the request; the caller should ensure no further writes are done to w. The error message should be plain text.

              func Handle

              func Handle(pattern string, handler Handler)

                Handle registers the handler for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns are matched.

                func HandleFunc

                func HandleFunc(pattern string, handler func(ResponseWriter, *Request))

                  HandleFunc registers the handler function for the given pattern in the DefaultServeMux. The documentation for ServeMux explains how patterns are matched.

                  func ListenAndServe

                  func ListenAndServe(addr string, handler Handler) error

                    ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections.

                    A trivial example server is:

                    package main
                    
                    import (
                        "io"
                        "log"
                    
                        "within.website/gopher"
                    )
                    
                    // hello world, the gopher server
                    func HelloServer(w gopher.ResponseWriter, req *gopher.Request) {
                        w.WriteInfo("hello, world!")
                    }
                    
                    func main() {
                        gopher.HandleFunc("/hello", HelloServer)
                        log.Fatal(gopher.ListenAndServe(":7000", nil))
                    }
                    

                    ListenAndServe always returns a non-nil error.

                    func ListenAndServeTLS

                    func ListenAndServeTLS(addr, certFile, keyFile string, handler Handler) error

                      ListenAndServeTLS acts identically to ListenAndServe, except that it expects TLS connections. Additionally, files containing a certificate and matching private key for the server must be provided. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate, any intermediates, and the CA's certificate.

                      A trivial example server is:

                      import (
                          "log"
                      
                          "github.com/prologic/go-gopher",
                      )
                      
                      func HelloServer(w gopher.ResponseWriter, req *gopher.Request) {
                          w.WriteInfo("hello, world!")
                      }
                      
                      func main() {
                          gopher.HandleFunc("/", handler)
                          log.Printf("About to listen on 73. Go to gophers://127.0.0.1:73/")
                          err := gopher.ListenAndServeTLS(":73", "cert.pem", "key.pem", nil)
                          log.Fatal(err)
                      }
                      

                      One can use generate_cert.go in crypto/tls to generate cert.pem and key.pem.

                      ListenAndServeTLS always returns a non-nil error.

                      func NotFound

                      func NotFound(w ResponseWriter, r *Request)

                        NotFound replies to the request with an resouce not found error item.

                        Types

                        type Dir

                        type Dir string

                          A Dir implements FileSystem using the native file system restricted to a specific directory tree.

                          While the FileSystem.Open method takes '/'-separated paths, a Dir's string value is a filename on the native file system, not a URL, so it is separated by filepath.Separator, which isn't necessarily '/'.

                          An empty Dir is treated as ".".

                          func (Dir) Name

                          func (d Dir) Name() string

                            Name returns the directory

                            func (Dir) Open

                            func (d Dir) Open(name string) (File, error)

                              Open opens the directory

                              type Directory

                              type Directory struct {
                              	Items []Item `json:"items"`
                              }

                                Directory representes a Gopher Menu of Items

                                func (*Directory) ToJSON

                                func (d *Directory) ToJSON() ([]byte, error)

                                  ToJSON returns the Directory as JSON bytes

                                  func (*Directory) ToText

                                  func (d *Directory) ToText() ([]byte, error)

                                    ToText returns the Directory as UTF-8 encoded bytes

                                    type File

                                    type File interface {
                                    	io.Closer
                                    	io.Reader
                                    	io.Seeker
                                    	Readdir(count int) ([]os.FileInfo, error)
                                    	Stat() (os.FileInfo, error)
                                    }

                                      A File is returned by a FileSystem's Open method and can be served by the FileServer implementation.

                                      The methods should behave the same as those on an *os.File.

                                      type FileSystem

                                      type FileSystem interface {
                                      	Name() string
                                      	Open(name string) (File, error)
                                      }

                                        A FileSystem implements access to a collection of named files. The elements in a file path are separated by slash ('/', U+002F) characters, regardless of host operating system convention.

                                        type Handler

                                        type Handler interface {
                                        	ServeGopher(ResponseWriter, *Request)
                                        }

                                          A Handler responds to a Gopher request.

                                          ServeGopher should write data or items to the ResponseWriter and then return. Returning signals that the request is finished; it is not valid to use the ResponseWriter concurrently with the completion of the ServeGopher call.

                                          Handlers should not modify the provided request.

                                          If ServeGopher panics, the server (the caller of ServeGopher) assumes that the effect of the panic was isolated to the active request. It recovers the panic, logs a stack trace to the server error log, and hangs up the connection.

                                          func FileServer

                                          func FileServer(root FileSystem) Handler

                                            FileServer returns a handler that serves Gopher requests with the contents of the file system rooted at root.

                                            To use the operating system's file system implementation, use gopher.Dir:

                                            gopher.Handle("/", gopher.FileServer(gopher.Dir("/tmp")))
                                            

                                            func NotFoundHandler

                                            func NotFoundHandler() Handler

                                              NotFoundHandler returns a simple request handler that replies to each request with a “resource page not found” reply.

                                              type HandlerFunc

                                              type HandlerFunc func(ResponseWriter, *Request)

                                                The HandlerFunc type is an adapter to allow the use of ordinary functions as Gopher handlers. If f is a function with the appropriate signature, HandlerFunc(f) is a Handler that calls f.

                                                func (HandlerFunc) ServeGopher

                                                func (f HandlerFunc) ServeGopher(w ResponseWriter, r *Request)

                                                  ServeGopher calls f(w, r).

                                                  type Item

                                                  type Item struct {
                                                  	Type        ItemType `json:"type"`
                                                  	Description string   `json:"description"`
                                                  	Selector    string   `json:"selector"`
                                                  	Host        string   `json:"host"`
                                                  	Port        int      `json:"port"`
                                                  
                                                  	// non-standard extensions (ignored by standard clients)
                                                  	Extras []string `json:"extras"`
                                                  }

                                                    Item describes an entry in a directory listing.

                                                    func ParseItem

                                                    func ParseItem(line string) (item *Item, err error)

                                                      ParseItem parses a line of text into an item

                                                      func (*Item) FetchDirectory

                                                      func (i *Item) FetchDirectory() (Directory, error)

                                                        FetchDirectory fetches directory information, not data. Calling this on an Item whose type is not DIRECTORY will return an error.

                                                        func (*Item) FetchFile

                                                        func (i *Item) FetchFile() (io.Reader, error)

                                                          FetchFile fetches data, not directory information. Calling this on a DIRECTORY Item type or unsupported type will return an error.

                                                          func (Item) MarshalJSON

                                                          func (i Item) MarshalJSON() ([]byte, error)

                                                            MarshalJSON serializes an Item into a JSON structure

                                                            func (Item) MarshalText

                                                            func (i Item) MarshalText() ([]byte, error)

                                                              MarshalText serializes an Item into an array of bytes

                                                              type ItemType

                                                              type ItemType byte

                                                                ItemType represents the type of an item

                                                                func GetItemType

                                                                func GetItemType(p string) ItemType

                                                                  GetItemType returns the Gopher Type of the given path

                                                                  func (ItemType) String

                                                                  func (it ItemType) String() string

                                                                    Return a human friendly represation of an ItemType

                                                                    type Request

                                                                    type Request struct {
                                                                    	Selector  string
                                                                    	LocalHost string
                                                                    	LocalPort int
                                                                    	// contains filtered or unexported fields
                                                                    }

                                                                      Request repsesnts an inbound request to a listening server. LocalHost and LocalPort may be used by the Handler for local links. These are specified in the call to ListenAndServe.

                                                                      type Response

                                                                      type Response struct {
                                                                      	Type ItemType
                                                                      	Dir  Directory
                                                                      	Body io.Reader
                                                                      }

                                                                        Response represents a Gopher resource that Items contains a non-empty array of Item(s) for directory types, otherwise the Body contains the fetched resource (file, image, etc).

                                                                        func Get

                                                                        func Get(uri string) (*Response, error)

                                                                          Get fetches a Gopher resource by URI

                                                                          type ResponseWriter

                                                                          type ResponseWriter interface {
                                                                          	// Server returns the connection's server instance
                                                                          	Server() *Server
                                                                          
                                                                          	// End ends the document by writing the terminating period and crlf
                                                                          	End() error
                                                                          
                                                                          	// Write writes the data to the connection as part of a Gopher reply.
                                                                          	//
                                                                          	Write([]byte) (int, error)
                                                                          
                                                                          	// WriteError writes an error item
                                                                          	WriteError(err string) error
                                                                          
                                                                          	// WriteInfo writes an informational item
                                                                          	WriteInfo(msg string) error
                                                                          
                                                                          	// WriteItem writes an item
                                                                          	WriteItem(i Item) error
                                                                          }

                                                                            A ResponseWriter interface is used by a Gopher handler to construct an Gopher response.

                                                                            A ResponseWriter may not be used after the Handler.ServeGopher method has returned.

                                                                            type ServeMux

                                                                            type ServeMux struct {
                                                                            	// contains filtered or unexported fields
                                                                            }

                                                                              ServeMux is a Gopher request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.

                                                                              Patterns name fixed, rooted paths, like "/favicon.ico", or rooted subtrees, like "/images/" (note the trailing slash). Longer patterns take precedence over shorter ones, so that if there are handlers registered for both "/images/" and "/images/thumbnails/", the latter handler will be called for paths beginning "/images/thumbnails/" and the former will receive requests for any other paths in the "/images/" subtree.

                                                                              Note that since a pattern ending in a slash names a rooted subtree, the pattern "/" matches all paths not matched by other registered patterns, not just the URL with Path == "/".

                                                                              If a subtree has been registered and a request is received naming the subtree root without its trailing slash, ServeMux redirects that request to the subtree root (adding the trailing slash). This behavior can be overridden with a separate registration for the path without the trailing slash. For example, registering "/images/" causes ServeMux to redirect a request for "/images" to "/images/", unless "/images" has been registered separately.

                                                                              ServeMux also takes care of sanitizing the URL request path, redirecting any request containing . or .. elements or repeated slashes to an equivalent, cleaner URL.

                                                                              func NewServeMux

                                                                              func NewServeMux() *ServeMux

                                                                                NewServeMux allocates and returns a new ServeMux.

                                                                                func (*ServeMux) Handle

                                                                                func (mux *ServeMux) Handle(pattern string, handler Handler)

                                                                                  Handle registers the handler for the given pattern. If a handler already exists for pattern, Handle panics.

                                                                                  func (*ServeMux) HandleFunc

                                                                                  func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))

                                                                                    HandleFunc registers the handler function for the given pattern.

                                                                                    func (*ServeMux) Handler

                                                                                    func (mux *ServeMux) Handler(r *Request) (h Handler, pattern string)

                                                                                      Handler returns the handler to use for the given request, consulting r.Selector. It always returns a non-nil handler.

                                                                                      Handler also returns the registered pattern that matches the request.

                                                                                      If there is no registered handler that applies to the request, Handler returns a “resource not found” handler and an empty pattern.

                                                                                      func (*ServeMux) ServeGopher

                                                                                      func (mux *ServeMux) ServeGopher(w ResponseWriter, r *Request)

                                                                                        ServeGopher dispatches the request to the handler whose pattern most closely matches the request URL.

                                                                                        type Server

                                                                                        type Server struct {
                                                                                        	Addr     string  // TCP address to listen on, ":gopher" if empty
                                                                                        	Handler  Handler // handler to invoke, gopher.DefaultServeMux if nil
                                                                                        	Hostname string  // FQDN Hostname to reach this server on
                                                                                        }

                                                                                          Server defines parameters for running a Gopher server. A zero value for Server is valid configuration.

                                                                                          func (*Server) ListenAndServe

                                                                                          func (s *Server) ListenAndServe() error

                                                                                            ListenAndServe starts serving gopher requests using the given Handler. The address passed to ListenAndServe should be an internet-accessable domain name, optionally followed by a colon and the port number.

                                                                                            If the address is not a FQDN, LocalHost as passed to the Handler may not be accessible to clients, so links may not work.

                                                                                            func (*Server) ListenAndServeTLS

                                                                                            func (s *Server) ListenAndServeTLS(certFile, keyFile string) error

                                                                                              ListenAndServeTLS listens on the TCP network address srv.Addr and then calls Serve to handle requests on incoming TLS connections. Accepted connections are configured to enable TCP keep-alives.

                                                                                              Filenames containing a certificate and matching private key for the server must be provided if neither the Server's TLSConfig.Certificates nor TLSConfig.GetCertificate are populated. If the certificate is signed by a certificate authority, the certFile should be the concatenation of the server's certificate, any intermediates, and the CA's certificate.

                                                                                              If srv.Addr is blank, ":gophers" is used (port 73).

                                                                                              ListenAndServeTLS always returns a non-nil error.

                                                                                              func (*Server) Serve

                                                                                              func (s *Server) Serve(l net.Listener) error

                                                                                                Serve ...

                                                                                                Source Files

                                                                                                Directories

                                                                                                Path Synopsis
                                                                                                examples