spdy

package module
v0.0.0-...-a513b59 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: May 12, 2014 License: BSD-2-Clause Imports: 22 Imported by: 0

README

spdy

A full-featured SPDY library for the Go language (still under very active development).

Note that this implementation currently supports SPDY drafts 2 and 3, and support for SPDY/4, and HTTP/2.0 is upcoming.

The GoDoc documentation for this package can be found at http://godoc.org/github.com/SlyMarbo/spdy.

Servers

Adding SPDY support to an existing Go server requires minimal work.

Modifying a simple example server like the following:

package main

import (
	"net/http"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	// Remember not to add any headers after calling
	// w.WriteHeader().
	
	w.Write([]byte("Hello, HTTP!"))
}

func main() {
	
	// Register handler.
	http.HandleFunc("/", Serve)

	err := http.ListenAndServeTLS("localhost:443", "cert.pem", "key.pem", nil)
	if err != nil {
		// handle error.
	}
}

Simply requires the following changes:

package main

import (
	"github.com/SlyMarbo/spdy" // Import SPDY.
	"net/http"
)

// This handler will now serve HTTP, HTTPS, and SPDY requests.
func Serve(w http.ResponseWriter, r *http.Request) {
	// Remember not to add any headers after calling
	// w.WriteHeader().

	w.Write([]byte("Hello, HTTP!"))
}

func main() {
	
	http.HandleFunc("/", Serve)

	// Use spdy's ListenAndServe.
	err := spdy.ListenAndServeTLS("localhost:443", "cert.pem", "key.pem", nil)
	if err != nil {
		// handle error.
	}
}

A very simple file server for both SPDY and HTTPS:

package main

import (
	"github.com/SlyMarbo/spdy"
	"net/http"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	if spdy.UsingSPDY(w) {
		// Using SPDY.
	} else {
		// Using HTTP(S).
	}
	http.ServeFile(w, r, "." + r.RequestURI)
}

func main() {
	
	// Register handler.
	http.HandleFunc("/", Serve)

	err := spdy.ListenAndServeTLS("localhost:443", "cert.pem", "key.pem", nil)
	if err != nil {
		// handle error.
	}
}

The following examples use features specific to SPDY.

Just the handler is shown.

Use SPDY's pinging features to test the connection:

package main

import (
	"github.com/SlyMarbo/spdy"
	"net/http"
	"time"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	// Ping returns a channel which will send an empty struct.
	ping, err := spdy.PingClient(w)
	if err != nil {
		// Not using SPDY.
	}
	
	select {
	case response := <- ping:
		if response != nil {
			// Connection is fine.
		} else {
			// Something went wrong.
		}
		
	case <-time.After(timeout):
		// Ping took too long.
		
	}
	
	// ...
}

Sending a server push:

package main

import (
	"github.com/SlyMarbo/spdy"
	"net/http"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	// Push returns a separate http.ResponseWriter and an error.
	path := r.URL.Scheme + "://" + r.URL.Host + "/example.js"
	push, err := spdy.Push(path)
	if err != nil {
		// Not using SPDY.
	}
	http.ServeFile(push, r, "./content/example.js")

	// Note that a PushStream must be finished manually once
	// all writing has finished.
	push.Finish()
	
	// ...
}

Clients

The client API is even easier to use. Simply import the spdy package to add SPDY support. Here's a simple example that will fetch the requested page over HTTP, HTTPS, or SPDY, as necessary.

package main

import (
	"fmt"
	_ "github.com/SlyMarbo/spdy" // Simply import SPDY.
	"io/ioutil"
	"net/http"
)

func main() {
	res, err := http.Get("https://example.com/") // http.Get (and .Post etc) can now use SPDY.
	if err != nil {
		// handle the error.
	}
	
	bytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		// handle the error.
	}
	res.Body.Close()
	
	fmt.Printf("Received: %s\n", bytes)
}

To add SPDY support to your own client, just use the spdy package's Transport.

package main

import (
	"github.com/SlyMarbo/spdy" // Import SPDY.
	"net/http"
)

func main() {
	client := new(http.Client)
	client.Transport = new(spdy.Transport) // This client now supports HTTP, HTTPS, and SPDY.
	
	// ...
}

Documentation

Overview

Package spdy is a full-featured SPDY library for the Go language (still under very active development).

