You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2014/02/12 07:21:43 UTC

[11/50] [abbrv] mochiweb commit: updated refs/heads/import-master to 3a54dbf

Update MochiWeb in trunk to r97. Closes COUCHDB-255.

git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@747575 13f79535-47bb-0310-9956-ffa450edef68


Project: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/commit/728043dd
Tree: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/tree/728043dd
Diff: http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/diff/728043dd

Branch: refs/heads/import-master
Commit: 728043dd68aebea5194733b2e86a353b7c4284c2
Parents: 3b32683
Author: Christopher Lenz <cm...@apache.org>
Authored: Tue Feb 24 22:10:04 2009 +0000
Committer: Christopher Lenz <cm...@apache.org>
Committed: Tue Feb 24 22:10:04 2009 +0000

----------------------------------------------------------------------
 mochijson.erl        |   4 --
 mochijson2.erl       | 100 +++++++++++++++++++++++++++++++++++++++++++---
 mochiweb.app         |   5 ++-
 mochiweb_headers.erl |  10 ++++-
 mochiweb_html.erl    |  49 ++++++++++++++++++++++-
 mochiweb_http.erl    |  22 +++++++---
 mochiweb_util.erl    |   7 +++-
 7 files changed, 176 insertions(+), 21 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochijson.erl
----------------------------------------------------------------------
diff --git a/mochijson.erl b/mochijson.erl
index 0ce5b5e..0e887a9 100644
--- a/mochijson.erl
+++ b/mochijson.erl
@@ -478,10 +478,6 @@ test_one([{E, J} | Rest], N) ->
     true = equiv(E, decode(encode(E))),
     test_one(Rest, 1+N).
 
-e2j_test_vec(unicode) -> 
-    [
-     {"foo" ++ [500] ++ "bar", [$", $f, $o, $o, 500, $b, $a, $r, $"]}
-    ];
 e2j_test_vec(utf8) ->
     [
     {1, "1"},

http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochijson2.erl
----------------------------------------------------------------------
diff --git a/mochijson2.erl b/mochijson2.erl
index 9b59c7d..8bfd23c 100644
--- a/mochijson2.erl
+++ b/mochijson2.erl
@@ -132,13 +132,81 @@ json_encode_proplist(Props, State) ->
     lists:reverse([$\} | Acc1]).
 
 json_encode_string(A, _State) when is_atom(A) ->
-    json_encode_string_unicode(xmerl_ucs:from_utf8(atom_to_list(A)), [?Q]);
+    L = atom_to_list(A),
+    case json_string_is_safe(L) of
+        true ->
+            [?Q, L, ?Q];
+        false ->
+            json_encode_string_unicode(xmerl_ucs:from_utf8(L), [?Q])
+    end;
 json_encode_string(B, _State) when is_binary(B) ->
-    json_encode_string_unicode(xmerl_ucs:from_utf8(B), [?Q]);
+    case json_bin_is_safe(B) of
+        true ->
+            [?Q, B, ?Q];
+        false ->
+            json_encode_string_unicode(xmerl_ucs:from_utf8(B), [?Q])
+    end;
 json_encode_string(I, _State) when is_integer(I) ->
-    json_encode_string_unicode(integer_to_list(I), [?Q]);
+    [?Q, integer_to_list(I), ?Q];
 json_encode_string(L, _State) when is_list(L) ->
