Documentation ¶
Overview ¶
Package uhttp provides a transport for HTTP over UDP. It implements http.RoundTripper so that it can plug in to stock Go HTTP libraries.
Caveat: No real standard for HTTP over UDP exists. This may not work well for all protocols that look like HTTP over UDP.
Index ¶
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var DefaultClient = &Client{ Transport: DefaultTransport, }
DefaultClient is the Client used by the top-level Do and Get functions.
var ErrTimeout error = timeoutErr("timeout waiting for responses")
var Stop = errors.New("stop processing")
Functions ¶
func Do ¶
func Do(r *http.Request, wait time.Duration, fn func(sender net.Addr, resp *http.Response) error) error
Do issues r via DefaultClient, waits up to wait, and delivers any responses received to fn. If an error occurs, fn returns an error, or r.Context() expires, execution will return immediately. The sentinal error Stop may be returned by fn to cause Do to return immediately with no error.
Types ¶
type Client ¶
type Client struct {
Transport RoundTripMultier
}
Client is an HTTP over UDP client. It is largely a simplistic wrapper over RoundTripMultier, meant to ease use for people familiar with http.Client.
Example (SSDP) ¶
package main import ( "fmt" "net" "net/http" "os" "strings" "time" "github.com/dnesting/uhttp" ) func main() { // This example performs an SSDP M-SEARCH to the local Multicast SSDP address. // It uses the uhttp.Client so as to receive multiple responses, but this same // transport could be used with a stock http.Client is you're OK only getting // the first response. client := uhttp.Client{ Transport: &uhttp.Transport{ // SSDP requires upper-case header names HeaderCanon: func(n string) string { return strings.ToUpper(n) }, Repeat: uhttp.RepeatAfter(50*time.Millisecond, 1), }, } // Build M-SEARCH request req, _ := http.NewRequest("M-SEARCH", "", nil) req.URL.Host = "239.255.255.250:1900" req.URL.Path = "*" req.Header.Add("MAN", `"ssdp:discover"`) req.Header.Add("MX", "1") req.Header.Add("ST", "upnp:rootdevice") req.Header.Add("CPFN.UPNP.ORG", "Test") err := client.Do(req, 3*time.Second, func(sender net.Addr, resp *http.Response) error { fmt.Printf("From %s:\n", sender) resp.Write(os.Stdout) fmt.Println("---") return nil }) if err != nil { fmt.Printf("error: %s\n", err) } }
Output:
func (*Client) Do ¶
func (c *Client) Do(r *http.Request, wait time.Duration, fn func(sender net.Addr, resp *http.Response) error) error
Do issues r, waits up to wait, and delivers any responses received to fn. If an error occurs, fn returns an error, or r.Context() expires, execution will return immediately. The sentinal error Stop may be returned by fn to cause Do to return immediately with no error.
func (*Client) Get ¶
func (c *Client) Get(url string, wait time.Duration, fn func(sender net.Addr, resp *http.Response) error) error
Get makes a GET request for url, waits up to wait, and delivers any responses received to fn. If an error occurs, or fn returns an error, execution will return immediately. The sentinal error Stop may be returned by fn to cause Get to return immediately with no error.
type RepeatFunc ¶
RepeatFunc generates delays between successive repeats of a request. prev will contain the value of the previous repeat (zero for the first). It should return nil to stop repeating, and should not be called after that.
type RepeatGenerator ¶
type RepeatGenerator func() RepeatFunc
RepeatGenerator produces RepeatFuncs.
func RepeatAfter ¶
func RepeatAfter(delay time.Duration, num int) RepeatGenerator
RepeatAfter generates a RepeatFunc that returns delay num times, and then returns nil. If num is <= 0, this will return delay forever.
func RepeatJoin ¶
func RepeatJoin(gens ...RepeatGenerator) RepeatGenerator
RepeatJoin generates a RepeatFunc that iterates over gens, instantiates RepeatFuncs from them, and returns values from each until they return nil, at which point it moves on to the next RepeatFunc. Returns nil once all resulting RepeatFunc instances have returned nil.
Example ¶
tenHzFor3 := RepeatAfter(time.Second/10, 3) oneHz := RepeatAfter(time.Second, 0) joined := RepeatJoin(tenHzFor3, oneHz)() for i := 0; i < 6; i++ { next := joined(0) if next == nil { break } fmt.Println(*next) }
Output: 100ms 100ms 100ms 1s 1s 1s
func RepeatRandom ¶
func RepeatRandom(low, high time.Duration, num int) RepeatGenerator
RepeatRandom generates a RepeatFunc that returns a random duration between [low, high), num times, and then returns nil. If num is 0, this will return delays forever.
type RoundTripMultier ¶
type RoundTripMultier interface { http.RoundTripper // RoundTripMulti is responsible for delivering req, and waiting for responses to arrive. For // each response received, fn will be invoked so that the caller can process it. This method will // return when wait is reached (if non-zero), req.Context() expires, or an error occurs. The fn // implementation may return the sentinal error Stop to halt processing without causing // RoundTripMulti to return an error. RoundTripMulti(req *http.Request, wait time.Duration, fn func(sender net.Addr, res *http.Response) error) error }
var DefaultTransport RoundTripMultier = &Transport{ MaxSize: defaultPacketSize, WaitTime: 3 * time.Second, }
type Transport ¶
type Transport struct { // MaxSize is the maximum allowable size of an HTTP Request. It cannot be larger than 64k (UDP limit). // A zero value will use the default of 8k. MaxSize int // WaitTime is the default time we will spend waiting for HTTP responses before returning. A zero // value means wait forever. WaitTime time.Duration // HeaderCanon provides the canonical header name for the given header. If this function returns an // empty string, the header will be omitted. This is used when precise control over the case of the // resulting HTTP headers is needed. Filtering headers such as "Host" may break compatibility with // HTTP/1.1 (but let's face it, none of this is standard). HeaderCanon func(name string) string // Repeat enables requests to be repeated, according to the delays returned by the resulting // RepeatFunc. Repeat RepeatGenerator // contains filtered or unexported fields }
Transport implements http.RoundTripper and RoundTripMultier and allows for sending HTTP requests over UDP. It supports both unicast and multicast destinations.
Example (SSDP) ¶
package main import ( "fmt" "net/http" "os" "strings" "time" "github.com/dnesting/uhttp" ) func main() { // This example performs an SSDP M-SEARCH to the local Multicast SSDP address. // It leverages the stock Go http.Client with uhttp.Transport. Only the first // response will be returned. client := http.Client{ Transport: &uhttp.Transport{ // SSDP requires upper-case header names HeaderCanon: func(n string) string { return strings.ToUpper(n) }, WaitTime: 2 * time.Second, Repeat: uhttp.RepeatAfter(50*time.Millisecond, 1), }, } // Build M-SEARCH request req, _ := http.NewRequest("M-SEARCH", "", nil) req.URL.Host = "239.255.255.250:1900" req.URL.Path = "*" req.Header.Add("MAN", `"ssdp:discover"`) req.Header.Add("MX", "1") req.Header.Add("ST", "upnp:rootdevice") req.Header.Add("CPFN.UPNP.ORG", "Test") // Leverage stock http.Client to actually do the work. resp, err := client.Do(req) if err != nil { fmt.Printf("error: %s\n", err) } else { resp.Write(os.Stdout) } }
Output:
func (*Transport) RoundTrip ¶
RoundTrip issues a UDP HTTP request and waits for a single response. Returns when a response was received, when the req.Context() expires, or when t.MaxWait is reached (if non-zero).
func (*Transport) RoundTripMulti ¶
func (t *Transport) RoundTripMulti(req *http.Request, wait time.Duration, fn func(sender net.Addr, r *http.Response) error) (err error)
RoundTripMulti issues a UDP HTTP request and calls fn for each response received. Returns when wait is reached (no error), req.Context() expires, an error occurs, or when fn returns an error. The sentinal error Stop may be returned by fn to cause this method to return immediately without error.