84 lines
2.3 KiB
Go
84 lines
2.3 KiB
Go
// Package web serves the pcap tools web UI.
|
|
package web
|
|
|
|
import (
|
|
"bytes"
|
|
"embed"
|
|
"html/template"
|
|
"io/fs"
|
|
"log"
|
|
"net/http"
|
|
)
|
|
|
|
//go:embed templates static
|
|
var assets embed.FS
|
|
|
|
// Tool is one sub-application, listed on the index page and in the navigation.
|
|
type Tool struct {
|
|
Name string
|
|
Path string
|
|
Description string
|
|
}
|
|
|
|
var tools = []Tool{
|
|
{Name: "Hex → pcap", Path: "/hex2pcap", Description: "Build a pcap file from hex-encoded layer 2, layer 3 and payload bytes, optionally fixing IP lengths and checksums."},
|
|
}
|
|
|
|
// Server is the HTTP handler for the whole application.
|
|
type Server struct {
|
|
mux *http.ServeMux
|
|
pages map[string]*template.Template
|
|
}
|
|
|
|
// New parses the templates and sets up the routes.
|
|
func New() (*Server, error) {
|
|
s := &Server{mux: http.NewServeMux(), pages: map[string]*template.Template{}}
|
|
|
|
// Each page is parsed together with the shared layout so pages can define
|
|
// their own "title" and "content" blocks.
|
|
for _, page := range []string{"index.html", "hex2pcap.html"} {
|
|
t, err := template.New(page).ParseFS(assets, "templates/layout.html", "templates/"+page)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.pages[page] = t
|
|
}
|
|
|
|
static, err := fs.Sub(assets, "static")
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
s.mux.Handle("GET /static/", http.StripPrefix("/static/", http.FileServerFS(static)))
|
|
s.mux.HandleFunc("GET /{$}", s.handleIndex)
|
|
s.mux.HandleFunc("GET /hex2pcap", s.handleHex2PcapForm)
|
|
s.mux.HandleFunc("POST /hex2pcap", s.handleHex2Pcap)
|
|
return s, nil
|
|
}
|
|
|
|
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
|
s.mux.ServeHTTP(w, r)
|
|
}
|
|
|
|
// pageData is passed to every page template.
|
|
type pageData struct {
|
|
Tools []Tool
|
|
Active string // path of the current tool, for nav highlighting
|
|
Data any // page specific data
|
|
}
|
|
|
|
func (s *Server) render(w http.ResponseWriter, status int, page, active string, data any) {
|
|
var buf bytes.Buffer
|
|
if err := s.pages[page].ExecuteTemplate(&buf, "layout", pageData{Tools: tools, Active: active, Data: data}); err != nil {
|
|
log.Printf("render %s: %v", page, err)
|
|
http.Error(w, "internal error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
|
w.WriteHeader(status)
|
|
w.Write(buf.Bytes())
|
|
}
|
|
|
|
func (s *Server) handleIndex(w http.ResponseWriter, r *http.Request) {
|
|
s.render(w, http.StatusOK, "index.html", "/", nil)
|
|
}
|