No puede seleccionar más de 25 temas Los temas deben comenzar con una letra o número, pueden incluir guiones ('-') y pueden tener hasta 35 caracteres de largo.

195 líneas
7.1 KiB

hace 14 años
hace 14 años
hace 14 años
hace 14 años
hace 14 años
hace 14 años
hace 14 años
hace 14 años
  1. %%% File : ibrowse_test_server.erl
  2. %%% Author : Chandrashekhar Mullaparthi <chandrashekhar.mullaparthi@t-mobile.co.uk>
  3. %%% Description : A server to simulate various test scenarios
  4. %%% Created : 17 Oct 2010 by Chandrashekhar Mullaparthi <chandrashekhar.mullaparthi@t-mobile.co.uk>
  5. -module(ibrowse_test_server).
  6. -export([
  7. start_server/2,
  8. stop_server/1
  9. ]).
  10. -record(request, {method, uri, version, headers = [], body = []}).
  11. -define(dec2hex(X), erlang:integer_to_list(X, 16)).
  12. start_server(Port, Sock_type) ->
  13. Fun = fun() ->
  14. register(server_proc_name(Port), self()),
  15. case do_listen(Sock_type, Port, [{active, false},
  16. {reuseaddr, true},
  17. {nodelay, true},
  18. {packet, http}]) of
  19. {ok, Sock} ->
  20. do_trace("Server listening on port: ~p~n", [Port]),
  21. accept_loop(Sock, Sock_type);
  22. Err ->
  23. erlang:error(
  24. lists:flatten(
  25. io_lib:format(
  26. "Failed to start server on port ~p. ~p~n",
  27. [Port, Err]))),
  28. exit({listen_error, Err})
  29. end
  30. end,
  31. spawn_link(Fun).
  32. stop_server(Port) ->
  33. exit(whereis(server_proc_name(Port)), kill).
  34. server_proc_name(Port) ->
  35. list_to_atom("ibrowse_test_server_"++integer_to_list(Port)).
  36. do_listen(tcp, Port, Opts) ->
  37. gen_tcp:listen(Port, Opts);
  38. do_listen(ssl, Port, Opts) ->
  39. application:start(crypto),
  40. application:start(ssl),
  41. ssl:listen(Port, Opts).
  42. do_accept(tcp, Listen_sock) ->
  43. gen_tcp:accept(Listen_sock);
  44. do_accept(ssl, Listen_sock) ->
  45. ssl:ssl_accept(Listen_sock).
  46. accept_loop(Sock, Sock_type) ->
  47. case do_accept(Sock_type, Sock) of
  48. {ok, Conn} ->
  49. Pid = spawn_link(
  50. fun() ->
  51. server_loop(Conn, Sock_type, #request{})
  52. end),
  53. set_controlling_process(Conn, Sock_type, Pid),
  54. Pid ! {setopts, [{active, true}]},
  55. accept_loop(Sock, Sock_type);
  56. Err ->
  57. Err
  58. end.
  59. set_controlling_process(Sock, tcp, Pid) ->
  60. gen_tcp:controlling_process(Sock, Pid);
  61. set_controlling_process(Sock, ssl, Pid) ->
  62. ssl:controlling_process(Sock, Pid).
  63. setopts(Sock, tcp, Opts) ->
  64. inet:setopts(Sock, Opts);
  65. setopts(Sock, ssl, Opts) ->
  66. ssl:setopts(Sock, Opts).
  67. server_loop(Sock, Sock_type, #request{headers = Headers} = Req) ->
  68. receive
  69. {http, Sock, {http_request, HttpMethod, HttpUri, HttpVersion}} ->
  70. server_loop(Sock, Sock_type, Req#request{method = HttpMethod,
  71. uri = HttpUri,
  72. version = HttpVersion});
  73. {http, Sock, {http_header, _, _, _, _} = H} ->
  74. server_loop(Sock, Sock_type, Req#request{headers = [H | Headers]});
  75. {http, Sock, http_eoh} ->
  76. process_request(Sock, Sock_type, Req),
  77. server_loop(Sock, Sock_type, #request{});
  78. {http, Sock, {http_error, Err}} ->
  79. do_trace("Error parsing HTTP request:~n"
  80. "Req so far : ~p~n"
  81. "Err : ", [Req, Err]),
  82. exit({http_error, Err});
  83. {setopts, Opts} ->
  84. setopts(Sock, Sock_type, Opts),
  85. server_loop(Sock, Sock_type, Req);
  86. {tcp_closed, Sock} ->
  87. do_trace("Client closed connection~n", []),
  88. ok;
  89. Other ->
  90. do_trace("Recvd unknown msg: ~p~n", [Other]),
  91. exit({unknown_msg, Other})
  92. after 5000 ->
  93. do_trace("Timing out client connection~n", []),
  94. ok
  95. end.
  96. do_trace(Fmt, Args) ->
  97. do_trace(get(my_trace_flag), Fmt, Args).
  98. do_trace(true, Fmt, Args) ->
  99. io:format("~s -- " ++ Fmt, [ibrowse_lib:printable_date() | Args]);
  100. do_trace(_, _, _) ->
  101. ok.
  102. process_request(Sock, Sock_type,
  103. #request{method='GET',
  104. headers = Headers,
  105. uri = {abs_path, "/ibrowse_stream_once_chunk_pipeline_test"}} = Req) ->
  106. Req_id = case lists:keysearch("X-Ibrowse-Request-Id", 3, Headers) of
  107. false ->
  108. "";
  109. {value, {http_header, _, _, _, Req_id_1}} ->
  110. Req_id_1
  111. end,
  112. Req_id_header = ["x-ibrowse-request-id: ", Req_id, "\r\n"],
  113. do_trace("Recvd req: ~p~n", [Req]),
  114. Body = string:join([integer_to_list(X) || X <- lists:seq(1,100)], "-"),
  115. Chunked_body = chunk_request_body(Body, 50),
  116. Resp_1 = [<<"HTTP/1.1 200 OK\r\n">>,
  117. Req_id_header,
  118. <<"Transfer-Encoding: chunked\r\n\r\n">>],
  119. Resp_2 = Chunked_body,
  120. do_send(Sock, Sock_type, Resp_1),
  121. timer:sleep(100),
  122. do_send(Sock, Sock_type, Resp_2);
  123. process_request(Sock, Sock_type, Req) ->
  124. do_trace("Recvd req: ~p~n", [Req]),
  125. Resp = <<"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n">>,
  126. do_send(Sock, Sock_type, Resp).
  127. do_send(Sock, tcp, Resp) ->
  128. ok = gen_tcp:send(Sock, Resp);
  129. do_send(Sock, ssl, Resp) ->
  130. ok = ssl:send(Sock, Resp).
  131. %%------------------------------------------------------------------------------
  132. %% Utility functions
  133. %%------------------------------------------------------------------------------
  134. chunk_request_body(Body, _ChunkSize) when is_tuple(Body) orelse
  135. is_function(Body) ->
  136. Body;
  137. chunk_request_body(Body, ChunkSize) ->
  138. chunk_request_body(Body, ChunkSize, []).
  139. chunk_request_body(Body, _ChunkSize, Acc) when Body == <<>>; Body == [] ->
  140. LastChunk = "0\r\n",
  141. lists:reverse(["\r\n", LastChunk | Acc]);
  142. chunk_request_body(Body, ChunkSize, Acc) when is_binary(Body),
  143. size(Body) >= ChunkSize ->
  144. <<ChunkBody:ChunkSize/binary, Rest/binary>> = Body,
  145. Chunk = [?dec2hex(ChunkSize),"\r\n",
  146. ChunkBody, "\r\n"],
  147. chunk_request_body(Rest, ChunkSize, [Chunk | Acc]);
  148. chunk_request_body(Body, _ChunkSize, Acc) when is_binary(Body) ->
  149. BodySize = size(Body),
  150. Chunk = [?dec2hex(BodySize),"\r\n",
  151. Body, "\r\n"],
  152. LastChunk = "0\r\n",
  153. lists:reverse(["\r\n", LastChunk, Chunk | Acc]);
  154. chunk_request_body(Body, ChunkSize, Acc) when length(Body) >= ChunkSize ->
  155. {ChunkBody, Rest} = split_list_at(Body, ChunkSize),
  156. Chunk = [?dec2hex(ChunkSize),"\r\n",
  157. ChunkBody, "\r\n"],
  158. chunk_request_body(Rest, ChunkSize, [Chunk | Acc]);
  159. chunk_request_body(Body, _ChunkSize, Acc) when is_list(Body) ->
  160. BodySize = length(Body),
  161. Chunk = [?dec2hex(BodySize),"\r\n",
  162. Body, "\r\n"],
  163. LastChunk = "0\r\n",
  164. lists:reverse(["\r\n", LastChunk, Chunk | Acc]).
  165. split_list_at(List, N) ->
  166. split_list_at(List, N, []).
  167. split_list_at([], _, Acc) ->
  168. {lists:reverse(Acc), []};
  169. split_list_at(List2, 0, List1) ->
  170. {lists:reverse(List1), List2};
  171. split_list_at([H | List2], N, List1) ->
  172. split_list_at(List2, N-1, [H | List1]).