### Install Go UUID Package Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/google/uuid/README.md Installs the `github.com/google/uuid` Go package using the `go get` command. This command fetches the package and its dependencies, making it available for use in Go projects. ```sh go get github.com/google/uuid ``` -------------------------------- ### Go Example: Using LoggingHandler and CompressHandler Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/handlers/README.md This example demonstrates how to integrate `handlers.LoggingHandler` to log specific requests (e.g., to an admin dashboard) to standard output, and `handlers.CompressHandler` to automatically GZIP compress all HTTP responses served by the application. ```Go import ( "net/http" "github.com/gorilla/handlers" "os" ) func main() { r := http.NewServeMux() // Only log requests to our admin dashboard to stdout r.Handle("/admin", handlers.LoggingHandler(os.Stdout, http.HandlerFunc(ShowAdminDashboard))) r.HandleFunc("/", ShowIndex) // Wrap our server with our gzip handler to gzip compress all responses. http.ListenAndServe(":8000", handlers.CompressHandler(r)) } ``` -------------------------------- ### Install gorilla/mux package Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet shows the command to install the `gorilla/mux` package using the Go module system. It fetches the latest version of the package. ```sh go get -u github.com/gorilla/mux ``` -------------------------------- ### Serve SPA and API from a Single Go Server with Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go example demonstrates how to serve a Single Page Application (SPA) and an API from a single HTTP server using the `gorilla/mux` router. It includes a custom `spaHandler` struct that implements `http.Handler` to serve static files, falling back to `index.html` for SPA routing, and integrates an example API health check endpoint. ```Go package main import ( "encoding/json" "log" "net/http" "os" "path/filepath" "time" "github.com/gorilla/mux" ) // spaHandler implements the http.Handler interface, so we can use it // to respond to HTTP requests. The path to the static directory and // path to the index file within that static directory are used to // serve the SPA in the given static directory. type spaHandler struct { staticPath string indexPath string } // ServeHTTP inspects the URL path to locate a file within the static dir // on the SPA handler. If a file is found, it will be served. If not, the // file located at the index path on the SPA handler will be served. This // is suitable behavior for serving an SPA (single page application). func (h spaHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { // Join internally call path.Clean to prevent directory traversal path := filepath.Join(h.staticPath, r.URL.Path) // check whether a file exists or is a directory at the given path fi, err := os.Stat(path) if os.IsNotExist(err) || fi.IsDir() { // file does not exist or path is a directory, serve index.html http.ServeFile(w, r, filepath.Join(h.staticPath, h.indexPath)) return } if err != nil { // if we got an error (that wasn't that the file doesn't exist) stating the // file, return a 500 internal server error and stop http.Error(w, err.Error(), http.StatusInternalServerError) return } // otherwise, use http.FileServer to serve the static file http.FileServer(http.Dir(h.staticPath)).ServeHTTP(w, r) } func main() { router := mux.NewRouter() router.HandleFunc("/api/health", func(w http.ResponseWriter, r *http.Request) { // an example API handler json.NewEncoder(w).Encode(map[string]bool{"ok": true}) }) spa := spaHandler{staticPath: "build", indexPath: "index.html"} router.PathPrefix("/").Handler(spa) srv := &http.Server{ Handler: router, Addr: "127.0.0.1:8000", // Good practice: enforce timeouts for servers you create! WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, } log.Fatal(srv.ListenAndServe()) } ``` -------------------------------- ### Example Usage of POST /download with curl Source: https://github.com/scosman/zipstreamer/blob/master/README.md Demonstrates how to use the curl command-line tool to interact with the POST /download endpoint. This example first downloads a sample JSON descriptor and then uses it to make a POST request to the ZipStreamer server, saving the returned zip file. ```curl # download a sample json descriptor curl https://gist.githubusercontent.com/scosman/f57a3561fed98caab2d0ae285a0d7251/raw/4a9630951373e50f467f41d8c7b9d440c13a14d2/zipJsonDescriptor.json > zipJsonDescriptor.json # call POST /download endpoint, passing json descriptor in body curl --data-binary "@./zipJsonDescriptor.json" http://localhost:4008/download > archive.zip ``` -------------------------------- ### Registering basic URL paths and handlers with gorilla/mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go example demonstrates how to initialize a new `mux.Router` and register simple URL paths to corresponding HTTP handler functions. It sets up a basic web server routing for home, products, and articles pages. ```go func main() { r := mux.NewRouter() r.HandleFunc("/", HomeHandler) r.HandleFunc("/products", ProductsHandler) r.HandleFunc("/articles", ArticlesHandler) http.Handle("/", r) } ``` -------------------------------- ### Example JSON Zip File Descriptor Source: https://github.com/scosman/zipstreamer/blob/master/README.md An example of the JSON descriptor used to specify two files for inclusion in a zip archive. It demonstrates how to define a suggested filename for the zip and how to specify URLs and internal zip paths for individual files, including files within subfolders. ```JSON { "suggestedFilename": "tps_reports.zip", "files": [ { "url":"https://server.com/image1.jpg", "zipPath":"image1.jpg" }, { "url":"https://server.com/image2.jpg", "zipPath":"in-a-sub-folder/image2.jpg" } ] } ``` -------------------------------- ### Complete Go Gorilla Mux Basic Web Server Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md A self-contained, runnable Go example demonstrating a minimal web server using the Gorilla Mux router. It defines a simple handler for the root path and binds the server to port 8000. ```Go package main import ( "net/http" "log" "github.com/gorilla/mux" ) func YourHandler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Gorilla!\n")) } func main() { r := mux.NewRouter() // Routes consist of a path and a handler function. r.HandleFunc("/", YourHandler) // Bind to a port and pass our router in log.Fatal(http.ListenAndServe(":8000", r)) } ``` -------------------------------- ### Build Specific URL Components (Host or Path) in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Demonstrates how to generate only the host or path component of a URL using `URLHost()` and `URLPath()` methods respectively. This is useful when only a part of the URL is needed, for example, to get "http://news.example.com/" or "/articles/technology/42". ```Go // "http://news.example.com/" host, err := r.Get("article").URLHost("subdomain", "news") // "/articles/technology/42" path, err := r.Get("article").URLPath("category", "technology", "id", "42") ``` -------------------------------- ### Match Routes by Path Prefix in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This code shows how to match routes based on a URL path prefix using the `PathPrefix` matcher. Any request path starting with '/products/' will be matched by this route. ```go r.PathPrefix("/products/") ``` -------------------------------- ### Serve Static Files with Go Mux Router Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This complete example demonstrates how to serve static files using the `mux` router and `http.FileServer`. It configures a path prefix '/static/' to map requests to a local directory, stripping the prefix before serving the file, and sets up a basic HTTP server with timeouts. ```go func main() { var dir string flag.StringVar(&dir, "dir", ".", "the directory to serve files from. Defaults to the current dir") flag.Parse() r := mux.NewRouter() // This will serve files under http://localhost:8000/static/ r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(dir)))) srv := &http.Server{ Handler: r, Addr: "127.0.0.1:8000", // Good practice: enforce timeouts for servers you create! WriteTimeout: 15 * time.Second, ReadTimeout: 15 * time.Second, } log.Fatal(srv.ListenAndServe()) } ``` -------------------------------- ### Walk and Inspect All Registered Routes in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Provides a comprehensive example of using `mux.Router.Walk()` to iterate over all registered routes. The callback function extracts and prints various details for each route, such as path templates, regexps, query templates, and HTTP methods, demonstrating how to inspect the router's configuration. ```Go package main import ( "fmt" "net/http" "strings" "github.com/gorilla/mux" ) func handler(w http.ResponseWriter, r *http.Request) { return } func main() { r := mux.NewRouter() r.HandleFunc("/", handler) r.HandleFunc("/products", handler).Methods("POST") r.HandleFunc("/articles", handler).Methods("GET") r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT") r.HandleFunc("/authors", handler).Queries("surname", "{surname}") err := r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error { pathTemplate, err := route.GetPathTemplate() if err == nil { fmt.Println("ROUTE:", pathTemplate) } pathRegexp, err := route.GetPathRegexp() if err == nil { fmt.Println("Path regexp:", pathRegexp) } queriesTemplates, err := route.GetQueriesTemplates() if err == nil { fmt.Println("Queries templates:", strings.Join(queriesTemplates, ",")) } queriesRegexps, err := route.GetQueriesRegexp() if err == nil { fmt.Println("Queries regexps:", strings.Join(queriesRegexps, ",")) } methods, err := route.GetMethods() if err == nil { fmt.Println("Methods:", strings.Join(methods, ",")) } fmt.Println() return nil }) if err != nil { fmt.Println(err) } http.Handle("/", r) } ``` -------------------------------- ### Define and Initialize Go Authentication Middleware Struct Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go code defines an `authenticationMiddleware` struct to hold a mapping of session tokens to users. The `Populate` method demonstrates how to initialize this map with example token-user pairs, simulating a user database for authentication purposes. ```Go // Define our struct type authenticationMiddleware struct { tokenUsers map[string]string } // Initialize it somewhere func (amw *authenticationMiddleware) Populate() { amw.tokenUsers["00000000"] = "user0" amw.tokenUsers["aaaaaaaa"] = "userA" amw.tokenUsers["05f717e5"] = "randomUser" amw.tokenUsers["deadbeef"] = "user0" } ``` -------------------------------- ### Build URLs with Nested Subrouters in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Explains how to define routes within subrouters and then build complete URLs for them. This example shows how the `URL()` method correctly handles variables defined across the main router and its subrouters. ```Go r := mux.NewRouter() s := r.Host("{subdomain}.example.com").Subrouter() s.Path("/articles/{category}/{id:[0-9]+}"). HandlerFunc(ArticleHandler). Name("article") // "http://news.example.com/articles/technology/42" url, err := r.Get("article").URL("subdomain", "news", "category", "technology", "id", "42") ``` -------------------------------- ### Go: Implementing CORS with gorilla/mux Middleware Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go example demonstrates configuring a `gorilla/mux` router to handle CORS. It shows how to register routes with specific HTTP methods, including `OPTIONS`, and apply `mux.CORSMethodMiddleware`. A `fooHandler` is included to set `Access-Control-Allow-Origin` and respond to `OPTIONS` requests, ensuring proper CORS header management. ```Go package main import ( "net/http" "github.com/gorilla/mux" ) func main() { r := mux.NewRouter() // IMPORTANT: you must specify an OPTIONS method matcher for the middleware to set CORS headers r.HandleFunc("/foo", fooHandler).Methods(http.MethodGet, http.MethodPut, http.MethodPatch, http.MethodOptions) r.Use(mux.CORSMethodMiddleware(r)) http.ListenAndServe(":8080", r) } func fooHandler(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") if r.Method == http.MethodOptions { return } w.Write([]byte("foo")) } ``` -------------------------------- ### Build Complex URLs with Host and Query Variables in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Illustrates how to define routes with host and query parameters and then build URLs that include these variables. This example demonstrates the `URL()` method's capability for handling complex patterns, resulting in a URL like "http://news.example.com/articles/technology/42?filter=gorilla". ```Go r := mux.NewRouter() r.Host("{subdomain}.example.com"). Path("/articles/{category}/{id:[0-9]+}"). Queries("filter", "{filter}"). HandlerFunc(ArticleHandler). Name("article") // url.String() will be "http://news.example.com/articles/technology/42?filter=gorilla" url, err := r.Get("article").URL("subdomain", "news", "category", "technology", "id", "42", "filter", "gorilla") ``` -------------------------------- ### Match Routes by URL Scheme in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This example demonstrates how to enforce a specific URL scheme (e.g., HTTPS) for a route using the `Schemes` matcher. The route will only match if the request uses the specified protocol. ```go r.Schemes("https") ``` -------------------------------- ### Bash: Sending a GET Request to a CORS Endpoint Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Bash snippet illustrates how to use `curl` to send a `GET` request to a local endpoint configured with CORS. The `-v` flag is used to display verbose output, including the request and response headers, which is crucial for observing CORS behavior. ```Bash curl localhost:8080/foo -v ``` -------------------------------- ### Combine Multiple Route Matchers in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This example demonstrates how to chain multiple matchers (Host, Methods, Schemes) to a single route definition. The route will only match if all specified conditions are met simultaneously, providing precise control over route activation. ```go r.HandleFunc("/products", ProductsHandler). Host("www.example.com"). Methods("GET"). Schemes("http") ``` -------------------------------- ### Define Routes with Host Matching in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet demonstrates how to restrict routes to specific domains or subdomains using the `Host` matcher in the Go `mux` router. It shows examples for matching a fixed domain and a dynamic subdomain with a variable. ```go r := mux.NewRouter() // Only matches if domain is "www.example.com". r.Host("www.example.com") // Matches a dynamic subdomain. r.Host("{subdomain:[a-z]+}.example.com") ``` -------------------------------- ### Go Table-Driven Test for Gorilla Mux Route Variables Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Provides a table-driven test example for a Gorilla Mux handler that processes route variables. It iterates through multiple test cases, constructs requests with varying path segments, and uses a router to ensure proper variable extraction during testing. ```Go // endpoints_test.go func TestMetricsHandler(t *testing.T) { tt := []struct{ routeVariable string shouldPass bool }{ {"goroutines", true}, {"heap", true}, {"counters", true}, {"queries", true}, {"adhadaeqm3k", false}, } for _, tc := range tt { path := fmt.Sprintf("/metrics/%s", tc.routeVariable) req, err := http.NewRequest("GET", path, nil) if err != nil { t.Fatal(err) } rr := httptest.NewRecorder() // To add the vars to the context, // we need to create a router through which we can pass the request. router := mux.NewRouter() router.HandleFunc("/metrics/{type}", MetricsHandler) router.ServeHTTP(rr, req) // In this case, our MetricsHandler returns a non-200 response // for a route variable it doesn't know about. if rr.Code == http.StatusOK && !tc.shouldPass { t.Errorf("handler should have failed on routeVariable %s: got %v want %v", tc.routeVariable, rr.Code, http.StatusOK) } } } ``` -------------------------------- ### Match Routes by Query Parameters in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This example demonstrates how to match routes based on the presence and value of URL query parameters using the `Queries` matcher. The route will only match if the URL contains a query parameter named 'key' with the value 'value'. ```go r.Queries("key", "value") ``` -------------------------------- ### Match Routes by HTTP Methods in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet illustrates how to restrict a route to specific HTTP methods, such as GET and POST, using the `Methods` matcher. The route will only be activated if the incoming request uses one of the specified methods. ```go r.Methods("GET", "POST") ``` -------------------------------- ### Accessing path variables from a gorilla/mux request Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go example shows how to extract the values of path variables from an incoming HTTP request using `mux.Vars(r)`. The extracted variables are returned as a map, allowing handlers to access dynamic parts of the URL. ```go func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) w.WriteHeader(http.StatusOK) fmt.Fprintf(w, "Category: %v\n", vars["category"]) } ``` -------------------------------- ### Download Zip File via GET Request Source: https://github.com/scosman/zipstreamer/blob/master/README.md This endpoint fetches a JSON zip file descriptor hosted on another server and returns a zip file. It is useful for hiding original file locations, supporting use cases where POST requests are difficult, and triggering a browser's 'Save File' UI. ```APIDOC GET /download Description: Fetches a JSON zip file descriptor hosted on another server, and returns a zip file. Parameters: zsurl: string (query) - The full URL to the JSON file describing the zip. Example: /download?zsurl=https://yourserver.com/path_to_descriptors/82a1b54cd20ab44a916bd76a5 zsid: string (query) - An ID used with the ZS_LISTFILE_URL_PREFIX environment variable to fetch the JSON file. Example: /download?zsid=82a1b54cd20ab44a916bd76a5 ``` ```curl curl -X GET "http://localhost:4008/download?zsurl=https://gist.githubusercontent.com/scosman/f57a3561fed98caab2d0ae285a0d7251/raw/4a9630951373e50f467f41d8c7b9d440c13a14d2/zipJsonDescriptor.json" > archive.zip ``` ```shell ZS_LISTFILE_URL_PREFIX="https://gist.githubusercontent.com/scosman/" ./zipstreamer ``` ```curl curl -X GET "http://localhost:4008/download?zsid=f57a3561fed98caab2d0ae285a0d7251/raw/4a9630951373e50f467f41d8c7b9d440c13a14d2/zipJsonDescriptor.json" > archive.zip ``` -------------------------------- ### Implement Basic Request Logging Middleware in Go Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go function demonstrates a simple middleware that logs the URI of incoming requests. It wraps the `next` handler, performs its logging action, and then calls `next.ServeHTTP` to continue the request processing chain. ```Go func loggingMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Do stuff here log.Println(r.RequestURI) // Call the next handler, which can be another middleware in the chain, or the final handler. next.ServeHTTP(w, r) }) } ``` -------------------------------- ### API Documentation: gorilla/handlers Middleware Overview Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/handlers/README.md An overview of the key HTTP middleware functions provided by the `gorilla/handlers` package, detailing their primary purpose and functionality. ```APIDOC LoggingHandler: Logs HTTP requests in the Apache Common Log Format. ``` ```APIDOC CombinedLoggingHandler: Logs HTTP requests in the Apache Combined Log Format, commonly used by Apache and nginx. ``` ```APIDOC CompressHandler: Gzips HTTP responses for improved performance. ``` ```APIDOC ContentTypeHandler: Validates incoming requests against a list of accepted content types. ``` ```APIDOC MethodHandler: Matches HTTP methods against a map of `http.Handler` instances for method-specific routing. ``` ```APIDOC ProxyHeaders: Populates `r.RemoteAddr` and `r.URL.Scheme` based on `X-Forwarded-For`, `X-Real-IP`, `X-Forwarded-Proto`, and RFC7239 `Forwarded` headers when running behind a reverse proxy. ``` ```APIDOC CanonicalHost: Redirects requests to a preferred host when handling multiple domains or CNAME aliases. ``` ```APIDOC RecoveryHandler: Recovers from unexpected panics during HTTP request processing to prevent server crashes. ``` -------------------------------- ### ZipStreamer Server Configuration Environment Variables Source: https://github.com/scosman/zipstreamer/blob/master/README.md Environment variables used to configure the ZipStreamer server's behavior, including port binding, URL prefix validation, and compression settings. ```APIDOC PORT - Defaults to 4008. Sets which port the HTTP server binds to. ZS_URL_PREFIX - If set, the server will verify the `url` property of the files in the JSON zip file descriptors start with this prefix. Useful to preventing others from using your server to serve their files. ZS_COMPRESSION - Defaults to no compression. It's not universally known, but zip files can be uncompressed, and used only to combining many files into one file. Set to `DEFLATE` to use zip deflate compression. **WARNING - enabling compression uses CPU, and will reduce throughput of server**. Note: for files with internal compression (JPEGs, MP4s, etc), zip DEFLATE compression will often increase the total zip file size. ZS_LISTFILE_URL_PREFIX - See documentation for `GET /download` ``` -------------------------------- ### Implement Graceful Shutdown for Go HTTP Server with Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go code snippet demonstrates how to set up an `http.Server` with `gorilla/mux` and enable graceful shutdown. It configures timeouts, runs the server in a goroutine, and listens for `SIGINT` signals to initiate a controlled shutdown, allowing active connections to complete within a specified timeout. ```go package main import ( "context" "flag" "log" "net/http" "os" "os/signal" "time" "github.com/gorilla/mux" ) func main() { var wait time.Duration flag.DurationVar(&wait, "graceful-timeout", time.Second * 15, "the duration for which the server gracefully wait for existing connections to finish - e.g. 15s or 1m") flag.Parse() r := mux.NewRouter() // Add your routes as needed srv := &http.Server{ Addr: "0.0.0.0:8080", // Good practice to set timeouts to avoid Slowloris attacks. WriteTimeout: time.Second * 15, ReadTimeout: time.Second * 15, IdleTimeout: time.Second * 60, Handler: r, // Pass our instance of gorilla/mux in. } // Run our server in a goroutine so that it doesn't block. go func() { if err := srv.ListenAndServe(); err != nil { log.Println(err) } }() c := make(chan os.Signal, 1) // We'll accept graceful shutdowns when quit via SIGINT (Ctrl+C) // SIGKILL, SIGQUIT or SIGTERM (Ctrl+/) will not be caught. signal.Notify(c, os.Interrupt) // Block until we receive our signal. <-c // Create a deadline to wait for. ctx, cancel := context.WithTimeout(context.Background(), wait) defer cancel() // Doesn't block if no connections, but will otherwise wait // until the timeout deadline. srv.Shutdown(ctx) // Optionally, you could run srv.Shutdown in a goroutine and block on // <-ctx.Done() if your application should wait for other services // to finalize based on context cancellation. log.Println("shutting down") os.Exit(0) } ``` -------------------------------- ### Understand Route Order Precedence in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet illustrates how route matching order works in `mux`: routes are tested in the order they are added. The first matching route, even if less specific, will handle the request, as shown by the specific handler taking precedence over a catch-all prefix. ```go r := mux.NewRouter() r.HandleFunc("/specific", specificHandler) r.PathPrefix("/").Handler(catchAllHandler) ``` -------------------------------- ### Go Unit Test for Health Check Handler Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Illustrates how to write a unit test for the `HealthCheckHandler` using Go's `net/http/httptest` package. It creates a mock HTTP request and response recorder, then asserts the returned status code and body content. ```Go // endpoints_test.go package main import ( "net/http" "net/http/httptest" "testing" ) func TestHealthCheckHandler(t *testing.T) { // Create a request to pass to our handler. We don't have any query parameters for now, so we'll // pass 'nil' as the third parameter. req, err := http.NewRequest("GET", "/health", nil) if err != nil { t.Fatal(err) } // We create a ResponseRecorder (which satisfies http.ResponseWriter) to record the response. rr := httptest.NewRecorder() handler := http.HandlerFunc(HealthCheckHandler) // Our handlers satisfy http.Handler, so we can call their ServeHTTP method // directly and pass in our Request and ResponseRecorder. handler.ServeHTTP(rr, req) // Check the status code is what we expect. if status := rr.Code; status != http.StatusOK { t.Errorf("handler returned wrong status code: got %v want %v", status, http.StatusOK) } // Check the response body is what we expect. expected := `{\"alive\": true}` if rr.Body.String() != expected { t.Errorf("handler returned unexpected body: got %v want %v", rr.Body.String(), expected) } } ``` -------------------------------- ### Implement Go Authentication Middleware Logic Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go method implements the core logic for an authentication middleware. It extracts an `X-Session-Token` header, checks it against a predefined map of valid tokens, and either logs the authenticated user and passes the request to the next handler or returns a `403 Forbidden` error. ```Go // Middleware function, which will be called for each request func (amw *authenticationMiddleware) Middleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { token := r.Header.Get("X-Session-Token") if user, found := amw.tokenUsers[token]; found { // We found the token in our map log.Printf("Authenticated user %s\n", user) // Pass down the request to the next middleware (or final handler) next.ServeHTTP(w, r) } else { // Write an error and stop the handler chain http.Error(w, "Forbidden", http.StatusForbidden) } }) } ``` -------------------------------- ### Build a Simple URL from a Named Route in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Shows how to reverse a URL for a named route by calling the `URL()` method on the route object, passing a sequence of key-value pairs for the route variables. The resulting `url.URL` will have the path "/articles/technology/42". ```Go url, err := r.Get("article").URL("category", "technology", "id", "42") ``` -------------------------------- ### Run Official ZipStreamer Docker Image from Github Packages Source: https://github.com/scosman/zipstreamer/blob/master/README.md Steps to pull and run the official ZipStreamer Docker image published on Github Packages. This allows users to quickly deploy the stable release of ZipStreamer. ```Docker docker pull ghcr.io/scosman/packages/zipstreamer:stable # Start on port 8080 docker run --env PORT=8080 -p 8080:8080 ghcr.io/scosman/packages/zipstreamer:stable ``` -------------------------------- ### Register Complex Authentication Middleware with Mux Router Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go snippet demonstrates how to instantiate and register the `authenticationMiddleware` with a Mux router. It initializes the middleware's internal token-user map and then uses `r.Use()` to apply the middleware to all subsequent requests handled by this router. ```Go r := mux.NewRouter() r.HandleFunc("/", handler) amw := authenticationMiddleware{tokenUsers: make(map[string]string)} amw.Populate() r.Use(amw.Middleware) ``` -------------------------------- ### Build Docker Image for ZipStreamer Source: https://github.com/scosman/zipstreamer/blob/master/README.md Instructions to build a custom Docker image for ZipStreamer from the source repository. This involves cloning the repo and executing Docker build commands, followed by running the image on a specified port. ```Docker docker build --tag docker-zipstreamer . # Start on port 8080 docker run --env PORT=8080 -p 8080:8080 docker-zipstreamer ``` -------------------------------- ### Register Simple Middleware with Mux Router in Go Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go snippet shows how to register a previously defined middleware, such as `loggingMiddleware`, with a Mux router using the `r.Use()` method. Middlewares are executed in the order they are added for matching routes. ```Go r := mux.NewRouter() r.HandleFunc("/", handler) r.Use(loggingMiddleware) ``` -------------------------------- ### Define a Named Route in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Demonstrates how to define a named route using the `Name()` method on a `mux.Router` in Go, which is essential for URL reversal (building URLs from route names). ```Go r := mux.NewRouter() r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler). Name("article") ``` -------------------------------- ### Defining routes with path variables in gorilla/mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go snippet illustrates how to define routes that include variables in their paths. Variables can be simple names (`{key}`) or include regular expressions for more specific matching (`{id:[0-9]+}`). This allows for dynamic URL structures. ```go r := mux.NewRouter() r.HandleFunc("/products/{key}", ProductHandler) r.HandleFunc("/articles/{category}/", ArticlesCategoryHandler) r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) ``` -------------------------------- ### POST /download Endpoint API Reference Source: https://github.com/scosman/zipstreamer/blob/master/README.md API documentation for the POST /download endpoint. This endpoint accepts a JSON zip file descriptor in the request body and responds by streaming the generated zip file directly to the client. ```APIDOC POST /download: Description: This endpoint takes an HTTP POST body containing the JSON zip file descriptor and returns a zip file. ``` -------------------------------- ### ZipStreamer HTTP Endpoints Overview Source: https://github.com/scosman/zipstreamer/blob/master/README.md An overview of the primary HTTP endpoints provided by the ZipStreamer service for interacting with its zip file streaming capabilities. This includes endpoints for direct downloads and for creating downloadable links. ```APIDOC HTTP Endpoints: POST /download GET /download POST /create_download_link GET /download_link/{link_id} ``` -------------------------------- ### Go Gorilla Mux Route with Path Variable Definition Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Demonstrates how to define a route with a path variable (e.g., `/metrics/{type}`) using Gorilla Mux. This allows the server to capture dynamic segments from the URL and pass them to the handler. ```Go // endpoints.go func main() { r := mux.NewRouter() // A route with a route variable: r.HandleFunc("/metrics/{type}", MetricsHandler) log.Fatal(http.ListenAndServe("localhost:8080", r)) } ``` -------------------------------- ### Match Headers with Regular Expressions in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Shows how to use `HeadersRegexp()` to define a route that matches requests based on a regular expression pattern in a specific header, such as `Content-Type`. This allows a single route to match multiple header values. ```Go r.HeadersRegexp("Content-Type", "application/(text|json)") ``` -------------------------------- ### Define Standard Mux MiddlewareFunc Type in Go Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Go type definition establishes the standard signature for Mux middlewares. A `MiddlewareFunc` takes an `http.Handler` and returns another `http.Handler`, allowing for request processing before passing control to the next handler in the chain. ```Go type MiddlewareFunc func(http.Handler) http.Handler ``` -------------------------------- ### Capture HTTP Metrics with httpsnoop in Go Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/felixge/httpsnoop/README.md This snippet demonstrates how to use `httpsnoop.CaptureMetrics` to wrap an existing `http.Handler` and log request details such as method, URL, HTTP status code, duration, and bytes written. It shows a typical integration pattern for monitoring HTTP requests in a Go application. ```go // myH is your app's http handler, perhaps a http.ServeMux or similar. var myH http.Handler // wrappedH wraps myH in order to log every request. wrappedH := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { m := httpsnoop.CaptureMetrics(myH, w, r) log.Printf( "%s %s (code=%d dt=%s written=%d)", r.Method, r.URL, m.Code, m.Duration, m.Written, ) }) http.ListenAndServe(":8080", wrappedH) ``` -------------------------------- ### Create a Subrouter for Grouping Routes in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet shows how to create a subrouter based on a parent route's matching conditions, such as a specific host. Subrouters allow grouping multiple routes that share common requirements, improving organization and matching efficiency. ```go r := mux.NewRouter() s := r.Host("www.example.com").Subrouter() ``` -------------------------------- ### Retrieve Required Variable Names for a Route in Gorilla Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Illustrates how to use `GetVarNames()` on a named route to programmatically discover all required variables for URL building. This aids in dynamic URL generation and validation, printing a slice like `[domain group item_id some_data1 some_data2]`. ```Go r := mux.NewRouter() r.Host("{domain}"). Path("/{group}/{item_id}"). Queries("some_data1", "{some_data1}"). Queries("some_data2", "{some_data2}"). Name("article") // Will print [domain group item_id some_data1 some_data2] fmt.Println(r.Get("article").GetVarNames()) ``` -------------------------------- ### Register Routes within a Go Mux Subrouter Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet demonstrates how to register individual routes within a previously defined subrouter. These routes will only be tested if the subrouter's conditions are met, providing a hierarchical and optimized routing structure. ```go s.HandleFunc("/products/", ProductsHandler) s.HandleFunc("/products/{key}", ProductHandler) s.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler) ``` -------------------------------- ### Create Temporary Download Link for Zip Source: https://github.com/scosman/zipstreamer/blob/master/README.md This endpoint takes a JSON zip file descriptor in the HTTP POST body, stores it in a local cache, and returns a link ID. This is useful for triggering a browser's 'Save File' UI. Links are temporary (60 seconds) and stored in-memory, requiring session affinity for multi-server deployments. ```APIDOC POST /create_download_link Description: Takes a HTTP POST body containing the JSON zip file descriptor, stores it in a local cache, and returns a link ID. Request Body: JSON zip file descriptor Response Body: status: string - "ok" link_id: string (UUID) - The unique ID which allows the caller to fetch the zip file via an additional call to GET /download_link/{link_id}. ``` ```json { "status":"ok", "link_id":"b4ecfdb7-e0fa-4aca-ad87-cb2e4245c8dd" } ``` -------------------------------- ### Download Zip File Using Temporary Link ID Source: https://github.com/scosman/zipstreamer/blob/master/README.md Call this endpoint with a `link_id` generated by `/create_download_link` to download the associated zip file. This is typically used immediately after link creation. ```APIDOC GET /download_link/{link_id} Description: Downloads a zip file using a link_id generated with /create_download_link. Parameters: link_id: string (path) - The unique ID obtained from the POST /create_download_link endpoint. ``` ```curl # download a sample json descriptor curl https://gist.githubusercontent.com/scosman/f57a3561fed98caab2d0ae285a0d7251/raw/4a9630951373e50f467f41d8c7b9d440c13a14d2/zipJsonDescriptor.json > zipJsonDescriptor.json # call POST endpoint to create link curl --data-binary "@./zipJsonDescriptor.json" http://localhost:4008/create_download_link # Call GET endpoint to download zip. Note: must copy UUID from output of above POST command into this URL curl -X GET "http://localhost:4008/download_link/UUID_FROM_ABOVE" > archive.zip ``` -------------------------------- ### Define Custom Route Matcher Function in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet illustrates how to define a custom matching logic for a route using `MatcherFunc`. It allows for highly flexible matching conditions based on the `http.Request` object and `RouteMatch` details, returning true if the route should match. ```go r.MatcherFunc(func(r *http.Request, rm *RouteMatch) bool { return r.ProtoMajor == 0 }) ``` -------------------------------- ### Bash: Verifying CORS Headers in Curl Response Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This Bash output shows the expected response from a `curl` request to a CORS-enabled endpoint. It specifically highlights the `Access-Control-Allow-Methods` and `Access-Control-Allow-Origin` headers, confirming that the `gorilla/mux` middleware and custom handler are correctly setting the necessary CORS response headers. ```Bash * Trying ::1... * TCP_NODELAY set * Connected to localhost (::1) port 8080 (#0) > GET /foo HTTP/1.1 > Host: localhost:8080 > User-Agent: curl/7.59.0 > Accept: */* > < HTTP/1.1 200 OK < Access-Control-Allow-Methods: GET,PUT,PATCH,OPTIONS < Access-Control-Allow-Origin: * < Date: Fri, 28 Jun 2019 20:13:30 GMT < Content-Length: 3 < Content-Type: text/plain; charset=utf-8 < * Connection #0 to host localhost left intact foo ``` -------------------------------- ### Define Subrouter with Path Prefix in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet illustrates how a subrouter can inherit a path prefix from its parent, making inner routes relative to that prefix. This creates 'namespaces' for URLs, simplifying route definitions and maintaining consistency for related paths. ```go r := mux.NewRouter() s := r.PathPrefix("/products").Subrouter() // "/products/" s.HandleFunc("/", ProductsHandler) // "/products/{key}/" s.HandleFunc("/{key}/", ProductHandler) // "/products/{key}/details" s.HandleFunc("/{key}/details", ProductDetailsHandler) ``` -------------------------------- ### Match Routes by Header Values in Go Mux Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md This snippet shows how to match routes based on specific HTTP header key-value pairs using the `Headers` matcher. The route will only match if the request includes the 'X-Requested-With' header with the value 'XMLHttpRequest'. ```go r.Headers("X-Requested-With", "XMLHttpRequest") ``` -------------------------------- ### Go Gorilla Mux Health Check Handler Source: https://github.com/scosman/zipstreamer/blob/master/vendor/github.com/gorilla/mux/README.md Defines a basic HTTP handler in Go for a health check endpoint (`/health`). It sets the content type to JSON, writes an `alive: true` response, and integrates with a Gorilla Mux router for serving. ```Go // endpoints.go package main func HealthCheckHandler(w http.ResponseWriter, r *http.Request) { // A very simple health check. w.Header().Set("Content-Type", "application/json") w.WriteHeader(http.StatusOK) // In the future we could report back on the status of our DB, or our cache // (e.g. Redis) by performing a simple PING, and include them in the response. io.WriteString(w, "{\"alive\": true}") } func main() { r := mux.NewRouter() r.HandleFunc("/health", HealthCheckHandler) log.Fatal(http.ListenAndServe("localhost:8080", r)) } ``` -------------------------------- ### JSON Zip File Descriptor API Structure Source: https://github.com/scosman/zipstreamer/blob/master/README.md Defines the required JSON structure for describing the contents of a desired zip file. It includes a suggested filename for the archive and an array of file objects, each specifying a public URL and its intended path within the zip. ```APIDOC JSON Zip File Descriptor: suggestedFilename: [Optional, string] Description: The filename to suggest in the "Save As" UI in browsers. Defaults to `archive.zip` if not provided or invalid. Limited to US-ASCII. files: [Required, array] Description: An array describing the files to include in the zip file. Each array entry requires 2 properties: - url: [Required, string] Description: The public URL of the file to include in the zip. Zipstreamer will fetch this via a GET request. The file must be publically accessible via this URL. - zipPath: [Required, string] Description: The path and filename where this entry should appear in the resulting zip file. This is a relative path to the root of the zip file. ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.