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

Compare commits

..

13 commits

Author SHA1 Message Date
edgurgel
cb6373be97 Update URLs to point to render URL 2024-06-26 21:54:55 +12:00
edgurgel
e716a1a327 Add render build script 2024-06-26 21:41:50 +12:00
edgurgel
4f87d8262a mix release.init 2024-06-26 21:37:33 +12:00
Eduardo Gurgel
ca31d47221
Merge pull request #40 from edgurgel/ssl-fix
SSL Fix
2024-06-25 21:30:51 +12:00
edgurgel
690dc6fc30 Bump version 2024-06-25 21:25:35 +12:00
edgurgel
5982706dbb Add .github actions 2024-06-25 21:23:15 +12:00
edgurgel
312b6723f3 mix format and replace certs 2024-06-25 21:23:13 +12:00
Nathan Youngman
d2607766b0 warning: negative steps are not supported in String.slice/2, pass 1..-1//1 instead 2024-06-25 21:22:32 +12:00
Nathan Youngman
6b30597487 update all dependencies 2024-06-25 21:22:30 +12:00
Nathan Youngman
71675f8d3d resolve compiler warnings 2024-06-25 21:21:16 +12:00
Nathan Youngman
aa7ca908f0 update travis ci 2024-06-25 21:21:16 +12:00
Eduardo Gurgel
d6d83a8ac6
Merge pull request #37 from kianmeng/misc-doc-changes
Misc doc changes
2024-06-22 08:01:21 +12:00
Kian-Meng, Ang
3b7d5d5eea Misc doc changes
Besides other documentation changes, this commit ensures the generated
HTML doc for HexDocs.pm will become the source of truth for this Elixir
library and leverage on latest features of ExDoc.
2021-08-30 23:08:45 +08:00
41 changed files with 407 additions and 246 deletions

4
.formatter.exs Normal file
View file

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

54
.github/workflows/main.yml vendored Normal file
View file

@ -0,0 +1,54 @@
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

28
.gitignore vendored
View file

@ -1,6 +1,26 @@
/_build # The directory Mix will write compiled artifacts to.
/deps /_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.
erl_crash.dump erl_crash.dump
# Also ignore archive artifacts (built via "mix archive.build").
*.ez *.ez
/doc
.elixir_ls # Ignore package tarball (built via "mix hex.build").
httparrot-*.tar
# Temporary files, for example, from tests.
/tmp/

View file

@ -1,25 +0,0 @@
language: elixir
notifications:
recipients:
- eduardo@gurgel.me
cache:
directories:
- _build
- deps
sudo: false
script: mix test
matrix:
include:
otp_release: 21.0
- elixir: 1.7
otp_release: 19.3
- elixir: 1.7
otp_release: 20.3
- elixir: 1.7
otp_release: 21.0
- elixir: 1.8
otp_release: 20.3
- elixir: 1.8
otp_release: 21.0
- elixir: 1.8
otp_release: 22.0.1

View file

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

View file

