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:
commit
8d693e8073
5 changed files with 163 additions and 1 deletions
|
@ -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, []},
|
||||
|
|
43
lib/httparrot/stream_bytes_handler.ex
Normal file
43
lib/httparrot/stream_bytes_handler.ex
Normal 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
|
|
@ -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>
|
||||
|
|
117
test/stream_bytes_handler_test.exs
Normal file
117
test/stream_bytes_handler_test.exs
Normal 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
|
|
@ -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}
|
||||
|
|
Loading…
Add table
Reference in a new issue