Skip to content

Commit

Permalink
Merge remote-tracking branch 'github.com/mccutchen/go-httpbin/main' i…
Browse files Browse the repository at this point in the history
…nto relative-doc-links
  • Loading branch information
waschik committed Dec 9, 2023
2 parents 55b2b2a + b63a792 commit aef0101
Show file tree
Hide file tree
Showing 29 changed files with 3,612 additions and 1,774 deletions.
3 changes: 2 additions & 1 deletion .dockerignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
.git
.*
dist
examples
6 changes: 3 additions & 3 deletions .github/workflows/lint.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v2
- uses: actions/setup-go@v2
with:
go-version: '1.20'
- uses: golangci/golangci-lint-action@v3.4.0
go-version: '1.21'
- uses: golangci/golangci-lint-action@v3.7.0
with:
version: v1.52.2
version: v1.55.2
4 changes: 2 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ jobs:
steps:
- uses: actions/setup-go@v2
with:
go-version: '1.20'
go-version: '1.21'

- uses: actions/checkout@v2

Expand All @@ -43,8 +43,8 @@ jobs:
strategy:
matrix:
go_version:
- '1.20'
- '1.19'
- '1.18'

steps:
- uses: actions/setup-go@v2
Expand Down
23 changes: 1 addition & 22 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,27 +1,6 @@
# Compiled Object files, Static and Dynamic libs (Shared Objects)
*.o
*.a
*.so

# Folders
_obj
_test

# Architecture specific extensions/prefixes
*.[568vq]
[568vq].out

*.cgo1.go
*.cgo2.c
_cgo_defun.c
_cgo_gotypes.go
_cgo_export.*

_testmain.go

.*
*.exe
*.test
*.prof

