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

Merge pull request #11 from jordan0day/master

add a stream-bytes/:n endpoint & tests
This commit is contained in:
Eduardo Gurgel 2015-01-21 11:29:01 +13:00
commit 8d693e8073
5 changed files with 163 additions and 1 deletions

View file

@ -23,6 +23,7 @@ defmodule HTTParrot do
{'/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, []},

View file

@ -0,0 +1,43 @@
defmodule HTTParrot.StreamBytesHandler do
@moduledoc """
Streams n bytes of data, with chunked transfer encoding.
"""
alias HTTParrot.GeneralRequestInfo
use HTTParrot.Cowboy, methods: ~w(GET)
def content_types_provided(req, state) do
{[{{"application", "octet-stream", []}, :get_bytes}], req, state}
end
def malformed_request(req, state) do
{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
{false, req, {n, seed, chunk_size}}
rescue
ArgumentError -> {true, req, state}
end
end
def get_bytes(req, state) do
{n, seed, chunk_size} = state
:random.seed(seed, seed, seed)
{{:chunked, stream_response(n, chunk_size)}, req, nil}
end
defp stream_response(n, chunk_size) do
fn(send_func) ->
Stream.repeatedly(fn -> :random.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

@ -86,6 +86,7 @@
<li><a href="/robots.txt" data-bare-link="true"><code>/robots.txt</code></a> Returns some robots.txt rules.</li>
<li><a href="/deny" data-bare-link="true"><code>/deny</code></a> Denied by robots.txt file.</li>
<li><a href="/cache" data-bare-link="true"><code>/cache</code></a> 200 unless If-Modified-Since was sent, then 304.</li>
<li><a href="/stream-bytes/1024"><code>/stream-bytes/:n</code></a> Streams <em>n</em> random bytes of binary data, accepts optional <em>seed</em> and <em>chunk_size</em> integer parameters.</li>
<li><a href="/base64/LytiYXNlNjQrLw" data-bare-link="true"><code>/base64/:value</code></a> Decodes <em>value</em> base64url-encoded string.</li>
<li><a href="/image" data-bare-link="true"><code>/image</code></a> Return an image based on Accept header.</li>
<li><code>/websocket</code> Echo message received through websocket.</li>

View file

@ -0,0 +1,117 @@
defmodule HTTParrot.StreamBytesHandlerTest do
use ExUnit.Case, async: false
import :meck
import HTTParrot.StreamBytesHandler
setup do
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=", :req2}}])
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {true, :req4, :state}
assert validate :cowboy_req
end
test "malformed_request returns false if n is an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {false, :req4, {2, 1234, 1024}}
assert validate :cowboy_req
end
test "malformed_request returns true if seed is not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{"seed", :req2, "1234"} -> {"a2B=", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {true, :req4, :state}
assert validate :cowboy_req
end
test "malformed_request returns false if seed is an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{"seed", :req2, "1234"} -> {"7", :req3}
{"chunk_size", :req3, "1024"} -> {"1024", :req4}
end
end)
assert malformed_request(:req1, :state) == {false, :req4, {2, 7, 1024}}
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", :req2}}])
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"a2B=", :req4}
end
end)
assert malformed_request(:req1, :state) == {true, :req4, :state}
assert validate :cowboy_req
end
test "malformed_request returns false if chunk_size is an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], {"2", :req2}}])
expect(:cowboy_req, :qs_val, fn name, req, default ->
case {name, req, default} do
{"seed", :req2, "1234"} -> {"1234", :req3}
{"chunk_size", :req3, "1024"} -> {"13", :req4}
end
end)
assert malformed_request(:req1, :state) == {false, :req4, {2, 1234, 13}}
assert validate :cowboy_req
end
test "response must stream chunks" do
assert {{:chunked, func}, :req1, nil} = get_bytes(:req1, {9, 3, 4})
assert is_function(func)
send_func = fn(body) -> send(self, {:chunk, body}) end
func.(send_func)
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

View file

@ -11,7 +11,7 @@ defmodule HTTParrot.StreamHandlerTest do
:ok
end
test "malformed_request returns false if it's not an integer" do
test "malformed_request returns true if it's not an integer" do
expect(:cowboy_req, :binding, [{[:n, :req1], {"a2B=", :req2}}])
assert malformed_request(:req1, :state) == {true, :req2, :state}