@ -1,49 +1,56 @@
# HTTParrot [![Build Status](https://travis-ci.org/edgurgel/httparrot.png?branch=master)](https://travis-ci.org/edgurgel/httparrot) # HTTParrot
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). [![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).
## Endpoints ## Endpoints
* / This page. * `/` This page.
* /ip Returns Origin IP. * `/ip` Returns Origin IP.
* /user-agent Returns user-agent. * `/user-agent` Returns user-agent.
* /headers Returns header dict. * `/headers` Returns header dict.
* /get Returns GET data. * `/get` Returns GET data.
* /post Returns POST data. * `/post` Returns POST data.
* /put Returns PUT data. * `/put` Returns PUT data.
* /patch Returns PATCH data. * `/patch` Returns PATCH data.
* /delete Returns DELETE data * `/delete` Returns DELETE data
* /gzip Returns gzip-encoded data. * `/gzip` Returns gzip-encoded data.
* /status/:code Returns given HTTP Status code. * `/status/:code` Returns given HTTP Status code.
* /response-headers?key=val Returns given response headers. * `/response-headers?key=val` Returns given response headers.
* /redirect/:n 301 Redirects n times. * `/redirect/:n` 301 Redirects n times.
* /redirect-to?url=foo 301 Redirects to the foo URL. * `/redirect-to?url=foo` 301 Redirects to the foo URL.
* /relative-redirect/:n 301 Relative redirects n times. * `/relative-redirect/:n` 301 Relative redirects n times.
* /cookies Returns cookie data. * `/cookies` Returns cookie data.
* /cookies/set?name=value Sets one or more simple cookies. * `/cookies/set?name=value` Sets one or more simple cookies.
* /cookies/set/name/value Sets one cookie . * `/cookies/set/name/value` Sets one cookie .
* /cookies/delete?name Deletes one or more simple cookies. * `/cookies/delete?name` Deletes one or more simple cookies.
* /basic-auth/:user/:passwd Challenges HTTPBasic Auth. * `/basic-auth/:user/:passwd` Challenges HTTPBasic Auth.
* /hidden-basic-auth/:user/:passwd 404'd BasicAuth. * `/hidden-basic-auth/:user/:passwd` 404'd BasicAuth.
* /digest-auth/:qop/:user/:passwd Challenges HTTP Digest Auth. * `/digest-auth/:qop/:user/:passwd` Challenges HTTP Digest Auth.
* /stream/:n Streams n100 lines. * `/stream/:n` Streams n100 lines.
* /delay/:n Delays responding for n10 seconds. * `/delay/:n` Delays responding for n10 seconds.
* /html Renders an HTML Page. * `/html` Renders an HTML Page.
* /robots.txt Returns some robots.txt rules. * `/robots.txt` Returns some robots.txt rules.
* /deny Denied by robots.txt file. * `/deny` Denied by robots.txt file.
* /cache Returns 200 unless an If-Modified-Since header is provided, when it returns a 304 Not Modified. * `/cache` Returns 200 unless an If-Modified-Since header is provided, when it returns a 304 Not Modified.
* /base64/:value Decodes base64url-encoded string. * `/base64/:value` Decodes base64url-encoded string.
* /image Return an image based on Accept header. * `/image` Return an image based on Accept header.
* /websocket Echo message received through websocket * `/websocket` Echo message received through websocket
## TODO ## TODO
* [ ] /deflate Returns deflate-encoded data. * [ ] `/deflate` Returns deflate-encoded data.
* [ ] /digest-auth/:qop/:user/:passwd Challenges HTTP Digest Auth. * [ ] `/digest-auth/:qop/:user/:passwd` Challenges HTTP Digest Auth.
## License ## Copyright and License
Copyright 2013-2016 Eduardo Gurgel <eduardo@gurgel.me> Copyright (c) 2013 Eduardo Gurgel <eduardo@gurgel.me>
This work is free. You can redistribute it and/or modify it under the 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. terms of the MIT License. See the [LICENSE.md](./LICENSE.md) file for more details.

10
build.sh Executable file
View file

@ -0,0 +1,10 @@
#!/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,4 +1,4 @@
import Mix.Config import Config
port = System.get_env("PORT", "8080") port = System.get_env("PORT", "8080")
port = String.to_integer(port) port = String.to_integer(port)
@ -14,4 +14,3 @@ config :httparrot,
https_port: ssl_port, https_port: ssl_port,
unix_socket: unix_socket, unix_socket: unix_socket,
socket_path: System.get_env("SOCKET_PATH", "httparrot.sock") socket_path: System.get_env("SOCKET_PATH", "httparrot.sock")

View file

@ -14,4 +14,3 @@ config :httparrot,
https_port: ssl_port, https_port: ssl_port,
unix_socket: unix_socket, unix_socket: unix_socket,
socket_path: System.get_env("SOCKET_PATH", "httparrot.sock") socket_path: System.get_env("SOCKET_PATH", "httparrot.sock")

View file

@ -7,7 +7,7 @@ defmodule HTTParrot do
end end
def init(_) do def init(_) do
supervise([], strategy: :simple_one_for_one) Supervisor.start_link([], strategy: :one_for_one)
end end
def start(_type, _args) do def start(_type, _args) do
@ -71,9 +71,9 @@ defmodule HTTParrot do
:https, :https,
[ [
port: https_port, port: https_port,
cacertfile: priv_dir ++ '/ssl/server-ca.crt', cacertfile: priv_dir ++ ~c"/ssl/server-ca.crt",
certfile: priv_dir ++ '/ssl/server.crt', certfile: priv_dir ++ ~c"/ssl/server.crt",
keyfile: priv_dir ++ '/ssl/server.key' keyfile: priv_dir ++ ~c"/ssl/server.key"
], ],
%{env: %{dispatch: dispatch}} %{env: %{dispatch: dispatch}}
) )

View file

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

View file

