PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/deps/mochiweb-r88/src/mochiweb_http.erl

http://github.com/tonyg/reversehttp
Erlang | 132 lines | 112 code | 17 blank | 3 comment | 0 complexity | aa6c8ceda64ce2058cf59bd937390299 MD5 | raw file
Possible License(s): MIT
  1. %% @author Bob Ippolito <bob@mochimedia.com>
  2. %% @copyright 2007 Mochi Media, Inc.
  3. %% @doc HTTP server.
  4. -module(mochiweb_http).
  5. -author('bob@mochimedia.com').
  6. -export([start/0, start/1, stop/0, stop/1]).
  7. -export([loop/2, default_body/1]).
  8. -define(IDLE_TIMEOUT, 30000).
  9. -define(DEFAULTS, [{name, ?MODULE},
  10. {port, 8888}]).
  11. set_default({Prop, Value}, PropList) ->
  12. case proplists:is_defined(Prop, PropList) of
  13. true ->
  14. PropList;
  15. false ->
  16. [{Prop, Value} | PropList]
  17. end.
  18. set_defaults(Defaults, PropList) ->
  19. lists:foldl(fun set_default/2, PropList, Defaults).
  20. parse_options(Options) ->
  21. {loop, HttpLoop} = proplists:lookup(loop, Options),
  22. Loop = fun (S) ->
  23. ?MODULE:loop(S, HttpLoop)
  24. end,
  25. Options1 = [{loop, Loop} | proplists:delete(loop, Options)],
  26. set_defaults(?DEFAULTS, Options1).
  27. stop() ->
  28. mochiweb_socket_server:stop(?MODULE).
  29. stop(Name) ->
  30. mochiweb_socket_server:stop(Name).
  31. start() ->
  32. start([{ip, "127.0.0.1"},
  33. {loop, {?MODULE, default_body}}]).
  34. start(Options) ->
  35. mochiweb_socket_server:start(parse_options(Options)).
  36. frm(Body) ->
  37. ["<html><head></head><body>"
  38. "<form method=\"POST\">"
  39. "<input type=\"hidden\" value=\"message\" name=\"hidden\"/>"
  40. "<input type=\"submit\" value=\"regular POST\">"
  41. "</form>"
  42. "<br />"
  43. "<form method=\"POST\" enctype=\"multipart/form-data\""
  44. " action=\"/multipart\">"
  45. "<input type=\"hidden\" value=\"multipart message\" name=\"hidden\"/>"
  46. "<input type=\"file\" name=\"file\"/>"
  47. "<input type=\"submit\" value=\"multipart POST\" />"
  48. "</form>"
  49. "<pre>", Body, "</pre>"
  50. "</body></html>"].
  51. default_body(Req, M, "/chunked") when M =:= 'GET'; M =:= 'HEAD' ->
  52. Res = Req:ok({"text/plain", [], chunked}),
  53. Res:write_chunk("First chunk\r\n"),
  54. timer:sleep(5000),
  55. Res:write_chunk("Last chunk\r\n"),
  56. Res:write_chunk("");
  57. default_body(Req, M, _Path) when M =:= 'GET'; M =:= 'HEAD' ->
  58. Body = io_lib:format("~p~n", [[{parse_qs, Req:parse_qs()},
  59. {parse_cookie, Req:parse_cookie()},
  60. Req:dump()]]),
  61. Req:ok({"text/html",
  62. [mochiweb_cookies:cookie("mochiweb_http", "test_cookie")],
  63. frm(Body)});
  64. default_body(Req, 'POST', "/multipart") ->
  65. Body = io_lib:format("~p~n", [[{parse_qs, Req:parse_qs()},
  66. {parse_cookie, Req:parse_cookie()},
  67. {body, Req:recv_body()},
  68. Req:dump()]]),
  69. Req:ok({"text/html", [], frm(Body)});
  70. default_body(Req, 'POST', _Path) ->
  71. Body = io_lib:format("~p~n", [[{parse_qs, Req:parse_qs()},
  72. {parse_cookie, Req:parse_cookie()},
  73. {parse_post, Req:parse_post()},
  74. Req:dump()]]),
  75. Req:ok({"text/html", [], frm(Body)});
  76. default_body(Req, _Method, _Path) ->
  77. Req:respond({501, [], []}).
  78. default_body(Req) ->
  79. default_body(Req, Req:get(method), Req:get(path)).
  80. loop(Socket, Body) ->
  81. inet:setopts(Socket, [{packet, http}]),
  82. request(Socket, Body).
  83. request(Socket, Body) ->
  84. case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
  85. {ok, {http_request, Method, Path, Version}} ->
  86. headers(Socket, {Method, Path, Version}, [], Body);
  87. {error, {http_error, "\r\n"}} ->
  88. request(Socket, Body);
  89. {error, {http_error, "\n"}} ->
  90. request(Socket, Body);
  91. _Other ->
  92. gen_tcp:close(Socket),
  93. exit(normal)
  94. end.
  95. headers(Socket, Request, Headers, Body) ->
  96. case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
  97. {ok, http_eoh} ->
  98. inet:setopts(Socket, [{packet, raw}]),
  99. Req = mochiweb:new_request({Socket, Request,
  100. lists:reverse(Headers)}),
  101. Body(Req),
  102. case Req:should_close() of
  103. true ->
  104. gen_tcp:close(Socket),
  105. exit(normal);
  106. false ->
  107. Req:cleanup(),
  108. ?MODULE:loop(Socket, Body)
  109. end;
  110. {ok, {http_header, _, Name, _, Value}} ->
  111. headers(Socket, Request, [{Name, Value} | Headers], Body);
  112. _Other ->
  113. gen_tcp:close(Socket),
  114. exit(normal)
  115. end.