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

svn commit: r747541 - in /couchdb/vendor/mochiweb/current: ./ src/ support/

Author: cmlenz
Date: Tue Feb 24 20:56:11 2009
New Revision: 747541

URL: http://svn.apache.org/viewvc?rev=747541&view=rev
Log:
Updated MochiWeb vendor branch to r96 from <http://mochiweb.googlecode.com/svn/trunk/>.

Modified:
    couchdb/vendor/mochiweb/current/Makefile
    couchdb/vendor/mochiweb/current/src/Makefile
    couchdb/vendor/mochiweb/current/src/mochijson.erl
    couchdb/vendor/mochiweb/current/src/mochijson2.erl
    couchdb/vendor/mochiweb/current/src/mochiweb.app
    couchdb/vendor/mochiweb/current/src/mochiweb_headers.erl
    couchdb/vendor/mochiweb/current/src/mochiweb_html.erl
    couchdb/vendor/mochiweb/current/src/mochiweb_http.erl
    couchdb/vendor/mochiweb/current/src/mochiweb_request.erl
    couchdb/vendor/mochiweb/current/src/mochiweb_response.erl
    couchdb/vendor/mochiweb/current/src/mochiweb_util.erl
    couchdb/vendor/mochiweb/current/support/include.mk

Modified: couchdb/vendor/mochiweb/current/Makefile
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/Makefile?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/Makefile (original)
+++ couchdb/vendor/mochiweb/current/Makefile Tue Feb 24 20:56:11 2009
@@ -1,5 +1,8 @@
 all:
-	(cd src;$(MAKE))
+	(cd src;$(MAKE) all)
+
+edoc:
+	(cd src;$(MAKE) edoc)
 
 test:
 	(cd src;$(MAKE) test)

Modified: couchdb/vendor/mochiweb/current/src/Makefile
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/Makefile?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/Makefile (original)
+++ couchdb/vendor/mochiweb/current/src/Makefile Tue Feb 24 20:56:11 2009
@@ -1,5 +1,8 @@
 include ../support/include.mk
 
+APPLICATION=mochiweb
+DOC_OPTS={dir,\"../doc\"}
+
 all: $(EBIN_FILES)
 
 debug:
@@ -8,5 +11,10 @@
 clean:
 	rm -rf $(EBIN_FILES)
 
+edoc:
+	$(ERL) -noshell -pa ../ebin \
+		-eval "edoc:application($(APPLICATION), \".\", [$(DOC_OPTS)])" \
+		-s init stop
+
 test: all
-	$(ERL) -noshell -pa ../ebin -s mochiweb test -s init stop
+	$(ERL) -noshell -pa ../ebin -s $(APPLICATION) test -s init stop

Modified: couchdb/vendor/mochiweb/current/src/mochijson.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochijson.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochijson.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochijson.erl Tue Feb 24 20:56:11 2009
@@ -478,10 +478,6 @@
     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"},

Modified: couchdb/vendor/mochiweb/current/src/mochijson2.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochijson2.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochijson2.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochijson2.erl Tue Feb 24 20:56:11 2009
@@ -132,13 +132,81 @@
     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, 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

Modified: couchdb/vendor/mochiweb/current/src/mochiweb.app
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb.app?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb.app (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb.app Tue Feb 24 20:56:11 2009
@@ -21,7 +21,10 @@
         mochiweb_socket_server,
         mochiweb_sup,
         mochiweb_util,
-        reloader
+        reloader,
+        mochifmt,
+        mochifmt_std,
+        mochifmt_records
 	    ]},
   {registered, []},
   {mod, {mochiweb_app, []}},

Modified: couchdb/vendor/mochiweb/current/src/mochiweb_headers.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb_headers.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb_headers.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb_headers.erl Tue Feb 24 20:56:11 2009
@@ -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 @@
                         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 @@
             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}) ->

Modified: couchdb/vendor/mochiweb/current/src/mochiweb_html.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb_html.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb_html.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb_html.erl Tue Feb 24 20:56:11 2009
@@ -129,7 +129,9 @@
 test() ->
     test_destack(),
     test_tokens(),
+    test_tokens2(),
     test_parse(),
+    test_parse2(),
     test_parse_tokens(),
     test_escape(),
     test_escape_attr(),
@@ -426,6 +428,34 @@
     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 @@
         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);

Modified: couchdb/vendor/mochiweb/current/src/mochiweb_http.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb_http.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb_http.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb_http.erl Tue Feb 24 20:56:11 2009
@@ -10,6 +10,7 @@
 
 -define(IDLE_TIMEOUT, 30000).
 
+-define(MAX_HEADERS, 1000).
 -define(DEFAULTS, [{name, ?MODULE},
                    {port, 8888}]).
 
@@ -37,7 +38,7 @@
 
 stop(Name) ->
     mochiweb_socket_server:stop(Name).
-    
+
 start() ->
     start([{ip, "127.0.0.1"},
            {loop, {?MODULE, default_body}}]).
@@ -80,12 +81,12 @@
                                    {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 @@
 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 @@
             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 @@
                     ?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)

