push

package module
v0.0.0-...-99b0e25 Latest Latest
Warning

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

Go to latest
Published: Mar 25, 2017 License: MIT Imports: 17 Imported by: 0

README

Push Build Status GoDoc Coverage Status

Push is a package that uses HTTP2 to push resources to the client as it parses content. By parsing HTML, CSS and SVG it extracts referenced resource URIs and pushes them towards the client, which is quicker than waiting for the client to parse and request those resources.

Installation

You need Go1.8 (from tip for example).

Run the following command

go get github.com/tdewolff/push

or add the following import and run the project with go get

import (
	"github.com/tdewolff/push"
)

Parsers

HTML

Parses

  • <style>...</style> as CSS
  • <x style="..."> as inline CSS
  • <iframe>...</iframe> as HTML
  • <svg>...</svg> as SVG

Extracts URIs from

  • <link href="...">
  • <script src="...">
  • <img src="...">
  • <img srcset="..., ...">
  • <object data="...">
  • <source src="...">
  • <audio src="...">
  • <video src="...">
  • <track src="...">
  • <embed src="...">
  • <input src="...">
  • <iframe src="...">
CSS

Parses

  • url(data:image/svg+xml,...) as SVG data URI SVGs are not allowed to load external resources

Extracts URIs from

  • url("...")
SVG

Parses

  • <style>...</style> as CSS
  • <x style="..."> as inline CSS

Extracts URIs from

  • <script href="..." xlink:href="...">
  • <image href="..." xlink:href="...">
  • <feImage href="..." xlink:href="...">
  • <color-profile href="..." xlink:href="...">
  • <use href="..." xlink:href="...">

Usage

Middleware
fileOpener := push.DefaultFileOpener("resources/")
cache := push.DefaultCache()
p := push.New("example.com/", fileOpener, cache)
http.HandleFunc("/", p.Middleware(func(w http.ResponseWriter, r *http.Request) {
	// ...
}))

Pass nil for fileOpener and cache to disable recursive parsing and URI caching respectively.

ResponseWriter

Wrap an existing http.ResponseWriter so that it pushes resources automatically:

fileOpener := push.DefaultFileOpener("resources/")
cache := push.DefaultCache()
p := push.New("example.com/", fileOpener, cache)
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
	if pushWriter, err := p.ResponseWriter(w, r); err == nil {
		defer pushWriter.Close() // Close returns an error...
		w = pushWriter
	}

	// ...
})

Pass nil for fileOpener and cache to disable recursive parsing and URI caching respectively.

Reader

Wrap a reader and obtain the URIs from a channel:

func openIndex() io.Reader {
	r, _ := os.Open("index.html")

	uriHandler := push.URIHandlerFunc(func(uri string) error {
		// is called concurrently when using a recursive parser
		return nil
	})
	fileOpener := push.FileOpenerFunc(func(uri string) (io.Reader, string, error) {
		// open file for uri
		return r, mimetype, nil
	})
	parser := push.NewParser("example.com/", fileOpener, uriHandler)

	return p.Reader(r, parser, "text/html", "/index.html")
}
List

List the resource URIs found:

r, _ := os.Open("index.html")

uris, err := push.List("example.com/", fileOpener, r, "text/html", "/index.html")
if err != nil {
	panic(err)
}
Low-level usage

Push pushes resources to pusher. It is the underlying functionality of ResponseWriter.

httpPusher, ok := w.(http.Pusher)
if ok {
	pusher := NewPusher(httpPusher, &http.PushOptions{"", http.Header{}})

	parser, err := push.NewParser("example.com/", nil, pusher)
	if err != nil {
		panic(err)
	}

	tr := io.TeeReader(r, w)
	err := parser.Parse(r, "text/html", "/index.html")
}

Example

See example, it shows how a webserver with artificial 50ms delay per request can have the page load time reduced from 1.6s (http) to 0.4s (https).

License

Released under the MIT license.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrNoParser = errors.New("mimetype has no parser")

ErrNoParser is returned when the mimetype has no parser specified.

View Source
var ErrNoPusher = errors.New("ResponseWriter is not a Pusher")

ErrNoPusher is returned when the ResponseWriter does not implement the Pusher interface.

View Source
var ErrRecursivePush = errors.New("recursive push")

ErrRecursivePush is returned when the request was initiated by a push. This is determined via the X-Pushed header.

View Source
var ExtToMimetype = map[string]string{
	"":      "text/html",
	".html": "text/html",
	".css":  "text/css",
	".svg":  "image/svg+xml",
}

ExtToMimetype is an extension -> mimetype mapping used in ResponseWriter when the Content-Type header is not set.

Functions

func List

