1
0
Fork 0
mirror of https://github.com/edgurgel/httparrot synced 2025-04-05 08:12:31 -04:00

Initial commit

This commit is contained in:
Eduardo Gurgel 2013-12-26 17:29:18 -03:00
commit c3eb62d2c6
18 changed files with 386 additions and 0 deletions

4
.gitignore vendored Normal file
View file

@ -0,0 +1,4 @@
/_build
/deps
erl_crash.dump
*.ez

13
.travis.yml Normal file
View file

@ -0,0 +1,13 @@
language: erlang
notifications:
recipients:
- eduardo@gurgel.me
otp_release:
- R16B
- R16B01
- R16B02
before_install:
- git clone https://github.com/elixir-lang/elixir
- cd elixir && git checkout v0.11.2 && make && cd ..
before_script: "export PATH=`pwd`/elixir/bin:$PATH"
script: "MIX_ENV=test mix do deps.get, test --no-start"

35
README.md Normal file
View file

@ -0,0 +1,35 @@
# HTTParrot
httpbin.org clone
```
ENDPOINTS
/ This page.
/ip Returns Origin IP.
/user-agent Returns user-agent.
/headers Returns header dict.
/get Returns GET data.
/post Returns POST data.
/put Returns PUT data.
/patch Returns PATCH data.
/delete Returns DELETE data
/gzip Returns gzip-encoded data.
/status/:code Returns given HTTP Status code.
/response-headers?key=val Returns given response headers.
/redirect/:n 302 Redirects n times.
/redirect-to?url=foo 302 Redirects to the foo URL.
/relative-redirect/:n 302 Relative redirects n times.
/cookies Returns cookie data.
/cookies/set?name=value Sets one or more simple cookies.
/cookies/delete?name Deletes one or more simple cookies.
/basic-auth/:user/:passwd Challenges HTTPBasic Auth.
/hidden-basic-auth/:user/:passwd 404'd BasicAuth.
/digest-auth/:qop/:user/:passwd Challenges HTTP Digest Auth.
/stream/:n Streams n100 lines.
/delay/:n Delays responding for n10 seconds.
/html Renders an HTML Page.
/robots.txt Returns some robots.txt rules.
/deny Denied by robots.txt file.
/cache Returns 200 unless an If-Modified-Since header is provided, when it returns a 304 Not Modified.
```

28
lib/httparrot.ex Normal file
View file

@ -0,0 +1,28 @@
defmodule HTTParrot do
use Application.Behaviour
def start(_type, _args) do
dispatch = :cowboy_router.compile([
{:_, [ {'/ip', HTTParrot.IPHandler, []},
{'/user-agent', HTTParrot.UserAgentHandler, []},
{'/headers', HTTParrot.HeadersHandler, []},
{'/get', HTTParrot.GetHandler, []},
{'/status/:code', HTTParrot.StatusCodeHandler, []} ] }
])
{:ok, port} = :application.get_env(:httparrot, :port)
{:ok, _} = :cowboy.start_http(:http, 100, [port: port], [env: [dispatch: dispatch], onresponse: &prettify_json/4])
IO.puts "Starting HTTParrot using on port #{port}"
HTTParrot.Supervisor.start_link
end
def stop(_State), do: :ok
def prettify_json(status, headers, body, req) do
if JSEX.is_json? body do
body = JSEX.prettify!(body)
headers = ListDict.put(headers, "content-length", integer_to_list(String.length(body)))
end
{:ok, req} = :cowboy_req.reply(status, headers, body, req)
req
end
end

View file

@ -0,0 +1,31 @@
defmodule HTTParrot.GetHandler do
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
def allowed_methods(req, state) do
{["GET"], req, state}
end
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def get_json(req, state) do
{args, req} = :cowboy_req.qs_vals(req)
{headers, req} = :cowboy_req.headers(req)
{url, req} = :cowboy_req.url(req)
{{ip, _port}, req} = :cowboy_req.peer(req)
{response(args, headers, url, ip), req, state}
end
defp response(args, headers, url, ip) do
ip = :inet_parse.ntoa(ip) |> to_string
if args == [], do: args = [{}]
[args: args, headers: headers, url: url, origin: ip]
|> JSEX.encode!
end
def terminate(_, _, _), do: :ok
end

View file

