Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Use iolists instead of binaries for streamcontent_from_pid data, and

add a new test for the streamcontent_from_pid feature
  • Loading branch information...
commit 913aff8e1ad01c437dc1b9b82d44cc4e0f6f8ad4 1 parent 5f35f5b
@vinoski vinoski authored
View
13 doc/yaws.tex
@@ -1465,18 +1465,19 @@ \section{Stream content}
We call one of the following functions to send data:
\begin{itemize}
-\item \verb+yaws_api:stream_process_deliver(Socket, Bin)+ sends binary
- data \verb+Bin+ using socket \verb+Socket+ without chunking the data.
+\item \verb+yaws_api:stream_process_deliver(Socket, IoList)+ sends
+ data \verb+IoList+ using socket \verb+Socket+ without chunking the
+ data.
-\item \verb+yaws_api:stream_process_deliver_chunk(Socket, Bin)+ sends
- binary data \verb+Bin+ using socket \verb+Socket+ but converts the
- data into chunked transfer form before sending it.
+\item \verb+yaws_api:stream_process_deliver_chunk(Socket, IoList)+
+ sends data \verb+IoList+ using socket \verb+Socket+ but converts
+ the data into chunked transfer form before sending it.
\end{itemize}
Pids using chunked transfer must indicate the end of their transfer by
calling the following function:
\begin{itemize}
-\item \verb+yaws_api:stream_process_deliver_final_chunk(Socket, Bin)+
+\item \verb+yaws_api:stream_process_deliver_final_chunk(Socket, IoList)+
\end{itemize}
which delivers a special HTTP chunk to mark the end of the data
View
20 src/yaws_api.erl
@@ -837,26 +837,24 @@ stream_chunk_end(YawsPid) ->
YawsPid ! endofstreamcontent.
%% This won't work for SSL for now
-stream_process_deliver(Sock, Data) ->
- gen_tcp:send(Sock, Data).
+stream_process_deliver(Sock, IoList) ->
+ gen_tcp:send(Sock, IoList).
%% This won't work for SSL for now either
-stream_process_deliver_chunk(Sock, Data) ->
- Chunk = case size(Data) of
+stream_process_deliver_chunk(Sock, IoList) ->
+ Chunk = case erlang:iolist_size(IoList) of
0 ->
- stream_process_deliver_final_chunk(Sock, Data);
+ stream_process_deliver_final_chunk(Sock, IoList);
S ->
- list_to_binary([yaws:integer_to_hex(S), "\r\n",
- Data, "\r\n"])
+ [yaws:integer_to_hex(S), "\r\n", IoList, "\r\n"]
end,
gen_tcp:send(Sock, Chunk).
-stream_process_deliver_final_chunk(Sock, Data) ->
- Chunk = case size(Data) of
+stream_process_deliver_final_chunk(Sock, IoList) ->
+ Chunk = case erlang:iolist_size(IoList) of
0 ->
<<"0\r\n\r\n">>;
S ->
- list_to_binary([yaws:integer_to_hex(S), "\r\n",
- Data, "\r\n0\r\n\r\n"])
+ [yaws:integer_to_hex(S), "\r\n", IoList, "\r\n0\r\n\r\n"]
end,
gen_tcp:send(Sock, Chunk).
View
13 test/t2/Makefile
@@ -2,12 +2,12 @@ include ../support/include.mk
.PHONY: all test debug conf clean
-#
-all: conf setup app_test.beam
+#
+all: conf setup app_test.beam streamtest.beam
@echo "all ok"
-# invoke as
+# invoke as
# TEST=test3 make test
# or just make test to run all
@@ -30,9 +30,12 @@ test: conf start
debug:
- $(ERL) $(PA)
+ $(ERL) $(PA)
-conf: stdconf
+conf:
+ cat ../conf/stdconf.conf | \
+ ../../scripts/Subst %YTOP% $(YTOP) | \
+ perl -pe 's/^(\s*appmods =.+)/\1 streamtest/' > yaws.conf
clean: tclean
-rm -rf localhost:8000 logs yaws.conf
View
43 test/t2/app_test.erl
@@ -16,6 +16,7 @@ start() ->
test1(),
test2(),
test3(),
+ streamcontent_test(),
sendfile_get().
@@ -23,12 +24,12 @@ test1() ->
io:format("test1\n",[]),
L = lists:seq(1, 100),
SELF = self(),
- Pids = lists:map(fun(I) ->
+ Pids = lists:map(fun(I) ->
spawn(fun() -> slow_client(I, SELF) end)
end, L),
?line ok = allow_connects(Pids, 5),
?line ok = collect_pids(Pids).
-
+
collect_pids([]) ->
ok;
@@ -49,7 +50,7 @@ allow_connects(Pids, 0) ->
allow_connects(lists:delete(Pid, Pids), 1)
end;
allow_connects(Pids, I) ->
- receive
+ receive
{Pid, allow} ->
Pid ! allow,
allow_connects(Pids, I-1);
@@ -61,11 +62,11 @@ allow_connects(Pids, I) ->
slow_client(I, Top) ->
Top ! {self(), allow},
- receive
+ receive
allow ->
ok
end,
- ?line {ok, C} = gen_tcp:connect(localhost, 8000, [{active, false},
+ ?line {ok, C} = gen_tcp:connect(localhost, 8000, [{active, false},
{packet, http}]),
Top ! {self(), connected},
?line ok = gen_tcp:send(C, "GET /1000.txt HTTP/1.1\r\n"
@@ -86,7 +87,7 @@ read_loop(C, I, Sz) ->
get_cont_len(C) ->
- ?line {value, {http_header, _,_,_, LenStr}} =
+ ?line {value, {http_header, _,_,_, LenStr}} =
lists:keysearch('Content-Length', 3, tftest:get_headers(C)),
{ok, list_to_integer(LenStr)}.
@@ -116,12 +117,14 @@ blkget(I) ->
test3() ->
io:format("test3\n",[]),
- ?line {ok, "200", _Headers, []} = ibrowse:send_req("http://localhost:8000", [], head),
+ ?line {ok, "200", _Headers, []} = ibrowse:send_req("http://localhost:8000",
+ [], head),
ok.
server_options_test() ->
io:format("server_options_test\n",[]),
- {ok, S} = gen_tcp:connect("localhost", 8000, [{packet, raw}, list, {active, false}]),
+ {ok, S} = gen_tcp:connect("localhost", 8000, [{packet, raw}, list,
+ {active, false}]),
ok = gen_tcp:send(S, "OPTIONS * HTTP/1.1\r\nHost: localhost\r\n\r\n"),
inet:setopts(S, [{packet, http}]),
?line ok = server_options_recv(S),
@@ -157,9 +160,9 @@ sendfile_get() ->
K1 = lists:map(
fun(_) ->
spawn(fun() ->
- ?line {ok, "200", _Headers, _} =
+ ?line {ok, "200", _Headers, _} =
ibrowse:send_req(
- "http://localhost:8000/1000.txt",
+ "http://localhost:8000/1000.txt",
[], get, [], [], ?SENDFILE_GET_TIMEOUT),
SELF ! {self(), k1, done}
end)
@@ -168,9 +171,9 @@ sendfile_get() ->
K2 = lists:map(
fun(_) ->
spawn(fun() ->
- ?line {ok, "200", _Headers, _} =
+ ?line {ok, "200", _Headers, _} =
ibrowse:send_req(
- "http://localhost:8000/2000.txt",
+ "http://localhost:8000/2000.txt",
[], get, [], [], ?SENDFILE_GET_TIMEOUT),
SELF ! {self(), k2, done}
end)
@@ -179,9 +182,9 @@ sendfile_get() ->
K3 = lists:map(
fun(_) ->
spawn(fun() ->
- ?line {ok, "200", _Headers, _} =
+ ?line {ok, "200", _Headers, _} =
ibrowse:send_req(
- "http://localhost:8000/3000.txt",
+ "http://localhost:8000/3000.txt",
[], get, [], [], ?SENDFILE_GET_TIMEOUT),
SELF ! {self(), k3, done}
end)
@@ -191,12 +194,13 @@ sendfile_get() ->
collect(K1, 1, k1),
collect(K2, 1, k2),
collect(K3, 1, k3),
+ io:format("\n",[]),
ok.
collect([], _, _) ->
ok;
collect(L, Count, Tag) ->
- receive
+ receive
{Pid, Tag, done} ->
io:format("(~p ~p)", [Tag, Count]),
collect(lists:delete(Pid, L), Count+1, Tag)
@@ -204,3 +208,12 @@ collect(L, Count, Tag) ->
io:format("TIMEOUT ~p\n~p~n",[process_info(self()), L]),
?line exit(timeout)
end.
+
+
+streamcontent_test() ->
+ io:format("streamcontent_test\n",[]),
+ Uri = "http://localhost:8000/streamtest",
+ ?line {ok, "200", Headers, Body} = ibrowse:send_req(Uri, [], get),
+ ?line "chunked" = proplists:get_value("Transfer-Encoding", Headers),
+ ?line Body = "this is an iolist",
+ ok.
View
21 test/t2/streamtest.erl
@@ -0,0 +1,21 @@
+-module(streamtest).
+-export([out/1, streamer/1]).
+-include("../../include/yaws_api.hrl").
+
+
+out(Arg) ->
+ Sock = Arg#arg.clisock,
+ Pid = spawn(?MODULE, streamer, [Sock]),
+ {streamcontent_from_pid, "text/plain", Pid}.
+
+streamer(Sock) ->
+ receive
+ {discard, YawsPid} ->
+ yaws_api:stream_process_end(Sock, YawsPid);
+ {ok, YawsPid} ->
+ yaws_api:stream_process_deliver_final_chunk(
+ Sock,
+ ["this", " is", <<" an">>, <<" iolist">>]
+ ),
+ yaws_api:stream_process_end(Sock, YawsPid)
+ end.
View
12 www/stream.yaws
@@ -62,18 +62,18 @@ out(A) ->
{p,[],"Pid can send data on the socket by calling:"},
- box(" yaws_api:stream_process_deliver(Socket, Bin)"),
+ box(" yaws_api:stream_process_deliver(Socket, IoList)"),
- {p,[],"where Bin is the binary data to be sent (all data must be sent as binaries). For chunked transfer, Pid must call:"},
+ {p,[],"where IoList is the data to be sent. For chunked transfer, Pid must call:"},
- box(" yaws_api:stream_process_deliver_chunk(Socket, Bin)"),
+ box(" yaws_api:stream_process_deliver_chunk(Socket, IoList)"),
- {p,[],"which tells yaws to use HTTP chunked transfer to send Bin. Applications using chunked transfer in this manner must always remember to end their data transfer by calling:"},
+ {p,[],"which tells yaws to use HTTP chunked transfer to send IoList. Applications using chunked transfer in this manner must always remember to end their data transfer by calling:"},
- box(" yaws_api:stream_process_deliver_final_chunk(Socket, Bin)"),
+ box(" yaws_api:stream_process_deliver_final_chunk(Socket, IoList)"),
- {p,[],"where Bin is a binary of length 0 or more. This creates the final HTTP chunk that the client uses to detect the end of the transfer."},
+ {p,[],"where IoList is an iolist of size 0 or more. This creates the final HTTP chunk that the client uses to detect the end of the transfer."},
{p,[],"When Pid finishes sending data, or when it receives a {discard, YawsPid} message, it must call:"},
Please sign in to comment.
Something went wrong with that request. Please try again.