Documentation
¶
Overview ¶
Amahi SPDY is a library built from scratch in the "Go way" for building SPDY clients and servers in the Go programming language.
It supports a subset of SPDY 3.1 http://www.chromium.org/spdy/spdy-protocol/spdy-protocol-draft3-1
Check the source code, examples and overview at https://github.com/amahi/spdy
This library is used in a streaming server/proxy implementation for Amahi, the [home and media server](https://www.amahi.org).
Goals ¶
The goals are reliability, streaming and performance/scalability.
1) Design for reliability means that network connections are assumed to disconnect at any time, especially when it's most inapropriate for the library to handle. This also includes potential issues with bugs in within the library, so the library tries to handle all crazy errors in the most reasonable way. A client or a server built with this library should be able to run for months and months of reliable operation. It's not there yet, but it will be.
2) Streaming requests, unlike typical HTTP requests (which are short), require working with an arbitrary large number of open requests (streams) simultaneously, and most of them are flow-constrained at the client endpoint. Streaming clients kind of misbehave too, for example, they open and close many streams rapidly with Range request to check certain parts of the file. This is common with endpoint clients like VLC or Quicktime (Safari on iOS or Mac OS X). We wrote this library with the goal of making it not just suitable for HTTP serving, but also for streaming.
3) The library was built with performance and scalability in mind, so things have been done using as little blocking and copying of data as possible. It was meant to be implemented in the "go way", using concurrency extensively and channel communication. The library uses mutexes very sparingly so that handling of errors at all manner of inapropriate times becomes easier. It goes to great lengths to not block, establishing timeouts when network and even channel communication may fail. The library should use very very little CPU, even in the presence of many streams and sessions running simultaneously.
Index ¶
- Constants
- func EnableDebug()
- func ListenAndServe(addr string, handler http.Handler) (err error)
- func ListenAndServeTLS(addr string, certFile string, keyFile string, handler http.Handler) error
- func ListenAndServeTLSSpdyOnly(addr string, certFile string, keyFile string, handler http.Handler) error
- func PriorityFor(req *url.URL) uint8
- func SetLog(w io.Writer)
- type Client
- type ResponseRecorder
- type Server
- type Session
- func (s *Session) Close()
- func (s *Session) NewClientStream() *Stream
- func (s *Session) NewStreamProxy(r *http.Request, w http.ResponseWriter) (err error)
- func (s *Session) Ping(d time.Duration) (pinged bool)
- func (s *Session) SendGoaway(f frameFlags, dat []byte)
- func (s *Session) Serve() (err error)
- type Stream
Constants ¶
const ( FRAME_SYN_STREAM = 0x0001 FRAME_SYN_REPLY = 0x0002 FRAME_RST_STREAM = 0x0003 FRAME_SETTINGS = 0x0004 FRAME_PING = 0x0006 FRAME_GOAWAY = 0x0007 FRAME_HEADERS = 0x0008 FRAME_WINDOW_UPDATE = 0x0009 )
const ( FLAG_NONE = frameFlags(0x00) FLAG_FIN = frameFlags(0x01) )
const ( HEADER_STATUS string = ":status" HEADER_VERSION string = ":version" HEADER_PATH string = ":path" HEADER_METHOD string = ":method" HEADER_HOST string = ":host" HEADER_SCHEME string = ":scheme" HEADER_CONTENT_LENGTH string = "Content-Length" )
const INITIAL_FLOW_CONTOL_WINDOW int32 = 64 * 1024
const MAX_DATA_PAYLOAD = 1<<24 - 1
maximum number of bytes in a frame
const NORTHBOUND_SLOTS = 5
Variables ¶
This section is empty.
Functions ¶
func EnableDebug ¶
func EnableDebug()
EnableDebug turns on the output of debugging messages to Stdout
func ListenAndServe ¶
ListenAndServe listens on the TCP network address addr and then calls Serve with handler to handle requests on incoming connections. Handler is typically nil, in which case the DefaultServeMux is used. This creates a spdy only server without TLS
A trivial example server is:
package main import ( "io" "net/http" "github.com/amahi/spdy" "log" ) // hello world, the web server func HelloServer(w http.ResponseWriter, req *http.Request) { io.WriteString(w, "hello, world!\n") } func main() { http.HandleFunc("/hello", HelloServer) err := spdy.ListenAndServe(":12345", nil) if err != nil { log.Fatal("ListenAndServe: ", err) } }
func ListenAndServeTLS ¶
ListenAndServeTLS acts identically to ListenAndServe, except that it expects HTTPS connections. Servers created this way have NPN Negotiation and accept requests from both spdy and http clients. 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 followed by the CA's certificate.
A trivial example server is:
import ( "log" "net/http" "github.com/amahi/spdy" ) func handler(w http.ResponseWriter, req *http.Request) { w.Header().Set("Content-Type", "text/plain") w.Write([]byte("This is an example server.\n")) } func main() { http.HandleFunc("/", handler) log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/") err := spdy.ListenAndServeTLS(":10443", "cert.pem", "key.pem", nil) if err != nil { log.Fatal(err) } }
One can use makecert.sh in /certs to generate certfile and keyfile
func PriorityFor ¶
PriorityFor returns the recommended priority for the given URL for best opteration with the library.
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
spdy client
func NewClientConn ¶
returns a client that reads and writes on c
type ResponseRecorder ¶
type ResponseRecorder struct { Code int // the HTTP response code from WriteHeader HeaderMap http.Header // the HTTP response headers Body *bytes.Buffer // if non-nil, the bytes.Buffer to append written data to // contains filtered or unexported fields }
ResponseRecorder is an implementation of http.ResponseWriter that is used to get a response.
func NewRecorder ¶
func NewRecorder() *ResponseRecorder
NewRecorder returns an initialized ResponseRecorder.
func (*ResponseRecorder) Header ¶
func (rw *ResponseRecorder) Header() http.Header
Header returns the response headers.
func (*ResponseRecorder) Write ¶
func (rw *ResponseRecorder) Write(buf []byte) (int, error)
Write always succeeds and writes to rw.Body.
func (*ResponseRecorder) WriteHeader ¶
func (rw *ResponseRecorder) WriteHeader(code int)
WriteHeader sets rw.Code.
type Server ¶
type Server struct { Handler http.Handler Addr string TLSConfig *tls.Config // contains filtered or unexported fields }
spdy server
func (*Server) Close ¶
close spdy server and return Any blocked Accept operations will be unblocked and return errors.
func (*Server) ListenAndServe ¶
ListenAndServe listens on the TCP network address s.Addr and then calls Serve to handle requests on incoming connections.
func (*Server) ListenAndServeTLSSpdyOnly ¶
ListenAndServeTLSSpdyOnly listens on the TCP network address srv.Addr and then calls Serve to handle requests on incoming TLS connections. This is a spdy-only server with TLS and no NPN.
Filenames 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 followed by the CA's certificate.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
func NewClientSession ¶
NewClientSession creates a new Session that should be used as a client. the given http.Server will be used to serve requests arriving. The user should call Serve() once it's ready to start serving. New streams will be created as per the SPDY protocol.
func NewServerSession ¶
NewServerSession creates a new Session with the given network connection. This Session should be used as a server, and the given http.Server will be used to serve requests arriving. The user should call Serve() once it's ready to start serving. New streams will be created as per the SPDY protocol.
func (*Session) Close ¶
func (s *Session) Close()
Close closes the Session and the underlaying network connection. It should be called when the Session is idle for best results.
func (*Session) NewClientStream ¶
NewClientStream starts a new Stream (in the given Session), to be used as a client
func (*Session) NewStreamProxy ¶
NewStreamProxy starts a new stream and proxies the given HTTP Request to it, writing the response to the given ResponseWriter. If there is an error, it will be returned, but the ResponseWriter will get a 404 Not Found.
func (*Session) Ping ¶
Ping issues a SPDY PING frame and returns true if it the other side returned the PING frame within the duration, else it returns false. NOTE only one outstanting ping works in the current implementation.
func (*Session) SendGoaway ¶
type Stream ¶
type Stream struct {
// contains filtered or unexported fields
}
func (*Stream) Request ¶
Request makes an http request down the client that gets a client Stream started and returning the request in the ResponseWriter
func (*Stream) WriteHeader ¶
WriteHeader makes streams compatible with the net/http handlers interface