@ -0,0 +1,25 @@
defmodule HTTParrot.HeadersHandler do
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
def allowed_methods(req, state) do
{["GET"], req, state}
end
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def get_json(req, state) do
{headers, req} = :cowboy_req.headers(req)
{response(headers), req, state}
end
defp response(headers) do
[headers: headers]
|> JSEX.encode!
end
def terminate(_, _, _), do: :ok
end

View file

@ -0,0 +1,27 @@
defmodule HTTParrot.IPHandler do
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
def allowed_methods(req, state) do
{["GET"], req, state}
end
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def get_json(req, state) do
{{ip, _port}, req} = :cowboy_req.peer(req)
{response(ip), req, state}
end
defp response(ip) do
ip = :inet_parse.ntoa(ip) |> to_string
[origin: ip]
|> JSEX.encode!
end
def terminate(_, _, _), do: :ok
end

View file

@ -0,0 +1,21 @@
defmodule HTTParrot.StatusCodeHandler do
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
def allowed_methods(req, state) do
{["GET"], req, state}
end
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def get_json(req, state) do
{code, req} = :cowboy_req.binding(:code, req)
{:ok, req} = :cowboy_req.reply(code, [], "", req)
{:halt, req, state}
end
def terminate(_, _, _), do: :ok
end

View file

@ -0,0 +1,14 @@
defmodule HTTParrot.Supervisor do
use Supervisor.Behaviour
def start_link do
:supervisor.start_link({:local, __MODULE__}, __MODULE__, [])
end
def init([]) do
children = []
supervise children, strategy: :one_for_one
end
end

View file

@ -0,0 +1,25 @@
defmodule HTTParrot.UserAgentHandler do
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
def allowed_methods(req, state) do
{["GET"], req, state}
end
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def get_json(req, state) do
{user_agent, req} = :cowboy_req.header("user-agent", req, "null")
{response(user_agent), req, state}
end
defp response(user_agent) do
[{"user-agent", user_agent}]
|> JSEX.encode!
end
def terminate(_, _, _), do: :ok
end

32
mix.exs Normal file
View file

@ -0,0 +1,32 @@
defmodule Httparrot.Mixfile do
use Mix.Project
def project do
[ app: :httparrot,
version: "0.0.1",
name: "HTTParrot",
elixir: "~> 0.11.2",
deps: deps(Mix.env) ]
end
def application do
[ applications: [ :compiler,
:syntax_tools,
:cowboy,
:jsex ],
mod: { HTTParrot, [] },
env: [ port: 8080 ] ]
end
defp deps(:dev) do
[ {:cowboy, github: "extend/cowboy", tag: "0.9.0" },
{:jsex, github: "talentdeficit/jsex", ref: "c9df36f07b2089a73ab6b32074c01728f1e5a2e1" } ]
end
defp deps(:test) do
deps(:dev) ++
[ {:meck, github: "eproxus/meck", tag: "0.8.1" } ]
end
defp deps(_), do: deps(:dev)
end

6
mix.lock Normal file
View file

@ -0,0 +1,6 @@
[ "cowboy": {:git, "git://github.com/extend/cowboy.git", "db52494371ea249f38d51108c7d79cf487ff6374", [{:tag, "0.9.0"}]},
"cowlib": {:git, "git://github.com/extend/cowlib.git", "63298e8e160031a70efff86a1acde7e7db1fcda6", [{:ref, "0.4.0"}]},
"jsex": {:git, "git://github.com/talentdeficit/jsex.git", "c9df36f07b2089a73ab6b32074c01728f1e5a2e1", [{:ref, "c9df36f07b2089a73ab6b32074c01728f1e5a2e1"}]},
"jsx": {:git, "git://github.com/talentdeficit/jsx.git", "e50af6e109cb03bd26acf715cbc77de746507d1d", [{:tag, "v1.4.3"}]},
"meck": {:git, "git://github.com/eproxus/meck.git", "1286aba1cb6bbd6c9fc3f817740758b224843ee7", [{:tag, "0.8.1"}]},
"ranch": {:git, "git://github.com/extend/ranch.git", "5df1f222f94e08abdcab7084f5e13027143cc222", [{:ref, "0.9.0"}]} ]

43
test/get_handler_test.exs Normal file
View file

