1
0
Fork 0
mirror of https://github.com/edgurgel/httparrot synced 2025-04-06 00:32:34 -04:00

Compare commits

..

No commits in common. "master" and "v0.4.2" have entirely different histories.

81 changed files with 699 additions and 1515 deletions

View file

@ -1,4 +0,0 @@
# Used by "mix format"
[
inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"]
]

View file

@ -1,54 +0,0 @@
name: CI
on: [push, pull_request]
jobs:
format:
name: Format & credo
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2.3.1
- name: Install OTP and Elixir
uses: erlef/setup-beam@v1
with:
otp-version: 26.x
elixir-version: 1.16.x
- name: Install dependencies
run: mix deps.get
- name: Compile with --warnings-as-errors
run: mix compile --warnings-as-errors
- name: Run "mix format"
run: mix format --check-formatted
test:
name: Test (Elixir ${{matrix.elixir}} | Erlang/OTP ${{matrix.otp}})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- otp: 26.x
elixir: 1.16.x
coverage: true
- otp: 27.x
elixir: 1.17.x
env:
MIX_ENV: test
steps:
- uses: actions/checkout@v2.3.1
- name: Install OTP and Elixir
uses: erlef/setup-beam@v1
with:
otp-version: ${{matrix.otp}}
elixir-version: ${{matrix.elixir}}
- name: Install dependencies
run: mix deps.get --only test
- name: Run tests
run: mix test --trace

27
.gitignore vendored
View file

@ -1,26 +1,5 @@
# The directory Mix will write compiled artifacts to.
/_build/
# If you run "mix test --cover", coverage assets end up here.
/cover/
# The directory Mix downloads your dependencies sources to.
/deps/
# Where third-party dependencies like ExDoc output generated docs.
/doc/
# Ignore .fetch files in case you like to edit your project deps locally.
/.fetch
# If the VM crashes, it generates a dump, let's ignore it too.
/_build
/deps
erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez
# Ignore package tarball (built via "mix hex.build").
httparrot-*.tar
# Temporary files, for example, from tests.
/tmp/
/doc

13
.travis.yml Normal file
View file

@ -0,0 +1,13 @@
language: elixir
notifications:
recipients:
- eduardo@gurgel.me
elixir:
- 1.2.4
- 1.3.0
otp_release:
- 18.0
- 18.1
- 19.0
sudo: false
script: mix test --no-start

View file

@ -1,38 +0,0 @@
# Based on https://github.com/hexpm/hexpm/blob/08e80ed4fe82b145f6cee1d01da16e162add2a56/Dockerfile
FROM elixir:1.9.0-alpine as build
ENV MIX_ENV=prod
RUN mkdir /app
WORKDIR /app
RUN mix local.hex --force && mix local.rebar --force
# install mix dependencies
COPY mix.exs mix.lock ./
COPY config config
RUN mix deps.get
RUN mix deps.compile
# build project
COPY priv priv
COPY lib lib
RUN mix compile
# build release
COPY rel rel
RUN mix release
# prepare release image
FROM alpine:3.9 AS app
RUN apk add --update bash openssl
RUN mkdir /app
WORKDIR /app
COPY --from=build /app/_build/prod/rel/httparrot ./
RUN chown -R nobody: /app
USER nobody
ENV HOME=/app
CMD /app/bin/httparrot start

View file

@ -1,6 +1,4 @@
# The MIT License
Copyright (c) 2013 Eduardo Gurgel <eduardo@gurgel.me>
Copyright (c) 2013-2014 Eduardo Gurgel Pinho
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the

View file

