diff --git a/.dockerignore b/.dockerignore index c58ffcd4..9eac0c96 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,3 @@ -.git +.* dist +examples diff --git a/.github/workflows/lint.yaml b/.github/workflows/lint.yaml index 1901739c..53fb89c4 100644 --- a/.github/workflows/lint.yaml +++ b/.github/workflows/lint.yaml @@ -20,6 +20,6 @@ jobs: - uses: actions/setup-go@v2 with: go-version: '1.21' - - uses: golangci/golangci-lint-action@v3.4.0 + - uses: golangci/golangci-lint-action@v3.7.0 with: - version: v1.52.2 + version: v1.55.2 diff --git a/Makefile b/Makefile index bbcd4ae8..033d7655 100644 --- a/Makefile +++ b/Makefile @@ -12,10 +12,14 @@ COVERAGE_ARGS ?= -covermode=atomic -coverprofile=$(COVERAGE_PATH) TEST_ARGS ?= -race # 3rd party tools -GOLINT := go run golang.org/x/lint/golint@latest +LINT := go run github.com/mgechev/revive@v1.3.4 REFLEX := go run github.com/cespare/reflex@v0.3.1 STATICCHECK := go run honnef.co/go/tools/cmd/staticcheck@2023.1.3 +# Host and port to use when running locally via `make run` or `make watch` +HOST ?= 127.0.0.1 +PORT ?= 8080 + # ============================================================================= # build @@ -45,7 +49,6 @@ test: go test $(TEST_ARGS) ./... .PHONY: test - # Test command to run for continuous integration, which includes code coverage # based on codecov.io's documentation: # https://github.com/codecov/example-go/blob/b85638743b972bd0bd2af63421fe513c6f968930/README.md @@ -61,7 +64,7 @@ testcover: testci lint: test -z "$$(gofmt -d -s -e .)" || (echo "Error: gofmt failed"; gofmt -d -s -e . ; exit 1) go vet ./... - $(GOLINT) -set_exit_status ./... + $(LINT) -set_exit_status ./... $(STATICCHECK) ./... .PHONY: lint @@ -70,7 +73,7 @@ lint: # run locally # ============================================================================= run: build - $(DIST_PATH)/go-httpbin -host 127.0.0.1 -port 8080 + HOST=$(HOST) PORT=$(PORT) $(DIST_PATH)/go-httpbin .PHONY: run watch: diff --git a/cmd/go-httpbin/main.go b/cmd/go-httpbin/main.go index 6cdcf927..36b83fec 100644 --- a/cmd/go-httpbin/main.go +++ b/cmd/go-httpbin/main.go @@ -1,3 +1,4 @@ +// Package main implements the go-httpbin command line tool. package main import ( diff --git a/examples/custom-instrumentation/main.go b/examples/custom-instrumentation/main.go index f414e0be..53a0cc35 100644 --- a/examples/custom-instrumentation/main.go +++ b/examples/custom-instrumentation/main.go @@ -1,3 +1,4 @@ +// Package main demonstrates how to instrument httpbin with custom metrics. package main import ( diff --git a/httpbin/cmd/cmd.go b/httpbin/cmd/cmd.go index 1a1b7098..d2c5283c 100644 --- a/httpbin/cmd/cmd.go +++ b/httpbin/cmd/cmd.go @@ -1,3 +1,5 @@ +// Package cmd implements the go-httpbin command line interface as a testable +// package. package cmd import ( diff --git a/httpbin/doc.go b/httpbin/doc.go new file mode 100644 index 00000000..9ced272f --- /dev/null +++ b/httpbin/doc.go @@ -0,0 +1,3 @@ +// Package httpbin provides a simple HTTP request and response testing server, +// modeled on the original httpbin.org Python project. +package httpbin diff --git a/httpbin/handlers.go b/httpbin/handlers.go index 0755a83d..a122a016 100644 --- a/httpbin/handlers.go +++ b/httpbin/handlers.go @@ -19,7 +19,7 @@ import ( var nilValues = url.Values{} -func notImplementedHandler(w http.ResponseWriter, r *http.Request) { +func notImplementedHandler(w http.ResponseWriter, _ *http.Request) { writeError(w, http.StatusNotImplemented, nil) } @@ -34,12 +34,12 @@ func (h *HTTPBin) Index(w http.ResponseWriter, r *http.Request) { } // FormsPost renders an HTML form that submits a request to the /post endpoint -func (h *HTTPBin) FormsPost(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) FormsPost(w http.ResponseWriter, _ *http.Request) { writeHTML(w, mustStaticAsset("forms-post.html"), http.StatusOK) } // UTF8 renders an HTML encoding stress test -func (h *HTTPBin) UTF8(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) UTF8(w http.ResponseWriter, _ *http.Request) { writeHTML(w, mustStaticAsset("utf8.html"), http.StatusOK) } @@ -80,7 +80,7 @@ func (h *HTTPBin) RequestWithBody(w http.ResponseWriter, r *http.Request) { URL: getURL(r).String(), } - if err := parseBody(w, r, resp); err != nil { + if err := parseBody(r, resp); err != nil { writeError(w, http.StatusBadRequest, fmt.Errorf("error parsing request body: %w", err)) return } @@ -718,12 +718,12 @@ func (h *HTTPBin) Range(w http.ResponseWriter, r *http.Request) { } // HTML renders a basic HTML page -func (h *HTTPBin) HTML(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) HTML(w http.ResponseWriter, _ *http.Request) { writeHTML(w, mustStaticAsset("moby.html"), http.StatusOK) } // Robots renders a basic robots.txt file -func (h *HTTPBin) Robots(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) Robots(w http.ResponseWriter, _ *http.Request) { robotsTxt := []byte(`User-agent: * Disallow: /deny `) @@ -731,7 +731,7 @@ Disallow: /deny } // Deny renders a basic page that robots should never access -func (h *HTTPBin) Deny(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) Deny(w http.ResponseWriter, _ *http.Request) { writeResponse(w, http.StatusOK, textContentType, []byte(`YOU SHOULDN'T BE HERE`)) } @@ -926,7 +926,7 @@ func (h *HTTPBin) Links(w http.ResponseWriter, r *http.Request) { } // doLinksPage renders a page with a series of N links -func doLinksPage(w http.ResponseWriter, r *http.Request, n int, offset int) { +func doLinksPage(w http.ResponseWriter, _ *http.Request, n int, offset int) { w.Header().Add("Content-Type", htmlContentType) w.WriteHeader(http.StatusOK) @@ -988,7 +988,7 @@ func doImage(w http.ResponseWriter, kind string) { } // XML responds with an XML document -func (h *HTTPBin) XML(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) XML(w http.ResponseWriter, _ *http.Request) { writeResponse(w, http.StatusOK, "application/xml", mustStaticAsset("sample.xml")) } @@ -1042,7 +1042,7 @@ func (h *HTTPBin) DigestAuth(w http.ResponseWriter, r *http.Request) { } // UUID - responds with a generated UUID -func (h *HTTPBin) UUID(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) UUID(w http.ResponseWriter, _ *http.Request) { writeJSON(http.StatusOK, w, uuidResponse{ UUID: uuidv4(), }) @@ -1085,7 +1085,7 @@ func (h *HTTPBin) DumpRequest(w http.ResponseWriter, r *http.Request) { } // JSON - returns a sample json -func (h *HTTPBin) JSON(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) JSON(w http.ResponseWriter, _ *http.Request) { w.Header().Set("Content-Type", jsonContentType) w.WriteHeader(http.StatusOK) w.Write(mustStaticAsset("sample.json")) @@ -1107,7 +1107,7 @@ func (h *HTTPBin) Bearer(w http.ResponseWriter, r *http.Request) { } // Hostname - returns the hostname. -func (h *HTTPBin) Hostname(w http.ResponseWriter, r *http.Request) { +func (h *HTTPBin) Hostname(w http.ResponseWriter, _ *http.Request) { writeJSON(http.StatusOK, w, hostnameResponse{ Hostname: h.hostname, }) diff --git a/httpbin/helpers.go b/httpbin/helpers.go index cff9b9cb..b9c36b39 100644 --- a/httpbin/helpers.go +++ b/httpbin/helpers.go @@ -160,7 +160,7 @@ func parseFiles(fileHeaders map[string][]*multipart.FileHeader) (map[string][]st // // Note: this function expects callers to limit the the maximum size of the // request body. See, e.g., the limitRequestSize middleware. -func parseBody(w http.ResponseWriter, r *http.Request, resp *bodyResponse) error { +func parseBody(r *http.Request, resp *bodyResponse) error { defer r.Body.Close() // Always set resp.Data to the incoming request body, in case we don't know diff --git a/httpbin/options.go b/httpbin/options.go index 0fa59762..74747d60 100644 --- a/httpbin/options.go +++ b/httpbin/options.go @@ -46,6 +46,8 @@ func WithObserver(o Observer) OptionFunc { } } +// WithExcludeHeaders sets the headers to exclude in outgoing responses, to +// prevent possible information leakage. func WithExcludeHeaders(excludeHeaders string) OptionFunc { return func(h *HTTPBin) { h.setExcludeHeaders(excludeHeaders) diff --git a/internal/testing/assert/assert.go b/internal/testing/assert/assert.go index 36b5e895..673773b3 100644 --- a/internal/testing/assert/assert.go +++ b/internal/testing/assert/assert.go @@ -1,3 +1,4 @@ +// Package assert implements common assertions used in go-httbin's unit tests. package assert import ( diff --git a/internal/testing/must/must.go b/internal/testing/must/must.go index 8737cd9d..3796dd25 100644 --- a/internal/testing/must/must.go +++ b/internal/testing/must/must.go @@ -1,3 +1,5 @@ +// Package must implements helper functions for testing to eliminate some error +// checking boilerplate. package must import (