Note that this implementation currently supports SPDY drafts 2 and 3, and support for SPDY/4, and HTTP/2.0 is upcoming.

-------------------------------

Servers

Adding SPDY support to an existing Go server requires minimal work.

Modifying a simple example server like the following:

package main

import (
	"net/http"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	// Remember not to add any headers after calling
	// w.WriteHeader().

	w.Write([]byte("Hello, HTTP!"))
}

func main() {

	// Register handler.
	http.HandleFunc("/", Serve)

	err := http.ListenAndServeTLS("localhost:443", "cert.pem", "key.pem", nil)
	if err != nil {
		// handle error.
	}
}

Simply requires the following changes:

package main

import (
	"github.com/SlyMarbo/spdy" // Import SPDY.
	"net/http"
)

// This handler will now serve HTTP, HTTPS, and SPDY requests.
func Serve(w http.ResponseWriter, r *http.Request) {
	// Remember not to add any headers after calling
	// w.WriteHeader().

	w.Write([]byte("Hello, HTTP!"))
}

func main() {

	http.HandleFunc("/", Serve)

	// Use spdy's ListenAndServe.
	err := spdy.ListenAndServeTLS("localhost:443", "cert.pem", "key.pem", nil)
	if err != nil {
		// handle error.
	}
}

A very simple file server for both SPDY and HTTPS:

package main

import (
	"github.com/SlyMarbo/spdy"
	"net/http"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	if spdy.UsingSPDY(w) {
		// Using SPDY.
	} else {
		// Using HTTP(S).
	}
	http.ServeFile(w, r, "." + r.RequestURI)
}

func main() {

	// Register handler.
	http.HandleFunc("/", Serve)

	err := spdy.ListenAndServeTLS("localhost:443", "cert.pem", "key.pem", nil)
	if err != nil {
		// handle error.
	}
}

The following examples use features specific to SPDY.

Just the handler is shown.

Use SPDY's pinging features to test the connection:

package main

import (
	"github.com/SlyMarbo/spdy"
	"net/http"
	"time"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	// Ping returns a channel which will send a bool.
	ping, err := spdy.PingClient(w)
	if err != nil {
		// Not using SPDY.
	}

	select {
	case _, ok := <- ping:
		if ok {
			// Connection is fine.
		} else {
			// Something went wrong.
		}

	case <-time.After(timeout):
		// Ping took too long.

	}

	// ...
}

Sending a server push:

package main

import (
	"github.com/SlyMarbo/spdy"
	"net/http"
)

func Serve(w http.ResponseWriter, r *http.Request) {
	// Push returns a separate http.ResponseWriter and an error.
	path := r.URL.Scheme + "://" + r.URL.Host + "/example.js"
	push, err := spdy.Push(path)
	if err != nil {
		// Not using SPDY.
	}
	http.ServeFile(push, r, "./content/example.js")

	// Note that a PushStream must be finished manually once
	// all writing has finished.
	push.Finish()

	// ...
}

-------------------------------

Clients

The client API is even easier to use. Simply import the spdy package to add SPDY support. Here's a simple example that will fetch the requested page over HTTP, HTTPS, or SPDY, as necessary.

package main

import (
	"fmt"
	_ "github.com/SlyMarbo/spdy" // Simply import SPDY.
	"io/ioutil"
	"net/http"
)

func main() {
	res, err := http.Get("https://example.com/") // http.Get (and .Post etc) can now use SPDY.
	if err != nil {
		// handle the error.
	}

	bytes, err := ioutil.ReadAll(res.Body)
	if err != nil {
		// handle the error.
	}
	res.Body.Close()

	fmt.Printf("Received: %s\n", bytes)
}

To add SPDY support to your own client, just use the spdy package's Transport.

package main

import (
	"github.com/SlyMarbo/spdy" // Import SPDY.
	"net/http"
)

func main() {
	client := new(http.Client)
	client.Transport = new(spdy.Transport) // This client now supports HTTP, HTTPS, and SPDY.

	// ...
}

Index

Constants

View Source
const (
	SYN_STREAMv2    = 1
	SYN_REPLYv2     = 2
	RST_STREAMv2    = 3
	SETTINGSv2      = 4
	NOOPv2          = 5
	PINGv2          = 6
	GOAWAYv2        = 7
	HEADERSv2       = 8
	WINDOW_UPDATEv2 = 9
	CONTROL_FRAMEv2 = -1
	DATA_FRAMEv2    = -2
)

