HttpProxy

Build Status

codecov

Simple multi HTTP Proxy using Plug. And support record/play requests.

MY GOAL

architecture

http_proxy
Client (server client) proxied_server
| | |
| 1.request | |
| ------> | 2.request |
| | ------> |
| | |
| | 3.response |
| 4.response | <------ |
| <------ | |
| | |
  1. The client sends request to http_proxy, then the http_proxy works as a proxy server.
  2. When the http_proxy receives request from the client, then the http_proxy sends request to proxied server, e.g. http://google.com, as client.
  3. The http_proxy receives responses from the proxied_server, then the http_proxy sets the response into its response to the client.
  4. The Client receives responses from the http_proxy.

Quick use as http proxy

requirement

set application and deps

def application do
[applications: [:logger, :http_proxy]]
end
...
defp deps do
[
{:http_proxy, "~> 1.2.1"}
]
end

set configuration

use Mix.Config
config :http_proxy,
proxies: [
%{port: 8080,
to: "http://google.com"},
%{port: 8081,
to: "http://yahoo.com"}
]
config :logger, :console,
level: :info

solve deps and run server

$ mix deps.get
$ mix clean
$ mix run --no-halt # start proxy server

If you would like to start production mode, you should run with MIX_ENV=prod like the following command.

$ MIX_ENV=prod mix run --no-halt

launch browser

Launch browser and open http://localhost:8080 or http://localhost:8081. Then, http://localhost:8080 redirect to http://google.com and http://localhost:8081 do to http://yahoo.com.

Configuration

Customize proxy port

use Mix.Config
config :http_proxy,
proxies: [
%{port: 4000,
to: "http://google.com"},
%{port: 8081,
to: "http://yahoo.com"}
]

Add proxy

use Mix.Config
config :http_proxy,
proxies: [
%{port: 8080,
to: "http://google.com"},
%{port: 8081,
to: "http://yahoo.com"},
%{port: 8082,
to: "http://apple.com"}
]

Play and Record mode

use Mix.Config
config :http_proxy,
proxies: [ # MUST
%{port: 8080, # proxy all request even play or record
to: "http://google.com"},
%{port: 8081,
to: "http://yahoo.com"}
]
timeout: 20_000, # Option, ms to wait http request.
record: false, # Option, true: record requests. false: don't record.
play: false, # Option, true: play stored requests. false: don't play.
export_path: "test/example", # Option, path to export recorded files.
play_path: "test/data" # Option, path to read json files as response to.

Example

Record request as the following

{
"request": {
"headers": [],
"method": "GET",
"options": {
"aspect": "query_params"
},
"remote": "127.0.0.1",
"request_body": "",
"url": "http://localhost:8080/hoge/inu?email=neko&pass=123"
},
"response": {
"body_file": "path/to/body_file.json",
"cookies": {},
"headers": {
"Cache-Control": "public, max-age=2592000",
"Content-Length": "251",
"Content-Type": "text/html; charset=UTF-8",
"Date": "Sat, 21 Nov 2015 00:37:38 GMT",
"Expires": "Mon, 21 Dec 2015 00:37:38 GMT",
"Location": "http://www.google.com/hoge/inu?email=neko&pass=123",
"Server": "sffe",
"X-Content-Type-Options": "nosniff",
"X-XSS-Protection": "1; mode=block"
},
"status_code": 301
}
}

Response body will save in "path/to/body_file.json".

Play request with the following JSON data

path and body case

{
"request": {
"path": "/request/path",
"port": 8080,
"method": "GET"
},
"response": {
"body": "<html>hello world</html>",
"cookies": {},
"headers": {
"Content-Type": "text/html; charset=UTF-8",
"Server": "GFE/2.0"
},
"status_code": 200
}
}

path_pattern and body_file case

{
"request": {
"path_pattern": "\A/request.*neko\z",
"port": 8080,
"method": "GET"
},
"response": {
"body_file": "file/to/path.json",
"cookies": {},
"headers": {
"Content-Type": "text/html; charset=UTF-8",
"Server": "GFE/2.0"
},
"status_code": 200
}
}

dependencies

$ mix xref graph
lib/http_proxy.ex
└── lib/http_proxy/supervisor.ex
├── lib/http_proxy/agent.ex
│ ├── lib/http_proxy/play/data.ex
│ │ ├── lib/http_proxy/agent.ex
│ │ └── lib/http_proxy/play/response.ex
│ │ ├── lib/http_proxy/play/data.ex
│ │ └── lib/http_proxy/utils/file.ex
│ └── lib/http_proxy/play/paths.ex
│ ├── lib/http_proxy/agent.ex
│ └── lib/http_proxy/play/response.ex
└── lib/http_proxy/handle.ex
├── lib/http_proxy/play/body.ex
├── lib/http_proxy/play/data.ex
├── lib/http_proxy/play/paths.ex
├── lib/http_proxy/play/response.ex
└── lib/http_proxy/record/response.ex
├── lib/http_proxy/format.ex
│ └── lib/http_proxy/data.ex (compile)
└── lib/http_proxy/utils/file.ex

TODO

styleguide

http://elixir.community/styleguide

LICENSE

MIT. Please read LICENSE.