dist/*
coverage.txt
113 changes: 113 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Development

## Local development

For interactive local development, use `make run` to build and run go-httpbin
or `make watch` to automatically re-build and re-run go-httpbin on every
change:

make run
make watch

By default, the server will listen on `http://127.0.0.1:8080`, but the host,
port, or any other [configuration option][config] may be overridden by
specifying the relevant environment variables:

make run PORT=9999
make run PORT=9999 MAX_DURATION=60s
make watch HOST=0.0.0.0 PORT=8888

## Testing

Run `make test` to run unit tests, using `TEST_ARGS` to pass arguments through
to `go test`:

make test
make test TEST_ARGS="-v -race -run ^TestDelay"

### Integration tests

go-httpbin includes its own minimal WebSocket echo server implementation, and
we use the incredibly helpful [Autobahn Testsuite][] to ensure that the
implementation conforms to the spec.

These tests can be slow to run (~40 seconds on my machine), so they are not run
by default when using `make test`.

They are run automatically as part of our extended "CI" test suite, which is
run on every pull request:

make testci

### WebSocket development

When working on the WebSocket implementation, it can also be useful to run
those integration tests directly, like so:

make testautobahn

Use the `AUTOBAHN_CASES` var to run a specific subset of the Autobahn tests,
which may or may not include wildcards:

make testautobahn AUTOBAHN_CASES=6.*
make testautobahn AUTOBAHN_CASES=6.5.*
make testautobahn AUTOBAHN_CASES=6.5.4


### Test coverage

We use [Codecov][] to measure and track test coverage as part of our continuous
integration test suite. While we strive for as much coverage as possible and
the Codecov CI check is configured with fairly strict requirements, 100% test
coverage is not an explicit goal or requirement for all contributions.

To view test coverage locally, use

make testcover

which will run the full suite of unit and integration tests and pop open a web
browser to view coverage results.


## Linting and code style

Run `make lint` to run our suite of linters and formatters, which include
gofmt, [revive][], and [staticcheck][]:

make lint


## Docker images

To build a docker image locally:

make image

To build a docker image an push it to a remote repository:

make imagepush

By default, images will be tagged as `mccutchen/go-httpbin:${COMMIT}` with the
current HEAD commit hash.

Use `VERSION` to override the tag value

make imagepush VERSION=v1.2.3

or `DOCKER_TAG` to override the remote repo and version at once:

make imagepush DOCKER_TAG=my-org/my-fork:v1.2.3

### Automated docker image builds

When a new release is created, the [Release][] GitHub Actions workflow
automatically builds and pushes new Docker images for both linux/amd64 and
linux/arm64 architectures.


[config]: /README.md#configuration
[revive]: https://github.com/mgechev/revive
[staticcheck]: https://staticcheck.dev/
[Release]: /.github/workflows/release.yaml
[Codecov]: https://app.codecov.io/gh/mccutchen/go-httpbin
[Autobahn Testsuite]: https://github.com/crossbario/autobahn-testsuite
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# syntax = docker/dockerfile:1.3
FROM golang:1.20 AS build
FROM golang:1.21 AS build

WORKDIR /go/src/github.com/mccutchen/go-httpbin

Expand Down
21 changes: 14 additions & 7 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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/[email protected]
REFLEX := go run github.com/cespare/[email protected]
STATICCHECK := go run honnef.co/go/tools/cmd/[email protected]

# Host and port to use when running locally via `make run` or `make watch`
HOST ?= 127.0.0.1
PORT ?= 8080


# =============================================================================
# build
Expand All @@ -34,7 +38,7 @@ buildtests:
.PHONY: buildtests

clean:
rm -rf $(DIST_PATH) $(COVERAGE_PATH)
rm -rf $(DIST_PATH) $(COVERAGE_PATH) .integrationtests
.PHONY: clean


Expand All @@ -45,23 +49,26 @@ 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
testci: build buildexamples
go test $(TEST_ARGS) $(COVERAGE_ARGS) ./...
git diff --exit-code
AUTOBAHN_TESTS=1 go test $(TEST_ARGS) $(COVERAGE_ARGS) ./...
.PHONY: testci

testcover: testci
go tool cover -html=$(COVERAGE_PATH)
.PHONY: testcover

# Run the autobahn fuzzingclient test suite
testautobahn:
AUTOBAHN_TESTS=1 AUTOBAHN_OPEN_REPORT=1 go test -v -run ^TestWebSocketServer$$ $(TEST_ARGS) ./...
.PHONY: autobahntests

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

Expand All @@ -70,7 +77,7 @@ lint:
# run locally
# =============================================================================
run: build
$(DIST_PATH)/go-httpbin
HOST=$(HOST) PORT=$(PORT) $(DIST_PATH)/go-httpbin
.PHONY: run

watch:
Expand Down
21 changes: 10 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ variables (or a combination of the two):
| `-max-duration` | `MAX_DURATION` | Maximum duration a response may take | 10s |
| `-port` | `PORT` | Port to listen on | 8080 |
| `-use-real-hostname` | `USE_REAL_HOSTNAME` | Expose real hostname as reported by os.Hostname() in the /hostname endpoint | false |
| `-exclude-headers` | `EXCLUDE_HEADERS` | Drop platform-specific headers. Comma-separated list of headers key to drop, supporting wildcard suffix matching. For example: `"foo,bar,x-fc-*"` | - |

**Notes:**
- Command line arguments take precedence over environment variables.
Expand Down Expand Up @@ -159,19 +160,16 @@ public internet, consider tuning it appropriately:
logging using [zerolog] and further hardens the HTTP server against
malicious clients by tuning lower-level timeouts and limits.

5. **Prevent leaking sensitive headers**

By default, go-httpbin will return any headers sent by the client in the response.
But if you want to deploy go-httpbin in some serverless environment, you may want to drop some headers.
You can use the `-exclude-headers` CLI argument or the `EXCLUDE_HEADERS` env var to configure an appropriate allowlist.
For example, Alibaba Cloud Function Compute will [add some headers like `x-fc-*` to the request](https://www.alibabacloud.com/help/en/fc/user-guide/specification-details). if you want to drop these `x-fc-*` headers, you can set `EXCLUDE_HEADERS=x-fc-*`.

## Development

```bash
# local development
make
make test
make testcover
make run

# building & pushing docker images
make image
make imagepush
```
See [DEVELOPMENT.md][].

## Motivation & prior art

Expand Down Expand Up @@ -210,3 +208,4 @@ Compared to [ahmetb/go-httpbin][ahmet]:
[Observer]: https://pkg.go.dev/github.com/mccutchen/go-httpbin/v2/httpbin#Observer
[Production considerations]: #production-considerations
[zerolog]: https://github.com/rs/zerolog
[DEVELOPMENT.md]: ./DEVELOPMENT.md
1 change: 1 addition & 0 deletions cmd/go-httpbin/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package main implements the go-httpbin command line tool.
package main

import (
Expand Down
1 change: 1 addition & 0 deletions examples/custom-instrumentation/main.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// Package main demonstrates how to instrument httpbin with custom metrics.
package main

import (
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module github.com/mccutchen/go-httpbin/v2

go 1.16
go 1.18
8 changes: 8 additions & 0 deletions httpbin/cmd/cmd.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package cmd implements the go-httpbin command line interface as a testable
// package.
package cmd

import (
Expand Down Expand Up @@ -69,6 +71,7 @@ func mainImpl(args []string, getEnv func(string) string, getHostname func() (str
httpbin.WithMaxBodySize(cfg.MaxBodySize),
httpbin.WithMaxDuration(cfg.MaxDuration),
httpbin.WithObserver(httpbin.StdLogObserver(logger)),
httpbin.WithExcludeHeaders(cfg.ExcludeHeaders),
}
if cfg.Prefix != "" {
opts = append(opts, httpbin.WithPrefix(cfg.Prefix))
Expand Down Expand Up @@ -102,6 +105,7 @@ func mainImpl(args []string, getEnv func(string) string, getHostname func() (str
type config struct {
AllowedRedirectDomains []string
ListenHost string
ExcludeHeaders string
ListenPort int
MaxBodySize int64
MaxDuration time.Duration
Expand Down Expand Up @@ -145,6 +149,7 @@ func loadConfig(args []string, getEnv func(string) string, getHostname func() (s
fs.StringVar(&cfg.Prefix, "prefix", "", "Path prefix (empty or start with slash and does not end with slash)")
fs.StringVar(&cfg.TLSCertFile, "https-cert-file", "", "HTTPS Server certificate file")
fs.StringVar(&cfg.TLSKeyFile, "https-key-file", "", "HTTPS Server private key file")
fs.StringVar(&cfg.ExcludeHeaders, "exclude-headers", "", "Drop platform-specific headers. Comma-separated list of headers key to drop, supporting wildcard matching.")

// in order to fully control error output whether CLI arguments or env vars
// are used to configure the app, we need to take control away from the
Expand Down Expand Up @@ -194,6 +199,9 @@ func loadConfig(args []string, getEnv func(string) string, getHostname func() (s
if cfg.ListenHost == defaultListenHost && getEnv("HOST") != "" {
cfg.ListenHost = getEnv("HOST")
}
if cfg.ExcludeHeaders == "" && getEnv("EXCLUDE_HEADERS") != "" {
cfg.ExcludeHeaders = getEnv("EXCLUDE_HEADERS")
}
if cfg.ListenPort == defaultListenPort && getEnv("PORT") != "" {
cfg.ListenPort, err = strconv.Atoi(getEnv("PORT"))
if err != nil {
Expand Down
12 changes: 9 additions & 3 deletions httpbin/cmd/cmd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ import (
const usage = `Usage of go-httpbin:
-allowed-redirect-domains string
Comma-separated list of domains the /redirect-to endpoint will allow
-exclude-headers string
Drop platform-specific headers. Comma-separated list of headers key to drop, supporting wildcard matching.
-host string
Host to listen on (default "0.0.0.0")
-https-cert-file string
Expand Down Expand Up @@ -457,18 +459,22 @@ func TestMainImpl(t *testing.T) {
wantOut: "error: could not look up real hostname: hostname failure",
},
"server error": {
args: []string{"-port", "-256"},
args: []string{
"-port", "-256",
"-host", "127.0.0.1", // default of 0.0.0.0 causes annoying permission popup on macOS
},
wantCode: 1,
wantOut: "go-httpbin listening on http://0.0.0.0:-256\nerror: listen tcp: address -256: invalid port\n",
wantOut: "go-httpbin listening on http://127.0.0.1:-256\nerror: listen tcp: address -256: invalid port\n",
},
"tls cert error": {
args: []string{
"-host", "127.0.0.1", // default of 0.0.0.0 causes annoying permission popup on macOS
"-port", "0",
"-https-cert-file", "./https-cert-does-not-exist",
"-https-key-file", "./https-key-does-not-exist",
},
wantCode: 1,
wantOut: "go-httpbin listening on https://0.0.0.0:0\nerror: open ./https-cert-does-not-exist: no such file or directory\n",
wantOut: "go-httpbin listening on https://127.0.0.1:0\nerror: open ./https-cert-does-not-exist: no such file or directory\n",
},
}

Expand Down
3 changes: 3 additions & 0 deletions httpbin/doc.go
Original file line number Diff line number Diff line change
@@ -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
Loading

0 comments on commit aef0101

Please sign in to comment.