Frame types in SPDY/2

View Source
const (
	SYN_STREAMv3    = 1
	SYN_REPLYv3     = 2
	RST_STREAMv3    = 3
	SETTINGSv3      = 4
	PINGv3          = 6
	GOAWAYv3        = 7
	HEADERSv3       = 8
	WINDOW_UPDATEv3 = 9
	CREDENTIALv3    = 10
	CONTROL_FRAMEv3 = -1
	DATA_FRAMEv3    = -2
)

Frame types in SPDY/3

View Source
const (
	DATAv4             = 0
	HEADERS_PRIORITYv4 = 1
	RST_STREAMv4       = 3
	SETTINGSv4         = 4
	PUSH_PROMISEv4     = 5
	PINGv4             = 6
	GOAWAYv4           = 7
	HEADERSv4          = 8
	WINDOW_UPDATEv4    = 9
	CREDENTIALv4       = 10
)

Frame types in SPDY/4 / HTTP/2.0

View Source
const (
	FLAG_FIN                     = 1
	FLAG_UNIDIRECTIONAL          = 2
	FLAG_SETTINGS_CLEAR_SETTINGS = 1
	FLAG_SETTINGS_PERSIST_VALUE  = 1
	FLAG_SETTINGS_PERSISTED      = 2
)

Flags

View Source
const (
	RST_STREAM_PROTOCOL_ERROR        = 1
	RST_STREAM_INVALID_STREAM        = 2
	RST_STREAM_REFUSED_STREAM        = 3
	RST_STREAM_UNSUPPORTED_VERSION   = 4
	RST_STREAM_CANCEL                = 5
	RST_STREAM_INTERNAL_ERROR        = 6
	RST_STREAM_FLOW_CONTROL_ERROR    = 7
	RST_STREAM_STREAM_IN_USE         = 8
	RST_STREAM_STREAM_ALREADY_CLOSED = 9
	RST_STREAM_INVALID_CREDENTIALS   = 10
	RST_STREAM_FRAME_TOO_LARGE       = 11
)

RST_STREAM status codes

View Source
const (
	GOAWAY_OK                 = 0
	GOAWAY_PROTOCOL_ERROR     = 1
	GOAWAY_INTERNAL_ERROR     = 2
	GOAWAY_FLOW_CONTROL_ERROR = 3
)

GOAWAY status codes

View Source
const (
	SETTINGS_UPLOAD_BANDWIDTH               = 1
	SETTINGS_DOWNLOAD_BANDWIDTH             = 2
	SETTINGS_ROUND_TRIP_TIME                = 3
	SETTINGS_MAX_CONCURRENT_STREAMS         = 4
	SETTINGS_CURRENT_CWND                   = 5
	SETTINGS_DOWNLOAD_RETRANS_RATE          = 6
	SETTINGS_INITIAL_WINDOW_SIZE            = 7
	SETTINGS_CLIENT_CERTIFICATE_VECTOR_SIZE = 8
)

Settings IDs

View Source
const DEFAULT_INITIAL_CLIENT_WINDOW_SIZE = 10485760

The default initial transfer window sent by the client.

View Source
const DEFAULT_INITIAL_WINDOW_SIZE = 65535

The default initial transfer window size, as defined in the spec.

View Source
const DEFAULT_SPDY_VERSION = 3.1

SPDY version of this implementation.

View Source
const DEFAULT_STREAM_LIMIT = 1000

The default maximum number of concurrent streams.

View Source
const MAX_DATA_SIZE = 0xffffff
View Source
const MAX_DELTA_WINDOW_SIZE = 0x7fffffff

Maximum delta window size field for WINDOW_UPDATE.

View Source
const MAX_FRAME_SIZE = 0xffffff

Maximum frame size (2 ** 24 -1).

View Source
const MAX_STREAM_ID = 0x7fffffff

Maximum stream ID (2 ** 31 -1).

View Source
const MAX_TRANSFER_WINDOW_SIZE = 0x80000000

Maximum number of bytes in the transfer window.

View Source
const NO_STREAM_LIMIT = 0x80000000

NO_STREAM_LIMIT can be used to disable the stream limit.

View Source
const SPDY4_CLIENT_CONNECTION_HEADER = "FOO * HTTP/2.0\r\n\r\nBA\r\n\r\n"

