151 lines
3.4 KiB
Go
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)
|
|
}
|
|
}
|