项目作者: KazuCocoa

项目描述 :
http proxy with Elixir. wait request with multi port and forward to each URIs
高级语言: Elixir
项目地址: git://github.com/KazuCocoa/http_proxy.git
创建时间: 2015-11-01T13:21:26Z
项目社区:https://github.com/KazuCocoa/http_proxy

开源协议:MIT License

下载


HttpProxy

Elixir CI

codecov

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

MY GOAL

  • Record/Play proxied requests
    • http_proxy support multi port and multi urls on one execution command mix proxy.
  • Support VCR

architecture

  1. http_proxy
  2. Client (server client) proxied_server
  3. | | |
  4. | 1.request | |
  5. | ------> | 2.request |
  6. | | ------> |
  7. | | |
  8. | | 3.response |
  9. | 4.response | <------ |
  10. | <------ | |
  11. | | |
  1. The client sends a request to http_proxy, then the http_proxy works as a proxy server.
  2. When the http_proxy receives the request from the client, then the http_proxy sends the request to a proxied server, e.g. http://google.com, as a 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

  • Elixir over 1.7

set application and deps

  • mix.exs
    • :logger is option.
    • :http_proxy is not need if you run http_proxy with HttpProxy.start/0 or HttpProxy.stop/0 manually.
  1. def application do
  2. [applications: [:logger, :http_proxy]]
  3. end
  4. ...
  5. defp deps do
  6. [
  7. {:http_proxy, "~> 1.4.0"}
  8. ]
  9. end

set configuration

  • config/config.exs
  1. use Mix.Config
  2. config :http_proxy,
  3. proxies: [
  4. %{port: 8080,
  5. to: "http://google.com"},
  6. %{port: 8081,
  7. to: "http://yahoo.com"}
  8. ]
  • To manage logger, you should define logger settings like the following.
  1. config :logger, :console,
  2. level: :info

solve deps and run a server

  1. $ mix deps.get
  2. $ mix clean
  3. $ 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.

  1. $ 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.

Development

  • Copy pre-commit hook
    • cp hooks/pre-commit ./git/hooks/pre-commit

Configuration

Customize proxy port

  • You can customize a proxy port. For example, if you change a waiting port from 8080 to 4000, then you can access to http://google.com via http://localhost:4000.
  1. use Mix.Config
  2. config :http_proxy,
  3. proxies: [
  4. %{port: 4000,
  5. to: "http://google.com"},
  6. %{port: 8081,
  7. to: "http://yahoo.com"}
  8. ]

Add proxy

  • You can add a waiting ports in configuration file. For example, the following setting allow you to access to http://apple.com via http://localhost:8082 in addition.
  1. use Mix.Config
  2. config :http_proxy,
  3. proxies: [
  4. %{port: 8080,
  5. to: "http://google.com"},
  6. %{port: 8081,
  7. to: "http://yahoo.com"},
  8. %{port: 8082,
  9. to: "http://apple.com"}
  10. ]

Play and Record mode

  • When :record and :play are false, then the http_proxy works just multi port proxy.
  • When :record is true, then the http_proxy works to record request which is proxied.
  • When :play is true, then the http_proxy works to play request between this the http_proxy and clients.
  1. use Mix.Config
  2. config :http_proxy,
  3. proxies: [ # MUST
  4. %{port: 8080, # proxy all request even play or record
  5. to: "http://google.com"},
  6. %{port: 8081,
  7. to: "http://yahoo.com"}
  8. ]
  9. timeout: 20_000, # Option, ms to wait http request.
  10. record: false, # Option, true: record requests. false: don't record.
  11. play: false, # Option, true: play stored requests. false: don't play.
  12. export_path: "test/example", # Option, path to export recorded files.
  13. play_path: "test/data" # Option, path to read json files as response to.

Example

Record request as the following

  1. {
  2. "request": {
  3. "headers": [],
  4. "method": "GET",
  5. "options": {
  6. "aspect": "query_params"
  7. },
  8. "remote": "127.0.0.1",
  9. "request_body": "",
  10. "url": "http://localhost:8080/hoge/inu?email=neko&pass=123"
  11. },
  12. "response": {
  13. "body_file": "path/to/body_file.json",
  14. "cookies": {},
  15. "headers": {
  16. "Cache-Control": "public, max-age=2592000",
  17. "Content-Length": "251",
  18. "Content-Type": "text/html; charset=UTF-8",
  19. "Date": "Sat, 21 Nov 2015 00:37:38 GMT",
  20. "Expires": "Mon, 21 Dec 2015 00:37:38 GMT",
  21. "Location": "http://www.google.com/hoge/inu?email=neko&pass=123",
  22. "Server": "sffe",
  23. "X-Content-Type-Options": "nosniff",
  24. "X-XSS-Protection": "1; mode=block"
  25. },
  26. "status_code": 301
  27. }
  28. }

Response body will save in “path/to/body_file.json”.

Play request with the following JSON data

  • Example is https://github.com/KazuCocoa/http_proxy/tree/master/test/data/mappings
  • You can set path or path_pattern as attribute under request.
    • If path, the http_proxy check requests are matched completely.
    • If path_pattern, the http_proxy check requests are matched with Regex.
  • You can set body or body_file as attribute under response.
    • If body, the http_proxy send the body string.
    • If body_file, the http_proxy send the body_file binary as response.

path and body case

  1. {
  2. "request": {
  3. "path": "/request/path",
  4. "port": 8080,
  5. "method": "GET"
  6. },
  7. "response": {
  8. "body": "<html>hello world</html>",
  9. "cookies": {},
  10. "headers": {
  11. "Content-Type": "text/html; charset=UTF-8",
  12. "Server": "GFE/2.0"
  13. },
  14. "status_code": 200
  15. }
  16. }

path_pattern and body_file case

  • Pattern match with Regex.match?(Regex.compile!("\A/request.*neko\z"), request_path)
  • File.read/2 via file/to/path.json and respond the binary
  1. {
  2. "request": {
  3. "path_pattern": "\A/request.*neko\z",
  4. "port": 8080,
  5. "method": "GET"
  6. },
  7. "response": {
  8. "body_file": "file/to/path.json",
  9. "cookies": {},
  10. "headers": {
  11. "Content-Type": "text/html; charset=UTF-8",
  12. "Server": "GFE/2.0"
  13. },
  14. "status_code": 200
  15. }
  16. }

dependencies

  1. $ mix xref graph
  2. lib/http_proxy.ex
  3. └── lib/http_proxy/supervisor.ex
  4. ├── lib/http_proxy/agent.ex
  5. ├── lib/http_proxy/play/data.ex
  6. ├── lib/http_proxy/agent.ex
  7. └── lib/http_proxy/play/response.ex
  8. ├── lib/http_proxy/play/data.ex
  9. └── lib/http_proxy/utils/file.ex
  10. └── lib/http_proxy/play/paths.ex
  11. ├── lib/http_proxy/agent.ex
  12. └── lib/http_proxy/play/response.ex
  13. └── lib/http_proxy/handle.ex
  14. ├── lib/http_proxy/play/body.ex
  15. ├── lib/http_proxy/play/data.ex
  16. ├── lib/http_proxy/play/paths.ex
  17. ├── lib/http_proxy/play/response.ex
  18. └── lib/http_proxy/record/response.ex
  19. ├── lib/http_proxy/format.ex
  20. └── lib/http_proxy/data.ex (compile)
  21. └── lib/http_proxy/utils/file.ex

TODO

styleguide

http://elixir.community/styleguide

LICENSE

MIT. Please read LICENSE.