Header sent by the client to initiate the connection.

Variables

View Source
var (
	ErrGoaway         = errors.New("Error: GOAWAY received.")
	ErrConnNil        = errors.New("Error: Connection is nil.")
	ErrNoFlowControl  = errors.New("Error: This connection does not use flow control.")
	ErrConnectFail    = errors.New("Error: Failed to connect.")
	ErrInvalidVersion = errors.New("Error: Invalid SPDY version.")
)

Important errors.

View Source
var ErrNotConnected = errors.New("Error: Not connected to given server.")

ErrNotConnected indicates that a SPDY-specific feature was attempted with a Client not connected to the given server.

View Source
var ErrNotSPDY = errors.New("Error: Not a SPDY connection.")

ErrNotSPDY indicates that a SPDY-specific feature was attempted with a ResponseWriter using a non-SPDY connection.

View Source
var HeaderDictionaryV2 = []byte{}/* 907 elements not displayed */

Compression header for SPDY/2

View Source
var HeaderDictionaryV3 = []byte{}/* 1423 elements not displayed */

Compression header for SPDY/3

View Source
var MaxBenignErrors = 0

MaxBenignErrors is the maximum number of minor errors each connection will allow without ending the session.

By default, MaxBenignErrors is set to 0, disabling checks and allowing minor errors to go unchecked, although they will still be reported to the debug logger. If it is important that no errors go unchecked, such as when testing another implementation, set MaxBenignErrors to 1 or higher.

View Source
var VerboseLogging = false

Functions

func AddSPDY

func AddSPDY(srv *http.Server)

AddSPDY adds SPDY support to srv, and must be called before srv begins serving.

func ConnectAndServe

func ConnectAndServe(addr string, config *tls.Config, srv *http.Server) error

ConnectAndServe is used to perform connection reversal. (See Connect() for more details.)

This works very similarly to ListenAndServeTLS, except that addr and config are used to connect to the client. If srv is nil, a new http.Server is used, with http.DefaultServeMux as the handler.

func DisableSpdyVersion

func DisableSpdyVersion(v float64) error

DisableSpdyVersion can be used to disable support for the given SPDY version. This process can be undone by using EnableSpdyVersion.

func EnableDebugOutput

func EnableDebugOutput()

EnableDebugOutput sets the output for the package's debug info logger to os.Stdout.

func EnableSpdyVersion

func EnableSpdyVersion(v float64) error

EnableSpdyVersion can re-enable support for versions of SPDY that have been disabled by DisableSpdyVersion.

func GetPriority

func GetPriority(w http.ResponseWriter) (int, error)

GetPriority is used to identify the request priority of the given stream. This can be used to manually enforce stream priority, although this is already performed by the library. If the underlying connection is using HTTP, and not SPDY, GetPriority will return the ErrNotSPDY error.

A simple example of finding a stream's priority is:

     import (
             "github.com/SlyMarbo/spdy"
             "log"
             "net/http"
     )

     func httpHandler(w http.ResponseWriter, r *http.Request) {
							priority, err := spdy.GetPriority(w)
             if err != nil {
                     // Non-SPDY connection.
             } else {
                     log.Println(priority)
             }
     }

     func main() {
             http.HandleFunc("/", httpHandler)
             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)
             }
     }

func ListenAndServeSPDY

func ListenAndServeSPDY(addr string, certFile string, keyFile string, handler http.Handler) error

ListenAndServeTLS 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. 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.

IMPORTANT NOTE: Unlike spdy.ListenAndServeTLS, this function will ONLY serve SPDY. HTTPS requests are refused.

A trivial example server is:

import (
        "github.com/SlyMarbo/spdy"
        "log"
        "net/http"
)

func httpHandler(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("/", httpHandler)
        log.Printf("About to listen on 10443. Go to https://127.0.0.1:10443/")
        err := spdy.ListenAndServeSPDY(":10443", "cert.pem", "key.pem", nil)
        if err != nil {
                log.Fatal(err)
        }
}

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

func ListenAndServeSPDYNoNPN

func ListenAndServeSPDYNoNPN(addr string, certFile string, keyFile string, handler http.Handler, version float64) error

func ListenAndServeTLS

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

ListenAndServeTLS 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. 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 (
        "github.com/SlyMarbo/spdy"
        "log"
        "net/http"
)