@ -1,56 +1,49 @@
# HTTParrot
# HTTParrot [![Build Status](https://travis-ci.org/edgurgel/httparrot.png?branch=master)](https://travis-ci.org/edgurgel/httparrot)
[![Build Status](https://travis-ci.org/edgurgel/httparrot.png?branch=master)](https://travis-ci.org/edgurgel/httparrot)
[![Module Version](https://img.shields.io/hexpm/v/httparrot.svg)](https://hex.pm/packages/httparrot)
[![Hex Docs](https://img.shields.io/badge/hex-docs-lightgreen.svg)](https://hexdocs.pm/httparrot/)
[![Total Download](https://img.shields.io/hexpm/dt/httparrot.svg)](https://hex.pm/packages/httparrot)
[![License](https://img.shields.io/hexpm/l/httparrot.svg)](https://github.com/edgurgel/httparrot/blob/master/LICENSE.md)
[![Last Updated](https://img.shields.io/github/last-commit/edgurgel/httparrot.svg)](https://github.com/edgurgel/httparrot/commits/master)
HTTP server built on top of [Cowboy](https://hex.pm/packages/cowboy) using (mostly) `cowboy_rest` handlers to serve useful endpoints for testing purposes. Its goal is to be as close as possible to [HTTPBin](http://httpbin.org).
HTTP server built on top of Cowboy using (mostly) `cowboy_rest` handlers to serve useful endpoints for testing purposes. Its goal is to be as close as possible to [HTTPBin](http://httpbin.org).
## 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` 301 Redirects n times.
* `/redirect-to?url=foo` 301 Redirects to the foo URL.
* `/relative-redirect/:n` 301 Relative redirects n times.
* `/cookies` Returns cookie data.
* `/cookies/set?name=value` Sets one or more simple cookies.
* `/cookies/set/name/value` Sets one cookie .
* `/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.
* `/base64/:value` Decodes base64url-encoded string.
* `/image` Return an image based on Accept header.
* `/websocket` Echo message received through websocket
* / 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 301 Redirects n times.
* /redirect-to?url=foo 301 Redirects to the foo URL.
* /relative-redirect/:n 301 Relative redirects n times.
* /cookies Returns cookie data.
* /cookies/set?name=value Sets one or more simple cookies.
* /cookies/set/name/value Sets one cookie .
* /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.
* /base64/:value Decodes base64url-encoded string.
* /image Return an image based on Accept header.
* /websocket Echo message received through websocket
## TODO
* [ ] `/deflate` Returns deflate-encoded data.
* [ ] `/digest-auth/:qop/:user/:passwd` Challenges HTTP Digest Auth.
* [ ] /deflate Returns deflate-encoded data.
* [ ] /digest-auth/:qop/:user/:passwd Challenges HTTP Digest Auth.
## Copyright and License
## License
Copyright (c) 2013 Eduardo Gurgel <eduardo@gurgel.me>
Copyright 2013-2016 Eduardo Gurgel <eduardo@gurgel.me>
This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.
This work is free. You can redistribute it and/or modify it under the
terms of the MIT License. See the LICENSE file for more details.

View file

@ -1,10 +0,0 @@
#!/usr/bin/env bash
# exit on error
set -o errexit
# Initial setup
mix deps.get --only prod
MIX_ENV=prod mix compile
# Build the release and overwrite the existing release directory
MIX_ENV=prod mix release --overwrite

View file

@ -1,16 +0,0 @@
import Config
port = System.get_env("PORT", "8080")
port = String.to_integer(port)
ssl_port = System.get_env("SSL_PORT", "8433")
ssl_port = String.to_integer(ssl_port)
unix_socket = System.get_env("UNIX_SOCKET", "false")
unix_socket = if unix_socket == "true", do: true, else: false
config :httparrot,
http_port: port,
https_port: ssl_port,
unix_socket: unix_socket,
socket_path: System.get_env("SOCKET_PATH", "httparrot.sock")

View file

@ -1,16 +0,0 @@
import Config
port = System.get_env("PORT", "8080")
port = String.to_integer(port)
ssl_port = System.get_env("SSL_PORT", "8433")
ssl_port = String.to_integer(ssl_port)
unix_socket = System.get_env("UNIX_SOCKET", "false")
unix_socket = if unix_socket == "true", do: true, else: false
config :httparrot,
http_port: port,
https_port: ssl_port,
unix_socket: unix_socket,
socket_path: System.get_env("SOCKET_PATH", "httparrot.sock")

View file

@ -1,128 +1,70 @@
defmodule HTTParrot do
use Application
use Supervisor
def start_link(arg) do
Supervisor.start_link(__MODULE__, arg)
end
def init(_) do
Supervisor.start_link([], strategy: :one_for_one)
end
def start(_type, _args) do
dispatch =
:cowboy_router.compile([
{:_,
[
{"/", :cowboy_static, {:priv_file, :httparrot, "index.html"}},
{"/ip", HTTParrot.IPHandler, []},
{"/user-agent", HTTParrot.UserAgentHandler, []},
{"/headers", HTTParrot.HeadersHandler, []},
{"/get", HTTParrot.GetHandler, []},
{"/post", HTTParrot.PHandler, []},
{"/put", HTTParrot.PHandler, []},
{"/patch", HTTParrot.PHandler, []},
{"/delete", HTTParrot.DeleteHandler, []},
{"/deflate", HTTParrot.DeflateHandler, []},
{"/gzip", HTTParrot.GzipHandler, []},
{"/status/:code", [code: :int], HTTParrot.StatusCodeHandler, []},
{"/redirect/:n", HTTParrot.RedirectHandler, []},
{"/redirect-to", HTTParrot.RedirectToHandler, []},
{"/relative-redirect/:n", HTTParrot.RelativeRedirectHandler, []},
{"/cookies", HTTParrot.CookiesHandler, []},
{"/cookies/set[/:name/:value]", HTTParrot.SetCookiesHandler, []},
{"/cookies/delete", HTTParrot.DeleteCookiesHandler, []},
{"/basic-auth/:user/:passwd", HTTParrot.BasicAuthHandler, []},
{"/hidden-basic-auth/:user/:passwd", HTTParrot.HiddenBasicAuthHandler, []},
{"/stream/:n", HTTParrot.StreamHandler, []},
{"/stream-bytes/:n", HTTParrot.StreamBytesHandler, []},
{"/delay/:n", HTTParrot.DelayedHandler, []},
{"/html", :cowboy_static, {:priv_file, :httparrot, "html.html"}},
{"/deny", HTTParrot.DenyHandler, []},
{"/cache", HTTParrot.CacheHandler, []},
{"/robots.txt", HTTParrot.RobotsHandler, []},
{"/base64/:value", HTTParrot.Base64Handler, []},
{"/image", HTTParrot.ImageHandler, []},
{"/websocket", HTTParrot.WebsocketHandler, []},
{"/response-headers", HTTParrot.ResponseHeadersHandler, []},
{"/store/:key", HTTParrot.StoreRequestHandler, []},
{"/retrieve/:key", HTTParrot.RetrieveRequestHandler, []}
]}
])
dispatch = :cowboy_router.compile([
{:_, [ {'/', :cowboy_static, {:priv_file, :httparrot, "index.html"}},
{'/ip', HTTParrot.IPHandler, []},
{'/user-agent', HTTParrot.UserAgentHandler, []},
{'/headers', HTTParrot.HeadersHandler, []},
{'/get', HTTParrot.GetHandler, []},
{'/post', HTTParrot.PHandler, []},
{'/put', HTTParrot.PHandler, []},
{'/patch', HTTParrot.PHandler, []},
{'/delete', HTTParrot.DeleteHandler, []},
{'/gzip', HTTParrot.GzipHandler, []},
{'/status/:code', [code: :int], HTTParrot.StatusCodeHandler, []},
{'/redirect/:n', HTTParrot.RedirectHandler, []},
{'/redirect-to', HTTParrot.RedirectToHandler, []},
{'/relative-redirect/:n', HTTParrot.RelativeRedirectHandler, []},
{'/cookies', HTTParrot.CookiesHandler, []},
{'/cookies/set[/:name/:value]', HTTParrot.SetCookiesHandler, []},
{'/cookies/delete', HTTParrot.DeleteCookiesHandler, []},
{'/basic-auth/:user/:passwd', HTTParrot.BasicAuthHandler, []},
{'/hidden-basic-auth/:user/:passwd', HTTParrot.HiddenBasicAuthHandler, []},
{'/stream/:n', HTTParrot.StreamHandler, []},
{'/stream-bytes/:n', HTTParrot.StreamBytesHandler, []},
{'/delay/:n', HTTParrot.DelayedHandler, []},
{'/html', :cowboy_static, {:priv_file, :httparrot, "html.html"}},
{'/deny', HTTParrot.DenyHandler, []},
{'/cache', HTTParrot.CacheHandler, []},
{'/robots.txt', HTTParrot.RobotsHandler, []},
{'/base64/:value', HTTParrot.Base64Handler, []},
{'/image', HTTParrot.ImageHandler, []},
{'/websocket', HTTParrot.WebsocketHandler, []},
{'/response-headers', HTTParrot.ResponseHeadersHandler, []} ] }
])
{:ok, http_port} = Application.fetch_env(:httparrot, :http_port)
IO.puts("Starting HTTParrot on port #{http_port}")
{:ok, _} =
:cowboy.start_clear(
:http,
[port: http_port],
%{env: %{dispatch: dispatch}}
)
IO.puts "Starting HTTParrot on port #{http_port}"
{:ok, _} = :cowboy.start_http(:http, 100,
[port: http_port],
[env: [dispatch: dispatch],
onresponse: &prettify_json/4])
if Application.get_env(:httparrot, :ssl, false) do
{:ok, https_port} = Application.fetch_env(:httparrot, :https_port)
priv_dir = :code.priv_dir(:httparrot)
IO.puts("Starting HTTParrot on port #{https_port} (SSL)")
{:ok, _} =
:cowboy.start_tls(
:https,
[
port: https_port,
cacertfile: priv_dir ++ ~c"/ssl/server-ca.crt",
certfile: priv_dir ++ ~c"/ssl/server.crt",
keyfile: priv_dir ++ ~c"/ssl/server.key"
],
%{env: %{dispatch: dispatch}}
)
IO.puts "Starting HTTParrot on port #{https_port} (SSL)"
{:ok, _} = :cowboy.start_https(:https, 100,
[port: https_port, cacertfile: priv_dir ++ '/ssl/server-ca.crt',
certfile: priv_dir ++ '/ssl/server.crt', keyfile: priv_dir ++ '/ssl/server.key'],
[env: [dispatch: dispatch], onresponse: &prettify_json/4])
end
if unix_socket_supported?() && Application.get_env(:httparrot, :unix_socket, false) do
{:ok, socket_path} = Application.fetch_env(:httparrot, :socket_path)
if File.exists?(socket_path), do: File.rm(socket_path)
IO.puts("Starting HTTParrot on unix socket #{socket_path}")
{:ok, _} =
:cowboy.start_clear(
:http_unix,
[port: 0, ip: {:local, socket_path}],
%{env: %{dispatch: dispatch}}
)
end
Supervisor.start_link(
[
{ConCache,
[
ttl_check_interval: :timer.minutes(5),
global_ttl: :timer.hours(12),
name: :requests_registry
]}
],
strategy: :one_for_one
)
Supervisor.start_link([], strategy: :one_for_one)
end
def stop(_State), do: :ok
def prettify_json(status, headers, body, req) do
if JSX.is_json?(body) do
if JSX.is_json? body do
body = JSX.prettify!(body)
headers = Map.put(headers, "content-length", Integer.to_charlist(String.length(body)))
:cowboy_req.reply(status, headers, body, req)
headers = List.keystore(headers, "content-length", 0, {"content-length", Integer.to_char_list(String.length(body))})
{:ok, req} = :cowboy_req.reply(status, headers, body, req)
req
else
req
end
end
def unix_socket_supported? do
case {:os.type(), Integer.parse("#{:erlang.system_info(:otp_release)}")} do
{{:unix, _}, {n, _}} when n >= 19 -> true
_ -> false
end
end
end

View file

@ -9,16 +9,16 @@ defmodule HTTParrot.Base64Handler do
end
def malformed_request(req, state) do
value = :cowboy_req.binding(:value, req)
{value, req} = :cowboy_req.binding(:value, req)
case decode(value) do
{:ok, result} -> {false, req, result}
:error -> {true, req, state}
{ :ok, result } -> {false, req, result}
:error -> {true, req, state}
end
end
defp decode(value) do
pad(value) |> Base.url_decode64()
pad(value) |> Base.url_decode64
end
defp pad(value) do

View file

@ -5,12 +5,11 @@ defmodule HTTParrot.BasicAuthHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def is_authorized(req, state) do
user = :cowboy_req.binding(:user, req)
passwd = :cowboy_req.binding(:passwd, req)
auth = :cowboy_req.parse_header("authorization", req)
{user, req} = :cowboy_req.binding(:user, req)
{passwd, req} = :cowboy_req.binding(:passwd, req)
{:ok, auth, req} = :cowboy_req.parse_header("authorization", req)
case auth do
{:basic, ^user, ^passwd} -> {true, req, user}
{"basic", {^user, ^passwd}} -> {true, req, user}
_ -> {{false, "Basic realm=\"Fake Realm\""}, req, state}
end
end
@ -24,6 +23,6 @@ defmodule HTTParrot.BasicAuthHandler do
end
defp response(user) do
[authenticated: true, user: user] |> JSX.encode!()
[authenticated: true, user: user] |> JSX.encode!
end
end

View file

@ -19,6 +19,6 @@ defmodule HTTParrot.CacheHandler do
end
defp response(info) do
info |> JSX.encode!()
info |> JSX.encode!
end
end

View file

@ -9,12 +9,12 @@ defmodule HTTParrot.CookiesHandler do
end
def get_json(req, state) do
cookies = :cowboy_req.parse_cookies(req)
{cookies, req} = :cowboy_req.cookies(req)
cookies = if cookies == [], do: [{}], else: cookies
{response(cookies), req, state}
end
defp response(cookies) do
[cookies: cookies] |> JSX.encode!()
[cookies: cookies] |> JSX.encode!
end
end

View file

@ -3,8 +3,8 @@ defmodule HTTParrot.Cowboy do
methods = Keyword.get(opts, :methods, [])
quote bind_quoted: [methods: methods] do
def init(req, state) do
{:cowboy_rest, req, state}
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
def allowed_methods(req, state) do

View file

@ -1,27 +0,0 @@
defmodule HTTParrot.DeflateHandler do
@moduledoc """
Encode body using deflate encoding
"""
alias HTTParrot.GeneralRequestInfo
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def get_json(req, state) do
zlib = :zlib.open()
:zlib.deflateInit(zlib)
{info, req} = GeneralRequestInfo.retrieve(req)
req = :cowboy_req.set_resp_header("content-encoding", "deflate", req)
json = response(info) |> JSX.prettify!()
response = :zlib.deflate(zlib, json, :finish)
:zlib.deflateEnd(zlib)
{response, req, state}
end
defp response(info) do
info |> JSX.encode!()
end
end

View file

@ -3,10 +3,9 @@ defmodule HTTParrot.DelayedHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def malformed_request(req, state) do
n = :cowboy_req.binding(:n, req)
{n, req} = :cowboy_req.binding(:n, req)
try do
n = n |> String.to_integer() |> min(10) |> max(0)
n = n |> String.to_integer |> min(10) |> max(0)
{false, req, n}
rescue
ArgumentError -> {true, req, state}
@ -19,11 +18,11 @@ defmodule HTTParrot.DelayedHandler do
def get_json(req, n) do
{info, req} = GeneralRequestInfo.retrieve(req)
:timer.sleep(n * 1000)
:timer.sleep(n*1000)
{response(info), req, n}
end
defp response(info) do
info |> JSX.encode!()
info |> JSX.encode!
end
end

View file

@ -5,7 +5,7 @@ defmodule HTTParrot.DeleteCookiesHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def malformed_request(req, state) do
qs_vals = :cowboy_req.parse_qs(req)
{qs_vals, req} = :cowboy_req.qs_vals(req)
if Enum.empty?(qs_vals), do: {true, req, state}, else: {false, req, qs_vals}
end
@ -14,18 +14,15 @@ defmodule HTTParrot.DeleteCookiesHandler do
end
def get_json(req, qs_vals) do
req =
Enum.reduce(qs_vals, req, fn {name, value}, req ->
delete_cookie(name, value, req)
end)
req = :cowboy_req.reply(302, %{"location" => "/cookies"}, "Redirecting...", req)
{:stop, req, qs_vals}
req = Enum.reduce qs_vals, req, fn({name, value}, req) ->
delete_cookie(name, value, req)
end
{:ok, req} = :cowboy_req.reply(302, [{"location", "/cookies"}], "Redirecting...", req)
{:halt, req, qs_vals}
end
defp delete_cookie(name, true, req), do: delete_cookie(name, "", req)
defp delete_cookie(name, value, req) do
:cowboy_req.set_resp_cookie(name, value, req, %{path: "/", max_age: 0})
:cowboy_req.set_resp_cookie(name, value, [path: "/", max_age: 0], req)
end
end

View file

@ -5,10 +5,6 @@ defmodule HTTParrot.DeleteHandler do
alias HTTParrot.GeneralRequestInfo
use HTTParrot.Cowboy, methods: ~w(DELETE)
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get_json}], req, state}
end
def delete_resource(req, state) do
{info, req} = GeneralRequestInfo.retrieve(req)
req = :cowboy_req.set_resp_body(response(info), req)
@ -16,6 +12,6 @@ defmodule HTTParrot.DeleteHandler do
end
defp response(info) do
info |> JSX.encode!()
info |> JSX.encode!
end
end

View file

@ -18,7 +18,7 @@ defmodule HTTParrot.DenyHandler do
\ .-"` `"-. /
'. .'
'-......-'
YOU SHOULDN'T BE HERE
YOU SHOUDN'T BE HERE
"""
def get_plain(req, state) do
{@body, req, state}

View file

@ -1,17 +1,11 @@
defmodule HTTParrot.GeneralRequestInfo do
def retrieve(req) do
args = :cowboy_req.parse_qs(req)
headers = :cowboy_req.headers(req)
url = IO.iodata_to_binary(:cowboy_req.uri(req))
{ip, _port} = :cowboy_req.peer(req)
ip =
case ip do
{127, 0, 0, 1} -> ""
:local -> ""
_ -> :inet_parse.ntoa(ip) |> to_string
end
{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)
ip = :inet_parse.ntoa(ip) |> to_string
args = group_by_keys(args)
{[args: args, headers: headers, url: url, origin: ip], req}
@ -20,12 +14,11 @@ defmodule HTTParrot.GeneralRequestInfo do
@doc """
Group by keys and if duplicated keys, aggregate them as a list
iex> group_by_keys([{"a", "v1"}, {"a", "v2"}, {"b", "v3"}, {"a", "v4"}])
%{"a" => ["v1", "v2", "v4"], "b" => "v3"}
iex> group_by_keys([a: "v1", a: "v2", b: "v3", a: "v4"])
%{a: ["v1", "v2", "v4"], b: "v3"}
"""
@spec group_by_keys(list) :: map
def group_by_keys([]), do: %{}
def group_by_keys(args) do
args
|> Enum.map(fn {k, v} -> %{k => v} end)

View file

@ -15,6 +15,6 @@ defmodule HTTParrot.GetHandler do
end
defp response(info) do
info |> JSX.encode!()
info |> JSX.encode!
end
end

View file

@ -12,11 +12,11 @@ defmodule HTTParrot.GzipHandler do
def get_json(req, state) do
{info, req} = GeneralRequestInfo.retrieve(req)
req = :cowboy_req.set_resp_header("content-encoding", "gzip", req)
response = response(info) |> JSX.prettify!() |> :zlib.gzip()
response = response(info) |> JSX.prettify! |> :zlib.gzip
{response, req, state}
end
defp response(info) do
info |> JSX.encode!()
info |> JSX.encode!
end
end

View file

@ -6,11 +6,11 @@ defmodule HTTParrot.HeadersHandler do
end
def get_json(req, state) do
headers = :cowboy_req.headers(req)
{headers, req} = :cowboy_req.headers(req)
{response(headers), req, state}
end
defp response(headers) do
[headers: headers] |> JSX.encode!()
[headers: headers] |> JSX.encode!
end
end

View file

@ -8,12 +8,11 @@ defmodule HTTParrot.HiddenBasicAuthHandler do
This method should be `is_authorized`, but this handler will return 404 if the auth fails
"""
def resource_exists(req, state) do
user = :cowboy_req.binding(:user, req)
passwd = :cowboy_req.binding(:passwd, req)
auth = :cowboy_req.parse_header("authorization", req)
{user, req} = :cowboy_req.binding(:user, req)
{passwd, req} = :cowboy_req.binding(:passwd, req)
{:ok, auth, req} = :cowboy_req.parse_header("authorization", req)
case auth do
{:basic, ^user, ^passwd} -> {true, req, user}
{"basic", {^user, ^passwd}} -> {true, req, user}
_ -> {false, req, state}
end
end
@ -27,6 +26,6 @@ defmodule HTTParrot.HiddenBasicAuthHandler do
end
defp response(user) do
[authenticated: true, user: user] |> JSX.encode!()
[authenticated: true, user: user] |> JSX.encode!
end
end

View file

@ -5,15 +5,12 @@ defmodule HTTParrot.ImageHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def content_types_provided(req, state) do
{[{{"image", "png", []}, :get_png}, {{"image", "jpeg", []}, :get_jpeg}], req, state}
{[{{"image", "png", []}, :get_png},
{{"image", "jpeg", []}, :get_jpeg}], req, state}
end
@png Base.decode64!(
"iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg=="
)
@jpeg Base.decode64!(
"/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k="
)
@png Base.decode64!("iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAACklEQVR4nGMAAQAABQABDQottAAAAABJRU5ErkJggg==")
@jpeg Base.decode64!("/9j/4AAQSkZJRgABAQEASABIAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/yQALCAABAAEBAREA/8wABgAQEAX/2gAIAQEAAD8A0s8g/9k=")
def get_png(req, state), do: {@png, req, state}
def get_jpeg(req, state), do: {@jpeg, req, state}

View file

@ -9,32 +9,12 @@ defmodule HTTParrot.IPHandler do
end
def get_json(req, state) do
{ip, _port} = :cowboy_req.peer(req)
forwarded_for = :cowboy_req.parse_header("x-forwarded-for", req)
case forwarded_for do
:undefined ->
{response(ip), req, state}
_ ->
{response(to_tuple(forwarded_for)), req, state}
end
end
defp to_tuple(client_ip) do
client_ip
|> hd
|> String.split(".")
|> Enum.map(fn x -> String.to_integer(x) end)
|> List.to_tuple()
end
defp response({127, 0, 0, 1}) do
[origin: ""] |> JSX.encode!()
{{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] |> JSX.encode!()
[origin: ip] |> JSX.encode!
end
end

View file

@ -4,27 +4,25 @@ defmodule HTTParrot.PHandler do
"""
alias HTTParrot.GeneralRequestInfo
def init(req, state) do
{:cowboy_rest, req, state}
def init(_transport, _req, _opts) do
{:upgrade, :protocol, :cowboy_rest}
end
@doc """
When a request is made to /post, allowed_methods will return POST for example
"""
def allowed_methods(req, state) do
path = :cowboy_req.path(req)
path = String.slice(path, 1..-1//1)
{path, req} = :cowboy_req.path(req)
path = String.slice(path, 1..-1)
{[String.upcase(path)], req, state}
end
def content_types_accepted(req, state) do
{[
{{"application", "json", :*}, :post_binary},
{{"application", "octet-stream", :*}, :post_binary},
{{"text", "plain", :*}, :post_binary},
{{"application", "x-www-form-urlencoded", :*}, :post_form},
{{"multipart", "form-data", :*}, :post_multipart}
], req, state}
{[{{"application", "json", :*}, :post_binary},
{{"application", "octet-stream", :*}, :post_binary},
{{"text", "plain", :*}, :post_binary},
{{"application", "x-www-form-urlencoded", :*}, :post_form},
{{"multipart", "form-data", :*}, :post_multipart}], req, state}
end
def content_types_provided(req, state) do
@ -32,31 +30,29 @@ defmodule HTTParrot.PHandler do
end
def post_form(req, _state) do
{:ok, body, req} = :cowboy_req.read_urlencoded_body(req)
post(req, form: body, data: "", json: nil)
{:ok, body, req} = :cowboy_req.body_qs(req)
post(req, [form: body, data: "", json: nil])
end
def post_binary(req, _state) do
{:ok, body, req} = handle_binary(req)
if String.valid?(body) do
if JSX.is_json?(body) do
post(req, form: [{}], data: body, json: JSX.decode!(body))
post(req, [form: [{}], data: body, json: JSX.decode!(body)])
else
post(req, form: [{}], data: body, json: nil)
post(req, [form: [{}], data: body, json: nil])
end
else
# Octet-stream
body = Base.encode64(body)
post(req, form: [{}], data: "data:application/octet-stream;base64," <> body, json: nil)
post(req, [form: [{}], data: "data:application/octet-stream;base64," <> body, json: nil])
end
end
def handle_binary(req, chunks \\ []) do
case :cowboy_req.read_body(req) do
defp handle_binary(req, chunks \\ []) do
case :cowboy_req.body(req) do
{:ok, chunk, req} ->
{:ok, Enum.join(chunks ++ [chunk]), req}
{:more, chunk, req} ->
handle_binary(req, chunks ++ [chunk])
end
@ -69,7 +65,7 @@ defmodule HTTParrot.PHandler do
end
defp response(info, body) do
(info ++ body) |> JSX.encode!()
info ++ body |> JSX.encode!
end
def post_multipart(req, _state) do
@ -78,32 +74,22 @@ defmodule HTTParrot.PHandler do
file_parts = for file <- parts, elem(file, 0) == :file, do: {elem(file, 1), elem(file, 2)}
form_parts = for form <- parts, elem(form, 0) == :form, do: {elem(form, 1), elem(form, 2)}
post(req,
form: normalize_list(form_parts),
files: normalize_list(file_parts),
data: "",
json: nil
)
post(req, [form: normalize_list(form_parts), files: normalize_list(file_parts), data: "", json: nil])
end
def handle_multipart(req, parts \\ []) do
case :cowboy_req.read_part(req) do
{:done, req} ->
{:ok, parts, req}
defp handle_multipart(req, parts \\ []) do
case :cowboy_req.part(req) do
{:done, req} -> {:ok, parts, req}
{:ok, headers, req} ->
content_disposition = headers["content-disposition"]
content_disposition = List.keyfind(headers, "content-disposition", 0)
if content_disposition do
case parse_content_disposition_header(content_disposition) do
%{:type => "form-data", "name" => name, "filename" => _filename} ->
{:ok, file, req} = handle_multipart_body(req)
handle_multipart(req, parts ++ [{:file, name, file}])
%{:type => "form-data", "name" => name} ->
{:ok, form_part, req} = handle_multipart_body(req)
handle_multipart(req, parts ++ [{:form, name, form_part}])
_ ->
{:ok, parts, req}
end
@ -114,29 +100,28 @@ defmodule HTTParrot.PHandler do
end
defp handle_multipart_body(req, parts \\ []) do
case :cowboy_req.read_part_body(req) do
case :cowboy_req.part_body(req) do
{:ok, data, req} ->
{:ok, Enum.join(parts ++ [data]), req}
{:more, data, req} ->
handle_multipart_body(req, parts ++ [data])
end
end
defp parse_content_disposition_header(header) do
parts =
String.split(header, ";")
|> Enum.map(&String.trim/1)
parts = elem(header, 1)
|> String.split(";")
|> Enum.map(&String.strip/1)
for part <- parts, into: %{} do
case String.split(part, "=") |> Enum.map(&String.trim/1) do
case String.split(part, "=") |> Enum.map(&String.strip/1) do
[type] -> {:type, type}
[key, value] -> {key, String.replace(value, "\"", "")}
end
end
end
def normalize_list([]), do: [{}]
defp normalize_list([]), do: [{}]
def normalize_list(list), do: list
defp normalize_list(list), do: list
end

View file

@ -5,10 +5,9 @@ defmodule HTTParrot.RedirectHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def malformed_request(req, state) do
n = :cowboy_req.binding(:n, req)
{n, req} = :cowboy_req.binding(:n, req)
try do
n = n |> String.to_integer() |> max(1)
n = n |> String.to_integer |> max(1)
{false, req, n}
rescue
ArgumentError -> {true, req, state}
@ -19,12 +18,8 @@ defmodule HTTParrot.RedirectHandler do
def previously_existed(req, state), do: {true, req, state}
def moved_permanently(req, n) do
host_url =
IO.iodata_to_binary(
:cowboy_req.uri(req, %{path: :undefined, qs: :undefined, fragment: :undefined})
)
url = if n > 1, do: "/redirect/#{n - 1}", else: "/get"
{host_url, req} = :cowboy_req.host_url(req)
url = if n > 1, do: "/redirect/#{n-1}", else: "/get"
{{true, host_url <> url}, req, nil}
end
end

View file

@ -5,7 +5,7 @@ defmodule HTTParrot.RedirectToHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def malformed_request(req, state) do
%{url: url} = :cowboy_req.match_qs([{:url, [], nil}], req)
{url, req} = :cowboy_req.qs_val("url", req, nil)
if url, do: {false, req, url}, else: {true, req, state}
end

View file

@ -12,7 +12,7 @@ defmodule HTTParrot.RelativeRedirectHandler do
def previously_existed(req, state), do: {true, req, state}
def moved_permanently(req, n) do
url = if n > 1, do: "/redirect/#{n - 1}", else: "/get"
url = if n > 1, do: "/redirect/#{n-1}", else: "/get"
{{true, url}, req, nil}
end
end

View file

@ -1,34 +0,0 @@
defmodule HTTParrot.RequestStore do
@moduledoc """
Used to store and retrieved requests
"""
@doc """
Store the requests to the key
"""
def store(key, info) do
map = retrieve(key) ++ [info]
ConCache.put(:requests_registry, key, map)
end
@doc """
Get the saved request using the key
"""
def retrieve(key) do
entry = ConCache.get(:requests_registry, key)
case entry do
nil ->
[]
_ ->
entry
end
end
@doc """
Clear the saved data on the corresponding key
"""
def clear(key) do
ConCache.delete(:requests_registry, key)
end
end

View file

@ -5,8 +5,7 @@ defmodule HTTParrot.ResponseHeadersHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def malformed_request(req, state) do
qs_vals = :cowboy_req.parse_qs(req)
{qs_vals, req} = :cowboy_req.qs_vals(req)
if not Enum.empty?(qs_vals) do
{false, req, qs_vals}
else
@ -19,15 +18,13 @@ defmodule HTTParrot.ResponseHeadersHandler do
end
def get_json(req, qs_vals) do
req =
Enum.reduce(qs_vals, req, fn {key, value}, req ->
:cowboy_req.set_resp_header(key, value, req)
end)
req = Enum.reduce qs_vals, req, fn({key, value}, req) ->
:cowboy_req.set_resp_header(key, value, req)
end
{response(qs_vals), req, qs_vals}
end
defp response(qs_vals) do
qs_vals |> JSX.encode!()
qs_vals |> JSX.encode!
end
end

View file

@ -1,21 +0,0 @@
defmodule HTTParrot.RetrieveRequestHandler do
@moduledoc """
Retrieve saved request and clear the conresponding :id
"""
use HTTParrot.Cowboy, methods: ~w(GET POST PUT HEAD OPTIONS)
def content_types_provided(req, state) do
{[{{"application", "json", []}, :retrieve_stored}], req, state}
end
def retrieve_stored(req, state) do
key = :cowboy_req.binding(:key, req)
requests = HTTParrot.RequestStore.retrieve(key)
HTTParrot.RequestStore.clear(key)
{response(requests), req, state}
end
defp response(info) do
info |> JSX.encode!()
end
end

View file

@ -5,11 +5,10 @@ defmodule HTTParrot.SetCookiesHandler do
use HTTParrot.Cowboy, methods: ~w(GET HEAD OPTIONS)
def malformed_request(req, state) do
qs_vals = :cowboy_req.parse_qs(req)
name = :cowboy_req.binding(:name, req, nil)
{qs_vals, req} = :cowboy_req.qs_vals(req)
{name, req} = :cowboy_req.binding(:name, req, nil)
if name do
value = :cowboy_req.binding(:value, req, nil)
{value, req} = :cowboy_req.binding(:value, req, nil)
{false, req, List.keystore(qs_vals, name, 0, {name, value})}
else
if Enum.empty?(qs_vals), do: {true, req, state}, else: {false, req, qs_vals}
@ -21,16 +20,14 @@ defmodule HTTParrot.SetCookiesHandler do
end
def get_json(req, qs_vals) do
req =
Enum.reduce(qs_vals, req, fn {name, value}, req ->
set_cookie(name, value, req)
end)
req = :cowboy_req.reply(302, %{"location" => "/cookies"}, "Redirecting...", req)
{:stop, req, qs_vals}
req = Enum.reduce qs_vals, req, fn({name, value}, req) ->
set_cookie(name, value, req)
end
{:ok, req} = :cowboy_req.reply(302, [{"location", "/cookies"}], "Redirecting...", req)
{:halt, req, qs_vals}
end
defp set_cookie(name, value, req) do
:cowboy_req.set_resp_cookie(name, value, req, %{path: "/"})
:cowboy_req.set_resp_cookie(name, value, [path: "/"], req)
end
end

View file

@ -9,8 +9,8 @@ defmodule HTTParrot.StatusCodeHandler do
end
def get_json(req, state) do
code = :cowboy_req.binding(:code, req)
req = :cowboy_req.reply(code, %{}, "", req)
{:stop, req, state}
{code, req} = :cowboy_req.binding(:code, req)
{:ok, req} = :cowboy_req.reply(code, [], "", req)
{:halt, req, state}
end
end

View file

@ -1,71 +0,0 @@
defmodule HTTParrot.StoreRequestHandler do
@moduledoc """
Store the sended request with the :id
"""
alias HTTParrot.GeneralRequestInfo
use HTTParrot.Cowboy, methods: ~w(GET POST PUT HEAD OPTIONS)
def content_types_accepted(req, state) do
{[
{{"application", "json", :*}, :post_binary},
{{"application", "octet-stream", :*}, :post_binary},
{{"text", "plain", :*}, :post_binary},
{{"application", "x-www-form-urlencoded", :*}, :post_form},
{{"multipart", "form-data", :*}, :post_multipart}
], req, state}
end
def content_types_provided(req, state) do
{[{{"application", "json", []}, :get}], req, state}
end
def get(req, state) do
{info, req} = GeneralRequestInfo.retrieve(req)
key = :cowboy_req.binding(:key, req)
HTTParrot.RequestStore.store(key, info)
{~c'{"saved": "true"}', req, state}
end
def post_binary(req, _state) do
{:ok, body, req} = HTTParrot.PHandler.handle_binary(req)
if String.valid?(body) do
if JSX.is_json?(body) do
save_post(req, form: [{}], data: body, json: JSX.decode!(body))
else
save_post(req, form: [{}], data: body, json: nil)
end
else
# Octet-stream
body = Base.encode64(body)
save_post(req, form: [{}], data: "data:application/octet-stream;base64," <> body, json: nil)
end
end
def post_form(req, _state) do
{:ok, body, req} = :cowboy_req.read_urlencoded_body(req)
save_post(req, form: body, data: "", json: nil)
end
def post_multipart(req, _state) do
{:ok, parts, req} = HTTParrot.PHandler.handle_multipart(req)
file_parts = for file <- parts, elem(file, 0) == :file, do: {elem(file, 1), elem(file, 2)}
form_parts = for form <- parts, elem(form, 0) == :form, do: {elem(form, 1), elem(form, 2)}
save_post(req,
form: HTTParrot.PHandler.normalize_list(form_parts),
files: HTTParrot.PHandler.normalize_list(file_parts),
data: "",
json: nil
)
end
def save_post(req, body) do
{info, req} = GeneralRequestInfo.retrieve(req)
key = :cowboy_req.binding(:key, req)
HTTParrot.RequestStore.store(key, info ++ body)
req = :cowboy_req.reply(200, %{}, "{\"saved\": \"true\"}", req)
{:stop, req, nil}
end
end

View file

@ -9,14 +9,14 @@ defmodule HTTParrot.StreamBytesHandler do
end
def malformed_request(req, state) do
n = :cowboy_req.binding(:n, req)
%{seed: seed} = :cowboy_req.match_qs([{:seed, [], "1234"}], req)
%{chunk_size: chunk_size} = :cowboy_req.match_qs([{:chunk_size, [], "1024"}], req)
{n, req} = :cowboy_req.binding(:n, req)
{seed, req} = :cowboy_req.qs_val("seed", req, "1234")
{chunk_size, req} = :cowboy_req.qs_val("chunk_size", req, "1024")
try do
n = n |> String.to_integer()
seed = seed |> String.to_integer()
chunk_size = chunk_size |> String.to_integer()
n = n |> String.to_integer
seed = seed |> String.to_integer
chunk_size = chunk_size |> String.to_integer
{false, req, {n, seed, chunk_size}}
rescue
ArgumentError -> {true, req, state}
@ -26,21 +26,17 @@ defmodule HTTParrot.StreamBytesHandler do
def get_bytes(req, state) do
{n, seed, chunk_size} = state
:rand.seed(:exs64, {seed, seed, seed})
req = stream_response!(n, chunk_size, req)
{:stop, req, nil}
{{:chunked, stream_response(n, chunk_size)}, req, nil}
end
defp stream_response!(n, chunk_size, req) do
req = :cowboy_req.stream_reply(200, %{"content-type" => "application/octet-stream"}, req)
Stream.repeatedly(fn -> :rand.uniform(255) end)
|> Stream.take(n)
|> Enum.chunk_every(chunk_size, chunk_size, [])
|> Enum.each(fn chunk ->
:cowboy_req.stream_body(List.to_string(chunk), :nofin, req)
end)
:cowboy_req.stream_body("", :fin, req)
req
defp stream_response(n, chunk_size) do
fn(send_func) ->
Stream.repeatedly(fn -> :rand.uniform(255) end)
|> Stream.take(n)
|> Enum.chunk(chunk_size, chunk_size, [])
|> Enum.each(fn chunk ->
send_func.(List.to_string(chunk))
end)
end
end
end

View file

@ -9,10 +9,9 @@ defmodule HTTParrot.StreamHandler do
`n` must be an integer between 1-100
"""
def malformed_request(req, state) do
n = :cowboy_req.binding(:n, req)
{n, req} = :cowboy_req.binding(:n, req)
try do
n = n |> String.to_integer() |> min(100) |> max(1)
n = n |> String.to_integer |> min(100) |> max(1)
{false, req, n}
rescue
ArgumentError -> {true, req, state}
@ -25,14 +24,14 @@ defmodule HTTParrot.StreamHandler do
def get_json(req, n) do
{info, req} = GeneralRequestInfo.retrieve(req)
req = :cowboy_req.stream_reply(200, %{"content-type" => "application/json"}, req)
{{:chunked, stream_response(n, info)}, req, nil}
end
Enum.each(0..(n - 1), fn i ->
body = JSX.encode!([id: i] ++ info)
:cowboy_req.stream_body(body, :nofin, req)
end)
:cowboy_req.stream_body("", :fin, req)
{:stop, req, nil}
defp stream_response(n, info) do
fn(send_func) ->
Enum.each 0..n-1, fn (i) ->
send_func.([id: i] ++ info |> JSX.encode!)
end
end
end
end

View file

@ -9,12 +9,12 @@ defmodule HTTParrot.UserAgentHandler do
end
def get_json(req, state) do
user_agent = :cowboy_req.header("user-agent", req, "null")
{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}]
|> JSX.encode!()
|> JSX.encode!
end
end

View file

@ -1,16 +1,15 @@
defmodule HTTParrot.WebsocketHandler do
@behaviour :cowboy_websocket
@behaviour :cowboy_websocket_handler
@moduledoc """
Echo given messages through websocket connection
"""
def init(req, state), do: {:cowboy_websocket, req, state}
def websocket_init(state), do: {:ok, state}
def init(_transport, _req, _opts), do: {:upgrade, :protocol, :cowboy_websocket}
def websocket_init(_transport, req, _opts), do: {:ok, req, nil}
def websocket_handle({:text, text}, state), do: {:reply, {:text, text}, state}
def websocket_handle({:binary, binary}, state), do: {:reply, {:binary, binary}, state}
def websocket_handle({:text, text}, req, state), do: {:reply, {:text, text}, req, state}
def websocket_handle({:binary, binary}, req, state), do: {:reply, {:binary, binary}, req, state}
def websocket_info(_info, req, state), do: {:ok, req, state}
def websocket_info(_info, state), do: {:ok, state}
def terminate(_reason, _req, _state), do: :ok
def websocket_terminate(_reason, _req, _state), do: :ok
end

67
mix.exs
View file

@ -1,62 +1,41 @@
defmodule Httparrot.Mixfile do
use Mix.Project
@source_url "https://github.com/edgurgel/httparrot"
@version "1.4.0"
@description """
HTTP Request & Response Server. An incomplete clone of http://httpbin.org
"""
def project do
[
app: :httparrot,
version: @version,
elixir: "~> 1.16",
[ app: :httparrot,
version: "0.4.2",
elixir: "~> 1.2",
name: "HTTParrot",
package: package(),
deps: deps(),
docs: docs()
]
description: @description,
package: package,
deps: deps ]
end
def application do
[
extra_applications: [:logger],
mod: {HTTParrot, []}
]
[ applications: [ :compiler,
:syntax_tools,
:cowboy,
:exjsx ],
mod: { HTTParrot, [] },
env: [ http_port: 8080, ssl: true, https_port: 8433 ] ]
end
defp deps do
[
{:cowboy, "~> 2.12"},
{:exjsx, "~> 3.0 or ~> 4.0"},
{:con_cache, "~> 1.1"},
{:earmark, "~> 1.0", only: :dev},
{:ex_doc, "~> 0.18", only: :dev},
{:meck, "~> 0.9", only: :test}
]
[ {:cowboy, "~> 1.0.0"},
{:exjsx, "~> 3.0"},
{:ex_doc, ">= 0.0.0", only: :dev},
{:meck, "~> 0.8.2", only: :test } ]
end
defp package do
[
description: "https://github.com/edgurgel/httparrot",
maintainers: ["Eduardo Gurgel Pinho"],
[ contributors: ["Eduardo Gurgel Pinho"],
licenses: ["MIT"],
links: %{
"Github" => @source_url,
"HTTParrot" => "https://httparrot.onrender.com/",
"httpbin" => "http://httpbin.org"
}
]
end
defp docs do
[
extras: [
"LICENSE.md": [title: "License"],
"README.md": [title: "Overview"]
],
main: "readme",
source_url: @source_url,
source_ref: "v#{@version}",
formatters: ["html"]
]
links: %{ "Github" => "https://github.com/edgurgel/httparrot",
"HTTParrot" => "http://httparrot.herokuapp.com",
"httpbin" => "http://httpbin.org" } ]
end
end

View file

@ -1,17 +1,8 @@
%{
"con_cache": {:hex, :con_cache, "1.1.0", "45c7c6cd6dc216e47636232e8c683734b7fe293221fccd9454fa1757bc685044", [:mix], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "8655f2ae13a1e56c8aef304d250814c7ed929c12810f126fc423ecc8e871593b"},
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
"earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"ex_doc": {:hex, :ex_doc, "0.34.1", "9751a0419bc15bc7580c73fde506b17b07f6402a1e5243be9e0f05a68c723368", [:mix], [{:earmark_parser, "~> 1.4.39", [hex: :earmark_parser, repo: "hexpm", optional: false]}, {:makeup_c, ">= 0.1.0", [hex: :makeup_c, repo: "hexpm", optional: true]}, {:makeup_elixir, "~> 0.14 or ~> 1.0", [hex: :makeup_elixir, repo: "hexpm", optional: false]}, {:makeup_erlang, "~> 0.1 or ~> 1.0", [hex: :makeup_erlang, repo: "hexpm", optional: false]}, {:makeup_html, ">= 0.1.0", [hex: :makeup_html, repo: "hexpm", optional: true]}], "hexpm", "d441f1a86a235f59088978eff870de2e815e290e44a8bd976fe5d64470a4c9d2"},
"exjsx": {:hex, :exjsx, "4.0.0", "60548841e0212df401e38e63c0078ec57b33e7ea49b032c796ccad8cde794b5c", [:mix], [{:jsx, "~> 2.8.0", [hex: :jsx, repo: "hexpm", optional: false]}], "hexpm", "32e95820a97cffea67830e91514a2ad53b888850442d6d395f53a1ac60c82e07"},
"jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"},
"makeup": {:hex, :makeup, "1.1.2", "9ba8837913bdf757787e71c1581c21f9d2455f4dd04cfca785c70bbfff1a76a3", [:mix], [{:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "cce1566b81fbcbd21eca8ffe808f33b221f9eee2cbc7a1706fc3da9ff18e6cac"},
"makeup_elixir": {:hex, :makeup_elixir, "0.16.2", "627e84b8e8bf22e60a2579dad15067c755531fea049ae26ef1020cad58fe9578", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}, {:nimble_parsec, "~> 1.2.3 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "41193978704763f6bbe6cc2758b84909e62984c7752b3784bd3c218bb341706b"},
"makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"},
}
%{"cowboy": {:hex, :cowboy, "1.0.0", "d0b46a5e5f971c5543eb46f86fe76b9add567d12fb5262a852b8f27c64c0555d", [:make, :rebar], [{:cowlib, "~> 1.0.0", [hex: :cowlib, optional: false]}, {:ranch, "~> 1.0", [hex: :ranch, optional: false]}]},
"cowlib": {:hex, :cowlib, "1.0.0", "397d890d669e56d486b0b5329973ad1a07012412bc110d34a737698dd6941741", [:make], []},
"earmark": {:hex, :earmark, "1.0.1", "2c2cd903bfdc3de3f189bd9a8d4569a075b88a8981ded9a0d95672f6e2b63141", [:mix], []},
"ex_doc": {:hex, :ex_doc, "0.13.0", "aa2f8fe4c6136a2f7cfc0a7e06805f82530e91df00e2bff4b4362002b43ada65", [:mix], [{:earmark, "~> 1.0", [hex: :earmark, optional: false]}]},
"exjsx": {:hex, :exjsx, "3.1.0", "d419162cb2d5be80070835c2c2b8c78c8c45907706c991d23f3750dae506d1e9", [:mix], [{:jsx, "~> 2.4.0", [hex: :jsx, optional: false]}]},
"jsx": {:hex, :jsx, "2.4.0", "fb83830ac15e981b6ce310b645324ceecd01b1e0847d23921c33df829de5d2db", [:mix], []},
"meck": {:hex, :meck, "0.8.2", "f15f7d513e14ec8c8dee9a95d4ae585b3e5a88bf0fa6a7573240d6ddb58a7236", [:make, :rebar], []},
"ranch": {:hex, :ranch, "1.0.0", "e3ac054e4265de77e2d2696dd7e1d6a67b7525aade13ba10c860e7f499a0d433", [:make], []}}

View file

@ -56,7 +56,7 @@
<div class='mp'>
<h1>httparrot(1): HTTP Request &amp; Response Service</h1>
<p>Freely hosted in <a href="https://httparrot.onrender.com/">HTTPS</a>
<p>Freely hosted in <a href="http://httparrot.herokuapp.com">HTTP</a> &amp; <a href="https://httparrot.herokuapp.com">HTTPS</a>
<h2 id="ENDPOINTS">ENDPOINTS</h2>
@ -104,46 +104,34 @@ scenarios. Additional endpoints are being considered (e.g. <code>/deflate</code>
<h2 id="EXAMPLES">EXAMPLES</h2>
<h3 id="-curl-http-httparrot-org-ip">$ curl https://httparrot.onrender.com/</h3>
<h3 id="-curl-http-httparrot-org-ip">$ curl http://httparrot.herokuapp.com/ip</h3>
<pre><code>{"origin": "24.127.96.129"}
</code></pre>
<h3 id="-curl-http-httparrot-org-user-agent">$ curl https://httparrot.onrender.com/user-agent</h3>
<h3 id="-curl-http-httparrot-org-user-agent">$ curl http://httparrot.herokuapp.com/user-agent</h3>
<pre><code>{"user-agent": "curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3"}
</code></pre>
<h3 id="-curl-http-httparrot-org-get">$ curl https://httparrot.onrender.com/get</h3>
<h3 id="-curl-http-httparrot-org-get">$ curl http://httparrot.herokuapp.com/get</h3>
<pre><code>
{
"args": {},
"headers": {
"accept": "*/*",
"accept-encoding": "gzip",
"cdn-loop": "cloudflare; subreqs=1",
"cf-connecting-ip": "118.148.71.18",
"cf-ew-via": "15",
"cf-ipcountry": "NZ",
"cf-ray": "899c4ca20494508c-AKL",
"cf-visitor": "{\"scheme\":\"https\"}",
"cf-worker": "onrender.com",
"host": "httparrot.onrender.com",
"render-proxy-ttl": "4",
"rndr-id": "1cf65e46-55f1-429d",
"true-client-ip": "118.148.71.18",
"user-agent": "curl/7.81.0",
"x-forwarded-for": "118.148.71.18, 10.213.36.192, 10.214.43.80",
"x-forwarded-proto": "https",
"x-request-start": "1719395492280333"
},
"url": "http://httparrot.onrender.com/get",
"origin": ""
}
<pre><code>{
"args": {},
"headers": {
"Accept": "*/*",
"Connection": "close",
"Content-Length": "",
"Content-Type": "",
"Host": "httparrot.herokuapp.com",
"User-Agent": "curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3"
},
"origin": "24.127.96.129",
"url": "http://httparrot.herokuapp.com/get"
}
</code></pre>
<h3 id="-curl-I-http-httparrot-org-status-418">$ curl -I https://httparrot.onrender.com/status/201</h3>
<h3 id="-curl-I-http-httparrot-org-status-418">$ curl -I http://httparrot.herokuapp.com/status/201</h3>
<pre><code>HTTP/1.1 201
Server: Cowboy

View file

@ -1,27 +1,16 @@
-----BEGIN CERTIFICATE-----
MIIEqjCCAxKgAwIBAgIRANXKM01Lqak+6N93VnHgkl4wDQYJKoZIhvcNAQELBQAw
bTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSEwHwYDVQQLDBhlZHVh
cmRvQHBvcC1vcyAoRWR1YXJkbykxKDAmBgNVBAMMH21rY2VydCBlZHVhcmRvQHBv
cC1vcyAoRWR1YXJkbykwHhcNMjQwNjIzMDU1MzA0WhcNMzQwNjIzMDU1MzA0WjBt
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExITAfBgNVBAsMGGVkdWFy
ZG9AcG9wLW9zIChFZHVhcmRvKTEoMCYGA1UEAwwfbWtjZXJ0IGVkdWFyZG9AcG9w
LW9zIChFZHVhcmRvKTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAK6p
DThGWoUHwCVf8DqHDFthUTvNIKRJzyxArh4GF71dHehiLVBZQ9i/jA1nRASzsVcu
UGyZT18N+XvCCeoPevHXOPjUJZtMkhPqlt55N9gzrniEsmRRQOPzIt8+BiFjJ5Jn
RzRD9S+9AwNIaZKUjiQ1Oexxgvd7pbWy3S/IzXCyFsKIZqYcvvpBY6FroDSEZbrk
xMA4Fhvy2370nTrlKzuoVTGZ8WdHOsh7Ef+mCZp1QwTtCkIPHdCa3OMs5F7u4q8P
tB4QgaWnvEmRtDwsst/CCQr4nIrQzjDwCMS41x0DZwMrQ8lzSjnAHxayWoll9aJK
38jaDviT9qvnIjjdMHN9jJ7fDBZeonrGqdGSs/754oxpSFAiErpBY6dPGYgzkjQM
IxKi4zqYW9ZWPSYacAmRwZsYWp50tvtwxtdY63GslFrnVjtG7e+H1rJJWsQ2Eq5w
sQekS/EqOpufBuoildwGMiyW1CEhXezW5lCiA++kyA6DkVA2zQRi0huJ4LPvDQID
AQABo0UwQzAOBgNVHQ8BAf8EBAMCAgQwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNV
HQ4EFgQUSGXO0OyaSJ4ztTJkQt8atnaqe7MwDQYJKoZIhvcNAQELBQADggGBAA6c
pCJO1U2S79McbKZylJ13Nv+qMSWvTF5ax+/tSahAgvauaQiDInLa9wOUHfiTqNwH
q42UUexfm04Yre+R9NR9jOVHCFwT9uq3MOPKDuRS3UUUCCUjy0b0CSDc1uCi9BGu
jykYViGNCDvTeOI8AZfIEtD77TGJt/8kn7Z6Qe9EFe1N+k8PtbFJgt1/rjIOtFz0
638iHBSky+U4ozznxQmwwseR3KSSNS0JWQDxm/gWqy4MP1m0pW5Pd543ms2BPUzO
2P1PkEV4jz8J4j2C3EctdoiCudqa8BCFMXIE+t/hKQ+LgbW6phoIN6DLp65Yhs7Z
DHPq64f8005EXB8GDHLoP/HL/wnO60e+hjjvsumvCWc7EZeZiHl2QwFMQ6csExeZ
9bky+h1WiQeV2poEyJSPOVAXThaxf3GOV+V/zrnY+DHNio/IRa4Z+/1Fwxs26+o7
Qnkf9UqSZrKr/B7ilQ/Cb1sv3dLzIPAmfNuDjqPWb4eYT+B26n264znHlhvmWw==
MIICeDCCAeGgAwIBAgIJAOvpU0y2e5J4MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczETMBEGA1UECgwKTmluZSBOaW5lczEPMA0G
A1UECwwGQ293Ym95MRAwDgYDVQQDDAdST09UIENBMB4XDTEzMDIyODA1MTAwMVoX
DTMzMDIyMzA1MTAwMVowVTELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRMw
EQYDVQQKDApOaW5lIE5pbmVzMQ8wDQYDVQQLDAZDb3dib3kxEDAOBgNVBAMMB1JP
T1QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMzmY7Us06yjyUbpqwPx
Iv+xh/g3V7we07ClC9GEYnvr3OQvdA1jFEHccMBUUjRoQ8DPd6uSyK5UkixABs08
Tt5B3VsnGKr0DIN+IO4SN2PkmBqIU/BN3KdcwN65YNr3iM0KsKWeFtAZdYx4CakX
7REbO0wjK20AH3xSBn3uFGiBAgMBAAGjUDBOMB0GA1UdDgQWBBRKfZ8KF2jlLBDm
NL6IuEuGY0pdbzAfBgNVHSMEGDAWgBRKfZ8KF2jlLBDmNL6IuEuGY0pdbzAMBgNV
HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAG1I0kBxXiLkM1b7rl2zPLizREYg
1m+ajb6rWzPOBg6TXjv58Be+H4tqoHIL/M/crixew5emftBkuAGjiKMhbIokjvan
aPTCV8U6HHvNvz9c68HpESWbd+56cHqfsS5XCKp1OpW5tbL2UQYpFKMP4qmbv3Ea
pBfPPmSFMBb1i2AI
-----END CERTIFICATE-----

View file

@ -1,26 +1,17 @@
-----BEGIN CERTIFICATE-----
MIIEZTCCAs2gAwIBAgIQIJarIG+LC7mjP0IRrFcI0zANBgkqhkiG9w0BAQsFADBt
MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExITAfBgNVBAsMGGVkdWFy
ZG9AcG9wLW9zIChFZHVhcmRvKTEoMCYGA1UEAwwfbWtjZXJ0IGVkdWFyZG9AcG9w
LW9zIChFZHVhcmRvKTAeFw0yNDA2MjMwNTU0MTBaFw0yNjA5MjMwNTU0MTBaMEwx
JzAlBgNVBAoTHm1rY2VydCBkZXZlbG9wbWVudCBjZXJ0aWZpY2F0ZTEhMB8GA1UE
CwwYZWR1YXJkb0Bwb3Atb3MgKEVkdWFyZG8pMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAx8lf20sm9KkWh/u6ehJ4YpDlx7DGaebBok3JR6rdV42c9flu
pXdi0Uu7tq4utk4rGu6gotIlPFDeRxokqNIaCUmpIW2msG6KzPBp2Lf+AR0EbdQS
EvqiMLx5dU3yEafGKeH1z4qMobhEWIWU9F0V8zuuJvCeHRCdBkse1XQ64X6gyN1m
5lYEEIlGfOj7rrAFdCkv63W5dUeph9yoIF//T9yhTx0yNGUeCOuqQEL5HsSdD6HL
hqIsjmlI33uHWJd9fr72ZTjmxawRca3tS4ljR6QeZw8zE51lh5P4f1pTGa2vUPxX
A11O8jmuXkflgLyDNlm1Pob0tuoNOpa2Zi+mAQIDAQABo4GhMIGeMA4GA1UdDwEB
/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATAfBgNVHSMEGDAWgBRIZc7Q7JpI
njO1MmRC3xq2dqp7szBWBgNVHREETzBNggtleGFtcGxlLmNvbYINKi5leGFtcGxl
LmNvbYIMZXhhbXBsZS50ZXN0gglsb2NhbGhvc3SHBH8AAAGHEAAAAAAAAAAAAAAA
AAAAAAEwDQYJKoZIhvcNAQELBQADggGBAKuzr0Vb6NZV5XlByLgMb1sddIhl3DWq
RGcAf556am51zvZQFz9W/SBm0Ww7+W1fLx7lasyawsxNhfgNHgP05WKZqghodqIw
1tQJAu8PRuXClrvADUnvMz4a3ELCkygSZNn1Oo84YXssEBe1vy70ZTGZS8hhq5qJ
uKTwN0/UtJXXF0dapd4T+N0kuWuoB1xsf7U9Hdn0Bmw5idWe+U2xvb4/Eo0rPUKa
+GJafosfJ17zV5D4oUbuf1uPg8MqQJzEcQDEOcVDgds7tyy3A3igQ+v1WYDkUcUZ
IfOoQxMfHF7mGDbAETGnn0pSRztgKdobpg7MItbdiI04XSIwgGZL4puLJZfSkRDC
ZLqZk9JJc8DpLRjGmH7lRcKkq8TkbrKGsYOQ3bWV6rLP1xH++rE7Sld7P8bLhapQ
hIwcy1rg38v6u2OmApfEbp+VBa62h7RqBDsW0JSNo8Ut1d0VS2HxHMNZ+pr0WVqO
nGcNj0IS+dchbyqN7WF4X9h1iqD09qWeaw==
MIICpTCCAg6gAwIBAgIJAOvpU0y2e5J5MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczETMBEGA1UECgwKTmluZSBOaW5lczEPMA0G
A1UECwwGQ293Ym95MRAwDgYDVQQDDAdST09UIENBMB4XDTEzMDIyODA1MjMzNFoX
DTMzMDIyMzA1MjMzNFowVzELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRMw
EQYDVQQKDApOaW5lIE5pbmVzMQ8wDQYDVQQLDAZDb3dib3kxEjAQBgNVBAMMCWxv
Y2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAzbW1GjECzHUc/WST
qLiAGqjCNccR5saVS+yoz2SPRhpoyf0/qBrX5BY0tzmgozoTiRfE4wCiVD99Cc+D
rp/FM49r4EpZdocIovprmOmv/gwkoj95zaA6PKNn1OdmDp2hwJsX2Zm3kpbGUZTx
jDkkccmgUb4EjL7qNHq7saQtivUCAwEAAaN7MHkwCQYDVR0TBAIwADAsBglghkgB
hvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYE
FB6jTEIWI8T1ckORA4GezbyYxtbvMB8GA1UdIwQYMBaAFEp9nwoXaOUsEOY0voi4
S4ZjSl1vMA0GCSqGSIb3DQEBBQUAA4GBACMboVQjrx8u/fk3gl/sR0tbA0Wf/NcS
2Dzsy2czndgVUAG4Sqb+hfgn0dqAyUKghRrj3JDcYxYksGPIklDfPzZb7yJ39l16
6x5ZiIzhp8CAVdPvRxRznw5rZwaXesryXu1jVSZxTr3MYZdkG6KaAM0t90+YlGLZ
UG8fAicx0Bf+
-----END CERTIFICATE-----

View file

@ -1,28 +1,15 @@
-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHyV/bSyb0qRaH
+7p6EnhikOXHsMZp5sGiTclHqt1XjZz1+W6ld2LRS7u2ri62Tisa7qCi0iU8UN5H
GiSo0hoJSakhbaawborM8GnYt/4BHQRt1BIS+qIwvHl1TfIRp8Yp4fXPioyhuERY
hZT0XRXzO64m8J4dEJ0GSx7VdDrhfqDI3WbmVgQQiUZ86PuusAV0KS/rdbl1R6mH
3KggX/9P3KFPHTI0ZR4I66pAQvkexJ0PocuGoiyOaUjfe4dYl31+vvZlOObFrBFx
re1LiWNHpB5nDzMTnWWHk/h/WlMZra9Q/FcDXU7yOa5eR+WAvIM2WbU+hvS26g06
lrZmL6YBAgMBAAECggEAY2zlJnZdGa84hk4RfITKoornv5xK8hMj1EkP3Xm8E8Fn
FsaeePxUEkK1VXGTz6hRLWMKUF1yqHS6Wfo5ukZtLKga4ob2SKGKs/kFRBQ09Yri
VGIQ6J8Qrl5tt6Il0QGEzf0k3rddy3GvmbpI6d+Vd+oAfmKK3X4SFzq1SpdAYk1H
RcC+VLfu60v7yFMtk0IMKMvtXBNY4TPmvJFKv439mLDyIRA5Dsk8P6TZrf473PVJ
JpofVVIKtug8z++CFojhiQYX2bcyIxHWdbUer/snJq4UV+0pOjVYqtB+cVjToBSV
BGNcR+qe8Sg0HXVjpSpKUl3d3GOmCTjKeFzHbu4yTQKBgQD498zP1pW4jH1RVxo8
RVsZWKmZip7iD9MhrUakMW9G9pUrWzl6DG7Na8pnYi5TsZXXak/f5sWhhCPxkae0
0x4Pp7qnSqPvGuTMZQsuG8bvFBWg5XwwrLbx8AzKQ6WggnRumamV5KEwQ8pHMa20
b2fZWPEn3KNR5LASzp9QW3cS2wKBgQDNbfYZOmrEAZw9c53VJG9S1JiqClYHg99T
oTlklsfdNfot78odTto29LO9Tr997ZX0w93jDrxSdLyyiIdZEDVSSkbS3HSdSjfm
nqwlogNXf5TnH88j+EkVvQWs63Q7lyrFNcEftT44ebYXH5ehzPkVbKlocztY0AWw
iVgD8AlrUwKBgQCHE8L+fJks0KRpTk3Ap4x+mvkhgfEkC5vsaJusF9oc8UoLhOoR
Ss+PCk19e+pQpEf84QRHIWjWceAif3kzBVwI+GKvwzJgVwIN10CSmqV7LzVw3zFb
I0n6x9fYoY0qIb1UCHDXD31Yt17284AgJlV8ueHVU8MUenQBMDOFoKphAwKBgGGc
/5SLSpIqhbg5iOTvtCoytPwPf0OA6QyPDnt6nivB60gKqgp1HoGAkyvAEIPg8iFl
NLkglmHD8KoQ7+dlKUEZ5D9r28mlq5xdB0W2j0nzaKjOV5oq72dx8xFwrEFomj0t
RsAvWgpx4xFnxKBwimcgw/rKzodsCVgSWw078O3bAoGBAOyz3sgE9c6mv5jwg2bt
59rqGfHZizMRH0gxiC8P1Ui9dlZfnvdeBLUR/FD6XBSb450vRdcgG4AQ+HPECKkb
kECHkBb542ymb/GqgutNLPzQ8n0Q1zO92CSX5KKmY2B+lEfer5NSc2c9gY261YMH
AApeuDGbws/XXVLWnR1fGbH0
-----END PRIVATE KEY-----
-----BEGIN RSA PRIVATE KEY-----
MIICXQIBAAKBgQDNtbUaMQLMdRz9ZJOouIAaqMI1xxHmxpVL7KjPZI9GGmjJ/T+o
GtfkFjS3OaCjOhOJF8TjAKJUP30Jz4Oun8Uzj2vgSll2hwii+muY6a/+DCSiP3nN
oDo8o2fU52YOnaHAmxfZmbeSlsZRlPGMOSRxyaBRvgSMvuo0eruxpC2K9QIDAQAB
AoGAaD85c/h6bpq7Aj7CBbLaWKhFI3OqwsTITB22vsM7SE+B4zsP02UnG1OVi3UM
zytTUxpUkKV1njQ+bYZYOVqGWF4Up8tTqUglHn0FTPok1AIemELWtz3sXvdSHC1T
lqvFBAZ9kibn13qGyVOiyCFaMwfOM/05RvV7p3jfUMTWnNECQQDs7yCJZ8Ol8MyH
TGZzvkjoN2zg1KwmTbSD1hkP6QAJtPdRuqFbjlEru0/PefgOXsWLRIa3/3v0qw2G
xGkV6AXTAkEA3kNbFisqUydjPnZIYv/P6SvPdUimHJEjXbAbfNfzS9dzszrOVJd2
XqGH7z5yzjoH3IyaIMW8GnubVzGDSjrHFwJAKSU5vELlygpwKkrNO+pelN0TLlQg
dSJnZ8GlZorq88SWcn37iX/EftivenNO7YftvEqxLoDSkOGnnrC7Iw/A+wJBAIEe
L/QY72WPJCBNJpAce/PA96vyoE1II3txqwZDjZspdpVQPDz4IFOpEwbxCFC1dYuy
Qnd3Z2cbF4r3wIWGz9ECQQCJGNhUNtY+Om1ELdqPcquxE2VRV/pucnvJSTKwyo2C
Rvm6H7kFDwPDuN23YnTOlTiho0zzCkclcIukhIVJ+dKz
-----END RSA PRIVATE KEY-----

View file

@ -1,8 +0,0 @@
@echo off
rem Set the release to load code on demand (interactive) instead of preloading (embedded).
rem set RELEASE_MODE=interactive
rem Set the release to work across nodes.
rem RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
rem set RELEASE_DISTRIBUTION=name
rem set RELEASE_NODE=<%= @release.name %>

View file

@ -1,20 +0,0 @@
#!/bin/sh
# # Sets and enables heart (recommended only in daemon mode)
# case $RELEASE_COMMAND in
# daemon*)
# HEART_COMMAND="$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND"
# export HEART_COMMAND
# export ELIXIR_ERL_OPTIONS="-heart"
# ;;
# *)
# ;;
# esac
# # Set the release to load code on demand (interactive) instead of preloading (embedded).
# export RELEASE_MODE=interactive
# # Set the release to work across nodes.
# # RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
# export RELEASE_DISTRIBUTION=name
# export RELEASE_NODE=<%= @release.name %>

View file

@ -1,12 +0,0 @@
## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html
## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
## Increase number of concurrent ports/sockets
##+Q 65536
## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10
## Enable deployment without epmd
## (requires changing both vm.args and remote.vm.args)
##-start_epmd false -erl_epmd_port 6789 -dist_listen false

View file

@ -1,12 +0,0 @@
## Customize flags given to the VM: https://www.erlang.org/doc/man/erl.html
## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
## Increase number of concurrent ports/sockets
##+Q 65536
## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10
## Enable deployment without epmd
## (requires changing both vm.args and remote.vm.args)
##-start_epmd false -erl_epmd_port 6789false

View file

@ -4,22 +4,22 @@ defmodule HTTParrot.Base64HandlerTest do
import HTTParrot.Base64Handler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "halts with error" do
expect(:cowboy_req, :binding, [{[:value, :req1], "I="}])
expect(:cowboy_req, :binding, [{[:value, :req1], {"I=", :req2}}])
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate(:cowboy_req)
end
test "proceeds with decoded base64 urlsafe" do
expect(:cowboy_req, :binding, [{[:value, :req1], "LytiYXNlNjQrLw"}])
expect(:cowboy_req, :binding, [{[:value, :req1], {"LytiYXNlNjQrLw", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, "/+base64+/"}
assert malformed_request(:req1, :state) == {false, :req2, "/+base64+/"}
assert validate(:cowboy_req)
end

View file

@ -4,33 +4,32 @@ defmodule HTTParrot.BasicAuthHandlerTest do
import HTTParrot.BasicAuthHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "is_authorized returns true if user and passwd match" do
expect(:cowboy_req, :binding, [{[:user, :req1], :user}, {[:passwd, :req1], :passwd}])
expect(:cowboy_req, :parse_header, [{["authorization", :req1], {:basic, :user, :passwd}}])
expect(:cowboy_req, :binding, [{[:user, :req1], {:user, :req2}},
{[:passwd, :req2], {:passwd, :req3}}])
expect(:cowboy_req, :parse_header, [{["authorization", :req3], {:ok, {"basic", {:user, :passwd}}, :req4}}])
assert is_authorized(:req1, :state) == {true, :req1, :user}
assert is_authorized(:req1, :state) == {true, :req4, :user}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
test "is_authorized returns false if user and passwd doesnt match" do
expect(:cowboy_req, :binding, [{[:user, :req1], :user}, {[:passwd, :req1], :passwd}])
expect(:cowboy_req, :binding, [{[:user, :req1], {:user, :req2}},
{[:passwd, :req2], {:passwd, :req3}}])
expect(:cowboy_req, :parse_header, [{["authorization", :req3], {:ok, {"basic", {:not_the_user, :passwd}}, :req4}}])
expect(:cowboy_req, :parse_header, [
{["authorization", :req1], {:basic, :not_the_user, :passwd}}
])
assert is_authorized(:req1, :state) == {{false, "Basic realm=\"Fake Realm\""}, :req4, :state}
assert is_authorized(:req1, :state) == {{false, "Basic realm=\"Fake Realm\""}, :req1, :state}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
test "returns user and if it's authenticated" do
@ -38,6 +37,6 @@ defmodule HTTParrot.BasicAuthHandlerTest do
assert get_json(:req1, :user) == {:json, :req1, nil}
assert validate(JSX)
assert validate JSX
end
end

View file

@ -4,9 +4,9 @@ defmodule HTTParrot.CacheHandlerTest do
import HTTParrot.CacheHandler
setup do
new(HTTParrot.GeneralRequestInfo)
new(JSX)
on_exit(fn -> unload() end)
new HTTParrot.GeneralRequestInfo
new JSX
on_exit fn -> unload end
:ok
end
@ -16,7 +16,7 @@ defmodule HTTParrot.CacheHandlerTest do
assert get_json(:req1, :state) == {:json, :req2, :state}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
assert validate HTTParrot.GeneralRequestInfo
assert validate JSX
end
end

View file

@ -4,19 +4,19 @@ defmodule HTTParrot.CookiesHandlerTest do
import HTTParrot.CookiesHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "returns a JSON with all the cookies o/" do
expect(:cowboy_req, :parse_cookies, 1, k1: :v1)
expect(:cowboy_req, :cookies, 1, {[k1: :v1], :req2})
expect(JSX, :encode!, [{[[cookies: [k1: :v1]]], :json}])
assert get_json(:req1, :state) == {:json, :req1, :state}
assert get_json(:req1, :state) == {:json, :req2, :state}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
end

View file

@ -1,30 +0,0 @@
defmodule HTTParrot.DeflateHandlerTest do
use ExUnit.Case
import :meck
import HTTParrot.DeflateHandler
setup do
new(HTTParrot.GeneralRequestInfo)
new(JSX)
on_exit(fn -> unload() end)
:ok
end
test "returns prettified json with query values, headers, url and origin" do
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req2})
expect(JSX, :encode!, [{[:info], :json}])
expect(JSX, :prettify!, [{[:json], "json"}])
expect(:cowboy_req, :set_resp_header, 3, :req3)
opened_zlib = :zlib.open()
:zlib.deflateInit(opened_zlib)
body = :zlib.deflate(opened_zlib, "json", :finish)
:zlib.deflateEnd(opened_zlib)
assert get_json(:req1, :state) == {body, :req3, :state}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
assert validate(:cowboy_req)
end
end

View file

@ -4,43 +4,43 @@ defmodule HTTParrot.DelayedHandlerTest do
import HTTParrot.DelayedHandler
setup do
new(HTTParrot.GeneralRequestInfo)
new(JSX)
new(:cowboy_req)
on_exit(fn -> unload() end)
new HTTParrot.GeneralRequestInfo
new JSX
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "malformed_request returns false if it's not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "a2B="}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"a2B=", :req2}}])
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if it's an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 2}
assert malformed_request(:req1, :state) == {false, :req2, 2}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns 0 if 'n' is less than 0" do
expect(:cowboy_req, :binding, [{[:n, :req1], "-1"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"-1", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 0}
assert malformed_request(:req1, :state) == {false, :req2, 0}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns 10 if 'n' is greater than 10" do
expect(:cowboy_req, :binding, [{[:n, :req1], "20"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"20", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 10}
assert malformed_request(:req1, :state) == {false, :req2, 10}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "returns json with query values, headers, url and origin" do
@ -49,7 +49,7 @@ defmodule HTTParrot.DelayedHandlerTest do
assert get_json(:req1, 0) == {:json, :req2, 0}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
assert validate HTTParrot.GeneralRequestInfo
assert validate JSX
end
end

View file

@ -4,24 +4,18 @@ defmodule HTTParrot.DeleteCookiesHandlerTest do
import HTTParrot.DeleteCookiesHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "delete cookies and redirect to /cookies " do
expect(:cowboy_req, :set_resp_cookie, [
{["k1", "v1", :req1, %{path: "/", max_age: 0}], :req2},
{["k2", "v2", :req2, %{path: "/", max_age: 0}], :req3}
])
expect(:cowboy_req, :set_resp_cookie, [{[:k1, :v1, [path: "/", max_age: 0], :req1], :req2},
{[:k2, :v2, [path: "/", max_age: 0], :req2], :req3}])
expect(:cowboy_req, :reply, [{[302, [{"location", "/cookies"}], "Redirecting...", :req3], {:ok, :req4}}])
expect(:cowboy_req, :reply, [
{[302, %{"location" => "/cookies"}, "Redirecting...", :req3], :req4}
])
assert get_json(:req1, [k1: :v1, k2: :v2]) == {:halt, :req4, [k1: :v1, k2: :v2]}
assert get_json(:req1, [{"k1", "v1"}, {"k2", "v2"}]) ==
{:stop, :req4, [{"k1", "v1"}, {"k2", "v2"}]}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
end

View file

@ -4,10 +4,10 @@ defmodule HTTParrot.DeleteHandlerTest do
import HTTParrot.DeleteHandler
setup do
new(:cowboy_req)
new(HTTParrot.GeneralRequestInfo)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new HTTParrot.GeneralRequestInfo
new JSX
on_exit fn -> unload end
:ok
end
@ -18,8 +18,8 @@ defmodule HTTParrot.DeleteHandlerTest do
assert delete_resource(:req1, :state) == {true, :req3, :state}
assert validate(:cowboy_req)
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
assert validate :cowboy_req
assert validate HTTParrot.GeneralRequestInfo
assert validate JSX
end
end

View file

@ -4,8 +4,8 @@ defmodule HTTParrot.GeneralRequestInfoTest do
import HTTParrot.GeneralRequestInfo
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
@ -13,65 +13,46 @@ defmodule HTTParrot.GeneralRequestInfoTest do
test "returns a list of args, headers, url and original ip" do
qs_vals = [{"a", "b"}]
headers = %{"header1" => "value 1", "header2" => "value 2"}
headers = [header1: "value 1", header2: "value 2"]
ip = {127, 1, 2, 3}
url = "http://localhost/get?a=b"
expect(:cowboy_req, :parse_qs, 1, qs_vals)
expect(:cowboy_req, :headers, 1, headers)
expect(:cowboy_req, :uri, 1, url)
expect(:cowboy_req, :peer, 1, {ip, 0})
expect(:cowboy_req, :qs_vals, 1, {qs_vals, :req2})
expect(:cowboy_req, :headers, 1, {headers, :req3})
expect(:cowboy_req, :url, 1, {url, :req4})
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req5})
assert retrieve(:req1) ==
{[args: %{"a" => "b"}, headers: headers, url: url, origin: "127.1.2.3"], :req1}
assert retrieve(:req1) == {[args: %{"a" => "b"}, headers: headers, url: url, origin: "127.1.2.3"], :req5}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "returns a list of args with duplicated keys, headers, url and original ip" do
qs_vals = [{"a", "b"}, {"a", "c"}]
headers = %{"header1" => "value 1", "header2" => "value 2"}
headers = [header1: "value 1", header2: "value 2"]
ip = {127, 1, 2, 3}
url = "http://localhost/get?a=b&a=c"
expect(:cowboy_req, :parse_qs, 1, qs_vals)
expect(:cowboy_req, :headers, 1, headers)
expect(:cowboy_req, :uri, 1, url)
expect(:cowboy_req, :peer, 1, {ip, 0})
expect(:cowboy_req, :qs_vals, 1, {qs_vals, :req2})
expect(:cowboy_req, :headers, 1, {headers, :req3})
expect(:cowboy_req, :url, 1, {url, :req4})
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req5})
assert retrieve(:req1) ==
{[args: %{"a" => ["b", "c"]}, headers: headers, url: url, origin: "127.1.2.3"],
:req1}
assert retrieve(:req1) == {[args: %{"a" => ["b", "c"]}, headers: headers, url: url, origin: "127.1.2.3"], :req5}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "returns a list of empty args, headers, url and original ip" do
qs_vals = []
headers = %{"header1" => "value 1", "header2" => "value 2"}
headers = [header1: "value 1", header2: "value 2"]
ip = {127, 1, 2, 3}
url = "http://localhost/get"
expect(:cowboy_req, :parse_qs, 1, qs_vals)
expect(:cowboy_req, :headers, 1, headers)
expect(:cowboy_req, :uri, 1, url)
expect(:cowboy_req, :peer, 1, {ip, 0})
expect(:cowboy_req, :qs_vals, 1, {qs_vals, :req2})
expect(:cowboy_req, :headers, 1, {headers, :req3})
expect(:cowboy_req, :url, 1, {url, :req4})
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req5})
assert retrieve(:req1) ==
{[args: %{}, headers: headers, url: url, origin: "127.1.2.3"], :req1}
assert retrieve(:req1) == {[args: %{}, headers: headers, url: url, origin: "127.1.2.3"], :req5}
assert validate(:cowboy_req)
end
test "returns empty origin when using unix sockets" do
qs_vals = [{"a", "b"}]
headers = %{"header1" => "value 1", "header2" => "value 2"}
url = "http://localhost/get?a=b"
expect(:cowboy_req, :parse_qs, 1, qs_vals)
expect(:cowboy_req, :headers, 1, headers)
expect(:cowboy_req, :uri, 1, url)
expect(:cowboy_req, :peer, 1, {{127, 0, 0, 1}, 0})
assert retrieve(:req1) ==
{[args: %{"a" => "b"}, headers: headers, url: url, origin: ""], :req1}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
end

View file

@ -4,9 +4,9 @@ defmodule HTTParrot.GetHandlerTest do
import HTTParrot.GetHandler
setup do
new(HTTParrot.GeneralRequestInfo)
new(JSX)
on_exit(fn -> unload() end)
new HTTParrot.GeneralRequestInfo
new JSX
on_exit fn -> unload end
:ok
end
@ -16,7 +16,7 @@ defmodule HTTParrot.GetHandlerTest do
assert get_json(:req1, :state) == {:json, :req2, :state}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
assert validate HTTParrot.GeneralRequestInfo
assert validate JSX
end
end

View file

@ -4,9 +4,9 @@ defmodule HTTParrot.GzipHandlerTest do
import HTTParrot.GzipHandler
setup do
new(HTTParrot.GeneralRequestInfo)
new(JSX)
on_exit(fn -> unload() end)
new HTTParrot.GeneralRequestInfo
new JSX
on_exit fn -> unload end
:ok
end
@ -20,8 +20,8 @@ defmodule HTTParrot.GzipHandlerTest do
assert get_json(:req1, :state) == {body, :req3, :state}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
assert validate(:cowboy_req)
assert validate HTTParrot.GeneralRequestInfo
assert validate JSX
assert validate :cowboy_req
end
end

View file

@ -4,19 +4,19 @@ defmodule HTTParrot.HeadersHandlerTest do
import HTTParrot.HeadersHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "returns prettified json with headers list" do
expect(:cowboy_req, :headers, 1, :headers)
expect(:cowboy_req, :headers, 1, {:headers, :req2})
expect(JSX, :encode!, [{[[headers: :headers]], :json}])
assert get_json(:req1, :state) == {:json, :req1, :state}
assert get_json(:req1, :state) == {:json, :req2, :state}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
end

View file

@ -4,39 +4,32 @@ defmodule HTTParrot.HiddenBasicAuthHandlerTest do
import HTTParrot.HiddenBasicAuthHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "resource_exists returns true if user and passwd match" do
expect(:cowboy_req, :binding, [
{[:user, :req1], :user},
{[:passwd, :req1], :passwd}
])
expect(:cowboy_req, :binding, [{[:user, :req1], {:user, :req2}},
{[:passwd, :req2], {:passwd, :req3}}])
expect(:cowboy_req, :parse_header, [{["authorization", :req3], {:ok, {"basic", {:user, :passwd}}, :req4}}])
expect(:cowboy_req, :parse_header, [
{["authorization", :req1], {:basic, :user, :passwd}}
])
assert resource_exists(:req1, :state) == {true, :req4, :user}
assert resource_exists(:req1, :state) == {true, :req1, :user}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
test "resource_exists returns false if user and passwd doesn't match" do
expect(:cowboy_req, :binding, [{[:user, :req1], :user}, {[:passwd, :req1], :passwd}])
test "resource_exists returns false if user and passwd doesnt match" do
expect(:cowboy_req, :binding, [{[:user, :req1], {:user, :req2}},
{[:passwd, :req2], {:passwd, :req3}}])
expect(:cowboy_req, :parse_header, [{["authorization", :req3], {:ok, {"basic", {:not_the_user, :passwd}}, :req4}}])
expect(:cowboy_req, :parse_header, [
{["authorization", :req1], {:basic, :not_the_user, :passwd}}
])
assert resource_exists(:req1, :state) == {false, :req4, :state}
assert resource_exists(:req1, :state) == {false, :req1, :state}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
test "returns user and if it's authenticated" do
@ -44,6 +37,6 @@ defmodule HTTParrot.HiddenBasicAuthHandlerTest do
assert get_json(:req1, :user) == {:json, :req1, nil}
assert validate(JSX)
assert validate JSX
end
end

View file

@ -4,18 +4,16 @@ defmodule HTTParrotTest do
import HTTParrot
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "'prettify_json' prettifies body response if it's a JSON" do
expect(:cowboy_req, :reply, [
{[:status, %{"content-length" => ~c"14"}, "{\n \"a\": \"b\"\n}", :req1], :req2}
])
assert prettify_json(:status, %{"content-length" => ~c"12"}, "{\"a\":\"b\"}", :req1) == :req2
assert validate(:cowboy_req)
test "'prettify_json' prettifies body response if it's a JSON" do
expect(:cowboy_req, :reply, [{[:status, [{"content-length", '14'}], "{\n \"a\": \"b\"\n}", :req1], {:ok, :req2}}])
assert prettify_json(:status, [{"content-length", '12'}], "{\"a\":\"b\"}", :req1) == :req2
assert validate :cowboy_req
end
test "'prettify_json' does nothing if body is not a JSON" do

View file

@ -4,44 +4,20 @@ defmodule HTTParrot.IPHandlerTest do
import HTTParrot.IPHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "returns prettified json with origin" do
ip = {127, 1, 2, 3}
expect(:cowboy_req, :peer, 1, {ip, 0})
expect(:cowboy_req, :parse_header, 2, :undefined)
expect(:cowboy_req, :peer, 1, {{ip, :host}, :req2})
expect(JSX, :encode!, [{[[origin: "127.1.2.3"]], :json}])
assert get_json(:req1, :state) == {:json, :req1, :state}
assert get_json(:req1, :state) == {:json, :req2, :state}
assert validate(:cowboy_req)
assert validate(JSX)
end
test "returns prettified json with client ip when available" do
ip = {127, 1, 2, 3}
expect(:cowboy_req, :peer, 1, {ip, 0})
expect(:cowboy_req, :parse_header, 2, ["190.1.2.3"])
expect(JSX, :encode!, [{[[origin: "190.1.2.3"]], :json}])
assert get_json(:req1, :state) == {:json, :req1, :state}
assert validate(:cowboy_req)
assert validate(JSX)
end
test "returns empty when running over unix sockets" do
expect(:cowboy_req, :peer, 1, {{127, 0, 0, 1}, 0})
expect(:cowboy_req, :parse_header, 2, :undefined)
expect(JSX, :encode!, [{[[origin: ""]], :json}])
assert get_json(:req1, :state) == {:json, :req1, :state}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
end

View file

@ -4,55 +4,51 @@ defmodule HTTParrot.PHandlerTest do
import HTTParrot.PHandler
setup do
new(HTTParrot.GeneralRequestInfo)
new(JSX)
new(:cowboy_req)
on_exit(fn -> unload() end)
new HTTParrot.GeneralRequestInfo
new JSX
new :cowboy_req
on_exit fn -> unload end
:ok
end
Enum.each(
[{"/post", "POST"}, {"/patch", "PATCH"}, {"/put", "PUT"}],
fn {path, verb} ->
test "allowed_methods return verb related to #{path}" do
expect(:cowboy_req, :path, 1, unquote(path))
Enum.each [{"/post", "POST"},
{"/patch", "PATCH"},
{"/put", "PUT"}], fn {path, verb} ->
test "allowed_methods return verb related to #{path}" do
expect(:cowboy_req, :path, 1, {unquote(path), :req2})
assert allowed_methods(:req1, :state) == {[unquote(verb)], :req1, :state}
assert allowed_methods(:req1, :state) == {[unquote(verb)], :req2, :state}
assert validate(:cowboy_req)
end
assert validate :cowboy_req
end
)
end
test "returns json with general info and P[OST, ATCH, UT] form data" do
expect(:cowboy_req, :read_urlencoded_body, 1, {:ok, :body_qs, :req2})
expect(:cowboy_req, :body_qs, 1, {:ok, :body_qs, :req2})
expect(:cowboy_req, :set_resp_body, [{[:response, :req3], :req4}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req3})
expect(JSX, :encode!, [{[[:info, {:form, :body_qs}, {:data, ""}, {:json, nil}]], :response}])
assert post_form(:req1, :state) == {true, :req4, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, ATCH, UT] JSON body data" do
expect(:cowboy_req, :read_body, 1, {:ok, "body", :req2})
expect(:cowboy_req, :body, 1, {:ok, "body", :req2})
expect(:cowboy_req, :set_resp_body, [{[:response, :req3], :req4}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req3})
expect(JSX, :is_json?, 1, true)
expect(JSX, :decode!, 1, :decoded_json)
expect(JSX, :encode!, [
{[[:info, {:form, [{}]}, {:data, "body"}, {:json, :decoded_json}]], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{}]}, {:data, "body"}, {:json, :decoded_json}]], :response}])
assert post_binary(:req1, :state) == {true, :req4, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, ATCH, UT] non-JSON body data" do
expect(:cowboy_req, :read_body, 1, {:ok, "body", :req2})
expect(:cowboy_req, :body, 1, {:ok, "body", :req2})
expect(:cowboy_req, :set_resp_body, [{[:response, :req3], :req4}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req3})
expect(JSX, :is_json?, 1, false)
@ -60,40 +56,28 @@ defmodule HTTParrot.PHandlerTest do
assert post_binary(:req1, :state) == {true, :req4, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, ATCH, UT] octet-stream body data" do
expect(:cowboy_req, :read_body, 1, {:ok, <<0xFFFF::16>>, :req2})
expect(:cowboy_req, :body, 1, {:ok, <<0xffff :: 16>>, :req2})
expect(:cowboy_req, :set_resp_body, [{[:response, :req3], :req4}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req3})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[
[
:info,
{:form, [{}]},
{:data, "data:application/octet-stream;base64,//8="},
{:json, nil}
]
], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{}]}, {:data, "data:application/octet-stream;base64,//8="}, {:json, nil}]], :response}])
assert post_binary(:req1, :state) == {true, :req4, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, UT, ATCH] non-JSON body data for a chunked request" do
first_chunk = "first chunk"
second_chunk = "second chunk"
expect(:cowboy_req, :read_body, fn req ->
expect(:cowboy_req, :body, fn req ->
case req do
:req1 ->
{:more, first_chunk, :req2}
:req2 ->
{:ok, second_chunk, :req3}
end
@ -102,25 +86,20 @@ defmodule HTTParrot.PHandlerTest do
expect(:cowboy_req, :set_resp_body, [{[:response, :req4], :req5}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req4})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[[:info, {:form, [{}]}, {:data, first_chunk <> second_chunk}, {:json, nil}]], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{}]}, {:data, first_chunk <> second_chunk}, {:json, nil}]], :response}])
assert post_binary(:req1, :state) == {true, :req5, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, UT, ATCH] octect-stream body data for a chunked request" do
first_chunk = "first chunk" <> <<0xFFFF::16>>
first_chunk = "first chunk" <> <<0xffff :: 16>>
second_chunk = "second chunk"
expect(:cowboy_req, :read_body, fn req ->
expect(:cowboy_req, :body, fn req ->
case req do
:req1 ->
{:more, first_chunk, :req2}
:req2 ->
{:ok, second_chunk, :req3}
end
@ -129,204 +108,126 @@ defmodule HTTParrot.PHandlerTest do
expect(:cowboy_req, :set_resp_body, [{[:response, :req4], :req5}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req4})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[
[
:info,
{:form, [{}]},
{:data,
"data:application/octet-stream;base64,#{Base.encode64(first_chunk <> second_chunk)}"},
{:json, nil}
]
], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{}]}, {:data, "data:application/octet-stream;base64,#{Base.encode64(first_chunk <> second_chunk)}"}, {:json, nil}]], :response}])
assert post_binary(:req1, :state) == {true, :req5, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, ATCH, UT] form data for multipart request (simple)" do
expect(:cowboy_req, :read_part, fn req ->
expect(:cowboy_req, :part, fn req ->
case req do
:req1 ->
{:ok, %{"content-disposition" => "form-data; name=\"key1\""}, :req2}
{:ok, [{"content-disposition", "form-data; name=\"key1\""}], :req2}
:req3 ->
{:done, :req4}
end
end)
expect(:cowboy_req, :read_part_body, [{[:req2], {:ok, "value1", :req3}}])
expect(:cowboy_req, :parse_header, [
{["content-type", :req4],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]},
:req5}}
])
expect(:cowboy_req, :part_body, [{[:req2], {:ok, "value1", :req3}}])
expect(:cowboy_req, :parse_header,
[{["content-type", :req4],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]}, :req5}}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req6})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[[:info, {:form, [{"key1", "value1"}]}, {:files, [{}]}, {:data, ""}, {:json, nil}]],
:response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{"key1", "value1"}]}, {:files, [{}]}, {:data, ""}, {:json, nil}]], :response}])
expect(:cowboy_req, :set_resp_body, [{[:response, :req6], :req7}])
assert post_multipart(:req1, :state) == {true, :req7, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, ATCH, UT] form data for multipart requests (multiple parts)" do
expect(:cowboy_req, :read_part, fn req ->
expect(:cowboy_req, :part, fn req ->
case req do
:req1 ->
{:ok, %{"content-disposition" => "form-data; name=\"key1\""}, :req2}
{:ok, [{"content-disposition", "form-data; name=\"key1\""}], :req2}
:req3 ->
{:ok, %{"content-disposition" => "form-data; name=\"key2\""}, :req4}
{:ok, [{"content-disposition", "form-data; name=\"key2\""}], :req4}
:req5 ->
{:done, :req6}
end
end)
expect(:cowboy_req, :read_part_body, fn req ->
expect(:cowboy_req, :part_body, fn req ->
case req do
:req2 -> {:ok, "value1", :req3}
:req4 -> {:ok, "value2", :req5}
end
end)
expect(:cowboy_req, :parse_header, [
{["content-type", :req6],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]},
:req7}}
])
expect(:cowboy_req, :parse_header,
[{["content-type", :req6],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]}, :req7}}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req8})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[
[
:info,
{:form, [{"key1", "value1"}, {"key2", "value2"}]},
{:files, [{}]},
{:data, ""},
{:json, nil}
]
], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{"key1", "value1"}, {"key2", "value2"}]}, {:files, [{}]}, {:data, ""}, {:json, nil}]], :response}])
expect(:cowboy_req, :set_resp_body, [{[:response, :req8], :req9}])
assert post_multipart(:req1, :state) == {true, :req9, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, UT, ATCH] file data (one file)" do
expect(:cowboy_req, :read_part, fn req ->
expect(:cowboy_req, :part, fn req ->
case req do
:req1 ->
{:ok,
%{
"content-disposition" => "form-data; name=\"file1\"; filename=\"testdata.txt\"",
"content-type" => "text/plain"
}, :req2}
{:ok, [{"content-disposition", "form-data; name=\"file1\"; filename=\"testdata.txt\""}, {"content-type", "text/plain"}], :req2}
:req3 ->
{:done, :req4}
end
end)
expect(:cowboy_req, :read_part_body, [
{[:req2], {:ok, "here is some cool\ntest data.", :req3}}
])
expect(:cowboy_req, :parse_header, [
{["content-type", :req4],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]},
:req5}}
])
expect(:cowboy_req, :part_body, [{[:req2], {:ok, "here is some cool\ntest data.", :req3}}])
expect(:cowboy_req, :parse_header,
[{["content-type", :req4],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]}, :req5}}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req6})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[
[
:info,
{:form, [{}]},
{:files, [{"file1", "here is some cool\ntest data."}]},
{:data, ""},
{:json, nil}
]
], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{}]}, {:files, [{"file1", "here is some cool\ntest data."}]}, {:data, ""}, {:json, nil}]], :response}])
expect(:cowboy_req, :set_resp_body, [{[:response, :req6], :req7}])
assert post_multipart(:req1, :state) == {true, :req7, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
test "returns json with general info and P[OST, UT, ATCH] form data and file data (form-data plus one file)" do
expect(:cowboy_req, :read_part, fn req ->
expect(:cowboy_req, :part, fn req ->
case req do
:req1 ->
{:ok, %{"content-disposition" => "form-data; name=\"key1\""}, :req2}
{:ok, [{"content-disposition", "form-data; name=\"key1\""}], :req2}
:req3 ->
{:ok,
%{
"content-disposition" => "form-data; name=\"file1\"; filename=\"testdata.txt\"",
"content-type" => "text/plain"
}, :req4}
{:ok, [{"content-disposition", "form-data; name=\"file1\"; filename=\"testdata.txt\""}, {"content-type", "text/plain"}], :req4}
:req5 ->
{:done, :req6}
end
end)
expect(:cowboy_req, :read_part_body, fn req ->
expect(:cowboy_req, :part_body, fn req ->
case req do
:req2 -> {:ok, "value1", :req3}
:req4 -> {:ok, "here is some cool\ntest data", :req5}
end
end)
expect(:cowboy_req, :parse_header, [
{["content-type", :req6],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]},
:req7}}
])
expect(:cowboy_req, :parse_header,
[{["content-type", :req6],
{:ok, {"multipart", "form-data", [{"boundary", "----WebKitFormBoundary8BEQxJvZANFsvRV9"}]}, :req7}}])
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req8})
expect(JSX, :is_json?, 1, false)
expect(JSX, :encode!, [
{[
[
:info,
{:form, [{"key1", "value1"}]},
{:files, [{"file1", "here is some cool\ntest data"}]},
{:data, ""},
{:json, nil}
]
], :response}
])
expect(JSX, :encode!, [{[[:info, {:form, [{"key1", "value1"}]}, {:files, [{"file1", "here is some cool\ntest data"}]}, {:data, ""}, {:json, nil}]], :response}])
expect(:cowboy_req, :set_resp_body, [{[:response, :req8], :req9}])
assert post_multipart(:req1, :state) == {true, :req9, nil}
assert validate(HTTParrot.GeneralRequestInfo)
assert validate HTTParrot.GeneralRequestInfo
end
end

View file

@ -4,48 +4,49 @@ defmodule HTTParrot.RedirectHandlerTest do
import HTTParrot.RedirectHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "malformed_request returns true if it's not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "a2B="}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"a2B=", :req2}}])
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if it's an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 2}
assert malformed_request(:req1, :state) == {false, :req2, 2}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns 1 if 'n' is less than 1" do
expect(:cowboy_req, :binding, [{[:n, :req1], "0"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"0", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 1}
assert malformed_request(:req1, :state) == {false, :req2, 1}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "moved_permanently returns 'redirect/n-1' if n > 1" do
expect(:cowboy_req, :uri, 2, "host")
expect(:cowboy_req, :host_url, 1, {"host", :req2})
assert moved_permanently(:req1, 4) == {{true, "host/redirect/3"}, :req1, nil}
assert moved_permanently(:req1, 4) == {{true, "host/redirect/3"}, :req2, nil}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "moved_permanently returns '/get' if n = 1" do
expect(:cowboy_req, :uri, 2, "host")
expect(:cowboy_req, :host_url, 1, {"host", :req2})
assert moved_permanently(:req1, 1) == {{true, "host/get"}, :req1, nil}
assert moved_permanently(:req1, 1) == {{true, "host/get"}, :req2, nil}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
end

View file

@ -4,20 +4,20 @@ defmodule HTTParrot.RedirectToHandlerTest do
import HTTParrot.RedirectToHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "malformed_request returns true if no 'url' is defined" do
expect(:cowboy_req, :match_qs, 2, %{url: :url})
assert malformed_request(:req1, :state) == {false, :req1, :url}
assert validate(:cowboy_req)
expect(:cowboy_req, :qs_val, [{["url", :req1, nil], {:url, :req2}}])
assert malformed_request(:req1, :state) == {false, :req2, :url}
assert validate :cowboy_req
end
test "malformed_request returns false if no 'url' is defined" do
expect(:cowboy_req, :match_qs, 2, %{url: nil})
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert validate(:cowboy_req)
expect(:cowboy_req, :qs_val, [{["url", :req1, nil], {nil, :req2}}])
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate :cowboy_req
end
end

View file

@ -4,33 +4,33 @@ defmodule HTTParrot.RelativeRedirectHandlerTest do
import HTTParrot.RelativeRedirectHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "malformed_request returns false if it's not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "a2B="}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"a2B=", :req2}}])
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if it's an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 2}
assert malformed_request(:req1, :state) == {false, :req2, 2}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns 1 if 'n' is less than 1" do
expect(:cowboy_req, :binding, [{[:n, :req1], "0"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"0", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 1}
assert malformed_request(:req1, :state) == {false, :req2, 1}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "moved_permanently returns 'redirect/n-1' if n > 1" do
@ -40,4 +40,5 @@ defmodule HTTParrot.RelativeRedirectHandlerTest do
test "moved_permanently returns '/get' if n = 1" do
assert moved_permanently(:req1, 1) == {{true, "/get"}, :req1, nil}
end
end

View file

@ -1,13 +0,0 @@
defmodule HTTParrot.RequestStoreTest do
alias HTTParrot.RequestStore
use ExUnit.Case
test "save, retrieve, clear" do
request = %{req: 1}
RequestStore.clear(:test)
RequestStore.store(:test, request)
assert RequestStore.retrieve(:test) == [request]
RequestStore.clear(:test)
assert RequestStore.retrieve(:test) == []
end
end

View file

@ -4,36 +4,36 @@ defmodule HTTParrot.ResponseHeadersHandlerTest do
import HTTParrot.ResponseHeadersHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "malformed_request returns true if query string is empty" do
expect(:cowboy_req, :parse_qs, 1, [])
expect(:cowboy_req, :qs_vals, 1, {[], :req2})
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if query string is not empty" do
expect(:cowboy_req, :parse_qs, 1, [{"foo", "bar"}])
expect(:cowboy_req, :qs_vals, 1, {[{"foo", "bar"}], :req2})
assert malformed_request(:req1, :state) == {false, :req1, [{"foo", "bar"}]}
assert malformed_request(:req1, :state) == {false, :req2, [{"foo", "bar"}]}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "query string parameters are sent as headers" do
expect(:cowboy_req, :set_resp_header, [{[:k1, :v1, :req1], :req2}, {[:k2, :v2, :req2], :req3}])
expect(:cowboy_req, :set_resp_header, [{[:k1, :v1, :req1], :req2},
{[:k2, :v2, :req2], :req3}])
expect(JSX, :encode!, [{[[k1: :v1, k2: :v2]], :json}])
assert get_json(:req1, k1: :v1, k2: :v2) == {:json, :req3, [k1: :v1, k2: :v2]}
assert get_json(:req1, [k1: :v1, k2: :v2]) == {:json, :req3, [k1: :v1, k2: :v2]}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
end

View file

@ -1,17 +0,0 @@
defmodule HTTParrot.RetrieveRequestHandlerTests do
use ExUnit.Case
import :meck
import HTTParrot.RetrieveRequestHandler
setup do
HTTParrot.RequestStore.clear(:test)
on_exit(fn -> unload() end)
:ok
end
test "returns saved requests" do
expect(:cowboy_req, :binding, [:key, :req1], {:test, :req1})
HTTParrot.RequestStore.store(:test, :req1)
assert retrieve_stored(:req1, :state) == {"[\"req1\"]", :req1, :state}
end
end

View file

@ -4,72 +4,56 @@ defmodule HTTParrot.SetCookiesHandlerTest do
import HTTParrot.SetCookiesHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "malformed_request returns false if /name/value is sent" do
expect(:cowboy_req, :parse_qs, 1, [])
expect(:cowboy_req, :qs_vals, 1, {[], :req2})
expect(:cowboy_req, :binding, [{[:name, :req2, nil], {"name", :req3}},
{[:value, :req3, nil], {"value", :req4}}])
expect(:cowboy_req, :binding, [
{[:name, :req1, nil], "name"},
{[:value, :req1, nil], "value"}
])
assert malformed_request(:req1, :state) == {false, :req4, [{"name", "value"}]}
assert malformed_request(:req1, :state) == {false, :req1, [{"name", "value"}]}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns query string values too if /name/value is sent" do
expect(:cowboy_req, :parse_qs, 1, [{"name", "value2"}])
expect(:cowboy_req, :qs_vals, 1, {[{"name", "value2"}], :req2})
expect(:cowboy_req, :binding, [{[:name, :req2, nil], {"name", :req3}},
{[:value, :req3, nil], {"value", :req4}}])
expect(:cowboy_req, :binding, [
{[:name, :req1, nil], "name"},
{[:value, :req1, nil], "value"}
])
assert malformed_request(:req1, :state) == {false, :req4, [{"name", "value"}]}
expect(:cowboy_req, :binding, [
{[:name, :req1, nil], "name"},
{[:value, :req1, nil], "value"}
])
assert malformed_request(:req1, :state) == {false, :req1, [{"name", "value"}]}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if query string values are sent" do
expect(:cowboy_req, :parse_qs, 1, [{"name", "value"}])
expect(:cowboy_req, :binding, [{[:name, :req1, nil], nil}])
expect(:cowboy_req, :qs_vals, 1, {[{"name", "value"}], :req2})
expect(:cowboy_req, :binding, [{[:name, :req2, nil], {nil, :req3}}])
assert malformed_request(:req1, :state) == {false, :req1, [{"name", "value"}]}
assert malformed_request(:req1, :state) == {false, :req3, [{"name", "value"}]}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns true if query string values are not sent" do
expect(:cowboy_req, :parse_qs, 1, [])
expect(:cowboy_req, :binding, [{[:name, :req1, nil], nil}])
expect(:cowboy_req, :qs_vals, 1, {[], :req2})
expect(:cowboy_req, :binding, [{[:name, :req2, nil], {nil, :req3}}])
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req3, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "redirect to /cookies " do
expect(:cowboy_req, :set_resp_cookie, [
{[:k1, :v1, :req1, %{path: "/"}], :req2},
{[:k2, :v2, :req2, %{path: "/"}], :req3}
])
expect(:cowboy_req, :set_resp_cookie, [{[:k1, :v1, [path: "/"], :req1], :req2},
{[:k2, :v2, [path: "/"], :req2], :req3}])
expect(:cowboy_req, :reply, [{[302, [{"location", "/cookies"}], "Redirecting...", :req3], {:ok, :req4}}])
expect(:cowboy_req, :reply, [
{[302, %{"location" => "/cookies"}, "Redirecting...", :req3], :req4}
])
assert get_json(:req1, [k1: :v1, k2: :v2]) == {:halt, :req4, [k1: :v1, k2: :v2]}
assert get_json(:req1, k1: :v1, k2: :v2) == {:stop, :req4, [k1: :v1, k2: :v2]}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
end

View file

@ -4,16 +4,16 @@ defmodule HTTParrot.StatusCodeHandlerTest do
import HTTParrot.StatusCodeHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "reply with 'code' as status code" do
code = 123
expect(:cowboy_req, :binding, [{[:code, :req1], code}])
expect(:cowboy_req, :reply, [{[code, %{}, "", :req1], :req2}])
assert get_json(:req1, :state) == {:stop, :req2, :state}
assert validate(:cowboy_req)
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

View file

@ -1,26 +0,0 @@
defmodule HTTParrot.StoreRequestHandlerTests do
use ExUnit.Case
import :meck
import HTTParrot.StoreRequestHandler
setup do
HTTParrot.RequestStore.clear(:test)
on_exit(fn -> unload() end)
:ok
end
test "store a request" do
expect(:cowboy_req, :binding, [:key, :req1], :test)
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req1})
assert get(:req1, :state) == {~c'{"saved": "true"}', :req1, :state}
assert HTTParrot.RequestStore.retrieve(:test) == [:info]
end
test "store multiple requests" do
expect(:cowboy_req, :binding, [:key, :req1], :test)
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req1})
assert get(:req1, :state) == {~c'{"saved": "true"}', :req1, :state}
assert get(:req2, :state) == {~c'{"saved": "true"}', :req1, :state}
assert HTTParrot.RequestStore.retrieve(:test) == [:info, :info]
end
end

View file

@ -4,113 +4,114 @@ defmodule HTTParrot.StreamBytesHandlerTest do
import HTTParrot.StreamBytesHandler
setup do
new(:cowboy_req)
on_exit(fn -> unload() end)
new :cowboy_req
on_exit fn -> unload end
:ok
end
test "malformed_request returns true if n is not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "a2B="}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"a2B=", :req2}}])
expect(:cowboy_req, :match_qs, fn [{name, [], default}], req ->
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{:seed, :req1, "1234"} -> %{seed: "1234"}
{:chunk_size, :req1, "1024"} -> %{chunk_size: "1024"}
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req4, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if n is an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :match_qs, fn [{name, [], default}], req ->
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{:seed, :req1, "1234"} -> %{seed: "1234"}
{:chunk_size, :req1, "1024"} -> %{chunk_size: "1024"}
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {false, :req1, {2, 1234, 1024}}
assert malformed_request(:req1, :state) == {false, :req4, {2, 1234, 1024}}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns true if seed is not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :match_qs, fn [{name, [], default}], req ->
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{:seed, :req1, "1234"} -> %{seed: "a2B="}
{:chunk_size, :req1, "1024"} -> %{chunk_size: "1024"}
{"seed", :req2, "1234"} -> {"a2B=", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req4, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if seed is an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :match_qs, fn [{name, [], default}], req ->
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{:seed, :req1, "1234"} -> %{seed: "7"}
{:chunk_size, :req1, "1024"} -> %{chunk_size: "1024"}
{"seed", :req2, "1234"} -> {"7", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {false, :req1, {2, 7, 1024}}
assert malformed_request(:req1, :state) == {false, :req4, {2, 7, 1024}}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns true if chunk_size is not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :match_qs, fn [{name, [], default}], req ->
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{:seed, :req1, "1234"} -> %{seed: "1234"}
{:chunk_size, :req1, "1024"} -> %{chunk_size: "a2B="}
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"a2B=", :req4}
end
end)
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req4, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if chunk_size is an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :match_qs, fn [{name, [], default}], req ->
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{:seed, :req1, "1234"} -> %{seed: "1234"}
{:chunk_size, :req1, "1024"} -> %{chunk_size: "13"}
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"13", :req4}
end
end)
assert malformed_request(:req1, :state) == {false, :req1, {2, 1234, 13}}
assert malformed_request(:req1, :state) == {false, :req4, {2, 1234, 13}}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "response must stream chunks" do
expect(:cowboy_req, :stream_reply, 3, :req2)
expect(:cowboy_req, :stream_body, 3, :ok)
assert {{:chunked, func}, :req1, nil} = get_bytes(:req1, {9, 3, 4})
assert is_function(func)
assert {:stop, :req2, nil} = get_bytes(:req1, {9, 3, 4})
send_func = fn(body) -> send(self, {:chunk, body}) end
func.(send_func)
chunk1 = :meck.capture(1, :cowboy_req, :stream_body, :_, 1)
chunk2 = :meck.capture(2, :cowboy_req, :stream_body, :_, 1)
chunk3 = :meck.capture(3, :cowboy_req, :stream_body, :_, 1)
assert_receive {:chunk, chunk1}
assert_receive {:chunk, chunk2}
assert_receive {:chunk, chunk3}
assert String.length(chunk1) == 4
assert String.length(chunk2) == 4
assert String.length(chunk3) == 1
end
end
end

View file

@ -4,54 +4,60 @@ defmodule HTTParrot.StreamHandlerTest do
import HTTParrot.StreamHandler
setup do
new(:cowboy_req)
new(HTTParrot.GeneralRequestInfo)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new HTTParrot.GeneralRequestInfo
new JSX
on_exit fn -> unload end
:ok
end
test "malformed_request returns true if it's not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "a2B="}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"a2B=", :req2}}])
assert malformed_request(:req1, :state) == {true, :req1, :state}
assert malformed_request(:req1, :state) == {true, :req2, :state}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns false if it's an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], "2"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 2}
assert malformed_request(:req1, :state) == {false, :req2, 2}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns 1 if 'n' is less than 1" do
expect(:cowboy_req, :binding, [{[:n, :req1], "0"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"0", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 1}
assert malformed_request(:req1, :state) == {false, :req2, 1}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "malformed_request returns 100 if 'n' is greater than 100" do
expect(:cowboy_req, :binding, [{[:n, :req1], "200"}])
expect(:cowboy_req, :binding, [{[:n, :req1], {"200", :req2}}])
assert malformed_request(:req1, :state) == {false, :req1, 100}
assert malformed_request(:req1, :state) == {false, :req2, 100}
assert validate(:cowboy_req)
assert validate :cowboy_req
end
test "response must stream chunks" do
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {[:info], :req2})
expect(:cowboy_req, :stream_reply, 3, :req2)
expect(:cowboy_req, :stream_body, 3, :req2)
expect(JSX, :encode!, [{[[{:id, 0}, :info]], :json1}, {[[{:id, 1}, :info]], :json2}])
expect(JSX, :encode!, [{[[{:id, 0}, :info]], :json1},
{[[{:id, 1}, :info]], :json2}])
assert {:stop, :req2, nil} = get_json(:req1, 2)
assert {{:chunked, func}, :req2, nil} = get_json(:req1, 2)
assert is_function(func)
assert validate(HTTParrot.GeneralRequestInfo)
assert validate(JSX)
send_func = fn(body) -> send(self, {:chunk, body}) end
func.(send_func)
assert_receive {:chunk, :json1}
assert_receive {:chunk, :json2}
assert validate HTTParrot.GeneralRequestInfo
assert validate JSX
end
end

View file

@ -1 +1 @@
ExUnit.start()
ExUnit.start

View file

@ -4,19 +4,19 @@ defmodule HTTParrot.UserAgentHandlerTest do
import HTTParrot.UserAgentHandler
setup do
new(:cowboy_req)
new(JSX)
on_exit(fn -> unload() end)
new :cowboy_req
new JSX
on_exit fn -> unload end
:ok
end
test "returns prettified json with user agent" do
expect(:cowboy_req, :header, [{["user-agent", :req1, "null"], :user_agent}])
expect(:cowboy_req, :header, [{["user-agent", :req1, "null"], {:user_agent, :req2}}])
expect(JSX, :encode!, [{[[{"user-agent", :user_agent}]], :json}])
assert get_json(:req1, :state) == {:json, :req1, :state}
assert get_json(:req1, :state) == {:json, :req2, :state}
assert validate(:cowboy_req)
assert validate(JSX)
assert validate :cowboy_req
assert validate JSX
end
end