-
Notifications
You must be signed in to change notification settings - Fork 23
/
http.go
84 lines (76 loc) · 2.38 KB
/
http.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
// Package http implements an HTTP server for iPXE binaries.
package http
import (
"context"
"net"
"net/http"
"path"
"path/filepath"
"strings"
"unicode/utf8"
"github.com/go-logr/logr"
"github.com/tinkerbell/boots-ipxe/binary"
"inet.af/netaddr"
)
// Handler is the struct that implements the http.Handler interface.
type Handler struct {
Log logr.Logger
}
// ListenAndServe is a patterned after http.ListenAndServe.
// It listens on the TCP network address srv.Addr and then
// calls ServeHTTP to handle requests on incoming connections.
//
// ListenAndServe always returns a non-nil error. After Shutdown or Close,
// the returned error is http.ErrServerClosed.
func ListenAndServe(ctx context.Context, addr netaddr.IPPort, h *http.Server) error {
conn, err := net.Listen("tcp", addr.String())
if err != nil {
return err
}
return Serve(ctx, conn, h)
}
// Serve is patterned after http.Serve.
// It accepts incoming connections on the Listener conn and serves them
// using the Server h.
//
// Serve always returns a non-nil error and closes conn.
// After Shutdown or Close, the returned error is http.ErrServerClosed.
func Serve(_ context.Context, conn net.Listener, h *http.Server) error {
return h.Serve(conn)
}
func trimFirstRune(s string) string {
_, i := utf8.DecodeRuneInString(s)
return s[i:]
}
// Handle handles responses to HTTP requests.
func (s Handler) Handle(w http.ResponseWriter, req *http.Request) {
s.Log.V(1).Info("handling request", "method", req.Method, "path", req.URL.Path)
if req.Method != "GET" {
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
return
}
host, port, _ := net.SplitHostPort(req.RemoteAddr)
s.Log = s.Log.WithValues("host", host, "port", port)
m := path.Dir(req.URL.Path)
if strings.HasPrefix(m, "/") {
m = trimFirstRune(path.Dir(req.URL.Path))
}
// If a mac address is provided, log it. Mac address is optional.
// Mac address would be useful for logging and tracing.
mac, _ := net.ParseMAC(m)
s.Log = s.Log.WithValues("mac", mac)
got := filepath.Base(req.URL.Path)
file, found := binary.Files[got]
if !found {
s.Log.Info("requested file not found", "file", got)
http.NotFound(w, req)
return
}
b, err := w.Write(file)
if err != nil {
s.Log.Error(err, "error serving file")
w.WriteHeader(http.StatusInternalServerError)
return
}
s.Log.Info("file served", "bytes sent", b, "file size", len(file), "file", got)
}