func httpHandler(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("/", httpHandler)
        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 generate_cert.go in crypto/tls to generate cert.pem and key.pem.

func PingClient

func PingClient(w http.ResponseWriter) (<-chan Ping, error)

PingClient is used to send PINGs with SPDY servers. PingClient takes a ResponseWriter and returns a channel on which a spdy.Ping will be sent when the PING response is received. If the channel is closed before a spdy.Ping has been sent, this indicates that the PING was unsuccessful.

If the underlying connection is using HTTP, and not SPDY, PingClient will return the ErrNotSPDY error.

A simple example of sending a ping is:

import (
        "github.com/SlyMarbo/spdy"
        "log"
        "net/http"
)

func httpHandler(w http.ResponseWriter, req *http.Request) {
        ping, err := spdy.PingClient(w)
        if err != nil {
                // Non-SPDY connection.
        } else {
                resp, ok <- ping
                if ok {
                        // Ping was successful.
                }
        }

}

func main() {
        http.HandleFunc("/", httpHandler)
        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)
        }
}

func PingServer

func PingServer(c http.Client, server string) (<-chan Ping, error)

PingServer is used to send PINGs with http.Clients using. SPDY. PingServer takes a ResponseWriter and returns a channel onwhich a spdy.Ping will be sent when the PING response is received. If the channel is closed before a spdy.Ping has been sent, this indicates that the PING was unsuccessful.

If the underlying connection is using HTTP, and not SPDY, PingServer will return the ErrNotSPDY error.

If an underlying connection has not been made to the given server, PingServer will return the ErrNotConnected error.

A simple example of sending a ping is:

import (
        "github.com/SlyMarbo/spdy"
        "net/http"
)

func main() {
        resp, err := http.Get("https://example.com/")

        // ...

        ping, err := spdy.PingServer(http.DefaultClient, "https://example.com")
        if err != nil {
                // No SPDY connection.
        } else {
                resp, ok <- ping
                if ok {
                        // Ping was successful.
                }
        }
}

func ProxyConnections

func ProxyConnections(handler ProxyConnHandler) http.Handler

ProxyConnections is used with ConnectAndServe in connection- reversing proxies. This returns an http.Handler which will call handler each time a client connects. The call is treated as an event loop and the connection may be terminated if the call returns. The returned Handler should then be used in a normal HTTP server, like the following:

package main

import (
  "net/http"

  "github.com/SlyMarbo/spdy"
)

func handleProxy(conn spdy.Conn) {
  // make requests...
}

func main() {
  handler := spdy.ProxyConnHandlerFunc(handleProxy)
  http.Handle("/", spdy.ProxyConnections(handler))
  http.ListenAndServeTLS(":80", "cert.pem", "key.pem", nil)
}

Use Conn.Request to make requests to the client and Conn.Conn to access the underlying connection for further details like the client's address.

func SPDYversion

func SPDYversion(w http.ResponseWriter) float64

SPDYversion returns the SPDY version being used in the underlying connection used by the given http.ResponseWriter. This is 0 for connections not using SPDY.

func SetDebugLogger

func SetDebugLogger(l *logging.Logger)

SetDebugLogger sets the package's debug info logger.

func SetDebugOutput

func SetDebugOutput(w io.Writer)

SetDebugOutput sets the output for the package's debug info logger.

func SetFlowControl

func SetFlowControl(w http.ResponseWriter, f FlowControl) error

SetFlowControl can be used to set the flow control mechanism on the underlying SPDY connection.

func SetLogOutput

func SetLogOutput(w io.Writer)

SetLogOutput sets the output for the package's error logger.

func SetLogger

func SetLogger(l *logging.Logger)

SetLogger sets the package's error logger.

func SupportedVersion

func SupportedVersion(v float64) bool

SupportedVersion determines if the provided SPDY version is supported by this instance of the library. This can be modified with EnableSpdyVersion and DisableSpdyVersion.

func SupportedVersions

func SupportedVersions() []float64

SupportedVersions will return a slice of supported SPDY versions. The returned versions are sorted into order of most recent first.

func UsingSPDY

func UsingSPDY(w http.ResponseWriter) bool

UsingSPDY indicates whether a given ResponseWriter is using SPDY.

Types

type Compressor

