Initial work for receiving HTTPU broadcasts.
This commit is contained in:
parent
ca8dc4faf5
commit
dcc00c8629
25
cmd/example_httpu_serving/example_httpu_serving.go
Normal file
25
cmd/example_httpu_serving/example_httpu_serving.go
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/huin/goupnp/httpu"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
eth0, err := net.InterfaceByName("eth0")
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
srv := httpu.Server{
|
||||||
|
Addr: "239.255.255.250:1900",
|
||||||
|
Interface: eth0,
|
||||||
|
Handler: httpu.HandlerFunc(func(r *http.Request) {
|
||||||
|
log.Printf("Got %s %s message from %v: %v", r.Method, r.URL.Path, r.RemoteAddr, r.Header)
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
err = srv.ListenAndServe()
|
||||||
|
log.Printf("Serving failed with error: %v", err)
|
||||||
|
}
|
106
httpu/serve.go
Normal file
106
httpu/serve.go
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package httpu
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"bytes"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"net/http"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
DefaultMaxMessageBytes = 2048
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
trailingWhitespaceRx = regexp.MustCompile(" +\r\n")
|
||||||
|
crlf = []byte("\r\n")
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handler is the interface by which received HTTPU messages are passed to
|
||||||
|
// handling code.
|
||||||
|
type Handler interface {
|
||||||
|
// ServeMessage is called for each HTTPU message received. peerAddr contains
|
||||||
|
// the address that the message was received from.
|
||||||
|
ServeMessage(r *http.Request)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HandlerFunc is a function-to-Handler adapter.
|
||||||
|
type HandlerFunc func(r *http.Request)
|
||||||
|
|
||||||
|
func (f HandlerFunc) ServeMessage(r *http.Request) {
|
||||||
|
f(r)
|
||||||
|
}
|
||||||
|
|
||||||
|
// A Server defines parameters for running an HTTPU server.
|
||||||
|
type Server struct {
|
||||||
|
Addr string // UDP address to listen on
|
||||||
|
Interface *net.Interface // Network interface to listen on
|
||||||
|
Handler Handler // handler to invoke
|
||||||
|
MaxMessageBytes int // maximum number of bytes to read from a packet, DefaultMaxMessageBytes if 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListenAndServe listens on the UDP network address srv.Addr. If srv.Interface
|
||||||
|
// != nil, then a multicast UDP listener will be used on the given interface.
|
||||||
|
func (srv *Server) ListenAndServe() error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
var addr *net.UDPAddr
|
||||||
|
if addr, err = net.ResolveUDPAddr("udp", srv.Addr); err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var conn net.PacketConn
|
||||||
|
if srv.Interface != nil {
|
||||||
|
if conn, err = net.ListenMulticastUDP("udp", srv.Interface, addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if conn, err = net.ListenUDP("udp", addr); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return srv.Serve(conn)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve messages received on the given packet listener to the srv.Handler.
|
||||||
|
func (srv *Server) Serve(l net.PacketConn) error {
|
||||||
|
maxMessageBytes := DefaultMaxMessageBytes
|
||||||
|
if srv.MaxMessageBytes != 0 {
|
||||||
|
maxMessageBytes = srv.MaxMessageBytes
|
||||||
|
}
|
||||||
|
for {
|
||||||
|
buf := make([]byte, maxMessageBytes)
|
||||||
|
n, peerAddr, err := l.ReadFrom(buf)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
buf = buf[:n]
|
||||||
|
|
||||||
|
go func(buf []byte, peerAddr net.Addr) {
|
||||||
|
// At least one router's UPnP implementation has added a trailing space
|
||||||
|
// after "HTTP/1.1" - trim it.
|
||||||
|
buf = trailingWhitespaceRx.ReplaceAllLiteral(buf, crlf)
|
||||||
|
|
||||||
|
req, err := http.ReadRequest(bufio.NewReader(bytes.NewBuffer(buf)))
|
||||||
|
if err != nil {
|
||||||
|
log.Printf("httpu: Failed to parse request: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
req.RemoteAddr = peerAddr.String()
|
||||||
|
srv.Handler.ServeMessage(req)
|
||||||
|
// No need to call req.Body.Close - underlying reader is bytes.Buffer.
|
||||||
|
}(buf, peerAddr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Serve messages received on the given packet listener to the given handler.
|
||||||
|
func Serve(l net.PacketConn, handler Handler) error {
|
||||||
|
srv := Server{
|
||||||
|
Handler: handler,
|
||||||
|
MaxMessageBytes: DefaultMaxMessageBytes,
|
||||||
|
}
|
||||||
|
return srv.Serve(l)
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user