func List(baseURL string, opener FileOpener, r io.Reader, mimetype, uri string) ([]string, error)

List parses r with mimetype and served by uri. It returns a list of local resource URIs. If FileOpener is not nil, it will read and parse the referenced URIs recursively.

func Reader

func Reader(r io.Reader, parser *Parser, mimetype, uri string) io.Reader

Reader wraps an io.Reader that parses r with mimetype and served by uri. Any reads done at the returned reader will be parsed concurrently.

func Writer

func Writer(w io.Writer, parser *Parser, mimetype, uri string) *pushingWriter

Types

type Cache

type Cache interface {
	Get(string) ([]string, bool)
	Add(string, string)
	Del(string)
}

Cache is an interface that allows Middleware and ResponseWriter to cache the results of the list of resources to improve performance.

type DefaultCache

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

func NewDefaultCache

func NewDefaultCache() *DefaultCache

func (*DefaultCache) Add

func (c *DefaultCache) Add(uri string, resource string)

func (*DefaultCache) Del

func (c *DefaultCache) Del(uri string)

func (*DefaultCache) Get

func (c *DefaultCache) Get(uri string) ([]string, bool)

type DefaultFileOpener

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

func NewDefaultFileOpener

func NewDefaultFileOpener(basePath string) *DefaultFileOpener

func (*DefaultFileOpener) Open

func (o *DefaultFileOpener) Open(uri string) (io.Reader, string, error)

type FileOpener

type FileOpener interface {
	Open(string) (io.Reader, string, error)
}

FileOpener is an interface that allows the parser to load embedded resources recursively.

type FileOpenerFunc

type FileOpenerFunc func(string) (io.Reader, string, error)

func (FileOpenerFunc) Open

func (f FileOpenerFunc) Open(uri string) (io.Reader, string, error)

type ListHandler

type ListHandler struct {
	URIs []string
	// contains filtered or unexported fields
}

ListHandler is a URIHandler that collects all resource URIs in a list.

func NewListHandler

func NewListHandler() *ListHandler

func (*ListHandler) URI

func (h *ListHandler) URI(uri string) error

type P

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

func New

func New(baseURL string, opener FileOpener, cache Cache) *P

func (*P) Middleware

func (p *P) Middleware(next http.Handler) http.Handler

Middleware wraps an http.Handler and pushes local resources to the client. If FileOpener is not nil, it will read and parse the referenced URIs recursively. If Cache is not nil, it will cache the URIs found and use it on subsequent requests.

func (*P) ResponseWriter

func (p *P) ResponseWriter(w http.ResponseWriter, r *http.Request) (ResponseWriterCloser, error)

ResponseWriter wraps a ResponseWriter interface. It parses anything written to the returned ResponseWriter and pushes local resources to the client. If FileOpener is not nil, it will read and parse the referenced URIs recursively. If Cache is not nil, it will cache the URIs found and use it on subsequent requests. ResponseWriter can only return ErrNoPusher, ErrRecursivePush or ErrNoParser errors. Parsing errors are returned by Close on the writer. The writer must be closed explicitly.

type Parser

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

Parser parses resources and calls uriHandler for all found URIs.

func NewParser

func NewParser(rawBaseURL string, opener FileOpener, uriHandler URIHandler) (*Parser, error)

NewParser returns a new Parser. rawBaseURL defines the prefix an URL must have to be considered a local resource. If FileOpener is not nil, it will read and parse the referenced URIs recursively.

func (*Parser) IsRecursive

func (p *Parser) IsRecursive() bool

IsRecursive returns true when the URIs within documents are aso read and parsed.

func (*Parser) Parse

func (p *Parser) Parse(r io.Reader, mimetype, uri string) error

Parse parses r with mimetype and served by uri. When Parser is recursive, it will be blocking until all resources are parsed.

type PushHandler

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

PushHandler is a URIHandler that pushes resources to the client.

func NewPushHandler

func NewPushHandler(pusher http.Pusher, opts *http.PushOptions) *PushHandler

func NewPushHandlerFromResponseWriter

func NewPushHandlerFromResponseWriter(w http.ResponseWriter) (*PushHandler, error)

func (*PushHandler) URI

func (p *PushHandler) URI(uri string) error

type ResponseWriterCloser

type ResponseWriterCloser interface {
	http.ResponseWriter
	Close() error
}

ResponseWriterCloser makes sure that all data has been written on calling Close (can be blocking).

type URIHandler

type URIHandler interface {
	URI(string) error
}

URIHandler is a callback definition that is called when a resource URI is found.

type URIHandlerFunc

type URIHandlerFunc func(string) error

func (URIHandlerFunc) URI

func (f URIHandlerFunc) URI(uri string) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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