@ -13,7 +13,7 @@ defmodule HTTParrot.PHandler do
""" """
def allowed_methods(req, state) do def allowed_methods(req, state) do
path = :cowboy_req.path(req) path = :cowboy_req.path(req)
path = String.slice(path, 1..-1) path = String.slice(path, 1..-1//1)
{[String.upcase(path)], req, state} {[String.upcase(path)], req, state}
end end

View file

@ -19,7 +19,11 @@ defmodule HTTParrot.RedirectHandler do
def previously_existed(req, state), do: {true, req, state} def previously_existed(req, state), do: {true, req, state}
def moved_permanently(req, n) do def moved_permanently(req, n) do
host_url = IO.iodata_to_binary(:cowboy_req.uri(req, %{path: :undefined, qs: :undefined, fragment: :undefined})) 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" url = if n > 1, do: "/redirect/#{n - 1}", else: "/get"
{{true, host_url <> url}, req, nil} {{true, host_url <> url}, req, nil}
end end

View file

@ -1,6 +1,6 @@
defmodule HTTParrot.RequestStore do defmodule HTTParrot.RequestStore do
@moduledoc """ @moduledoc """
Used to store and retrived requests Used to store and retrieved requests
""" """
@doc """ @doc """
Store the requests to the key Store the requests to the key
@ -26,7 +26,7 @@ defmodule HTTParrot.RequestStore do
end end
@doc """ @doc """
Clear the saved data on the coresponding key Clear the saved data on the corresponding key
""" """
def clear(key) do def clear(key) do
ConCache.delete(:requests_registry, key) ConCache.delete(:requests_registry, key)

View file

@ -1,6 +1,6 @@
defmodule HTTParrot.RetrieveRequestHandler do defmodule HTTParrot.RetrieveRequestHandler do
@moduledoc """ @moduledoc """
Retreive saved request and clear the conresponding :id Retrieve saved request and clear the conresponding :id
""" """
use HTTParrot.Cowboy, methods: ~w(GET POST PUT HEAD OPTIONS) use HTTParrot.Cowboy, methods: ~w(GET POST PUT HEAD OPTIONS)

View file

@ -23,7 +23,7 @@ defmodule HTTParrot.StoreRequestHandler do
{info, req} = GeneralRequestInfo.retrieve(req) {info, req} = GeneralRequestInfo.retrieve(req)
key = :cowboy_req.binding(:key, req) key = :cowboy_req.binding(:key, req)
HTTParrot.RequestStore.store(key, info) HTTParrot.RequestStore.store(key, info)
{'{"saved": "true"}', req, state} {~c'{"saved": "true"}', req, state}
end end
def post_binary(req, _state) do def post_binary(req, _state) do

View file

@ -31,13 +31,15 @@ defmodule HTTParrot.StreamBytesHandler do
end end
defp stream_response!(n, chunk_size, req) do defp stream_response!(n, chunk_size, req) do
req = :cowboy_req.stream_reply(200, %{ "content-type" => "application/octet-stream" }, req) req = :cowboy_req.stream_reply(200, %{"content-type" => "application/octet-stream"}, req)
Stream.repeatedly(fn -> :rand.uniform(255) end) Stream.repeatedly(fn -> :rand.uniform(255) end)
|> Stream.take(n) |> Stream.take(n)
|> Enum.chunk_every(chunk_size, chunk_size, []) |> Enum.chunk_every(chunk_size, chunk_size, [])
|> Enum.each(fn chunk -> |> Enum.each(fn chunk ->
:cowboy_req.stream_body(List.to_string(chunk), :nofin, req) :cowboy_req.stream_body(List.to_string(chunk), :nofin, req)
end) end)
:cowboy_req.stream_body("", :fin, req) :cowboy_req.stream_body("", :fin, req)
req req
end end

View file

@ -25,11 +25,13 @@ defmodule HTTParrot.StreamHandler do
def get_json(req, n) do def get_json(req, n) do
{info, req} = GeneralRequestInfo.retrieve(req) {info, req} = GeneralRequestInfo.retrieve(req)
req = :cowboy_req.stream_reply(200, %{ "content-type" => "application/json" }, req) req = :cowboy_req.stream_reply(200, %{"content-type" => "application/json"}, req)
Enum.each(0..(n - 1), fn i -> Enum.each(0..(n - 1), fn i ->
body = JSX.encode!([id: i] ++ info) body = JSX.encode!([id: i] ++ info)
:cowboy_req.stream_body(body, :nofin, req) :cowboy_req.stream_body(body, :nofin, req)
end) end)
:cowboy_req.stream_body("", :fin, req) :cowboy_req.stream_body("", :fin, req)
{:stop, req, nil} {:stop, req, nil}
end end

37
mix.exs
View file

@ -1,19 +1,18 @@
defmodule Httparrot.Mixfile do defmodule Httparrot.Mixfile do
use Mix.Project use Mix.Project
@description """ @source_url "https://github.com/edgurgel/httparrot"
HTTP Request & Response Server. An incomplete clone of http://httpbin.org @version "1.4.0"
"""
def project do def project do
[ [
app: :httparrot, app: :httparrot,
version: "1.3.0", version: @version,
elixir: "~> 1.7", elixir: "~> 1.16",
name: "HTTParrot", name: "HTTParrot",
description: @description,
package: package(), package: package(),
deps: deps() deps: deps(),
docs: docs()
] ]
end end
@ -26,24 +25,38 @@ defmodule Httparrot.Mixfile do
defp deps do defp deps do
[ [
{:cowboy, "~> 2.8.0"}, {:cowboy, "~> 2.12"},
{:exjsx, "~> 3.0 or ~> 4.0"}, {:exjsx, "~> 3.0 or ~> 4.0"},
{:con_cache, "~> 0.14.0"}, {:con_cache, "~> 1.1"},
{:earmark, "~> 1.0", only: :dev}, {:earmark, "~> 1.0", only: :dev},
{:ex_doc, "~> 0.18", only: :dev}, {:ex_doc, "~> 0.18", only: :dev},
{:meck, "~> 0.8.13", only: :test} {:meck, "~> 0.9", only: :test}
] ]
end end
defp package do defp package do
[ [
description: "https://github.com/edgurgel/httparrot",
maintainers: ["Eduardo Gurgel Pinho"], maintainers: ["Eduardo Gurgel Pinho"],
licenses: ["MIT"], licenses: ["MIT"],
links: %{ links: %{
"Github" => "https://github.com/edgurgel/httparrot", "Github" => @source_url,
"HTTParrot" => "http://httparrot.herokuapp.com", "HTTParrot" => "https://httparrot.onrender.com/",
"httpbin" => "http://httpbin.org" "httpbin" => "http://httpbin.org"
} }
] ]
end 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"]
]
end
end end

