31
32
-define(SAVE_COOKIE, mochiweb_request_cookie).
32
33
-define(SAVE_FORCE_CLOSE, mochiweb_request_force_close).
34
%% @type iolist() = [iolist() | binary() | char()].
35
%% @type iodata() = binary() | iolist().
36
35
%% @type key() = atom() | string() | binary()
37
36
%% @type value() = atom() | string() | binary() | integer()
38
37
%% @type headers(). A mochiweb_headers structure.
39
38
%% @type response(). A mochiweb_response parameterized module instance.
40
39
%% @type ioheaders() = headers() | [{key(), value()}].
42
% 10 second default idle timeout
43
-define(IDLE_TIMEOUT, 10000).
41
% 5 minute default idle timeout
42
-define(IDLE_TIMEOUT, 300000).
45
44
% Maximum recv_body() length of 1MB
46
45
-define(MAX_RECV_BODY, 104857600).
498
494
%% @spec read_chunk_length() -> integer()
499
495
%% @doc Read the length of the next HTTP chunk.
500
496
read_chunk_length() ->
501
mochiweb_socket:setopts(Socket, [{packet, line}]),
497
ok = mochiweb_socket:setopts(Socket, [{packet, line}]),
502
498
case mochiweb_socket:recv(Socket, 0, ?IDLE_TIMEOUT) of
504
mochiweb_socket:setopts(Socket, [{packet, raw}]),
500
ok = mochiweb_socket:setopts(Socket, [{packet, raw}]),
505
501
Splitter = fun (C) ->
506
502
C =/= $\r andalso C =/= $\n andalso C =/= $
706
%% @spec accepts_content_type(string() | binary()) -> boolean() | bad_accept_header
708
%% @doc Determines whether a request accepts a given media type by analyzing its
713
%% 1) For a missing "Accept" header:
714
%% accepts_content_type("application/json") -> true
716
%% 2) For an "Accept" header with value "text/plain, application/*":
717
%% accepts_content_type("application/json") -> true
719
%% 3) For an "Accept" header with value "text/plain, */*; q=0.0":
720
%% accepts_content_type("application/json") -> false
722
%% 4) For an "Accept" header with value "text/plain; q=0.5, */*; q=0.1":
723
%% accepts_content_type("application/json") -> true
725
%% 5) For an "Accept" header with value "text/*; q=0.0, */*":
726
%% accepts_content_type("text/plain") -> false
728
accepts_content_type(ContentType1) ->
729
ContentType = re:replace(ContentType1, "\\s", "", [global, {return, list}]),
730
AcceptHeader = accept_header(),
731
case mochiweb_util:parse_qvalues(AcceptHeader) of
732
invalid_qvalue_string ->
735
[MainType, _SubType] = string:tokens(ContentType, "/"),
736
SuperType = MainType ++ "/*",
738
fun({"*/*", Q}) when Q > 0.0 ->
740
({Type, Q}) when Q > 0.0 ->
741
Type =:= ContentType orelse Type =:= SuperType;
747
(not lists:member({ContentType, 0.0}, QList)) andalso
748
(not lists:member({SuperType, 0.0}, QList))
751
%% @spec accepted_content_types([string() | binary()]) -> [string()] | bad_accept_header
753
%% @doc Filters which of the given media types this request accepts. This filtering
754
%% is performed by analyzing the "Accept" header. The returned list is sorted
755
%% according to the preferences specified in the "Accept" header (higher Q values
756
%% first). If two or more types have the same preference (Q value), they're order
757
%% in the returned list is the same as they're order in the input list.
761
%% 1) For a missing "Accept" header:
762
%% accepted_content_types(["text/html", "application/json"]) ->
763
%% ["text/html", "application/json"]
765
%% 2) For an "Accept" header with value "text/html, application/*":
766
%% accepted_content_types(["application/json", "text/html"]) ->
767
%% ["application/json", "text/html"]
769
%% 3) For an "Accept" header with value "text/html, */*; q=0.0":
770
%% accepted_content_types(["text/html", "application/json"]) ->
773
%% 4) For an "Accept" header with value "text/html; q=0.5, */*; q=0.1":
774
%% accepts_content_types(["application/json", "text/html"]) ->
775
%% ["text/html", "application/json"]
777
accepted_content_types(Types1) ->
779
fun(T) -> re:replace(T, "\\s", "", [global, {return, list}]) end,
781
AcceptHeader = accept_header(),
782
case mochiweb_util:parse_qvalues(AcceptHeader) of
783
invalid_qvalue_string ->
786
TypesQ = lists:foldr(
788
case proplists:get_value(T, QList) of
790
[MainType, _SubType] = string:tokens(T, "/"),
791
case proplists:get_value(MainType ++ "/*", QList) of
793
case proplists:get_value("*/*", QList) of
794
Q when is_float(Q), Q > 0.0 ->
811
% Note: Stable sort. If 2 types have the same Q value we leave them in the
812
% same order as in the input list.
813
SortFun = fun({Q1, _}, {Q2, _}) -> Q1 >= Q2 end,
814
[Type || {_Q, Type} <- lists:sort(SortFun, TypesQ)]
818
case get_header_value("Accept") of