@ -0,0 +1,43 @@
defmodule HTTParrot.GetHandlerTest do
use ExUnit.Case
import :meck
import HTTParrot.GetHandler
setup do
new :cowboy_req
end
teardown do
unload :cowboy_req
end
test "returns prettified json with query values, headers, url and origin" do
qs_vals = [{"a", "b"}]
headers = [header1: "value 1", header2: "value 2"]
ip = {127, 1, 2, 3}
url = "http://localhost/get?a=b"
expect(:cowboy_req, :qs_vals, 1, {qs_vals, :req2})
expect(:cowboy_req, :headers, 1, {headers, :req2})
expect(:cowboy_req, :url, 1, {url, :req2})
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req2})
assert get_json(:req1, :state) == {"{\"args\":{\"a\":\"b\"},\"headers\":{\"header1\":\"value 1\",\"header2\":\"value 2\"},\"url\":\"http://localhost/get?a=b\",\"origin\":\"127.1.2.3\"}", :req2, :state}
assert validate :cowboy_req
end
test "returns prettified json with no query value, headers, url and origin" do
qs_vals = []
headers = [header1: "value 1", header2: "value 2"]
ip = {127, 1, 2, 3}
url = "http://localhost/get"
expect(:cowboy_req, :qs_vals, 1, {qs_vals, :req2})
expect(:cowboy_req, :headers, 1, {headers, :req2})
expect(:cowboy_req, :url, 1, {url, :req2})
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req2})
assert get_json(:req1, :state) == {"{\"args\":{},\"headers\":{\"header1\":\"value 1\",\"header2\":\"value 2\"},\"url\":\"http://localhost/get\",\"origin\":\"127.1.2.3\"}", :req2, :state}
assert validate :cowboy_req
end
end

View file

@ -0,0 +1,20 @@
defmodule HTTParrot.HeadersHandlerTest do
use ExUnit.Case
import :meck
import HTTParrot.HeadersHandler
setup do
new :cowboy_req
end
teardown do
unload :cowboy_req
end
test "returns prettified json with headers list" do
headers = [header1: "value 1", header2: "value 2"]
expect(:cowboy_req, :headers, 1, {headers, :req2})
assert get_json(:req1, :state) == {"{\"headers\":{\"header1\":\"value 1\",\"header2\":\"value 2\"}}", :req2, :state}
assert validate :cowboy_req
end
end

20
test/ip_handler_test.exs Normal file
View file

@ -0,0 +1,20 @@
defmodule HTTParrot.IPHandlerTest do
use ExUnit.Case
import :meck
import HTTParrot.IPHandler
setup do
new :cowboy_req
end
teardown do
unload :cowboy_req
end
test "returns prettified json with origin" do
ip = {127, 1, 2, 3}
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req2})
assert get_json(:req1, :state) == {"{\"origin\":\"127.1.2.3\"}", :req2, :state}
assert validate :cowboy_req
end
end

View file

@ -0,0 +1,21 @@
defmodule HTTParrot.StatusCodeHandlerTest do
use ExUnit.Case
import :meck
import HTTParrot.StatusCodeHandler
setup do
new :cowboy_req
end
teardown do
unload :cowboy_req
end
test "reply with 'code' as status code" do
code = 123
expect(:cowboy_req, :binding, [{[:code, :req1], {code, :req2}}])
expect(:cowboy_req, :reply, [{[code, [], "", :req2], {:ok, :req3}}])
assert get_json(:req1, :state) == {:halt, :req3, :state}
assert validate :cowboy_req
end
end

1
test/test_helper.exs Normal file
View file

@ -0,0 +1 @@
ExUnit.start

20
test/user_agent_test.exs Normal file
View file

@ -0,0 +1,20 @@
defmodule HTTParrot.UserAgentHandlerTest do
use ExUnit.Case
import :meck
import HTTParrot.UserAgentHandler
setup do
new :cowboy_req
end
teardown do
unload :cowboy_req
end
test "returns prettified json with user agent" do
user_agent = "Mozilla Chrome"
expect(:cowboy_req, :header, [{["user-agent", :req1, "null"], {user_agent, :req2}}])
assert get_json(:req1, :state) == {"{\"user-agent\":\"Mozilla Chrome\"}", :req2, :state}
assert validate :cowboy_req
end
end