View file

@ -1,15 +1,17 @@
%{ %{
"con_cache": {:hex, :con_cache, "0.14.0", "863acb90fa08017be3129074993af944cf7a4b6c3ee7c06c5cd0ed6b94fbc223", [:mix], [], "hexpm", "50887a8949377d0b707a3c6653b7610de06074751b52d0f267f52135f391aece"}, "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.8.0", "f3dc62e35797ecd9ac1b50db74611193c29815401e53bac9a5c0577bd7bc667d", [:rebar3], [{:cowlib, "~> 2.9.1", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "~> 1.7.1", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "4643e4fba74ac96d4d152c75803de6fad0b3fa5df354c71afdd6cbeeb15fac8a"}, "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.9.1", "61a6c7c50cf07fdd24b2f45b89500bb93b6686579b069a89f88cb211e1125c78", [:rebar3], [], "hexpm", "e4175dc240a70d996156160891e1c62238ede1729e45740bdd38064dad476170"}, "cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"},
"earmark": {:hex, :earmark, "1.4.6", "f14260802d8998f30e1654189a0d1699c4aa7d099eb4dad904eb5f41283a70b2", [:mix], [], "hexpm", "c1653a90f63400d029b783a098f4d70a40418ddff14da4cc156a0fee9e72e8d6"}, "earmark": {:hex, :earmark, "1.4.46", "8c7287bd3137e99d26ae4643e5b7ef2129a260e3dcf41f251750cb4563c8fb81", [:mix], [], "hexpm", "798d86db3d79964e759ddc0c077d5eb254968ed426399fbf5a62de2b5ff8910a"},
"ex_doc": {:hex, :ex_doc, "0.22.1", "9bb6d51508778193a4ea90fa16eac47f8b67934f33f8271d5e1edec2dc0eee4c", [:mix], [{:earmark, "~> 1.4.0", [hex: :earmark, repo: "hexpm", optional: false]}, {:makeup_elixir, "~> 0.14", [hex: :makeup_elixir, repo: "hexpm", optional: false]}], "hexpm", "d957de1b75cb9f78d3ee17820733dc4460114d8b1e11f7ee4fd6546e69b1db60"}, "earmark_parser": {:hex, :earmark_parser, "1.4.39", "424642f8335b05bb9eb611aa1564c148a8ee35c9c8a8bba6e129d51a3e3c6769", [:mix], [], "hexpm", "06553a88d1f1846da9ef066b87b57c6f605552cfbe40d20bd8d59cc6bde41944"},
"exactor": {:hex, :exactor, "2.2.3", "a6972f43bb6160afeb73e1d8ab45ba604cd0ac8b5244c557093f6e92ce582786", [:mix], [], "hexpm"}, "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"}, "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"}, "jsx": {:hex, :jsx, "2.8.3", "a05252d381885240744d955fbe3cf810504eb2567164824e19303ea59eef62cf", [:mix, :rebar3], [], "hexpm", "fc3499fed7a726995aa659143a248534adc754ebd16ccd437cd93b649a95091f"},
"makeup": {:hex, :makeup, "1.0.3", "e339e2f766d12e7260e6672dd4047405963c5ec99661abdc432e6ec67d29ef95", [:mix], [{:nimble_parsec, "~> 0.5", [hex: :nimble_parsec, repo: "hexpm", optional: false]}], "hexpm", "2e9b4996d11832947731f7608fed7ad2f9443011b3b479ae288011265cdd3dad"}, "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.14.1", "4f0e96847c63c17841d42c08107405a005a2680eb9c7ccadfd757bd31dabccfb", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "f2438b1a80eaec9ede832b5c41cd4f373b38fd7aa33e3b22d9db79e640cbde11"}, "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"},
"meck": {:hex, :meck, "0.8.13", "ffedb39f99b0b99703b8601c6f17c7f76313ee12de6b646e671e3188401f7866", [:rebar3], [], "hexpm", "d34f013c156db51ad57cc556891b9720e6a1c1df5fe2e15af999c84d6cebeb1a"}, "makeup_erlang": {:hex, :makeup_erlang, "1.0.0", "6f0eff9c9c489f26b69b61440bf1b238d95badae49adac77973cbacae87e3c2e", [:mix], [{:makeup, "~> 1.0", [hex: :makeup, repo: "hexpm", optional: false]}], "hexpm", "ea7a9307de9d1548d2a72d299058d1fd2339e3d398560a0e46c27dab4891e4d2"},
"nimble_parsec": {:hex, :nimble_parsec, "0.6.0", "32111b3bf39137144abd7ba1cce0914533b2d16ef35e8abc5ec8be6122944263", [:mix], [], "hexpm", "27eac315a94909d4dc68bc07a4a83e06c8379237c5ea528a9acff4ca1c873c52"}, "meck": {:hex, :meck, "0.9.2", "85ccbab053f1db86c7ca240e9fc718170ee5bda03810a6292b5306bf31bae5f5", [:rebar3], [], "hexpm", "81344f561357dc40a8344afa53767c32669153355b626ea9fcbc8da6b3045826"},
"ranch": {:hex, :ranch, "1.7.1", "6b1fab51b49196860b733a49c07604465a47bdb78aa10c1c16a3d199f7f8c881", [:rebar3], [], "hexpm", "451d8527787df716d99dc36162fca05934915db0b6141bbdac2ea8d3c7afc7d7"}, "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"},
} }