-    json_encode_string_unicode(L, [?Q]).
+    case json_string_is_safe(L) of
+        true ->
+            [?Q, L, ?Q];
+        false ->
+            json_encode_string_unicode(L, [?Q])
+    end.
+
+json_string_is_safe([]) ->
+    true;
+json_string_is_safe([C | Rest]) ->
+    case C of
+        ?Q ->
+            false;
+        $\\ ->
+            false;
+        $\b ->
+            false;
+        $\f ->
+            false;
+        $\n ->
+            false;
+        $\r ->
+            false;
+        $\t ->
+            false;
+        C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
+            false;
+        C when C < 16#7f ->
+            json_string_is_safe(Rest);
+        _ ->
+            false
+    end.
+
+json_bin_is_safe(<<>>) ->
+    true;
+json_bin_is_safe(<<C, Rest/binary>>) ->
+    case C of
+        ?Q ->
+            false;
+        $\\ ->
+            false;
+        $\b ->
+            false;
+        $\f ->
+            false;
+        $\n ->
+            false;
+        $\r ->
+            false;
+        $\t ->
+            false;
+        C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
+            false;
+        C when C < 16#7f ->
+            json_bin_is_safe(Rest);
+        _ ->
+            false
+    end.
 
 json_encode_string_unicode([], Acc) ->
     lists:reverse([$\" | Acc]);
@@ -260,8 +328,28 @@ decode_array(B, S=#decoder{state=comma}, Acc) ->
             decode_array(B, S1#decoder{state=any}, Acc)
     end.
 
-tokenize_string(B, S) ->
-    tokenize_string(B, S, []).
+tokenize_string(B, S=#decoder{offset=O}) ->
+    case tokenize_string_fast(B, O) of
+        {escape, O1} ->
+            Length = O1 - O,
+            S1 = ?ADV_COL(S, Length),
+            <<_:O/binary, Head:Length/binary, _/binary>> = B,
+            tokenize_string(B, S1, lists:reverse(binary_to_list(Head)));
+        O1 ->
+            Length = O1 - O,
+            <<_:O/binary, String:Length/binary, ?Q, _/binary>> = B,
+            {{const, String}, ?ADV_COL(S, Length + 1)}
+    end.
+
+tokenize_string_fast(B, O) ->
+    case B of
+        <<_:O/binary, ?Q, _/binary>> ->
+            O;
+        <<_:O/binary, C, _/binary>> when C =/= $\\ ->
+            tokenize_string_fast(B, 1 + O);
+        _ ->
+            {escape, O}
+    end.
 
 tokenize_string(B, S=#decoder{offset=O}, Acc) ->
     case B of

http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochiweb.app
----------------------------------------------------------------------
diff --git a/mochiweb.app b/mochiweb.app
index dea0898..cd8dbb2 100644
--- a/mochiweb.app
+++ b/mochiweb.app
@@ -21,7 +21,10 @@
         mochiweb_socket_server,
         mochiweb_sup,
         mochiweb_util,
-        reloader
+        reloader,
+        mochifmt,
+        mochifmt_std,
+        mochifmt_records
 	    ]},
   {registered, []},
   {mod, {mochiweb_app, []}},

http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochiweb_headers.erl
----------------------------------------------------------------------
diff --git a/mochiweb_headers.erl b/mochiweb_headers.erl
index 371df9f..4c0a2d7 100644
--- a/mochiweb_headers.erl
+++ b/mochiweb_headers.erl
@@ -6,7 +6,7 @@
 -module(mochiweb_headers).
 -author('bob@mochimedia.com').
 -export([empty/0, from_list/1, insert/3, enter/3, get_value/2, lookup/2]).
--export([get_primary_value/2]).
+-export([delete_any/2, get_primary_value/2]).
 -export([default/3, enter_from_list/2, default_from_list/2]).
 -export([to_list/1, make/1]).
 -export([test/0]).
@@ -35,6 +35,8 @@ test() ->
                         H3),
     "application/x-www-form-urlencoded" = ?MODULE:get_primary_value(
                                              "content-type", H4),
+    H4 = ?MODULE:delete_any("nonexistent-header", H4),
+    H3 = ?MODULE:delete_any("content-type", H4),
     ok.
 
 %% @spec empty() -> headers()
@@ -145,6 +147,12 @@ insert(K, V, T) ->
             gb_trees:update(K1, {K0, V2}, T)
     end.
 
+%% @spec delete_any(key(), headers()) -> headers()
+%% @doc Delete the header corresponding to key if it is present.
+delete_any(K, T) ->
+    K1 = normalize(K),
+    gb_trees:delete_any(K1, T).
+
 %% Internal API
 
 expand({array, L}) ->

http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochiweb_html.erl
----------------------------------------------------------------------
diff --git a/mochiweb_html.erl b/mochiweb_html.erl
index 5918168..d9a3cf2 100644
--- a/mochiweb_html.erl
+++ b/mochiweb_html.erl
@@ -129,7 +129,9 @@ escape_attr(F) when is_float(F) ->
 test() ->
     test_destack(),
     test_tokens(),
+    test_tokens2(),
     test_parse(),
+    test_parse2(),
     test_parse_tokens(),
     test_escape(),
     test_escape_attr(),
@@ -426,6 +428,34 @@ test_parse() ->
     Expect = parse(D0),
     ok.
 
+test_tokens2() ->
+    D0 = <<"<channel><title>from __future__ import *</title><link>http://bob.pythonmac.org</link><description>Bob's Rants</description></channel>">>,
+    Expect = [{start_tag,<<"channel">>,[],false},
+              {start_tag,<<"title">>,[],false},
+              {data,<<"from __future__ import *">>,false},
+              {end_tag,<<"title">>},
+              {start_tag,<<"link">>,[],true},
+              {data,<<"http://bob.pythonmac.org">>,false},
+              {end_tag,<<"link">>},
+              {start_tag,<<"description">>,[],false},
+              {data,<<"Bob's Rants">>,false},
+              {end_tag,<<"description">>},
+              {end_tag,<<"channel">>}],
+    Expect = tokens(D0),
+    ok.
+
+test_parse2() ->
+    D0 = <<"<channel><title>from __future__ import *</title><link>http://bob.pythonmac.org<br>foo</link><description>Bob's Rants</description></channel>">>,
+    Expect = {<<"channel">>,[],
+              [{<<"title">>,[],[<<"from __future__ import *">>]},
+               {<<"link">>,[],[
+                               <<"http://bob.pythonmac.org">>,
+                               {<<"br">>,[],[]},
+                               <<"foo">>]},
+               {<<"description">>,[],[<<"Bob's Rants">>]}]},
+    Expect = parse(D0),
+    ok.
+
 test_parse_tokens() ->
     D0 = [{doctype,[<<"HTML">>,<<"PUBLIC">>,<<"-//W3C//DTD HTML 4.01 Transitional//EN">>]},
           {data,<<"\n">>,true},
@@ -562,8 +592,23 @@ destack(TagName, Stack) when is_list(Stack) ->
         end,
     case lists:splitwith(F, Stack) of
         {_, []} ->
-            %% No match, no state change
-            Stack;
+            %% If we're parsing something like XML we might find
+            %% a <link>tag</link> that is normally a singleton
+            %% in HTML but isn't here
+            case {is_singleton(TagName), Stack} of
+                {true, [{T0, A0, Acc0} | Post0]} ->
+                    case lists:splitwith(F, Acc0) of
+                        {_, []} ->
+                            %% Actually was a singleton
+                            Stack;
+                        {Pre, [{T1, A1, []} | Post1]} ->
+                            [{T0, A0, [{T1, A1, lists:reverse(Pre)} | Post1]}
+                             | Post0]
+                    end;
+                _ ->
+                    %% No match, no state change
+                    Stack
+            end;
         {_Pre, [_T]} ->
             %% Unfurl the whole stack, we're done
             destack(Stack);

http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochiweb_http.erl
----------------------------------------------------------------------
diff --git a/mochiweb_http.erl b/mochiweb_http.erl
index 7bbe3c8..14a3657 100644
--- a/mochiweb_http.erl
+++ b/mochiweb_http.erl
@@ -10,6 +10,7 @@
 
 -define(IDLE_TIMEOUT, 30000).
 
+-define(MAX_HEADERS, 1000).
 -define(DEFAULTS, [{name, ?MODULE},
                    {port, 8888}]).
 
@@ -37,7 +38,7 @@ stop() ->
 
 stop(Name) ->
     mochiweb_socket_server:stop(Name).
-    
+
 start() ->
     start([{ip, "127.0.0.1"},
            {loop, {?MODULE, default_body}}]).
@@ -80,12 +81,12 @@ default_body(Req, 'POST', "/multipart") ->
                                    {body, Req:recv_body()},
                                    Req:dump()]]),
     Req:ok({"text/html", [], frm(Body)});
-default_body(Req, 'POST', _Path) ->    
+default_body(Req, 'POST', _Path) ->
     Body = io_lib:format("~p~n", [[{parse_qs, Req:parse_qs()},
                                    {parse_cookie, Req:parse_cookie()},
                                    {parse_post, Req:parse_post()},
                                    Req:dump()]]),
-    Req:ok({"text/html", [], frm(Body)});           
+    Req:ok({"text/html", [], frm(Body)});
 default_body(Req, _Method, _Path) ->
     Req:respond({501, [], []}).
 
@@ -99,7 +100,7 @@ loop(Socket, Body) ->
 request(Socket, Body) ->
     case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
         {ok, {http_request, Method, Path, Version}} ->
-            headers(Socket, {Method, Path, Version}, [], Body);
+            headers(Socket, {Method, Path, Version}, [], Body, 0);
         {error, {http_error, "\r\n"}} ->
             request(Socket, Body);
         {error, {http_error, "\n"}} ->
@@ -109,7 +110,15 @@ request(Socket, Body) ->
             exit(normal)
     end.
 
-headers(Socket, Request, Headers, Body) ->
+headers(Socket, Request, Headers, _Body, ?MAX_HEADERS) ->
+    %% Too many headers sent, bad request.
+    inet:setopts(Socket, [{packet, raw}]),
+    Req = mochiweb:new_request({Socket, Request,
+                                lists:reverse(Headers)}),
+    Req:respond({400, [], []}),
+    gen_tcp:close(Socket),
+    exit(normal);
+headers(Socket, Request, Headers, Body, HeaderCount) ->
     case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
         {ok, http_eoh} ->
             inet:setopts(Socket, [{packet, raw}]),
@@ -125,7 +134,8 @@ headers(Socket, Request, Headers, Body) ->
                     ?MODULE:loop(Socket, Body)
             end;
         {ok, {http_header, _, Name, _, Value}} ->
-            headers(Socket, Request, [{Name, Value} | Headers], Body);
+            headers(Socket, Request, [{Name, Value} | Headers], Body,
+                    1 + HeaderCount);
         _Other ->
             gen_tcp:close(Socket),
             exit(normal)

http://git-wip-us.apache.org/repos/asf/couchdb-mochiweb/blob/728043dd/mochiweb_util.erl
----------------------------------------------------------------------
diff --git a/mochiweb_util.erl b/mochiweb_util.erl
index 63d0b98..9a0675f 100644
--- a/mochiweb_util.erl
+++ b/mochiweb_util.erl
@@ -134,12 +134,16 @@ revjoin([S | Rest], Separator, []) ->
 revjoin([S | Rest], Separator, Acc) ->
     revjoin(Rest, Separator, [S, Separator | Acc]).
 
-%% @spec quote_plus(atom() | integer() | string()) -> string()
+%% @spec quote_plus(atom() | integer() | float() | string() | binary()) -> string()
 %% @doc URL safe encoding of the given term.
 quote_plus(Atom) when is_atom(Atom) ->
     quote_plus(atom_to_list(Atom));
 quote_plus(Int) when is_integer(Int) ->
     quote_plus(integer_to_list(Int));
+quote_plus(Binary) when is_binary(Binary) ->
+    quote_plus(binary_to_list(Binary));
+quote_plus(Float) when is_float(Float) ->
+    quote_plus(mochinum:digits(Float));
 quote_plus(String) ->
     quote_plus(String, []).
 
@@ -542,6 +546,7 @@ test_join() ->
 test_quote_plus() ->
     "foo" = quote_plus(foo),
     "1" = quote_plus(1),
+    "1.1" = quote_plus(1.1),
     "foo" = quote_plus("foo"),
     "foo+bar" = quote_plus("foo bar"),
     "foo%0A" = quote_plus("foo\n"),