Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preserve header case. File contents to override response. #69

Merged
merged 15 commits into from
Aug 17, 2024
Merged
30 changes: 17 additions & 13 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,17 @@ jobs:
images: |
mendhak/http-https-echo

- name: Build the image multi-platform
uses: docker/build-push-action@v5
with:
context: .
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le
push: false
cache-from: type=gha
cache-to: type=gha,mode=max
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
# Commenting out, possible bug: https://github.com/nodejs/docker-node/issues/1946
# - name: Build the image multi-platform
# uses: docker/build-push-action@v5
# with:
# context: .
# platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/ppc64le
# push: false
# cache-from: type=gha
# cache-to: type=gha,mode=max
# tags: ${{ steps.meta.outputs.tags }}
# labels: ${{ steps.meta.outputs.labels }}

# Due to bug https://github.com/docker/buildx/issues/59, need to build for single platform, load, then run tests.
- name: Build a test image single platform and load it
Expand All @@ -65,7 +66,9 @@ jobs:
load: true
cache-from: type=gha
cache-to: type=gha,mode=max
tags: "mendhak/http-https-echo:testing"
tags: |
${{ steps.meta.outputs.tags }}
"mendhak/http-https-echo:testing"
labels: ${{ steps.meta.outputs.labels }}

- name: Run tests using the test image
Expand All @@ -75,9 +78,10 @@ jobs:
id: scan
uses: anchore/scan-action@v3
with:
image: "mendhak/http-https-echo:latest"
image: "mendhak/http-https-echo:testing"
output-format: sarif
severity-cutoff: critical
# severity-cutoff: critical
fail-build: false

- name: upload Anchore scan SARIF report
uses: github/codeql-action/upload-sarif@v3
Expand Down
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@

## Version `34` - `2024-08-11`
* Set `PRESERVE_HEADER_CASE` to `1` to attempt to preserve the case of headers in the response.

## Version `33` - `2024-04-07`
* Implementing configurable CORS settings by [ash0ne](https://github.com/mendhak/docker-http-https-echo/pull/65).

Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
FROM node:16-alpine AS build
FROM node:18-alpine AS build

WORKDIR /app
COPY . /app
Expand All @@ -19,7 +19,7 @@ RUN set -ex \
&& chown -R node:node /app \
&& chmod +r /app/privkey.pem

FROM node:16-alpine AS final
FROM node:18-alpine AS final
LABEL \
org.opencontainers.image.title="http-https-echo" \
org.opencontainers.image.description="Docker image that echoes request data as JSON; listens on HTTP/S, with various extra features, useful for debugging." \
Expand Down
20 changes: 20 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ This image is executed as non root by default and is fully compliant with Kubern
- [Include environment variables in the response](#include-environment-variables-in-the-response)
- [Configuring CORS policy](#setting-corscross-origin-resource-sharing-headers-in-the-response)
- [Client certificate details (mTLS) in the response](#client-certificate-details-mtls-in-the-response)
- [Preserve the case of headers in response body](#preserve-the-case-of-headers-in-response-body)
- [Override the response body with a file](#override-the-response-body-with-a-file)
- [Prometheus Metrics](#prometheus-metrics)
- [Screenshots](#screenshots)
- [Building](#building)
Expand Down Expand Up @@ -278,6 +280,24 @@ If you browse to https://localhost:8443/ in Firefox, you won't get prompted to s
openssl pkcs12 -export -in cert.pem -inkey privkey.pem -out certpkcs12.pfx
```

## Preserve the case of headers in response body

By default, the headers in the response body are lowercased. To attempt to preserve the case of headers in the response body, set the environment variable `PRESERVE_HEADER_CASE` to true.

```bash
docker run -e PRESERVE_HEADER_CASE=true -p 8080:8080 -p 8443:8443 --rm -t mendhak/http-https-echo:33
```

## Override the response body with a file

To override the response body with a file, set the environment variable `OVERRIDE_RESPONSE_BODY_FILE_PATH` to a file path.
The file path needs to be in the `/app` directory.

```bash
docker run -d --rm -v ${PWD}/test.html:/app/test.html -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:33
```


## Prometheus Metrics

To expose http performance metrics, set the `PROMETHEUS_ENABLED` environment variable to true, the metrics will be available at `/metrics`. This uses the [`express-prom-bundle`](https://github.com/jochen-schweizer/express-prom-bundle) middleware
Expand Down
23 changes: 23 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@ app.use(function(req, res, next){

//Handle all paths
app.all('*', (req, res) => {

if(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH){
// Path is relative to current directory
res.sendFile(process.env.OVERRIDE_RESPONSE_BODY_FILE_PATH, { root : __dirname});
return;
}

const echo = {
path: req.path,
headers: req.headers,
Expand All @@ -69,6 +76,22 @@ app.all('*', (req, res) => {
}
};

if(process.env.PRESERVE_HEADER_CASE){
let newHeaders = {...req.headers};

// req.headers is in lowercase, processed, deduplicated. req.rawHeaders is not.
// Match on the preserved case of the header name, populate newHeaders with preserved case and processed value.
for (let i = 0; i < req.rawHeaders.length; i += 2) {
let preservedHeaderName = req.rawHeaders[i];
if (preservedHeaderName == preservedHeaderName.toLowerCase()) { continue; }

newHeaders[preservedHeaderName] = req.header(preservedHeaderName);
delete newHeaders[preservedHeaderName.toLowerCase()];
}
echo.headers = newHeaders;
}


//Add client certificate details to the output, if present
//This only works if `requestCert` is true when starting the server.
if(req.socket.getPeerCertificate){
Expand Down
37 changes: 36 additions & 1 deletion tests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ docker ps -aq --filter "name=http-echo-tests" | grep -q . && docker stop http-ec

message " Start container normally "
docker run -d --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing
sleep 5
sleep 10


message " Make http(s) request, and test the path, method, header and status code. "
Expand Down Expand Up @@ -510,6 +510,41 @@ else
exit 1
fi


message " Stop containers "
docker stop http-echo-tests
sleep 5

message " Start container with PRESERVE_HEADER_CASE enabled "
docker run -d -e PRESERVE_HEADER_CASE=true --rm --name http-echo-tests -p 8080:8080 -p 8443:8443 -t mendhak/http-https-echo:testing

sleep 5
HEADER_CASE_CHECK=$(curl -s -H "prEseRVe-CaSE: A1b2C3" -H 'x-a-b: 999' -H 'X-a-B: 13' localhost:8080 | jq -r '.headers."prEseRVe-CaSE"')
if [[ "$HEADER_CASE_CHECK" == "A1b2C3" ]]
then
passed "PRESERVE_HEADER_CASE enabled"
else
failed "PRESERVE_HEADER_CASE failed"
exit 1
fi

message " Stop containers "
docker stop http-echo-tests
sleep 5

message " Start container with a custom response body from a file "
echo "<h1>Hello World</h1>" > test.html
docker run -d --rm -v ${PWD}/test.html:/app/test.html --name http-echo-tests -p 8080:8080 -e OVERRIDE_RESPONSE_BODY_FILE_PATH=/test.html -t mendhak/http-https-echo:testing
sleep 5
RESPONSE_BODY=$(curl -s http://localhost:8080)
if [[ "$RESPONSE_BODY" == "<h1>Hello World</h1>" ]]
then
passed "Custom response body from file"
else
failed "Custom response body from file failed"
exit 1
fi

message " Stop containers "
docker stop http-echo-tests
sleep 5
Expand Down