type Compressor interface {
	io.Closer
	Compress(http.Header) ([]byte, error)
}

Compressor is used to compress the text header of a SPDY frame.

func NewCompressor

func NewCompressor(version uint16) Compressor

NewCompressor is used to create a new compressor. It takes the SPDY version to use.

type Conn

type Conn interface {
	http.CloseNotifier
	io.Closer
	Conn() net.Conn
	InitialWindowSize() (uint32, error)
	Ping() (<-chan Ping, error)
	Push(url string, origin Stream) (PushStream, error)
	Request(request *http.Request, receiver Receiver, priority Priority) (Stream, error)
	RequestResponse(request *http.Request, receiver Receiver, priority Priority) (*http.Response, error)
	Run() error
	SetFlowControl(FlowControl) error
	SetTimeout(time.Duration)
	SetReadTimeout(time.Duration)
	SetWriteTimeout(time.Duration)
}

Connection represents a SPDY connection. The connection should be started with a call to Run, which will return once the connection has been terminated. The connection can be ended early by using Close.

func Connect

func Connect(addr string, config *tls.Config, srv *http.Server) (Conn, error)

Connect is used to perform connection reversal where the client (who is normally behind a NAT of some kind) connects to a server on the internet. The connection is then reversed so that the 'server' sends requests to the 'client'. See ConnectAndServe() for a blocking version of this

func NewClientConn

func NewClientConn(conn net.Conn, push Receiver, version float64) (spdyConn Conn, err error)

NewClientConn is used to create a SPDY connection, using the given net.Conn for the underlying connection, and the given Receiver to receive server pushes.

func NewServerConn

func NewServerConn(conn net.Conn, server *http.Server, version float64) (spdyConn Conn, err error)

NewServerConn is used to create a SPDY connection, using the given net.Conn for the underlying connection, and the given http.Server to configure the request serving.

type Decompressor

type Decompressor interface {
	Decompress([]byte) (http.Header, error)
}

Decompressor is used to decompress the text header of a SPDY frame.

func NewDecompressor

func NewDecompressor(version uint16) Decompressor

NewDecompressor is used to create a new decompressor. It takes the SPDY version to use.

type DefaultFlowControl

type DefaultFlowControl uint32

func (DefaultFlowControl) InitialWindowSize

func (f DefaultFlowControl) InitialWindowSize() uint32

func (DefaultFlowControl) ReceiveData

func (f DefaultFlowControl) ReceiveData(_ StreamID, initialWindowSize uint32, newWindowSize int64) uint32

type Flags

type Flags byte

Flags represent a frame's Flags.

func (Flags) CLEAR_SETTINGS

func (f Flags) CLEAR_SETTINGS() bool

CLEAR_SETTINGS indicates whether the CLEAR_SETTINGS flag is set.

func (Flags) FIN

func (f Flags) FIN() bool

FIN indicates whether the FIN flag is set.

func (Flags) PERSISTED

func (f Flags) PERSISTED() bool

PERSISTED indicates whether the PERSISTED flag is set.

func (Flags) PERSIST_VALUE

func (f Flags) PERSIST_VALUE() bool

PERSIST_VALUE indicates whether the PERSIST_VALUE flag is set.

func (Flags) UNIDIRECTIONAL

func (f Flags) UNIDIRECTIONAL() bool

UNIDIRECTIONAL indicates whether the UNIDIRECTIONAL flag is set.

type FlowControl

type FlowControl interface {
	InitialWindowSize() uint32
	ReceiveData(streamID StreamID, initialWindowSize uint32, newWindowSize int64) (deltaSize uint32)
}

Objects conforming to the FlowControl interface can be used to provide the flow control mechanism for a connection using SPDY version 3 and above.

InitialWindowSize is called whenever a new stream is created, and the returned value used as the initial flow control window size. Note that a values smaller than the default (65535) will likely result in poor network utilisation.

ReceiveData is called whenever a stream's window is consumed by inbound data. The stream's ID is provided, along with the stream's initial window size and the current window size after receiving the data that caused the call. If the window is to be regrown, ReceiveData should return the increase in size. A value of 0 does not change the window. Note that in SPDY/3.1 and later, the streamID may be 0 to represent the connection-level flow control window.

type Frame

type Frame interface {
	fmt.Stringer
	io.ReaderFrom
	io.WriterTo
	Compress(Compressor) error
	Decompress(Decompressor) error
	Name() string
}

