Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

219 rindas
8.3 KiB

pirms 14 gadiem
pirms 14 gadiem
pirms 14 gadiem
pirms 14 gadiem
pirms 14 gadiem
pirms 13 gadiem
pirms 14 gadiem
pirms 13 gadiem
pirms 14 gadiem
pirms 14 gadiem
pirms 13 gadiem
pirms 13 gadiem
pirms 13 gadiem
pirms 14 gadiem
pirms 14 gadiem
  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. server_proc_name(Port) ! stop,
  34. ok.
  35. server_proc_name(Port) ->
  36. list_to_atom("ibrowse_test_server_"++integer_to_list(Port)).
  37. do_listen(tcp, Port, Opts) ->
  38. gen_tcp:listen(Port, Opts);
  39. do_listen(ssl, Port, Opts) ->
  40. application:start(crypto),
  41. application:start(ssl),
  42. ssl:listen(Port, Opts).
  43. do_accept(tcp, Listen_sock) ->
  44. gen_tcp:accept(Listen_sock);
  45. do_accept(ssl, Listen_sock) ->
  46. ssl:ssl_accept(Listen_sock).
  47. accept_loop(Sock, Sock_type) ->
  48. case do_accept(Sock_type, Sock) of
  49. {ok, Conn} ->
  50. Pid = spawn_link(
  51. fun() ->
  52. server_loop(Conn, Sock_type, #request{})
  53. end),
  54. set_controlling_process(Conn, Sock_type, Pid),
  55. Pid ! {setopts, [{active, true}]},
  56. accept_loop(Sock, Sock_type);
  57. Err ->
  58. Err
  59. end.
  60. set_controlling_process(Sock, tcp, Pid) ->
  61. gen_tcp:controlling_process(Sock, Pid);
  62. set_controlling_process(Sock, ssl, Pid) ->
  63. ssl:controlling_process(Sock, Pid).
  64. setopts(Sock, tcp, Opts) ->
  65. inet:setopts(Sock, Opts);
  66. setopts(Sock, ssl, Opts) ->
  67. ssl:setopts(Sock, Opts).
  68. server_loop(Sock, Sock_type, #request{headers = Headers} = Req) ->
  69. receive
  70. {http, Sock, {http_request, HttpMethod, HttpUri, HttpVersion}} ->
  71. server_loop(Sock, Sock_type, Req#request{method = HttpMethod,
  72. uri = HttpUri,
  73. version = HttpVersion});
  74. {http, Sock, {http_header, _, _, _, _} = H} ->
  75. server_loop(Sock, Sock_type, Req#request{headers = [H | Headers]});
  76. {http, Sock, http_eoh} ->
  77. process_request(Sock, Sock_type, Req),
  78. server_loop(Sock, Sock_type, #request{});
  79. {http, Sock, {http_error, Err}} ->
  80. do_trace("Error parsing HTTP request:~n"
  81. "Req so far : ~p~n"
  82. "Err : ", [Req, Err]),
  83. exit({http_error, Err});
  84. {setopts, Opts} ->
  85. setopts(Sock, Sock_type, Opts),
  86. server_loop(Sock, Sock_type, Req);
  87. {tcp_closed, Sock} ->
  88. do_trace("Client closed connection~n", []),
  89. ok;
  90. stop ->
  91. ok;
  92. Other ->
  93. do_trace("Recvd unknown msg: ~p~n", [Other]),
  94. exit({unknown_msg, Other})
  95. after 5000 ->
  96. do_trace("Timing out client connection~n", []),
  97. ok
  98. end.
  99. do_trace(Fmt, Args) ->
  100. do_trace(get(my_trace_flag), Fmt, Args).
  101. do_trace(true, Fmt, Args) ->
  102. io:format("~s -- " ++ Fmt, [ibrowse_lib:printable_date() | Args]);
  103. do_trace(_, _, _) ->
  104. ok.
  105. process_request(Sock, Sock_type,
  106. #request{method='GET',
  107. headers = Headers,
  108. uri = {abs_path, "/ibrowse_stream_once_chunk_pipeline_test"}} = Req) ->
  109. Req_id = case lists:keysearch("X-Ibrowse-Request-Id", 3, Headers) of
  110. false ->
  111. "";
  112. {value, {http_header, _, _, _, Req_id_1}} ->
  113. Req_id_1
  114. end,
  115. Req_id_header = ["x-ibrowse-request-id: ", Req_id, "\r\n"],
  116. do_trace("Recvd req: ~p~n", [Req]),
  117. Body = string:join([integer_to_list(X) || X <- lists:seq(1,100)], "-"),
  118. Chunked_body = chunk_request_body(Body, 50),
  119. Resp_1 = [<<"HTTP/1.1 200 OK\r\n">>,
  120. Req_id_header,
  121. <<"Transfer-Encoding: chunked\r\n\r\n">>],
  122. Resp_2 = Chunked_body,
  123. do_send(Sock, Sock_type, Resp_1),
  124. timer:sleep(100),
  125. do_send(Sock, Sock_type, Resp_2);
  126. process_request(Sock, Sock_type,
  127. #request{method='GET',
  128. headers = _Headers,
  129. uri = {abs_path, "/ibrowse_inac_timeout_test"}} = Req) ->
  130. do_trace("Recvd req: ~p. Sleeping for 30 secs...~n", [Req]),
  131. timer:sleep(30000),
  132. do_trace("...Sending response now.~n", []),
  133. Resp = <<"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n">>,
  134. do_send(Sock, Sock_type, Resp);
  135. process_request(Sock, Sock_type,
  136. #request{method='HEAD',
  137. headers = _Headers,
  138. uri = {abs_path, "/ibrowse_head_transfer_enc"}}) ->
  139. Resp = <<"HTTP/1.1 400 Bad Request\r\nServer: Apache-Coyote/1.1\r\nContent-Length:5\r\nDate: Wed, 04 Apr 2012 16:53:49 GMT\r\n\r\nabcde">>,
  140. do_send(Sock, Sock_type, Resp);
  141. process_request(Sock, Sock_type,
  142. #request{method='HEAD',
  143. headers = _Headers,
  144. uri = {abs_path, "/ibrowse_head_test"}}) ->
  145. Resp = <<"HTTP/1.1 200 OK\r\nServer: Apache-Coyote/1.1\r\nTransfer-Encoding: chunked\r\nDate: Wed, 04 Apr 2012 16:53:49 GMT\r\nConnection: close\r\n\r\n">>,
  146. do_send(Sock, Sock_type, Resp);
  147. process_request(Sock, Sock_type, Req) ->
  148. do_trace("Recvd req: ~p~n", [Req]),
  149. Resp = <<"HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n">>,
  150. do_send(Sock, Sock_type, Resp).
  151. do_send(Sock, tcp, Resp) ->
  152. gen_tcp:send(Sock, Resp);
  153. do_send(Sock, ssl, Resp) ->
  154. ssl:send(Sock, Resp).
  155. %%------------------------------------------------------------------------------
  156. %% Utility functions
  157. %%------------------------------------------------------------------------------
  158. chunk_request_body(Body, _ChunkSize) when is_tuple(Body) orelse
  159. is_function(Body) ->
  160. Body;
  161. chunk_request_body(Body, ChunkSize) ->
  162. chunk_request_body(Body, ChunkSize, []).
  163. chunk_request_body(Body, _ChunkSize, Acc) when Body == <<>>; Body == [] ->
  164. LastChunk = "0\r\n",
  165. lists:reverse(["\r\n", LastChunk | Acc]);
  166. chunk_request_body(Body, ChunkSize, Acc) when is_binary(Body),
  167. size(Body) >= ChunkSize ->
  168. <<ChunkBody:ChunkSize/binary, Rest/binary>> = Body,
  169. Chunk = [?dec2hex(ChunkSize),"\r\n",
  170. ChunkBody, "\r\n"],
  171. chunk_request_body(Rest, ChunkSize, [Chunk | Acc]);
  172. chunk_request_body(Body, _ChunkSize, Acc) when is_binary(Body) ->
  173. BodySize = size(Body),
  174. Chunk = [?dec2hex(BodySize),"\r\n",
  175. Body, "\r\n"],
  176. LastChunk = "0\r\n",
  177. lists:reverse(["\r\n", LastChunk, Chunk | Acc]);
  178. chunk_request_body(Body, ChunkSize, Acc) when length(Body) >= ChunkSize ->
  179. {ChunkBody, Rest} = split_list_at(Body, ChunkSize),
  180. Chunk = [?dec2hex(ChunkSize),"\r\n",
  181. ChunkBody, "\r\n"],
  182. chunk_request_body(Rest, ChunkSize, [Chunk | Acc]);
  183. chunk_request_body(Body, _ChunkSize, Acc) when is_list(Body) ->
  184. BodySize = length(Body),
  185. Chunk = [?dec2hex(BodySize),"\r\n",
  186. Body, "\r\n"],
  187. LastChunk = "0\r\n",
  188. lists:reverse(["\r\n", LastChunk, Chunk | Acc]).
  189. split_list_at(List, N) ->
  190. split_list_at(List, N, []).
  191. split_list_at([], _, Acc) ->
  192. {lists:reverse(Acc), []};
  193. split_list_at(List2, 0, List1) ->
  194. {lists:reverse(List1), List2};
  195. split_list_at([H | List2], N, List1) ->
  196. split_list_at(List2, N-1, [H | List1]).