Modified: couchdb/vendor/mochiweb/current/src/mochiweb_request.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb_request.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb_request.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb_request.erl Tue Feb 24 20:56:11 2009
@@ -12,7 +12,7 @@
 -define(READ_SIZE, 8192).
 
 -export([get_header_value/1, get_primary_header_value/1, get/1, dump/0]).
--export([send/1, recv/1, recv/2, recv_body/0, recv_body/1]).
+-export([send/1, recv/1, recv/2, recv_body/0, recv_body/1, stream_body/3]).
 -export([start_response/1, start_response_length/1, start_raw_response/1]).
 -export([respond/1, ok/1]).
 -export([not_found/0, not_found/1]).
@@ -171,28 +171,54 @@
 %% @doc Receive the body of the HTTP request (defined by Content-Length).
 %%      Will receive up to MaxBody bytes.
 recv_body(MaxBody) ->
+    % we could use a sane constant for max chunk size
+    Body = stream_body(?MAX_RECV_BODY, fun
+        ({0, _ChunkedFooter}, {_LengthAcc, BinAcc}) -> 
+            iolist_to_binary(lists:reverse(BinAcc));
+        ({Length, Bin}, {LengthAcc, BinAcc}) ->
+            NewLength = Length + LengthAcc,
+            if NewLength > MaxBody ->
+                exit({body_too_large, chunked});
+            true -> 
+                {NewLength, [Bin | BinAcc]}
+            end
+        end, {0, []}, MaxBody),
+    put(?SAVE_BODY, Body),
+    Body.
+
+stream_body(MaxChunkSize, ChunkFun, FunState) ->
+    stream_body(MaxChunkSize, ChunkFun, FunState, undefined).
+    
+stream_body(MaxChunkSize, ChunkFun, FunState, MaxBodyLength) ->
+
     case get_header_value("expect") of
         "100-continue" ->
             start_raw_response({100, gb_trees:empty()});
         _Else ->
             ok
     end,
-    Body = case body_length() of
-               undefined ->
-                   undefined;
-               {unknown_transfer_encoding, Unknown} ->
-                   exit({unknown_transfer_encoding, Unknown});
-               chunked ->
-                   read_chunked_body(MaxBody, []);
-               0 ->
-                   <<>>;
-               Length when is_integer(Length), Length =< MaxBody ->
-                   recv(Length);
-               Length ->
-                   exit({body_too_large, Length})
-           end,
-    put(?SAVE_BODY, Body),
-    Body.
+    case body_length() of
+        undefined ->
+            undefined;
+        {unknown_transfer_encoding, Unknown} ->
+            exit({unknown_transfer_encoding, Unknown});
+        chunked ->
+            % In this case the MaxBody is actually used to
+            % determine the maximum allowed size of a single
+            % chunk.
+            stream_chunked_body(MaxChunkSize, ChunkFun, FunState);
+        0 ->
+            <<>>;
+        Length when is_integer(Length) ->
+            case MaxBodyLength of
+            MaxBodyLength when is_integer(MaxBodyLength), MaxBodyLength < Length ->
+                exit({body_too_large, content_length});
+            _ ->
+                stream_unchunked_body(Length, MaxChunkSize, ChunkFun, FunState)
+            end;     
+        Length ->
+            exit({length_not_integer, Length})
+    end.
 
 
 %% @spec start_response({integer(), ioheaders()}) -> response()
@@ -220,12 +246,18 @@
 
 %% @spec start_response_length({integer(), ioheaders(), integer()}) -> response()
 %% @doc Start the HTTP response by sending the Code HTTP response and
-%%      ResponseHeaders including a Content-Length of Length. The server
-%%      will set header defaults such as Server
+%%      ResponseHeaders including a Content-Length of Length if appropriate.
+%%      The server will set header defaults such as Server
 %%      and Date if not present in ResponseHeaders.
 start_response_length({Code, ResponseHeaders, Length}) ->
     HResponse = mochiweb_headers:make(ResponseHeaders),
-    HResponse1 = mochiweb_headers:enter("Content-Length", Length, HResponse),
+    HResponse1 = case (Length =/= 0 orelse (Code >= 200 andalso Code < 300)) of
+                     true ->
+                         mochiweb_headers:enter("Content-Length", Length,
+                                                HResponse);
+                     false ->
+                         HResponse
+                 end,
     start_response({Code, HResponse1}).
 
 %% @spec respond({integer(), ioheaders(), iodata() | chunked | {file, IoDevice}}) -> response()
@@ -408,17 +440,33 @@
             Cached
     end.
 
-read_chunked_body(Max, Acc) ->
+%% @spec stream_chunked_body(integer(), fun(), term()) -> term()
+%% @doc The function is called for each chunk.
+%%      Used internally by read_chunked_body.
+stream_chunked_body(MaxChunkSize, Fun, FunState) ->
     case read_chunk_length() of
         0 ->
