25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

191 satır
6.9 KiB

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