Frame represents a single SPDY frame.

type Ping

type Ping struct{}

Ping is used in indicating the response from a ping request.

type Priority

type Priority byte

Priority represents a stream's priority.

func DefaultPriority

func DefaultPriority(url *url.URL) Priority

DefaultPriority returns the default request priority for the given target path. This is currently in accordance with Google Chrome; giving 0 for pages, 1 for CSS, 2 for JS, 3 for images. Other types default to 2.

func (Priority) Byte

func (p Priority) Byte(version uint16) byte

Byte returns the priority in binary form, adjusted for the given SPDY version.

func (Priority) Valid

func (p Priority) Valid(version uint16) bool

Valid indicates whether the priority is in the valid range for the given SPDY version.

type ProxyConnHandler

type ProxyConnHandler interface {
	ProxyConnHandle(Conn)
}

type ProxyConnHandlerFunc

type ProxyConnHandlerFunc func(Conn)

func (ProxyConnHandlerFunc) ProxyConnHandle

func (p ProxyConnHandlerFunc) ProxyConnHandle(c Conn)

type PushStream

type PushStream interface {
	Stream

	// Fin is used to close the
	// push stream once writing
	// has finished.
	Finish()
}

PushStream contains a single SPDY push stream.

func Push

func Push(w http.ResponseWriter, url string) (PushStream, error)

Push is used to send server pushes with SPDY servers. Push takes a ResponseWriter and the url of the resource being pushed, and returns a ResponseWriter to which the push should be written.

If the underlying connection is using HTTP, and not SPDY, Push will return the ErrNotSPDY error.

A simple example of pushing a file is:

     import (
             "github.com/SlyMarbo/spdy"
             "log"
             "net/http"
     )

     func httpHandler(w http.ResponseWriter, r *http.Request) {
             path := r.URL.Scheme + "://" + r.URL.Host + "/javascript.js"
             push, err := spdy.Push(w, path)
             if err != nil {
                     // Non-SPDY connection.
             } else {
                     http.ServeFile(push, r, "./javascript.js") // Push the given file.
											push.Finish()                              // Finish the stream once used.
             }

     }

     func main() {
             http.HandleFunc("/", httpHandler)
             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)
             }
     }

type Receiver

type Receiver interface {
	ReceiveData(request *http.Request, data []byte, final bool)
	ReceiveHeader(request *http.Request, header http.Header)
	ReceiveRequest(request *http.Request) bool
}

Objects implementing the Receiver interface can be registered to receive requests on the Client.

ReceiveData is passed the original request, the data to receive and a bool indicating whether this is the final batch of data. If the bool is set to true, the data may be empty, but should not be nil.

ReceiveHeaders is passed the request and any sent text headers. This may be called multiple times. Note that these headers may contain the status code of the response, under the ":status" header. If the Receiver is being used to proxy a request, and the headers presented to ReceiveHeader are copied to another ResponseWriter, take care to call its WriteHeader method after copying all headers, since this may flush headers received so far.

ReceiveRequest is used when server pushes are sent. The returned bool should inticate whether to accept the push. The provided Request will be that sent by the server with the push.

type Setting

type Setting struct {
	Flags Flags
	ID    uint32
	Value uint32
}

Setting represents a single setting as sent in a SPDY SETTINGS frame.

func (*Setting) String

func (s *Setting) String() string

String gives the textual representation of a Setting.

type Settings

type Settings map[uint32]*Setting

Settings represents a series of settings, stored in a map by setting ID. This ensures that duplicate settings are not sent, since the new value will replace the old.

func (Settings) Settings

func (s Settings) Settings() []*Setting

Settings returns a slice of Setting, sorted into order by ID, as in the SPDY specification.

type StatusCode

type StatusCode uint32

StatusCode represents a status code sent in certain SPDY frames, such as RST_STREAM and GOAWAY.

func (StatusCode) String

func (r StatusCode) String() string

String gives the StatusCode in text form.

type Stream

type Stream interface {
	http.CloseNotifier
	http.ResponseWriter
	io.ReadCloser
	Conn() Conn
	ReceiveFrame(Frame) error
	Run() error
	State() *StreamState
	StreamID() StreamID
}

Stream contains a single SPDY stream.

type StreamID

type StreamID uint32

StreamID is the unique identifier for a single SPDY stream.