-            read_chunk(0),
-            iolist_to_binary(lists:reverse(Acc));
-        Length when Length > Max ->
-            exit({body_too_large, chunked});
+            Fun({0, read_chunk(0)}, FunState);
+        Length when Length > MaxChunkSize ->
+            NewState = read_sub_chunks(Length, MaxChunkSize, Fun, FunState),
+            stream_chunked_body(MaxChunkSize, Fun, NewState);
         Length ->
-            read_chunked_body(Max - Length, [read_chunk(Length) | Acc])
+            NewState = Fun({Length, read_chunk(Length)}, FunState),
+            stream_chunked_body(MaxChunkSize, Fun, NewState)
     end.
 
+stream_unchunked_body(0, _MaxChunkSize, Fun, FunState) ->
+    Fun({0, <<>>}, FunState);
+stream_unchunked_body(Length, MaxChunkSize, Fun, FunState) when Length > MaxChunkSize ->
+    Bin = recv(MaxChunkSize),
+    NewState = Fun({MaxChunkSize, Bin}, FunState),
+    stream_unchunked_body(Length - MaxChunkSize, MaxChunkSize, Fun, NewState);
+stream_unchunked_body(Length, MaxChunkSize, Fun, FunState) ->
+    Bin = recv(Length),
+    NewState = Fun({Length, Bin}, FunState),
+    stream_unchunked_body(0, MaxChunkSize, Fun, NewState).
+
+
 %% @spec read_chunk_length() -> integer()
 %% @doc Read the length of the next HTTP chunk.
 read_chunk_length() ->
@@ -461,6 +509,14 @@
             exit(normal)
     end.
 
+read_sub_chunks(Length, MaxChunkSize, Fun, FunState) when Length > MaxChunkSize ->
+    Bin = recv(MaxChunkSize),
+    NewState = Fun({size(Bin), Bin}, FunState),
+    read_sub_chunks(Length - MaxChunkSize, MaxChunkSize, Fun, NewState);
+
+read_sub_chunks(Length, _MaxChunkSize, Fun, FunState) ->
+    Fun({Length, read_chunk(Length)}, FunState).
+    
 %% @spec serve_file(Path, DocRoot) -> Response
 %% @doc Serve a file relative to DocRoot.
 serve_file(Path, DocRoot) ->

Modified: couchdb/vendor/mochiweb/current/src/mochiweb_response.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb_response.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb_response.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb_response.erl Tue Feb 24 20:56:11 2009
@@ -50,8 +50,7 @@
     case Request:get(version) of
         Version when Version >= {1, 1} ->
             Length = iolist_size(Data),
-            send(io_lib:format("~.16b\r\n", [Length])),
-            send([Data, <<"\r\n">>]);
+            send([io_lib:format("~.16b\r\n", [Length]), Data, <<"\r\n">>]);
         _ ->
             send(Data)
     end.

Modified: couchdb/vendor/mochiweb/current/src/mochiweb_util.erl
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/src/mochiweb_util.erl?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/src/mochiweb_util.erl (original)
+++ couchdb/vendor/mochiweb/current/src/mochiweb_util.erl Tue Feb 24 20:56:11 2009
@@ -133,12 +133,16 @@
 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, []).
 
@@ -527,6 +531,7 @@
 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"),

Modified: couchdb/vendor/mochiweb/current/support/include.mk
URL: http://svn.apache.org/viewvc/couchdb/vendor/mochiweb/current/support/include.mk?rev=747541&r1=747540&r2=747541&view=diff
==============================================================================
--- couchdb/vendor/mochiweb/current/support/include.mk (original)
+++ couchdb/vendor/mochiweb/current/support/include.mk Tue Feb 24 20:56:11 2009
@@ -19,17 +19,14 @@
 endif
 
 EBIN_DIR := ../ebin
-DOC_DIR  := ../doc
 EMULATOR := beam
 
 ERL_SOURCES := $(wildcard *.erl)
 ERL_HEADERS := $(wildcard *.hrl) $(wildcard ../include/*.hrl)
 ERL_OBJECTS := $(ERL_SOURCES:%.erl=$(EBIN_DIR)/%.$(EMULATOR))
-ERL_DOCUMENTS := $(ERL_SOURCES:%.erl=$(DOC_DIR)/%.html)
 ERL_OBJECTS_LOCAL := $(ERL_SOURCES:%.erl=./%.$(EMULATOR))
 APP_FILES := $(wildcard *.app)
-EBIN_FILES = $(ERL_OBJECTS) $(ERL_DOCUMENTS) $(APP_FILES:%.app=../ebin/%.app)
-EBIN_FILES_NO_DOCS = $(ERL_OBJECTS) $(APP_FILES:%.app=../ebin/%.app)
+EBIN_FILES = $(ERL_OBJECTS) $(APP_FILES:%.app=../ebin/%.app)
 MODULES = $(ERL_SOURCES:%.erl=%)
 
 ../ebin/%.app: %.app
@@ -40,7 +37,3 @@
 
 ./%.$(EMULATOR): %.erl
 	$(ERLC) $(ERLC_FLAGS) -o . $<
-
-$(DOC_DIR)/%.html: %.erl
-	$(ERL) -noshell -run edoc file $< -run init stop
-	mv *.html $(DOC_DIR)