View file

@ -56,7 +56,7 @@
<div class='mp'> <div class='mp'>
<h1>httparrot(1): HTTP Request &amp; Response Service</h1> <h1>httparrot(1): HTTP Request &amp; Response Service</h1>
<p>Freely hosted in <a href="http://httparrot.herokuapp.com">HTTP</a> &amp; <a href="https://httparrot.herokuapp.com">HTTPS</a> <p>Freely hosted in <a href="https://httparrot.onrender.com/">HTTPS</a>
<h2 id="ENDPOINTS">ENDPOINTS</h2> <h2 id="ENDPOINTS">ENDPOINTS</h2>
@ -104,34 +104,46 @@ scenarios. Additional endpoints are being considered (e.g. <code>/deflate</code>
<h2 id="EXAMPLES">EXAMPLES</h2> <h2 id="EXAMPLES">EXAMPLES</h2>
<h3 id="-curl-http-httparrot-org-ip">$ curl http://httparrot.herokuapp.com/ip</h3> <h3 id="-curl-http-httparrot-org-ip">$ curl https://httparrot.onrender.com/</h3>
<pre><code>{"origin": "24.127.96.129"} <pre><code>{"origin": "24.127.96.129"}
</code></pre> </code></pre>
<h3 id="-curl-http-httparrot-org-user-agent">$ curl http://httparrot.herokuapp.com/user-agent</h3> <h3 id="-curl-http-httparrot-org-user-agent">$ curl https://httparrot.onrender.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"} <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> </code></pre>
<h3 id="-curl-http-httparrot-org-get">$ curl http://httparrot.herokuapp.com/get</h3> <h3 id="-curl-http-httparrot-org-get">$ curl https://httparrot.onrender.com/get</h3>
<pre><code>{ <pre><code>
"args": {}, {
"headers": { "args": {},
"Accept": "*/*", "headers": {
"Connection": "close", "accept": "*/*",
"Content-Length": "", "accept-encoding": "gzip",
"Content-Type": "", "cdn-loop": "cloudflare; subreqs=1",
"Host": "httparrot.herokuapp.com", "cf-connecting-ip": "118.148.71.18",
"User-Agent": "curl/7.19.7 (universal-apple-darwin10.0) libcurl/7.19.7 OpenSSL/0.9.8l zlib/1.2.3" "cf-ew-via": "15",
}, "cf-ipcountry": "NZ",
"origin": "24.127.96.129", "cf-ray": "899c4ca20494508c-AKL",
"url": "http://httparrot.herokuapp.com/get" "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": ""
}
</code></pre> </code></pre>
<h3 id="-curl-I-http-httparrot-org-status-418">$ curl -I http://httparrot.herokuapp.com/status/201</h3> <h3 id="-curl-I-http-httparrot-org-status-418">$ curl -I https://httparrot.onrender.com/status/201</h3>
<pre><code>HTTP/1.1 201 <pre><code>HTTP/1.1 201
Server: Cowboy Server: Cowboy

View file

@ -1,16 +1,27 @@
-----BEGIN CERTIFICATE----- -----BEGIN CERTIFICATE-----
MIICeDCCAeGgAwIBAgIJAOvpU0y2e5J4MA0GCSqGSIb3DQEBBQUAMFUxCzAJBgNV MIIEqjCCAxKgAwIBAgIRANXKM01Lqak+6N93VnHgkl4wDQYJKoZIhvcNAQELBQAw
BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczETMBEGA1UECgwKTmluZSBOaW5lczEPMA0G bTEeMBwGA1UEChMVbWtjZXJ0IGRldmVsb3BtZW50IENBMSEwHwYDVQQLDBhlZHVh
A1UECwwGQ293Ym95MRAwDgYDVQQDDAdST09UIENBMB4XDTEzMDIyODA1MTAwMVoX cmRvQHBvcC1vcyAoRWR1YXJkbykxKDAmBgNVBAMMH21rY2VydCBlZHVhcmRvQHBv
DTMzMDIyMzA1MTAwMVowVTELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVRleGFzMRMw cC1vcyAoRWR1YXJkbykwHhcNMjQwNjIzMDU1MzA0WhcNMzQwNjIzMDU1MzA0WjBt
EQYDVQQKDApOaW5lIE5pbmVzMQ8wDQYDVQQLDAZDb3dib3kxEDAOBgNVBAMMB1JP MR4wHAYDVQQKExVta2NlcnQgZGV2ZWxvcG1lbnQgQ0ExITAfBgNVBAsMGGVkdWFy
T1QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMzmY7Us06yjyUbpqwPx ZG9AcG9wLW9zIChFZHVhcmRvKTEoMCYGA1UEAwwfbWtjZXJ0IGVkdWFyZG9AcG9w
Iv+xh/g3V7we07ClC9GEYnvr3OQvdA1jFEHccMBUUjRoQ8DPd6uSyK5UkixABs08 LW9zIChFZHVhcmRvKTCCAaIwDQYJKoZIhvcNAQEBBQADggGPADCCAYoCggGBAK6p
Tt5B3VsnGKr0DIN+IO4SN2PkmBqIU/BN3KdcwN65YNr3iM0KsKWeFtAZdYx4CakX DThGWoUHwCVf8DqHDFthUTvNIKRJzyxArh4GF71dHehiLVBZQ9i/jA1nRASzsVcu
7REbO0wjK20AH3xSBn3uFGiBAgMBAAGjUDBOMB0GA1UdDgQWBBRKfZ8KF2jlLBDm UGyZT18N+XvCCeoPevHXOPjUJZtMkhPqlt55N9gzrniEsmRRQOPzIt8+BiFjJ5Jn
NL6IuEuGY0pdbzAfBgNVHSMEGDAWgBRKfZ8KF2jlLBDmNL6IuEuGY0pdbzAMBgNV RzRD9S+9AwNIaZKUjiQ1Oexxgvd7pbWy3S/IzXCyFsKIZqYcvvpBY6FroDSEZbrk
HRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAG1I0kBxXiLkM1b7rl2zPLizREYg xMA4Fhvy2370nTrlKzuoVTGZ8WdHOsh7Ef+mCZp1QwTtCkIPHdCa3OMs5F7u4q8P
1m+ajb6rWzPOBg6TXjv58Be+H4tqoHIL/M/crixew5emftBkuAGjiKMhbIokjvan tB4QgaWnvEmRtDwsst/CCQr4nIrQzjDwCMS41x0DZwMrQ8lzSjnAHxayWoll9aJK
aPTCV8U6HHvNvz9c68HpESWbd+56cHqfsS5XCKp1OpW5tbL2UQYpFKMP4qmbv3Ea 38jaDviT9qvnIjjdMHN9jJ7fDBZeonrGqdGSs/754oxpSFAiErpBY6dPGYgzkjQM
pBfPPmSFMBb1i2AI 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==
-----END CERTIFICATE----- -----END CERTIFICATE-----

View file

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

View file

@ -1,15 +1,28 @@
-----BEGIN RSA PRIVATE KEY----- -----BEGIN PRIVATE KEY-----
MIICXQIBAAKBgQDNtbUaMQLMdRz9ZJOouIAaqMI1xxHmxpVL7KjPZI9GGmjJ/T+o MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDHyV/bSyb0qRaH
GtfkFjS3OaCjOhOJF8TjAKJUP30Jz4Oun8Uzj2vgSll2hwii+muY6a/+DCSiP3nN +7p6EnhikOXHsMZp5sGiTclHqt1XjZz1+W6ld2LRS7u2ri62Tisa7qCi0iU8UN5H
oDo8o2fU52YOnaHAmxfZmbeSlsZRlPGMOSRxyaBRvgSMvuo0eruxpC2K9QIDAQAB GiSo0hoJSakhbaawborM8GnYt/4BHQRt1BIS+qIwvHl1TfIRp8Yp4fXPioyhuERY
AoGAaD85c/h6bpq7Aj7CBbLaWKhFI3OqwsTITB22vsM7SE+B4zsP02UnG1OVi3UM hZT0XRXzO64m8J4dEJ0GSx7VdDrhfqDI3WbmVgQQiUZ86PuusAV0KS/rdbl1R6mH
zytTUxpUkKV1njQ+bYZYOVqGWF4Up8tTqUglHn0FTPok1AIemELWtz3sXvdSHC1T 3KggX/9P3KFPHTI0ZR4I66pAQvkexJ0PocuGoiyOaUjfe4dYl31+vvZlOObFrBFx
lqvFBAZ9kibn13qGyVOiyCFaMwfOM/05RvV7p3jfUMTWnNECQQDs7yCJZ8Ol8MyH re1LiWNHpB5nDzMTnWWHk/h/WlMZra9Q/FcDXU7yOa5eR+WAvIM2WbU+hvS26g06
TGZzvkjoN2zg1KwmTbSD1hkP6QAJtPdRuqFbjlEru0/PefgOXsWLRIa3/3v0qw2G lrZmL6YBAgMBAAECggEAY2zlJnZdGa84hk4RfITKoornv5xK8hMj1EkP3Xm8E8Fn
xGkV6AXTAkEA3kNbFisqUydjPnZIYv/P6SvPdUimHJEjXbAbfNfzS9dzszrOVJd2 FsaeePxUEkK1VXGTz6hRLWMKUF1yqHS6Wfo5ukZtLKga4ob2SKGKs/kFRBQ09Yri
XqGH7z5yzjoH3IyaIMW8GnubVzGDSjrHFwJAKSU5vELlygpwKkrNO+pelN0TLlQg VGIQ6J8Qrl5tt6Il0QGEzf0k3rddy3GvmbpI6d+Vd+oAfmKK3X4SFzq1SpdAYk1H
dSJnZ8GlZorq88SWcn37iX/EftivenNO7YftvEqxLoDSkOGnnrC7Iw/A+wJBAIEe RcC+VLfu60v7yFMtk0IMKMvtXBNY4TPmvJFKv439mLDyIRA5Dsk8P6TZrf473PVJ
L/QY72WPJCBNJpAce/PA96vyoE1II3txqwZDjZspdpVQPDz4IFOpEwbxCFC1dYuy JpofVVIKtug8z++CFojhiQYX2bcyIxHWdbUer/snJq4UV+0pOjVYqtB+cVjToBSV
Qnd3Z2cbF4r3wIWGz9ECQQCJGNhUNtY+Om1ELdqPcquxE2VRV/pucnvJSTKwyo2C BGNcR+qe8Sg0HXVjpSpKUl3d3GOmCTjKeFzHbu4yTQKBgQD498zP1pW4jH1RVxo8
Rvm6H7kFDwPDuN23YnTOlTiho0zzCkclcIukhIVJ+dKz RVsZWKmZip7iD9MhrUakMW9G9pUrWzl6DG7Na8pnYi5TsZXXak/f5sWhhCPxkae0
-----END RSA PRIVATE KEY----- 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-----

View file

@ -1,6 +1,8 @@
@echo off @echo off
rem Set the release to work across nodes. If using the long name format like rem Set the release to load code on demand (interactive) instead of preloading (embedded).
rem the one below (my_app@127.0.0.1), you need to also uncomment the rem set RELEASE_MODE=interactive
rem RELEASE_DISTRIBUTION variable below.
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_DISTRIBUTION=name
rem set RELEASE_NODE=<%= @release.name %>@127.0.0.1 rem set RELEASE_NODE=<%= @release.name %>

View file

@ -1,14 +1,20 @@
#!/bin/sh #!/bin/sh
# Sets and enables heart (recommended only in daemon mode) # # Sets and enables heart (recommended only in daemon mode)
# if [ "$RELEASE_COMMAND" = "daemon" ] || [ "$RELEASE_COMMAND" = "daemon_iex" ]; then # case $RELEASE_COMMAND in
# HEART_COMMAND="$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND" # daemon*)
# export HEART_COMMAND # HEART_COMMAND="$RELEASE_ROOT/bin/$RELEASE_NAME $RELEASE_COMMAND"
# export ELIXIR_ERL_OPTIONS="-heart" # export HEART_COMMAND
# fi # export ELIXIR_ERL_OPTIONS="-heart"
# ;;
# *)
# ;;
# esac
# Set the release to work across nodes. If using the long name format like # # Set the release to load code on demand (interactive) instead of preloading (embedded).
# the one below (my_app@127.0.0.1), you need to also uncomment the # export RELEASE_MODE=interactive
# RELEASE_DISTRIBUTION variable below.
# # Set the release to work across nodes.
# # RELEASE_DISTRIBUTION must be "sname" (local), "name" (distributed) or "none".
# export RELEASE_DISTRIBUTION=name # export RELEASE_DISTRIBUTION=name
# export RELEASE_NODE=<%= @release.name %>@127.0.0.1 # export RELEASE_NODE=<%= @release.name %>

12
rel/remote.vm.args.eex Normal file
View file

@ -0,0 +1,12 @@
## 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,11 +1,12 @@
## Customize flags given to the VM: http://erlang.org/doc/man/erl.html ## 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 ## -mode/-name/-sname/-setcookie are configured via env vars, do not set them here
## Number of dirty schedulers doing IO work (file, sockets, etc)
##+SDio 5
## Increase number of concurrent ports/sockets ## Increase number of concurrent ports/sockets
##+Q 65536 ##+Q 65536
## Tweak GC to run more often ## Tweak GC to run more often
##-env ERL_FULLSWEEP_AFTER 10 ##-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,8 +4,8 @@ defmodule HTTParrot.Base64HandlerTest do
import HTTParrot.Base64Handler import HTTParrot.Base64Handler
setup do setup do
new :cowboy_req new(:cowboy_req)
on_exit fn -> unload() end on_exit(fn -> unload() end)
:ok :ok
end end

View file

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

View file

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

View file

@ -4,9 +4,9 @@ defmodule HTTParrot.DeflateHandlerTest do
import HTTParrot.DeflateHandler import HTTParrot.DeflateHandler
setup do setup do
new HTTParrot.GeneralRequestInfo new(HTTParrot.GeneralRequestInfo)
new JSX new(JSX)
on_exit fn -> unload() end on_exit(fn -> unload() end)
:ok :ok
end end
@ -16,15 +16,15 @@ defmodule HTTParrot.DeflateHandlerTest do
expect(JSX, :prettify!, [{[:json], "json"}]) expect(JSX, :prettify!, [{[:json], "json"}])
expect(:cowboy_req, :set_resp_header, 3, :req3) expect(:cowboy_req, :set_resp_header, 3, :req3)
opened_zlib = :zlib.open opened_zlib = :zlib.open()
:zlib.deflateInit(opened_zlib) :zlib.deflateInit(opened_zlib)
body = :zlib.deflate(opened_zlib, "json", :finish) body = :zlib.deflate(opened_zlib, "json", :finish)
:zlib.deflateEnd(opened_zlib) :zlib.deflateEnd(opened_zlib)
assert get_json(:req1, :state) == {body, :req3, :state} assert get_json(:req1, :state) == {body, :req3, :state}
assert validate HTTParrot.GeneralRequestInfo assert validate(HTTParrot.GeneralRequestInfo)
assert validate JSX assert validate(JSX)
assert validate :cowboy_req assert validate(:cowboy_req)
end end
end end

View file

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

View file

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

View file

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

View file

@ -26,7 +26,7 @@ defmodule HTTParrot.HiddenBasicAuthHandlerTest do
assert validate(JSX) assert validate(JSX)
end end
test "resource_exists returns false if user and passwd doesnt match" do test "resource_exists returns false if user and passwd doesn't match" do
expect(:cowboy_req, :binding, [{[:user, :req1], :user}, {[:passwd, :req1], :passwd}]) expect(:cowboy_req, :binding, [{[:user, :req1], :user}, {[:passwd, :req1], :passwd}])
expect(:cowboy_req, :parse_header, [ expect(:cowboy_req, :parse_header, [

View file

@ -11,10 +11,10 @@ defmodule HTTParrotTest do
test "'prettify_json' prettifies body response if it's a JSON" do test "'prettify_json' prettifies body response if it's a JSON" do
expect(:cowboy_req, :reply, [ expect(:cowboy_req, :reply, [
{[:status, %{"content-length" => '14'}, "{\n \"a\": \"b\"\n}", :req1], :req2} {[:status, %{"content-length" => ~c"14"}, "{\n \"a\": \"b\"\n}", :req1], :req2}
]) ])
assert prettify_json(:status, %{"content-length" => '12'}, "{\"a\":\"b\"}", :req1) == :req2 assert prettify_json(:status, %{"content-length" => ~c"12"}, "{\"a\":\"b\"}", :req1) == :req2
assert validate(:cowboy_req) assert validate(:cowboy_req)
end end

View file

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

View file

@ -5,7 +5,7 @@ defmodule HTTParrot.RetrieveRequestHandlerTests do
setup do setup do
HTTParrot.RequestStore.clear(:test) HTTParrot.RequestStore.clear(:test)
on_exit fn -> unload() end on_exit(fn -> unload() end)
:ok :ok
end end

View file

@ -12,15 +12,15 @@ defmodule HTTParrot.StoreRequestHandlerTests do
test "store a request" do test "store a request" do
expect(:cowboy_req, :binding, [:key, :req1], :test) expect(:cowboy_req, :binding, [:key, :req1], :test)
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req1}) expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req1})
assert get(:req1, :state) == {'{"saved": "true"}', :req1, :state} assert get(:req1, :state) == {~c'{"saved": "true"}', :req1, :state}
assert HTTParrot.RequestStore.retrieve(:test) == [:info] assert HTTParrot.RequestStore.retrieve(:test) == [:info]
end end
test "store multiple requests" do test "store multiple requests" do
expect(:cowboy_req, :binding, [:key, :req1], :test) expect(:cowboy_req, :binding, [:key, :req1], :test)
expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req1}) expect(HTTParrot.GeneralRequestInfo, :retrieve, 1, {:info, :req1})
assert get(:req1, :state) == {'{"saved": "true"}', :req1, :state} assert get(:req1, :state) == {~c'{"saved": "true"}', :req1, :state}
assert get(:req2, :state) == {'{"saved": "true"}', :req1, :state} assert get(:req2, :state) == {~c'{"saved": "true"}', :req1, :state}
assert HTTParrot.RequestStore.retrieve(:test) == [:info, :info] assert HTTParrot.RequestStore.retrieve(:test) == [:info, :info]
end end
end end

View file

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