2025-11-08 16:17:55 +01:00

151 lines
3.4 KiB
Go

package main
import (
"html/template"
"io"
"log"
"net/http"
)
// RequestData holds all the information we want to display about a request
type RequestData struct {
Method string
URL string
Protocol string
Scheme string
Host string
Path string
RawQuery string
QueryParams map[string][]string
Headers map[string][]string
Body string
HasQuery bool
}
// collectRequestData extracts all relevant information from the HTTP request
func collectRequestData(r *http.Request) (*RequestData, error) {
body, err := io.ReadAll(r.Body)
if err != nil {
return nil, err
}
defer r.Body.Close()
bodyString := string(body)
if len(bodyString) == 0 {
bodyString = "(empty)"
}
data := &RequestData{
Method: r.Method,
URL: r.URL.String(),
Protocol: r.Proto,
Scheme: r.URL.Scheme,
Host: r.Host,
Path: r.URL.Path,
RawQuery: r.URL.RawQuery,
QueryParams: r.URL.Query(),
Headers: r.Header,
Body: bodyString,
HasQuery: len(r.URL.Query()) > 0,
}
return data, nil
}
const echoTemplate = `
<div id="echo">
<div >
<h1>Request Echo</h1>
<div >
<h2>Request Line</h2>
<p><span class="label">Method:</span><span class="value">{{.Method}}</span></p>
<p><span class="label">URL:</span><span class="value">{{.URL}}</span></p>
<p><span class="label">Protocol:</span><span class="value">{{.Protocol}}</span></p>
</div>
<div >
<h2>URL Components</h2>
<p><span class="label">Scheme:</span><span class="value">{{.Scheme}}</span></p>
<p><span class="label">Host:</span><span class="value">{{.Host}}</span></p>
<p><span class="label">Path:</span><span class="value">{{.Path}}</span></p>
<p><span class="label">RawQuery:</span><span class="value">{{.RawQuery}}</span></p>
</div>
<div >
<h2>Query Parameters</h2>
{{if .HasQuery}}
{{range $key, $values := .QueryParams}}
{{range $values}}
<p><span class="label">{{$key}}:</span><span class="value">{{.}}</span></p>
{{end}}
{{end}}
{{else}}
<p>No query parameters</p>
{{end}}
</div>
<div >
<h2>Headers</h2>
<table>
<tr>
<th>Header</th>
<th>Value</th>
</tr>
{{range $name, $values := .Headers}}
<tr>
<td>{{$name}}</td>
<td>{{range $i, $v := $values}}{{if $i}}, {{end}}{{$v}}{{end}}</td>
</tr>
{{end}}
</table>
</div>
<div >
<h2>Body</h2>
<pre>{{.Body}}</pre>
</div>
</div>
</div>
`
var tmpl *template.Template
func init() {
var err error
tmpl, err = template.New("echo").Parse(echoTemplate)
if err != nil {
log.Fatal("Error parsing template:", err)
}
}
func echoHandler(w http.ResponseWriter, r *http.Request) {
data, err := collectRequestData(r)
if err != nil {
http.Error(w, "Error reading request body", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "text/html; charset=utf-8")
err = tmpl.Execute(w, data)
if err != nil {
log.Printf("Error executing template: %v", err)
http.Error(w, "Error rendering response", http.StatusInternalServerError)
}
}
func main() {
http.HandleFunc("/echo", echoHandler)
fs := http.FileServer(http.Dir("./frontend"))
http.Handle("/", fs)
log.Println("Starting server on http://localhost:8080")
log.Println("Echo endpoint available at http://localhost:8080/echo")
if err := http.ListenAndServe(":8080", nil); err != nil {
log.Fatal(err)
}
}