### Minimal Production-Ready Xun Example Source: https://github.com/yaitoo/xun/blob/main/AGENTS.md This Go code snippet demonstrates how to set up a minimal, production-ready Xun application. It includes options for development mode with hot reloading and a production mode using embedded file system. It also configures a basic GET route and starts the HTTP server. ```go //go:embed app var fsys embed.FS func main(){ var dev bool flag.BoolVar(&dev, "dev", false, "dev") flag.Parse() var opts []xun.Option if dev { opts = []xun.Option{xun.WithFsys(os.DirFS("./app")), xun.WithWatch()} } else { v, _ := fs.Sub(fsys, "app"); opts = []xun.Option{xun.WithFsys(v)} } app := xun.New(opts..., xun.WithCompressor(&xun.GzipCompressor{})) app.Get("/{$}", func(c *xun.Context) error { return c.View(map[string]string{"hello":"xun"}) }) app.Start(); defer app.Close() http.ListenAndServe(":80", http.DefaultServeMux) } ``` -------------------------------- ### Create and Start Xun App Source: https://github.com/yaitoo/xun/blob/main/AGENTS.md Initializes a new Xun application with specified configurations like middleware, file system, hot-reloading, and compression. It then starts the app and ensures it's closed gracefully using defer. The application listens for HTTP requests on port 80. ```go app := xun.New( xun.WithMux(http.DefaultServeMux), xun.WithFsys(viewsFS), // fs root of components/layouts/pages/views/public/text xun.WithWatch(), // dev only xun.WithCompressor(&xun.GzipCompressor{}, &xun.DeflateCompressor{}), ) app.Start() def app.Close() http.ListenAndServe(":80", http.DefaultServeMux) ``` -------------------------------- ### Install Xun Web Framework (Go) Source: https://github.com/yaitoo/xun/blob/main/README.md Installs the Xun web framework using Go modules. Supports installation from the main branch or the latest release. ```go go get github.com/yaitoo/xun@main ``` ```go go get github.com/yaitoo/xun@latest ``` -------------------------------- ### Setup SSE Server with Go Source: https://context7.com/yaitoo/xun/llms.txt Implement a Server-Sent Events (SSE) server using the yaitoo/xun/ext/sse package for real-time push notifications. This setup includes creating an SSE server, handling client connections, sending messages to specific users, broadcasting messages to all clients, and managing server shutdown. It requires the `github.com/yaitoo/xun` and `github.com/yaitoo/xun/ext/sse` packages. ```go package main import ( "context" "net/http" "time" "github.com/yaitoo/xun" "github.com/yaitoo/xun/ext/sse" ) func main() { app := xun.New() // Create SSE server sseServer := sse.New() // Start keep-alive goroutine go sseServer.KeepAlive(context.Background()) // SSE endpoint app.Get("/events/{userID}", func(c *xun.Context) error { userID := c.Request.PathValue("userID") // Join SSE connection client, connID, isNew, err := sseServer.Join(userID, c.Response) if err != nil { c.WriteStatus(http.StatusBadRequest) return xun.ErrCancelled } // Send welcome message to new clients if isNew { client.Send(sse.TextEvent{ Name: "welcome", Data: "Connected to event stream", }) } // Wait for disconnect client.Wait() // Clean up sseServer.Leave(userID, connID) return nil }) // Send message to specific user app.Post("/notify/{userID}", func(c *xun.Context) error { userID := c.Request.PathValue("userID") client := sseServer.Get(userID) if client == nil { c.WriteStatus(http.StatusNotFound) return c.View(map[string]string{"error": "user not connected"}) } err := client.Send(sse.TextEvent{ Name: "notification", Data: "You have a new message", }) if err != nil { return err } return c.View(map[string]string{"status": "sent"}) }) // Broadcast to all connected users app.Post("/broadcast", func(c *xun.Context) error { ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() errors, err := sseServer.Broadcast(ctx, sse.TextEvent{ Name: "announcement", Data: "Server maintenance in 10 minutes", }) if err != nil { return err } return c.View(map[string]any{ "status": "broadcast complete", "errors": len(errors), }) }) // Shutdown endpoint app.Post("/shutdown", func(c *xun.Context) error { sseServer.Shutdown() return c.View(map[string]string{"status": "shutdown complete"}) }) app.Start() http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Serve HTTP with Proxy Protocol in Go Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code snippet shows how to start an HTTP server that supports the PROXY protocol. It configures a new Xun application with a ServeMux, starts the app, and then uses proxyproto.ListenAndServe to serve traffic. ```go mux := http.NewServeMux() srv := &http.Server{ Addr: ":80", Handler: mux, } app := xun.New(WithMux(mux)) app.Start() defer app.Close() // srv.ListenAndServe() proxyproto.ListenAndServe(srv) ``` -------------------------------- ### Bash: Install Tailwind CSS Source: https://github.com/yaitoo/xun/blob/main/README.md This bash script demonstrates the initial steps for installing Tailwind CSS. It uses npm to install the tailwindcss package as a development dependency and then generates the tailwind.config.js configuration file. These commands are essential prerequisites for setting up Tailwind CSS in a project. ```bash npm install -D tailwindcss npx tailwindcss init ``` -------------------------------- ### ACL Configuration File Source: https://github.com/yaitoo/xun/blob/main/README.md An example INI-formatted configuration file for the ACL middleware in Xun. It demonstrates how to define rules for allowed/denied hosts, IP networks, countries, and host redirection settings. ```ini [allow_hosts] abc.com www.abc.com [allow_ipnets] 89.207.132.170/24 # ::1 ; 127.0.0.1 [deny_ipnets] * [allow_countries] [deny_countries] us [host_redirect] url=http://yaitoo.cn status_code=302 ``` -------------------------------- ### Create Group with Middleware and Route Source: https://github.com/yaitoo/xun/blob/main/AGENTS.md Creates a new route group '/admin' and applies a global authentication middleware ('authMiddleware') to all routes within this group. A GET route is then defined at '/{$}' within the admin group, which will be handled by the 'handler' function after the middleware. ```go admin := app.Group("/admin") admin.Use(authMiddleware) admin.Get("/{$}", handler) ``` -------------------------------- ### Serve HTTPS with Proxy Protocol and Auto TLS in Go Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code snippet illustrates how to configure and start an HTTPS server that supports the PROXY protocol and automatic TLS certificate management. It sets up autotls, configures both HTTP and HTTPS servers, and uses proxyproto.ListenAndServeTLS. ```go httpsServer := &http.Server{ Addr: ":443", Handler: mux, } autotls.New(autotls.WithCache(autocert.DirCache("./certs")), autotls.WithHosts("yaitoo.cn", "www.yaitoo.cn")), Configure(srv, httpsServer) // httpsServer.ListenAndServeTLS( ", ") proxyproto.ListenAndServeTLS(httpsServer, "", "") ``` -------------------------------- ### Set and Get Cookie in Go Source: https://github.com/yaitoo/xun/blob/main/README.md These Go snippets show how to set, get, and delete cookies using the 'cookie' package. It covers basic cookie operations, URL encoding for values, and signed cookies with HMAC validation. ```go cookie.Set(ctx, http.Cookie{Name: "test", Value: "value"}) // Set-Cookie: test=dmFsdWU= ``` ```go v, err := cookie.Get(ctx,"test") fmt.Println(v) // value ``` ```go ts, err := cookie.SetSigned(ctx,http.Cookie{Name: "test", Value: "value"},[]byte("secret")) // ts is current timestamp v, ts, err := cookie.GetSigned(ctx, "test",[]byte("secret")) // v is value, ts is the timestamp that was signed ``` ```go cookie.Delete(ctx, http.Cookie{Name: "test", Value: "dmFsdWU="}) // Set-Cookie: test=; Expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0 ``` -------------------------------- ### Xun Go Context Operations for Request/Response Handling Source: https://context7.com/yaitoo/xun/llms.txt Illustrates how to use the Xun Context object to access request data such as path parameters and headers, and manipulate responses by setting status codes, writing headers, and rendering views. Includes examples for redirects and retrieving referer URLs. ```go package main import ( "net/http" "github.com/yaitoo/xun" ) func main() { app := xun.New() app.Get("/profile", func(c *xun.Context) error { // Get path parameters id := c.Request.PathValue("id") // Get Accept header languages languages := c.AcceptLanguage() // Get Accept header MIME types acceptTypes := c.Accept() // Store temporary data in context c.Set("UserID", id) c.Set("Language", languages[0]) // Retrieve data from context userID := c.Get("UserID").(string) // Write custom headers c.WriteHeader("X-User-ID", userID) c.WriteHeader("X-Request-ID", "req-123") // Set status code c.WriteStatus(http.StatusOK) // Render view with data return c.View(map[string]any{ "ID": userID, "Language": languages[0], "Accept": acceptTypes[0].String(), }) }) // Redirect example app.Get("/old-path", func(c *xun.Context) error { c.Redirect("/new-path", http.StatusMovedPermanently) return xun.ErrCancelled }) // Get referer app.Post("/submit", func(c *xun.Context) error { referer := c.RequestReferer() c.Set("RefererURL", referer) return c.View(map[string]string{"status": "success"}) }) app.Start() http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Handle PROXY Protocol Headers with Go Source: https://context7.com/yaitoo/xun/llms.txt This Go code snippet demonstrates how to enable support for HAProxy PROXY protocol v1 and v2 within an HTTP server. It utilizes the `proxyproto` extension from the `github.com/yaitoo/xun/ext/proxyproto` package to preserve the real client IP address when behind a load balancer. The code configures a standard `http.Server` and then uses `proxyproto.ListenAndServe` to start it, ensuring that incoming requests are correctly parsed. ```go package main import ( "net/http" "github.com/yaitoo/xun" "github.com/yaitoo/xun/ext/proxyproto" ) func main() { mux := http.NewServeMux() app := xun.New(xun.WithMux(mux)) app.Get("/", func(c *xun.Context) error { // Real client IP is preserved through proxy clientIP := c.Request.RemoteAddr return c.View(map[string]string{ "client_ip": clientIP, "status": "ok", }) }) app.Start() defer app.Close() // HTTP server with PROXY protocol support httpServer := &http.Server{ Addr: ":80", Handler: mux, } // Use proxyproto.ListenAndServe instead of httpServer.ListenAndServe() proxyproto.ListenAndServe(httpServer) // For HTTPS with PROXY protocol // httpsServer := &http.Server{ // Addr: ":443", // Handler: mux, // } // proxyproto.ListenAndServeTLS(httpsServer, "cert.pem", "key.pem") } ``` -------------------------------- ### Define Route with Explicit Viewer Source: https://github.com/yaitoo/xun/blob/main/AGENTS.md Defines a GET route for the root path '/{$}'. The handler function returns a JSON view containing a map with a 'Name' field. An explicit HtmlViewer is provided as an option, allowing for content negotiation to render via HTML templates if configured. ```go app.Get("/{$}", func(c *xun.Context) error { return c.View(map[string]string{"Name":"xun"}) }, xun.WithViewer(&xun.HtmlViewer{/* render via views/... if you set it */})) ``` -------------------------------- ### Define Route with Dynamic Segment and View Response Source: https://github.com/yaitoo/xun/blob/main/AGENTS.md Defines a GET route with a dynamic segment '/users/{id}'. The handler extracts the 'id' from the request path parameters and renders a User view with the extracted ID. It returns an error, which Xun framework handles. ```go app.Get("/users/{id}", func(c *xun.Context) error { id := c.Request.PathValue("id") return c.View(User{Name: id}) }) ``` -------------------------------- ### Integrate HTMX for Dynamic Server-Side Rendering in Go Source: https://context7.com/yaitoo/xun/llms.txt This Go code snippet demonstrates how to integrate HTMX for dynamic server-side rendering using the Xun framework. It sets up an HTMX extension using `htmx.New()` and provides handlers for serving the HTMX extension JavaScript, handling login forms with validation, and performing redirects. The example showcases how to use `htmx.WriteHeader` to send custom HTMX triggers and `c.Redirect` for HTMX-aware redirects. ```go package main import ( "net/http" "github.com/yaitoo/xun" "github.com/yaitoo/xun/ext/form" "github.com/yaitoo/xun/ext/htmx" ) type LoginForm struct { Email string `form:"email" validate:"required,email" Password string `form:"password" validate:"required" } func main() { app := xun.New(xun.WithInterceptor(htmx.New())) // Serve HTMX extension JavaScript app.Get("/htmx-ext.js", htmx.HandleFunc()) app.Get("/login", func(c *xun.Context) error { return c.View(map[string]string{"title": "Login"}) }) app.Post("/login", func(c *xun.Context) error { loginForm, err := form.BindForm[LoginForm](c.Request) if err != nil { c.WriteStatus(http.StatusBadRequest) return xun.ErrCancelled } if !loginForm.Validate(c.AcceptLanguage()...){ c.WriteStatus(http.StatusBadRequest) return c.View(loginForm) } // Check credentials if loginForm.Data.Email != "user@example.com" || loginForm.Data.Password != "secret" { // Send custom HTMX trigger htmx.WriteHeader(c, htmx.HxTrigger, htmx.HxHeader[string]{ "showMessage": "Invalid email or password", }) c.WriteStatus(http.StatusBadRequest) return c.View(loginForm) } // Set session cookie http.SetCookie(c.Response, &http.Cookie{ Name: "session", Value: loginForm.Data.Email, Path: "/", MaxAge: 3600, HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, }) // Redirect via HTMX c.Redirect("/dashboard") return nil }) app.Get("/dashboard", func(c *xun.Context) error { session, err := c.Request.Cookie("session") if err != nil || session.Value == "" { c.Redirect("/login") return xun.ErrCancelled } return c.View(map[string]string{ "user": session.Value, }) }) app.Start() http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Register Route Handlers in Xun Go Application Source: https://context7.com/yaitoo/xun/llms.txt Shows how to register HTTP route handlers for different methods (GET, POST, PUT, DELETE) in a Xun application, including handling dynamic path parameters and rendering different response types. ```go package main import ( "net/http" "github.com/yaitoo/xun" ) type User struct { ID string `json:"id"` Name string `json:"name"` Email string `json:"email"` } func main() { app := xun.New() // GET route app.Get("/{$}", func(c *xun.Context) error { return c.View(map[string]string{ "Name": "go-xun", }) }) // POST route app.Post("/users", func(c *xun.Context) error { user := User{ ID: "123", Name: "John Doe", Email: "john@example.com", } return c.View(user) }) // Dynamic route with path parameter app.Get("/user/{id}", func(c *xun.Context) error { id := c.Request.PathValue("id") user := User{ ID: id, Name: "User " + id, } return c.View(user) }) // PUT and DELETE routes app.Put("/users/{id}", func(c *xun.Context) error { c.WriteStatus(http.StatusOK) return nil }) app.Delete("/users/{id}", func(c *xun.Context) error { c.WriteStatus(http.StatusNoContent) return nil }) app.Start() http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Go: Send SSE Events Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code demonstrates how to send Server-Sent Events (SSE) using the 'sse' extension. It shows how to retrieve a specific SSE connection by user ID and send a named text event, or broadcast an event to all connected clients. It also includes an example of shutting down the SSE server and closing all connections. Dependencies include the 'sse' extension and Go's 'context' package. ```go // push an event to the user u := ss.Get("user_id") if u != nil { u.Send(sse.TextEvent{ Name:"showMessage", Data:"Hello", }) } // broadcast an event to all users ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defuncancel() ss.Broadcast(ctx, sse.TextEvent{ Name:"shutdown", Data:"Server is shutting down", }) // shutdown server and close all user connections ss.Shutdown() ``` -------------------------------- ### HTML: Link Compiled CSS and JS Source: https://github.com/yaitoo/xun/blob/main/README.md This HTML snippet shows how to link the compiled Tailwind CSS file (`theme.css`) and the application JavaScript file (`app.js`) in the `assets.html` file. It also includes a link to `skin.css`. This setup ensures that the project's styles and scripts are correctly loaded in the browser. ```html ``` -------------------------------- ### HTML: Include htmx.js and htmx-ext.js Source: https://github.com/yaitoo/xun/blob/main/README.md This HTML snippet illustrates how to include the htmx.js library and the custom `htmx-ext.js` script in a web page. It also includes links to CSS files and the main application JavaScript (`app.js`). This setup is crucial for enabling dynamic content loading and interactive features powered by htmx. ```html ``` -------------------------------- ### Cookie Management in Go with Xun Source: https://context7.com/yaitoo/xun/llms.txt Provides functions for setting, getting, and deleting cookies in Go using the Xun framework's cookie extension. Supports both standard and signed (HMAC protected) cookies with automatic encoding/decoding. ```go package main import ( "net/http" "time" "github.com/yaitoo/xun" "github.com/yaitoo/xun/ext/cookie" ) func main() { app := xun.New() secretKey := []byte("my-secret-key-32-bytes-long!!") // Set cookie (base64 encoded) app.Get("/set-cookie", func(c *xun.Context) error { err := cookie.Set(c, http.Cookie{ Name: "user_pref", Value: "theme=dark;lang=en", Path: "/", MaxAge: 3600, HttpOnly: true, Secure: true, SameSite: http.SameSiteLaxMode, }) if err != nil { return err } return c.View(map[string]string{"status": "cookie set"}) }) // Get cookie (automatically decoded from base64) app.Get("/get-cookie", func(c *xun.Context) error { value, err := cookie.Get(c, "user_pref") if err != nil { c.WriteStatus(http.StatusNotFound) return c.View(map[string]string{"error": "cookie not found"}) } return c.View(map[string]string{"value": value}) }) // Set signed cookie (HMAC protected) app.Get("/set-signed", func(c *xun.Context) error { timestamp, err := cookie.SetSigned(c, http.Cookie{ Name: "session", Value: "user-id-123", Path: "/", MaxAge: 7200, HttpOnly: true, Secure: true, }, secretKey) if err != nil { return err } c.Set("timestamp", timestamp) return c.View(map[string]any{"status": "signed cookie set", "ts": timestamp}) }) // Get signed cookie (validates HMAC) app.Get("/get-signed", func(c *xun.Context) error { value, timestamp, err := cookie.GetSigned(c, "session", secretKey) if err != nil { c.WriteStatus(http.StatusUnauthorized) return c.View(map[string]string{"error": "invalid or missing session"}) } return c.View(map[string]any{ "value": value, "timestamp": timestamp, }) }) // Delete cookie app.Get("/delete-cookie", func(c *xun.Context) error { err := cookie.Delete(c, http.Cookie{Name: "user_pref"}) if err != nil { return err } return c.View(map[string]string{"status": "cookie deleted"}) }) app.Start() http.ListenAndServe(":8080", nil) } ``` -------------------------------- ### Initialize Xun Web Application in Go Source: https://context7.com/yaitoo/xun/llms.txt Demonstrates how to initialize a new Xun application with default settings, custom file system and watch options, or custom configurations like HTTP multiplexers and response compressors. ```go package main import ( "net/http" "os" "github.com/yaitoo/xun" ) func main() { // Basic application with default settings app := xun.New() // Application with file system and view engines app := xun.New( xun.WithFsys(os.DirFS("./app")), xun.WithWatch(), // Enable hot reload in development ) // Application with custom configuration mux := http.NewServeMux() app := xun.New( xun.WithMux(mux), xun.WithCompressor(&xun.GzipCompressor{}, &xun.DeflateCompressor{}), xun.WithHandlerViewers(&xun.JsonViewer{}, &xun.HtmlViewer{}), ) app.Start() defer app.Close() http.ListenAndServe(":8080", http.DefaultServeMux) } ``` -------------------------------- ### Set up Auto TLS Certificates in Go Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code demonstrates setting up automatic TLS certificate management using autotls.Configure. It initializes a new autotls instance with certificate cache and hosts, then configures HTTP and HTTPS servers. ```go mux := http.NewServeMux() app := xun.New(xun.WithMux(mux)) //... httpServer := &http.Server{ Addr: ":http", //... } httpsServer := &http.Server{ Addr: ":https", //... } autotls. New(autotls.WithCache(autocert.DirCache("./certs")), autotls.WithHosts("abc.com", "123.com")), Configure(httpServer, httpsServer) go httpServer.ListenAndServe() go httpsServer.ListenAndServeTLS("", "") ``` -------------------------------- ### Go: Serve htmx-ext.js Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code snippet demonstrates how to serve the `htmx-ext.js` file within a Xun web application. It uses the `htmx.HandleFunc()` to provide the necessary JavaScript library that enables seamless integration between native JavaScript methods and htmx features, enhancing interactive capabilities. ```go app.Get("/htmx-ext.js", htmx.HandleFunc()) ``` -------------------------------- ### Deploy Application with Go Embed Directive Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code snippet demonstrates how to embed application assets into a single binary using Go's `//go:embed` directive. It differentiates between development (using local filesystem and watching for changes) and production (using embedded resources) environments. This approach creates dependency-free deployment. ```go //go:embed app var fsys embed.FS func main() { var dev bool flag.BoolVar(&dev, "dev", false, "it is development environment") flag.Parse() var opts []xun.Option if dev { // use local filesystem in development, and watch files to reload automatically opts = []xun.Option{xun.WithFsys(os.DirFS("./app")), xun.WithWatch()} } else { // use embed resources in production environment views, _ := fs.Sub(fsys, "app") opts = []xun.Option{xun.WithFsys(views)} } app := xun.New(opts...) //... app.Start() defer app.Close() if dev { slog.Default().Info("xun-admin is running in development") } else { slog.Default().Info("xun-admin is running in production") } err := http.ListenAndServe(":80", http.DefaultServeMux) if err != nil { panic(err) } } ``` -------------------------------- ### Go: Handle SSE Connections with Xun Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code snippet demonstrates how to initialize the SSE extension and handle incoming SSE connections within a Xun web application. It sets up a route to join SSE topics, manage client requests, and return errors for invalid requests. Dependencies include the 'sse' extension and the Xun framework. ```go ss := sse.New() app.Get("/topic/{id}", func(ctx *xun.Context)error { id := c.Get("SessionID").(string) s, err := ss.Join(c.Request.Context(), id, c.Response) if err != nil { c.WriteStatus(http.StatusBadRequest) return xun.ErrCancelled } s.Wait() ss.Leave(id) return nil }) ``` -------------------------------- ### Configure GZip and Deflate Compression in Go Source: https://github.com/yaitoo/xun/blob/main/README.md This Go code snippet configures the Xun application to use GZip and Deflate compression for handling 'Accept-Encoding' headers. It initializes the compressor with both GzipCompressor and DeflateCompressor. ```go app := xun.New(WithCompressor(&GzipCompressor{}, &DeflateCompressor{})) ``` -------------------------------- ### Virtual Host Routing with net/http (Go) Source: https://github.com/yaitoo/xun/blob/main/README.md Illustrates how to configure routing in Go's standard net/http package to handle requests for different hostnames that resolve to the same IP address. It defines handlers for specific domains. ```go mux.HandleFunc("GET /", func(w http.ResponseWriter, req *http.Request) {...}) mux.HandleFunc("GET abc.com/", func(w http.ResponseWriter, req *http.Request) {...}) mux.HandleFunc("GET 123.com/", func(w http.ResponseWriter, req *http.Request) {...}) ``` -------------------------------- ### Multiple Viewers based on Accept Header (Bash) Source: https://github.com/yaitoo/xun/blob/main/README.md Demonstrates how to make requests to an HTTP server and receive different responses based on the 'Accept' header, falling back to a default viewer if no specific match is found. This showcases content negotiation. ```bash curl -v http://127.0.0.1 > GET / HTTP/1.1 > Host: 127.0.0.1 > User-Agent: curl/8.7.1 > Accept: */* > * Request completely sent off < HTTP/1.1 200 OK < Date: Thu, 26 Dec 2024 07:46:13 GMT < Content-Length: 19 < Content-Type: text/plain; charset=utf-8 > {"Name":"go-xun"} curl --header "Accept: text/html; \*/\*" http://127.0.0.1 ``` > GET / HTTP/1.1 > Host: 127.0.0.1 > User-Agent: curl/8.7.1 > Accept: text/html; */* > * Request completely sent off < HTTP/1.1 200 OK < Date: Thu, 26 Dec 2024 07:49:47 GMT < Content-Length: 343 < Content-Type: text/html; charset=utf-8 >