mux

package module
v0.3.0 Latest Latest
Warning

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

Go to latest
Published: Jun 9, 2023 License: BSD-3-Clause Imports: 11 Imported by: 0

README

mux - Multiplexer for HTTP requests

This Go language module supports a multiplexer for HTTP requests that extends the pattern language of the ServeMux multiplexer of the net/http package of the Go standard library. The module supports now method selectors and wildcard variables in request pattern.

Those improvements have been proposed in a discussion of the Go language Github repository.

The implementation is fully functional, but not widely tested. Please report any issues in the mux Github repo.

The documentation can be found at https://pkg.go.dev/github.com/ulikunitz/mux.

Installation

Import it in your program and run

$ go get github.com/ulikunitz/mux

if required.

This code contains small subroutines from the Go net/http package. I added the Go Authors copyright to the BSD 3-Clause license.

Documentation

Overview

Package mux implements a multiplexer for http requests. The multiplexer may replace http.ServeMux because it extends the pattern language by HTTP methods and wildcard variables. Those variables can be accessed by the selected HTTP request handlers, saving the handlers from parsing the path again. Those improvements are discussed in a Go language discussion.

The multiplexer is fully functional. It is not widely tested and has not been optimized. Please report any issues you may encounter in module repo

The multiplexer can be simply declared.

var m mux.Mux

The multiplexer supports the ServeHTTP method, so it can be used everywhere a net/http.Handler can be used.

The methods Mux.Handle and Mux.HandleFunc register a net/http.Handler or a handler function for a specific pattern. The patterns supported by net/http.ServeMux can be used without modification.

A new feature is the support for methods, which need to precede host/path pattern by a space.

m.Handle("GET example.org/images/", imagesHandler)

The methods GET, HEAD, POST, PATCH, PUT, CONNECT, OPTIONS and TRACE are supported.

The other new feature is the support for wildcard variable names, which can replace the method, host or segments in the path component.

m.Handle("{method}  {host}/buckets/{bucketID}/objects/{objectID}", h)

Suffix wildcards are can be used additionally, which capture the rest of the request path.

m.Handle("/users/{userSpec...}", h)

If the wildcard doesn't define a variable name, it acts still as a wildcard but will not capture it. So following calls to Handle are valid.

m.Handle("{} {}/buckets/{bucketID}/objects/{}". h)
m.Handle("{} {host}/users/{...}", h)

The multiplexer allows different variables at the same position.

m.Handle("/buckets/{bucket2ID}/objects/{objectID}", h2o)
m.Handle("/buckets/{bucket1ID}/objects/{objectID}", h1o)
m.Handle("/buckets/{bucket2ID}/meta/", h2m)

However the variables will be ordered in lexicographically order. The multiplexer will route the a request with path /buckets/1/objects/1 always to the handler h1o. The handler h2o will not be reachable. However a request with path /buckets/1/meta/green will be routed to h2m.

The order of the pattern resolution is independent of the order of the Handle calls. A consequence is that redundant patterns lead to panics, if they would simply overwrite the handlers the sequence of the callers would influence the resolution.

The multiplexer doesn't support two suffix wildcards with different variables. Following calls will lead to a panic of the second call.

m.Handle("/users/{userSpec...}", h1)
m.Handle("/users/{uSpec...}", h2) // Call will panic!

The multiplexer keeps the redirect logic of a path /images to /images/ if only the second pattern has been registered. This is also valid for suffix wildcards as in /images/{imageSpec...}.

The multiplexer supports a special marker {$}. The pattern registered with

m.Handle("/{$}", h1)

will only resolve calls to a path with a single slash because

m.Handle("/", h2)

will resolve to all requests unless other patterns have been registered. The multiplexer always prefers the most specific pattern that matches.

The handler can access the wildcard variables by calling the Vars function on the provided request value. The returned map is always initialized, if no variables have been matched the map will be empty.

vmap := mux.Vars(request)
log.Printf("bucketID: %s", vmap["bucketID"])
log.Printf("objectID: %s", vmap["objectID"])

If the path cannot be found the multiplexer returns 404 page not found. If the method is unsupported, the status returned is 405 method not allowed.

Example
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"
	"net/http/httptest"

	"github.com/ulikunitz/mux"
)

func main() {
	type out struct {
		Method string
		Path   string
		VarMap map[string]string
	}

	h := func(w http.ResponseWriter, r *http.Request) {
		header := w.Header()
		header.Set("Content-Type", "application/json")
		out := out{
			Method: r.Method,
			Path:   r.URL.Path,
			VarMap: mux.Vars(r),
		}
		data, err := json.MarshalIndent(&out, "", "  ")
		if err != nil {
			http.Error(w, fmt.Sprintf("error %s", err),
				http.StatusInternalServerError)
			return
		}

		_, err = w.Write(data)
		if err != nil {
			panic(fmt.Errorf("w.Write(data) error %s", err))

		}
	}

	m := new(mux.Mux)
	m.HandleFunc("{method} /item/{itemNr}", h)
	m.HandleFunc("/foo/{remainder...}", h)

	ts := httptest.NewTLSServer(m)
	defer ts.Close()

	client := ts.Client()
	url := ts.URL + "/item/1"
	resp, err := client.Get(url)
	if err != nil {
		log.Fatalf("client.Get(%q) error %s", url, err)
	}
	defer resp.Body.Close()

	data, err := io.ReadAll(resp.Body)
	if err != nil {
		log.Fatalf("io.ReadAll(resp.Body) error %s", err)
	}

	fmt.Printf("%s", data)
}
Output:

{
  "Method": "GET",
  "Path": "/item/1",
  "VarMap": {
    "itemNr": "1",
    "method": "GET"
  }
}

Index

Examples

Constants

This section is empty.

Variables

View Source
var ErrPattern = errors.New("mux: invalid pattern")

ErrPattern indicates that an invalid pattern has been provided. The errors provided by the panics of the Mux.Handle and Mux.HandleFunc methods wrap this error.

Functions

func Vars

func Vars(r *http.Request) map[string]string

Vars retrieves the wildcard variable map from the request. The function returns always an initialized map, which may be empty.

Types

type Mux

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

Mux is the type for the multiplexer. It holds a tree resolving all patterns provided.

func (*Mux) Handle

func (mux *Mux) Handle(pattern string, handler http.Handler)

Handle registers the provided handler for the given pattern. The function might panic if the patterns contain errors or are redundant. The sequence of the Handle calls has no influence on the pattern resolution. (Note that this condition would be violated, if redundant patterns would not cause a panic.)

func (*Mux) HandleFunc

func (mux *Mux) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))

HandleFunc registers the handler function handler with the given pattern. It calls Mux.Handle and supports the semantics for the pattern.

func (*Mux) HandlerReq

func (mux *Mux) HandlerReq(r *http.Request) (h http.Handler, pattern string, s *http.Request)

HandlerReq returns the handler and possibly a new request. The return of the request is required because the variable segment map has to be attached to the context of the request.

func (*Mux) ServeHTTP

func (mux *Mux) ServeHTTP(w http.ResponseWriter, r *http.Request)

ServeHTTP provides the http.Handler functionality for the mux.

Directories

Path Synopsis
cmd
server
Server provides an example TLS server to test the new mux in a realistic environment.
Server provides an example TLS server to test the new mux in a realistic environment.

Jump to

Keyboard shortcuts

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