func (StreamID) Client

func (s StreamID) Client() bool

Client indicates whether the ID should belong to a client-sent stream.

func (StreamID) Server

func (s StreamID) Server() bool

Server indicates whether the ID should belong to a server-sent stream.

func (StreamID) Valid

func (s StreamID) Valid() bool

Valid indicates whether the ID is in the range of legal values (including 0).

func (StreamID) Zero

func (s StreamID) Zero() bool

Zero indicates whether the ID is zero.

type StreamState

type StreamState struct {
	sync.RWMutex
	// contains filtered or unexported fields
}

StreamState is used to store and query the stream's state. The active methods do not directly affect the stream's state, but it will use that information to effect the changes.

func (*StreamState) Close

func (s *StreamState) Close()

Closes the stream.

func (*StreamState) CloseHere

func (s *StreamState) CloseHere()

Half-close the stream locally.

func (*StreamState) CloseThere

func (s *StreamState) CloseThere()

Half-close the stream at the other endpoint.

func (*StreamState) Closed

func (s *StreamState) Closed() bool

Check whether the stream is closed.

func (*StreamState) ClosedHere

func (s *StreamState) ClosedHere() bool

Check whether the stream is half-closed at the other endpoint.

func (*StreamState) ClosedThere

func (s *StreamState) ClosedThere() bool

Check whether the stream is half-closed at the other endpoint.

func (*StreamState) Open

func (s *StreamState) Open() bool

Check whether the stream is open.

func (*StreamState) OpenHere

func (s *StreamState) OpenHere() bool

Check whether the stream is open locally.

func (*StreamState) OpenThere

func (s *StreamState) OpenThere() bool

Check whether the stream is open at the other endpoint.

func (*StreamState) String

func (s *StreamState) String() string

State description.

type Transport

type Transport struct {

	// Proxy specifies a function to return a proxy for a given
	// Request. If the function returns a non-nil error, the
	// request is aborted with the provided error.
	// If Proxy is nil or returns a nil *URL, no proxy is used.
	Proxy func(*http.Request) (*url.URL, error)

	// Dial specifies the dial function for creating TCP
	// connections.
	// If Dial is nil, net.Dial is used.
	Dial func(network, addr string) (net.Conn, error) // TODO: use

	// TLSClientConfig specifies the TLS configuration to use with
	// tls.Client. If nil, the default configuration is used.
	TLSClientConfig *tls.Config

	// DisableKeepAlives, if true, prevents re-use of TCP connections
	// between different HTTP requests.
	DisableKeepAlives bool

	// DisableCompression, if true, prevents the Transport from
	// requesting compression with an "Accept-Encoding: gzip"
	// request header when the Request contains no existing
	// Accept-Encoding value. If the Transport requests gzip on
	// its own and gets a gzipped response, it's transparently
	// decoded in the Response.Body. However, if the user
	// explicitly requested gzip it is not automatically
	// uncompressed.
	DisableCompression bool

	// MaxIdleConnsPerHost, if non-zero, controls the maximum idle
	// (keep-alive) to keep per-host.  If zero,
	// DefaultMaxIdleConnsPerHost is used.
	MaxIdleConnsPerHost int

	// ResponseHeaderTimeout, if non-zero, specifies the amount of
	// time to wait for a server's response headers after fully
	// writing the request (including its body, if any). This
	// time does not include the time to read the response body.
	ResponseHeaderTimeout time.Duration

	// Priority is used to determine the request priority of SPDY
	// requests. If nil, spdy.DefaultPriority is used.
	Priority func(*url.URL) Priority

	// Receiver is used to receive the server's response. If left
	// nil, the default Receiver will parse and create a normal
	// Response.
	Receiver Receiver

	// PushReceiver is used to receive server pushes. If left nil,
	// pushes will be refused. The provided Request will be that
	// sent with the server push. See Receiver for more detail on
	// its methods.
	PushReceiver Receiver
	// contains filtered or unexported fields
}

A Transport is an HTTP/SPDY http.RoundTripper.

func (*Transport) RoundTrip

func (t *Transport) RoundTrip(req *http.Request) (*http.Response, error)

RoundTrip handles the actual request; ensuring a connection is made, determining which protocol to use, and performing the request.

Directories

Path Synopsis
examples
proxy_client command
proxy_server command

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL