-
Notifications
You must be signed in to change notification settings - Fork 7
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Joris Berthelot
committed
Nov 6, 2015
0 parents
commit 23779e9
Showing
9 changed files
with
379 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.git | ||
.DS_Store | ||
node_modules |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
; This file is for unifying the coding style for different editors and IDEs. | ||
; More information at http://editorconfig.org | ||
|
||
root = true | ||
|
||
[*] | ||
charset = utf-8 | ||
end_of_line = lf | ||
indent_size = 4 | ||
indent_style = space | ||
insert_final_newline = true | ||
trim_trailing_whitespace = true | ||
|
||
; Works with some editors only | ||
quote_type = single | ||
max_line_length = 120 | ||
spaces_around_brackets = true | ||
spaces_around_operators = true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
sudo: required | ||
|
||
env: | ||
global: | ||
- TAG_PATTERN="^[0-9]+(\.[0-9]+){2}(-(alpha|beta|rc))?$" | ||
- DOCKER_IMAGE=eexit/mirror-http-server:${TRAVIS_TAG:=$TRAVIS_BUILD_NUMBER} | ||
|
||
services: | ||
- docker | ||
|
||
before_install: | ||
- docker login --email=$DOCKER_EMAIL --username=$DOCKER_USER --password=$DOCKER_PASSWD | ||
|
||
install: | ||
- docker build -t $DOCKER_IMAGE . | ||
|
||
script: | ||
- docker run $DOCKER_IMAGE npm test | ||
|
||
after_success: | ||
- if [[ "$TRAVIS_TAG" =~ $TAG_PATTERN ]]; then docker push $DOCKER_IMAGE; fi |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
FROM node:4.2-onbuild | ||
MAINTAINER Joris Berthelot <[email protected]> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
The MIT License (MIT) | ||
|
||
Copyright (c) 2015 Joris Berthelot | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,195 @@ | ||
![logo](logo.png) | ||
|
||
# Mirror HTTP Server [![Build Status](https://travis-ci.org/eexit/mirror-http-server.svg)](https://travis-ci.org/eexit/mirror-http-server) | ||
|
||
*A dummy HTTP server that responds whatever you told him to.* | ||
|
||
Build to play with HTTP or test your API. Make a HTTP call to the dummy server with the specified headers you want the server responds with. | ||
|
||
## Usage | ||
|
||
Pull the [Docker](https://www.docker.com) container: | ||
|
||
$ docker pull eexit/mirror-http-server | ||
|
||
Start the container: | ||
|
||
$ docker run -itp 80:80 eexit/mirror-http-server | ||
2015-11-05T20:59:57.353Z] INFO: mirror-http-server/17 on ccc867df5980: Listening on http://0.0.0.0:80 | ||
|
||
For this README examples, I use the great [HTTPie](https://github.com/jkbrzt/httpie) tool. | ||
|
||
Send request againt it: | ||
|
||
http $(docker-machine ip default) | ||
|
||
```http | ||
HTTP/1.1 200 OK | ||
Connection: keep-alive | ||
Content-Length: 0 | ||
Date: Thu, 05 Nov 2015 21:33:20 GMT | ||
X-Powered-By: Express | ||
``` | ||
|
||
You can use any [HTTP verbs](https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol#Request_methods) with any path, any request body and any header. | ||
|
||
### Behavioural request headers | ||
|
||
You can change the server response code and body by setting specific `X-Mirror-*` headers to your request. | ||
|
||
### `X-Mirror-Code` | ||
|
||
Change the server response [status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes). | ||
Here, simulate a server error: | ||
|
||
$ http $(docker-machine ip default) X-Mirror-Code:503 | ||
|
||
```http | ||
HTTP/1.1 503 Service Unavailable | ||
Connection: keep-alive | ||
Content-Length: 0 | ||
Date: Thu, 05 Nov 2015 22:30:11 GMT | ||
X-Powered-By: Express | ||
``` | ||
|
||
Here, simulate a `301` redirection: | ||
|
||
http $(docker-machine ip default) \ | ||
X-Mirror-Code:301 \ | ||
X-Mirror-Location:http://www.eexit.net \ | ||
X-Mirror-Content-Type:"text/plain; charset=ISO-8859-1" | ||
|
||
```http | ||
HTTP/1.1 301 Moved Permanently | ||
Connection: keep-alive | ||
Content-Length: 0 | ||
Content-Type: text/plain; charset=ISO-8859-1 | ||
Date: Thu, 05 Nov 2015 22:40:02 GMT | ||
Location: http://www.eexit.net | ||
X-Powered-By: Express | ||
``` | ||
|
||
If you add the `--follow` option, it will output my website HTML source. | ||
|
||
If you check the container logs: | ||
|
||
```json | ||
[2015-11-05T22:48:59.564Z] INFO: mirror-server/18 on 6cb74ed853b0: | ||
request: { | ||
"ip": "192.168.99.1", | ||
"ips": [], | ||
"method": "GET", | ||
"url": "/", | ||
"headers": { | ||
"host": "192.168.99.100", | ||
"x-mirror-code": "301", | ||
"accept-encoding": "gzip, deflate", | ||
"x-mirror-location": "http://www.eexit.net", | ||
"accept": "*/*", | ||
"user-agent": "HTTPie/0.9.2", | ||
"connection": "keep-alive", | ||
"x-mirror-content-type": "text/plain; charset=ISO-8859-1" | ||
}, | ||
"body": {} | ||
} | ||
``` | ||
|
||
### `X-Mirror-Request` | ||
|
||
If you access to the server logs or want to exploit the what's logged, set the `X-Mirror-Request` to receive what's logged in a JSON format: | ||
|
||
$ http POST $(docker-machine ip default)/resource \ | ||
X-Mirror-Code:201 \ | ||
X-Mirror-Request:true \ | ||
key1=value1 key2=value2 | ||
|
||
```http | ||
HTTP/1.1 201 Created | ||
Connection: keep-alive | ||
Content-Length: 373 | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Thu, 05 Nov 2015 22:57:17 GMT | ||
ETag: W/"175-3rxm7gM5Zwu88cZOABP92A" | ||
X-Powered-By: Express | ||
{ | ||
"request": { | ||
"body": { | ||
"key1": "value1", | ||
"key2": "value2" | ||
}, | ||
"headers": { | ||
"accept": "application/json", | ||
"accept-encoding": "gzip, deflate", | ||
"connection": "keep-alive", | ||
"content-length": "36", | ||
"content-type": "application/json", | ||
"host": "192.168.99.100", | ||
"user-agent": "HTTPie/0.9.2", | ||
"x-mirror-code": "201", | ||
"x-mirror-request": "true" | ||
}, | ||
"ip": "192.168.99.1", | ||
"ips": [], | ||
"method": "POST", | ||
"url": "/resource" | ||
} | ||
} | ||
``` | ||
|
||
### `X-Mirror-Body` | ||
|
||
Instead, if you with the dummy server to return you the same body you requested to it, set the `X-Mirror-Body` header. | ||
|
||
Note: the `X-Mirror-Request` header will override `X-Mirror-Body` header. | ||
|
||
$ http PUT $(docker-machine ip default)/resource \ | ||
X-Mirror-Code:400 \ | ||
X-Mirror-Body:true \ | ||
key1=value1 key2=value2 | ||
|
||
```http | ||
HTTP/1.1 400 Bad Request | ||
Connection: keep-alive | ||
Content-Length: 33 | ||
Content-Type: application/json; charset=utf-8 | ||
Date: Thu, 05 Nov 2015 23:52:34 GMT | ||
ETag: W/"21-/0XMODUWUwfvQUwjyixvZw" | ||
X-Powered-By: Express | ||
{ | ||
"key1": "value1", | ||
"key2": "value2" | ||
} | ||
``` | ||
|
||
### Works for all headers | ||
|
||
Aside to the previous three special headers, you can set your wanted response header by prepending your header name by `X-Mirror-`. | ||
|
||
In the request: | ||
|
||
```http | ||
Content-Type: application/json | ||
X-Mirror-Content-Type: text/html | ||
``` | ||
|
||
You'll get in your response: | ||
|
||
```http | ||
Content-Type: text/html | ||
``` | ||
|
||
You can even override Express headers or any other default header: | ||
|
||
```http | ||
X-Mirror-X-Powered-By: eexit-engine | ||
X-Mirror-Date: some date | ||
``` | ||
|
||
Will turn into: | ||
|
||
```http | ||
X-Powered-By: eexit-engine | ||
Date: some date | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
{ | ||
"name": "mirror-http-server", | ||
"version": "1.0.0", | ||
"description": "A dummy HTTP server that responds whatever you told him to", | ||
"scripts": { | ||
"start": "node server.js | npm run bunyan", | ||
"start:dev": "nodemon server.js | npm run bunyan", | ||
"test": "echo \"No test specified yet\"", | ||
"bunyan": "$(npm bin)/bunyan" | ||
}, | ||
"keywords": [ | ||
"node", | ||
"nodejs", | ||
"server", | ||
"http", | ||
"mirror", | ||
"dumb", | ||
"dump", | ||
"test", | ||
"development" | ||
], | ||
"author": "Joris Berthelot <[email protected]>", | ||
"license": "MIT", | ||
"dependencies": { | ||
"body-parser": "^1.14.1", | ||
"bunyan": "^1.5.1", | ||
"express": "^4.13.3", | ||
"lodash": "^3.10.1", | ||
"nodemon": "^1.8.1" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
'use strict'; | ||
|
||
var host = process.env.HOST || '0.0.0.0'; | ||
var port = process.env.PORT || 80; | ||
|
||
var _ = require('lodash'); | ||
var bunyan = require('bunyan'); | ||
var bodyParser = require('body-parser'); | ||
var pckg = require(__dirname + '/package.json'); | ||
var logger = bunyan.createLogger({name: pckg.name}); | ||
var express = require('express'); | ||
var app = express(); | ||
|
||
app.enable('trust proxy'); | ||
app.use(bodyParser.json()); | ||
app.use(bodyParser.urlencoded({ extended: true })); | ||
|
||
// Intercepts all HTTP verb requests | ||
app.all('*', function (req, res, next) { | ||
// Returned response headers | ||
var responseHeaders = {}; | ||
|
||
// Parses the wanted response code | ||
var mirrorCode = req.get('X-Mirror-Code') || 200; | ||
|
||
// Finds out if the request should be returned as the response | ||
var mirrorRequest = (req.get('X-Mirror-Request') | ||
&& req.get('X-Mirror-Request').toLowerCase() == 'true') | ||
|| false; | ||
|
||
// Finds out if the response should be returned | ||
var mirrorBody = (req.get('X-Mirror-Body') | ||
&& req.get('X-Mirror-Body').toLowerCase() == 'true') | ||
|| false; | ||
|
||
// Parses X-Mirror-* headers, skips app specific headers | ||
var reqHeaders = _.without( | ||
_.filter( | ||
Object.keys(req.headers), function (name) { | ||
return _.startsWith(name, 'x-mirror-'); | ||
} | ||
), 'x-mirror-code', 'x-mirror-request', 'x-mirror-body' | ||
); | ||
|
||
// Injects X-Mirror-* headers to response headers | ||
reqHeaders.forEach(function (name) { | ||
var resHeader = _.startCase(_.trimLeft(name, 'x-mirror-')).replace(' ', '-'); | ||
responseHeaders[resHeader] = req.headers[name]; | ||
}); | ||
|
||
// Builds the request object | ||
var request = { | ||
request: { | ||
ip: req.ip, | ||
ips: req.ips, | ||
method: req.method, | ||
url: req.originalUrl, | ||
headers: req.headers, | ||
body: req.body | ||
} | ||
}; | ||
|
||
logger.info(request); | ||
|
||
|
||
// Prepares the response | ||
res.status(mirrorCode).set(responseHeaders); | ||
|
||
// Appends the full request or only the request body if wanted | ||
if (mirrorRequest) { | ||
res.json(request); | ||
} else if (mirrorBody) { | ||
res.send(req.body); | ||
} | ||
|
||
// Flushes! | ||
res.end(); | ||
}); | ||
|
||
// Basic error handler | ||
app.use(function (err, req, res, next) { | ||
logger.fatal(err); | ||
res.status(500).json(err); | ||
}); | ||
|
||
app.listen(port, host, 511, function () { | ||
logger.info('Listening on http://%s:%s', host, port); | ||
}); |