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 2008/04/30 02:45:50 UTC

svn commit: r652206 - /incubator/couchdb/trunk/src/mochiweb/

Author: cmlenz
Date: Tue Apr 29 17:45:50 2008
New Revision: 652206

URL: http://svn.apache.org/viewvc?rev=652206&view=rev
Log:
Update MochiWeb code in trunk to r66.

Modified:
    incubator/couchdb/trunk/src/mochiweb/mochijson.erl
    incubator/couchdb/trunk/src/mochiweb/mochijson2.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_cookies.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_echo.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_headers.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_html.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_http.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_multipart.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_request.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_response.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_socket_server.erl
    incubator/couchdb/trunk/src/mochiweb/mochiweb_util.erl
    incubator/couchdb/trunk/src/mochiweb/reloader.erl

Modified: incubator/couchdb/trunk/src/mochiweb/mochijson.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochijson.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochijson.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochijson.erl Tue Apr 29 17:45:50 2008
@@ -39,13 +39,13 @@
 %% @type binary_decoder_option() = {object_hook, function()}
 
 -record(encoder, {input_encoding=unicode,
-		  handler=null}).
+                  handler=null}).
 
 -record(decoder, {input_encoding=utf8,
-		  object_hook=null,
-		  line=1,
-		  column=1,
-		  state=null}).
+                  object_hook=null,
+                  line=1,
+                  column=1,
+                  state=null}).
 
 %% @spec encoder([encoder_option()]) -> function()
 %% @doc Create an encoder/1 with the given options.
@@ -136,8 +136,8 @@
     "[]";
 json_encode_array(L, State) ->
     F = fun (O, Acc) ->
-		[$,, json_encode(O, State) | Acc]
-	end,
+                [$,, json_encode(O, State) | Acc]
+        end,
     [$, | Acc1] = lists:foldl(F, "[", L),
     lists:reverse([$\] | Acc1]).
 
@@ -145,17 +145,17 @@
     "{}";
 json_encode_proplist(Props, State) ->
     F = fun ({K, V}, Acc) ->
-		KS = case K of 
-			 K when is_atom(K) ->
-			     json_encode_string_utf8(atom_to_list(K));
-			 K when is_integer(K) ->
-			     json_encode_string(integer_to_list(K), State);
-			 K when is_list(K); is_binary(K) ->
-			     json_encode_string(K, State)
-		     end,
-		VS = json_encode(V, State),
-		[$,, VS, $:, KS | Acc]
-	end,
+                KS = case K of 
+                         K when is_atom(K) ->
+                             json_encode_string_utf8(atom_to_list(K));
+                         K when is_integer(K) ->
+                             json_encode_string(integer_to_list(K), State);
+                         K when is_list(K); is_binary(K) ->
+                             json_encode_string(K, State)
+                     end,
+                VS = json_encode(V, State),
+                [$,, VS, $:, KS | Acc]
+        end,
     [$, | Acc1] = lists:foldl(F, "{", Props),
     lists:reverse([$\} | Acc1]).
 
@@ -241,12 +241,12 @@
 
 decode1(L, S=#decoder{state=null}) ->
     case tokenize(L, S#decoder{state=any}) of
-	{{const, C}, L1, S1} ->
-	    {C, L1, S1};
-	{start_array, L1, S1} ->
-	    decode_array(L1, S1#decoder{state=any}, []);
-	{start_object, L1, S1} ->
-	    decode_object(L1, S1#decoder{state=key}, [])
+        {{const, C}, L1, S1} ->
+            {C, L1, S1};
+        {start_array, L1, S1} ->
+            decode_array(L1, S1#decoder{state=any}, []);
+        {start_object, L1, S1} ->
+            decode_object(L1, S1#decoder{state=key}, [])
     end.
 
 make_object(V, #decoder{object_hook=null}) ->
@@ -256,42 +256,42 @@
 
 decode_object(L, S=#decoder{state=key}, Acc) ->
     case tokenize(L, S) of
-	{end_object, Rest, S1} ->
-	    V = make_object({struct, lists:reverse(Acc)}, S1),
-	    {V, Rest, S1#decoder{state=null}};
-	{{const, K}, Rest, S1} when is_list(K) ->
-	    {colon, L2, S2} = tokenize(Rest, S1),
-	    {V, L3, S3} = decode1(L2, S2#decoder{state=null}),
-	    decode_object(L3, S3#decoder{state=comma}, [{K, V} | Acc])
+        {end_object, Rest, S1} ->
+            V = make_object({struct, lists:reverse(Acc)}, S1),
+            {V, Rest, S1#decoder{state=null}};
+        {{const, K}, Rest, S1} when is_list(K) ->
+            {colon, L2, S2} = tokenize(Rest, S1),
+            {V, L3, S3} = decode1(L2, S2#decoder{state=null}),
+            decode_object(L3, S3#decoder{state=comma}, [{K, V} | Acc])
     end;
 decode_object(L, S=#decoder{state=comma}, Acc) ->
     case tokenize(L, S) of
-	{end_object, Rest, S1} ->
-	    V = make_object({struct, lists:reverse(Acc)}, S1),
-	    {V, Rest, S1#decoder{state=null}};
-	{comma, Rest, S1} ->
-	    decode_object(Rest, S1#decoder{state=key}, Acc)
+        {end_object, Rest, S1} ->
+            V = make_object({struct, lists:reverse(Acc)}, S1),
+            {V, Rest, S1#decoder{state=null}};
+        {comma, Rest, S1} ->
+            decode_object(Rest, S1#decoder{state=key}, Acc)
     end.
 
 decode_array(L, S=#decoder{state=any}, Acc) ->
     case tokenize(L, S) of
-	{end_array, Rest, S1} ->
-	    {{array, lists:reverse(Acc)}, Rest, S1#decoder{state=null}};
-	{start_array, Rest, S1} ->
-	    {Array, Rest1, S2} = decode_array(Rest, S1#decoder{state=any}, []),
-	    decode_array(Rest1, S2#decoder{state=comma}, [Array | Acc]);
-	{start_object, Rest, S1} ->
-	    {Array, Rest1, S2} = decode_object(Rest, S1#decoder{state=key}, []),
-	    decode_array(Rest1, S2#decoder{state=comma}, [Array | Acc]);
-	{{const, Const}, Rest, S1} ->
-	    decode_array(Rest, S1#decoder{state=comma}, [Const | Acc])
+        {end_array, Rest, S1} ->
+            {{array, lists:reverse(Acc)}, Rest, S1#decoder{state=null}};
+        {start_array, Rest, S1} ->
+            {Array, Rest1, S2} = decode_array(Rest, S1#decoder{state=any}, []),
+            decode_array(Rest1, S2#decoder{state=comma}, [Array | Acc]);
+        {start_object, Rest, S1} ->
+            {Array, Rest1, S2} = decode_object(Rest, S1#decoder{state=key}, []),
+            decode_array(Rest1, S2#decoder{state=comma}, [Array | Acc]);
+        {{const, Const}, Rest, S1} ->
+            decode_array(Rest, S1#decoder{state=comma}, [Const | Acc])
     end;
 decode_array(L, S=#decoder{state=comma}, Acc) ->
     case tokenize(L, S) of
-	{end_array, Rest, S1} ->
-	    {{array, lists:reverse(Acc)}, Rest, S1#decoder{state=null}};
-	{comma, Rest, S1} ->
-	    decode_array(Rest, S1#decoder{state=any}, Acc)
+        {end_array, Rest, S1} ->
+            {{array, lists:reverse(Acc)}, Rest, S1#decoder{state=null}};
+        {comma, Rest, S1} ->
+            decode_array(Rest, S1#decoder{state=any}, Acc)
     end.
 
 tokenize_string(IoList=[C | _], S=#decoder{input_encoding=utf8}, Acc)
@@ -319,9 +319,9 @@
 tokenize_string([$\\, $u, C3, C2, C1, C0 | Rest], S, Acc) ->
     % coalesce UTF-16 surrogate pair?
     C = dehex(C0) bor
-	(dehex(C1) bsl 4) bor
-	(dehex(C2) bsl 8) bor 
-	(dehex(C3) bsl 12),
+        (dehex(C1) bsl 4) bor
+        (dehex(C2) bsl 8) bor 
+        (dehex(C3) bsl 12),
     tokenize_string(Rest, ?ADV_COL(S, 6), [C | Acc]);
 tokenize_string([C | Rest], S, Acc) when C >= $\s; C < 16#10FFFF ->
     tokenize_string(Rest, ?ADV_COL(S, 1), [C | Acc]).
@@ -400,10 +400,10 @@
     {{const, String}, Rest1, S1};
 tokenize(L=[C | _], S) when C >= $0, C =< $9; C == $- ->
     case tokenize_number(L, sign, S, []) of
-	{{int, Int}, Rest, S1} ->
-	    {{const, list_to_integer(Int)}, Rest, S1};
-	{{float, Float}, Rest, S1} ->
-	    {{const, list_to_float(Float)}, Rest, S1}
+        {{int, Int}, Rest, S1} ->
+            {{const, list_to_integer(Int)}, Rest, S1};
+        {{float, Float}, Rest, S1} ->
+            {{const, list_to_float(Float)}, Rest, S1}
     end.
 
 %% testing constructs borrowed from the Yaws JSON implementation.
@@ -415,10 +415,10 @@
 
 is_obj({struct, Props}) ->
     F = fun ({K, _}) when is_list(K) ->
-		true;
-	    (_) ->
-		false
-	end,	
+                true;
+            (_) ->
+                false
+        end,    
     lists:all(F, Props).
 
 obj_from_list(Props) ->
@@ -437,8 +437,8 @@
     equiv_object(Props1, Props2);
 equiv({array, L1}, {array, L2}) ->
     equiv_list(L1, L2);
-equiv(N1, N2) when is_number(N1), is_number(N2)	-> N1 == N2;
-equiv(S1, S2) when is_list(S1), is_list(S2)	-> S1 == S2;
+equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 == N2;
+equiv(S1, S2) when is_list(S1), is_list(S2)     -> S1 == S2;
 equiv(true, true) -> true;
 equiv(false, false) -> true;
 equiv(null, null) -> true.
@@ -451,7 +451,7 @@
     L2 = lists:keysort(1, Props2),
     Pairs = lists:zip(L1, L2),
     true = lists:all(fun({{K1, V1}, {K2, V2}}) ->
-	equiv(K1, K2) and equiv(V1, V2)
+        equiv(K1, K2) and equiv(V1, V2)
     end, Pairs).
 
 %% Recursively compare tuple elements for equivalence.
@@ -460,10 +460,10 @@
     true;
 equiv_list([V1 | L1], [V2 | L2]) ->
     case equiv(V1, V2) of
-	true ->
-	    equiv_list(L1, L2);
-	false ->
-	    false
+        true ->
+            equiv_list(L1, L2);
+        false ->
+            false
     end.
 
 test_all() ->

Modified: incubator/couchdb/trunk/src/mochiweb/mochijson2.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochijson2.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochijson2.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochijson2.erl Tue Apr 29 17:45:50 2008
@@ -31,7 +31,7 @@
                           offset=1+S#decoder.offset}
         end).
 -define(IS_WHITESPACE(C),
- 	(C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).
+        (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).
 
 %% @type iolist() = [char() | binary() | iolist()]
 %% @type iodata() = iolist() | binary()
@@ -45,10 +45,10 @@
 -record(encoder, {handler=null}).
 
 -record(decoder, {object_hook=null,
-		  offset=0,
+                  offset=0,
                   line=1,
-		  column=1,
-		  state=null}).
+                  column=1,
+                  state=null}).
 
 %% @spec encoder([encoder_option()]) -> function()
 %% @doc Create an encoder/1 with the given options.
@@ -115,8 +115,8 @@
     <<"[]">>;
 json_encode_array(L, State) ->
     F = fun (O, Acc) ->
-		[$,, json_encode(O, State) | Acc]
-	end,
+                [$,, json_encode(O, State) | Acc]
+        end,
     [$, | Acc1] = lists:foldl(F, "[", L),
     lists:reverse([$\] | Acc1]).
 
@@ -124,10 +124,10 @@
     <<"{}">>;
 json_encode_proplist(Props, State) ->
     F = fun ({K, V}, Acc) ->
-		KS = json_encode_string(K, State),
-		VS = json_encode(V, State),
-		[$,, VS, $:, KS | Acc]
-	end,
+                KS = json_encode_string(K, State),
+                VS = json_encode(V, State),
+                [$,, VS, $:, KS | Acc]
+        end,
     [$, | Acc1] = lists:foldl(F, "{", Props),
     lists:reverse([$\} | Acc1]).
 
@@ -144,8 +144,8 @@
     lists:reverse([$\" | Acc]);
 json_encode_string_unicode([C | Cs], Acc) ->
     Acc1 = case C of
-	       ?Q ->
-		   [?Q, $\\ | Acc];
+               ?Q ->
+                   [?Q, $\\ | Acc];
                %% Escaping solidus is only useful when trying to protect
                %% against "</script>" injection attacks which are only
                %% possible when JSON is inserted into a HTML document
@@ -153,28 +153,28 @@
                %% if you do insert directly into HTML then you need to
                %% uncomment the following case or escape the output of encode.
                %%
-	       %% $/ ->
-	       %%    [$/, $\\ | Acc];
+               %% $/ ->
+               %%    [$/, $\\ | Acc];
                %%
-	       $\\ ->
-		   [$\\, $\\ | Acc];
-	       $\b ->
-		   [$b, $\\ | Acc];
-	       $\f ->
-		   [$f, $\\ | Acc];
-	       $\n ->
-		   [$n, $\\ | Acc];
-	       $\r ->
-		   [$r, $\\ | Acc];
-	       $\t ->
-		   [$t, $\\ | Acc];
-	       C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
-		   [unihex(C) | Acc];
-	       C when C < 16#7f ->
-		   [C | Acc];
-	       _ ->
-		   exit({json_encode, {bad_char, C}})
-	   end,
+               $\\ ->
+                   [$\\, $\\ | Acc];
+               $\b ->
+                   [$b, $\\ | Acc];
+               $\f ->
+                   [$f, $\\ | Acc];
+               $\n ->
+                   [$n, $\\ | Acc];
+               $\r ->
+                   [$r, $\\ | Acc];
+               $\t ->
+                   [$t, $\\ | Acc];
+               C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
+                   [unihex(C) | Acc];
+               C when C < 16#7f ->
+                   [C | Acc];
+               _ ->
+                   exit({json_encode, {bad_char, C}})
+           end,
     json_encode_string_unicode(Cs, Acc1).
 
 hexdigit(C) when C >= 0, C =< 9 ->
@@ -201,12 +201,12 @@
 
 decode1(B, S=#decoder{state=null}) ->
     case tokenize(B, S#decoder{state=any}) of
-	{{const, C}, S1} ->
-	    {C, S1};
-	{start_array, S1} ->
-	    decode_array(B, S1);
-	{start_object, S1} ->
-	    decode_object(B, S1)
+        {{const, C}, S1} ->
+            {C, S1};
+        {start_array, S1} ->
+            decode_array(B, S1);
+        {start_object, S1} ->
+            decode_object(B, S1)
     end.
 
 make_object(V, #decoder{object_hook=null}) ->
@@ -219,21 +219,21 @@
 
 decode_object(B, S=#decoder{state=key}, Acc) ->
     case tokenize(B, S) of
-	{end_object, S1} ->
-	    V = make_object({struct, lists:reverse(Acc)}, S1),
-	    {V, S1#decoder{state=null}};
-	{{const, K}, S1} ->
-	    {colon, S2} = tokenize(B, S1),
-	    {V, S3} = decode1(B, S2#decoder{state=null}),
-	    decode_object(B, S3#decoder{state=comma}, [{K, V} | Acc])
+        {end_object, S1} ->
+            V = make_object({struct, lists:reverse(Acc)}, S1),
+            {V, S1#decoder{state=null}};
+        {{const, K}, S1} ->
+            {colon, S2} = tokenize(B, S1),
+            {V, S3} = decode1(B, S2#decoder{state=null}),
+            decode_object(B, S3#decoder{state=comma}, [{K, V} | Acc])
     end;
 decode_object(B, S=#decoder{state=comma}, Acc) ->
     case tokenize(B, S) of
-	{end_object, S1} ->
-	    V = make_object({struct, lists:reverse(Acc)}, S1),
-	    {V, S1#decoder{state=null}};
-	{comma, S1} ->
-	    decode_object(B, S1#decoder{state=key}, Acc)
+        {end_object, S1} ->
+            V = make_object({struct, lists:reverse(Acc)}, S1),
+            {V, S1#decoder{state=null}};
+        {comma, S1} ->
+            decode_object(B, S1#decoder{state=key}, Acc)
     end.
 
 decode_array(B, S) ->
@@ -241,23 +241,23 @@
 
 decode_array(B, S=#decoder{state=any}, Acc) ->
     case tokenize(B, S) of
-	{end_array, S1} ->
-	    {lists:reverse(Acc), S1#decoder{state=null}};
-	{start_array, S1} ->
-	    {Array, S2} = decode_array(B, S1),
-	    decode_array(B, S2#decoder{state=comma}, [Array | Acc]);
-	{start_object, S1} ->
-	    {Array, S2} = decode_object(B, S1),
-	    decode_array(B, S2#decoder{state=comma}, [Array | Acc]);
-	{{const, Const}, S1} ->
-	    decode_array(B, S1#decoder{state=comma}, [Const | Acc])
+        {end_array, S1} ->
+            {lists:reverse(Acc), S1#decoder{state=null}};
+        {start_array, S1} ->
+            {Array, S2} = decode_array(B, S1),
+            decode_array(B, S2#decoder{state=comma}, [Array | Acc]);
+        {start_object, S1} ->
+            {Array, S2} = decode_object(B, S1),
+            decode_array(B, S2#decoder{state=comma}, [Array | Acc]);
+        {{const, Const}, S1} ->
+            decode_array(B, S1#decoder{state=comma}, [Const | Acc])
     end;
 decode_array(B, S=#decoder{state=comma}, Acc) ->
     case tokenize(B, S) of
-	{end_array, S1} ->
-	    {lists:reverse(Acc), S1#decoder{state=null}};
-	{comma, S1} ->
-	    decode_array(B, S1#decoder{state=any}, Acc)
+        {end_array, S1} ->
+            {lists:reverse(Acc), S1#decoder{state=null}};
+        {comma, S1} ->
+            decode_array(B, S1#decoder{state=any}, Acc)
     end.
 
 tokenize_string(B, S) ->
@@ -400,10 +400,10 @@
 
 is_obj({struct, Props}) ->
     F = fun ({K, _}) when is_binary(K) ->
-		true;
-	    (_) ->
-		false
-	end,	
+                true;
+            (_) ->
+                false
+        end,    
     lists:all(F, Props).
 
 obj_from_list(Props) ->
@@ -422,8 +422,8 @@
     equiv_object(Props1, Props2);
 equiv(L1, L2) when is_list(L1), is_list(L2) ->
     equiv_list(L1, L2);
-equiv(N1, N2) when is_number(N1), is_number(N2)	-> N1 == N2;
-equiv(B1, B2) when is_binary(B1), is_binary(B2)	-> B1 == B2;
+equiv(N1, N2) when is_number(N1), is_number(N2) -> N1 == N2;
+equiv(B1, B2) when is_binary(B1), is_binary(B2) -> B1 == B2;
 equiv(true, true) -> true;
 equiv(false, false) -> true;
 equiv(null, null) -> true.
@@ -445,10 +445,10 @@
     true;
 equiv_list([V1 | L1], [V2 | L2]) ->
     case equiv(V1, V2) of
-	true ->
-	    equiv_list(L1, L2);
-	false ->
-	    false
+        true ->
+            equiv_list(L1, L2);
+        false ->
+            false
     end.
 
 test_all() ->

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb.erl Tue Apr 29 17:45:50 2008
@@ -65,25 +65,25 @@
 %% @doc Return a mochiweb_request data structure.
 new_request({Socket, {Method, {abs_path, Uri}, Version}, Headers}) ->
     mochiweb_request:new(Socket,
-			 Method,
-			 Uri,
-			 Version,
-			 mochiweb_headers:make(Headers));
+                         Method,
+                         Uri,
+                         Version,
+                         mochiweb_headers:make(Headers));
 % this case probably doesn't "exist".
 new_request({Socket, {Method, {absoluteURI, _Protocol, _Host, _Port, Uri},
-		      Version}, Headers}) ->
+                      Version}, Headers}) ->
     mochiweb_request:new(Socket,
-			 Method,
-			 Uri,
-			 Version,
-			 mochiweb_headers:make(Headers)).
+                         Method,
+                         Uri,
+                         Version,
+                         mochiweb_headers:make(Headers)).
 
 %% @spec new_response({Request, integer(), Headers}) -> MochiWebResponse
 %% @doc Return a mochiweb_response data structure.
 new_response({Request, Code, Headers}) ->
     mochiweb_response:new(Request,
-			  Code,
-			  mochiweb_headers:make(Headers)).
+                          Code,
+                          mochiweb_headers:make(Headers)).
 
 %% Internal API
 
@@ -94,8 +94,8 @@
 
 ensure_started(App) ->
     case application:start(App) of
-	ok ->
-	    ok;
-	{error, {already_started, App}} ->
-	    ok
+        ok ->
+            ok;
+        {error, {already_started, App}} ->
+            ok
     end.

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_cookies.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_cookies.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_cookies.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_cookies.erl Tue Apr 29 17:45:50 2008
@@ -9,15 +9,15 @@
 -define(QUOTE, $\").
 
 -define(IS_WHITESPACE(C),
-	(C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).
+        (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).
 
 %% RFC 2616 separators (called tspecials in RFC 2068)
 -define(IS_SEPARATOR(C),
-	(C < 32 orelse
-	 C =:= $\s orelse C =:= $\t orelse
-	 C =:= $( orelse C =:= $) orelse C =:= $< orelse C =:= $> orelse
-	 C =:= $@ orelse C =:= $, orelse C =:= $; orelse C =:= $: orelse
-	 C =:= $\\ orelse C =:= $\" orelse C =:= $/ orelse
+        (C < 32 orelse
+         C =:= $\s orelse C =:= $\t orelse
+         C =:= $( orelse C =:= $) orelse C =:= $< orelse C =:= $> orelse
+         C =:= $@ orelse C =:= $, orelse C =:= $; orelse C =:= $: orelse
+         C =:= $\\ orelse C =:= $\" orelse C =:= $/ orelse
          C =:= $[ orelse C =:= $] orelse C =:= $? orelse C =:= $= orelse
          C =:= ${ orelse C =:= $})).
 
@@ -137,13 +137,13 @@
 parse_cookie(String, Acc) -> 
     {{Token, Value}, Rest} = read_pair(String),
     Acc1 = case Token of
-	       "" ->
-		   Acc;
-	       "$" ++ _ ->
-		   Acc;
-	       _ ->
-		   [{Token, Value} | Acc]
-	   end,
+               "" ->
+                   Acc;
+               "$" ++ _ ->
+                   Acc;
+               _ ->
+                   [{Token, Value} | Acc]
+           end,
     parse_cookie(Rest, Acc1).
 
 read_pair(String) ->
@@ -154,10 +154,10 @@
 read_value([$= | Value]) ->
     Value1 = skip_whitespace(Value),
     case Value1 of
-	[?QUOTE | _] ->
-	    read_quoted(Value1);
-	_ ->
-	    read_token(Value1)
+        [?QUOTE | _] ->
+            read_quoted(Value1);
+        _ ->
+            read_token(Value1)
     end;
 read_value(String) ->
     {"", String}.
@@ -221,30 +221,30 @@
 
 cookie_test() ->
     C1 = {"Set-Cookie",
-	  "Customer=WILE_E_COYOTE; "
-	  "Version=1; "
-	  "Path=/acme"},
+          "Customer=WILE_E_COYOTE; "
+          "Version=1; "
+          "Path=/acme"},
     C1 = cookie("Customer", "WILE_E_COYOTE", [{path, "/acme"}]),
     C1 = cookie("Customer", "WILE_E_COYOTE",
-		[{path, "/acme"}, {badoption, "negatory"}]),
+                [{path, "/acme"}, {badoption, "negatory"}]),
     C1 = cookie('Customer', 'WILE_E_COYOTE', [{path, '/acme'}]),
     C1 = cookie(<<"Customer">>, <<"WILE_E_COYOTE">>, [{path, <<"/acme">>}]),
 
     {"Set-Cookie","=NoKey; Version=1"} = cookie("", "NoKey", []),
-	
-	LocalTime = calendar:universal_time_to_local_time({{2007, 5, 15}, {13, 45, 33}}), 
+        
+        LocalTime = calendar:universal_time_to_local_time({{2007, 5, 15}, {13, 45, 33}}), 
     C2 = {"Set-Cookie",
-	  "Customer=WILE_E_COYOTE; "
-	  "Version=1; "
-	  "Expires=Tue, 15 May 2007 13:45:33 GMT; "
-	  "Max-Age=0"},
+          "Customer=WILE_E_COYOTE; "
+          "Version=1; "
+          "Expires=Tue, 15 May 2007 13:45:33 GMT; "
+          "Max-Age=0"},
     C2 = cookie("Customer", "WILE_E_COYOTE",
-		[{max_age, -111}, {local_time, LocalTime}]),
+                [{max_age, -111}, {local_time, LocalTime}]),
     C3 = {"Set-Cookie",
-	  "Customer=WILE_E_COYOTE; "
-	  "Version=1; "
-	  "Expires=Wed, 16 May 2007 13:45:50 GMT; "
-	  "Max-Age=86417"},
+          "Customer=WILE_E_COYOTE; "
+          "Version=1; "
+          "Expires=Wed, 16 May 2007 13:45:50 GMT; "
+          "Max-Age=86417"},
     C3 = cookie("Customer", "WILE_E_COYOTE",
-		[{max_age, 86417}, {local_time, LocalTime}]),
+                [{max_age, 86417}, {local_time, LocalTime}]),
     ok.

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_echo.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_echo.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_echo.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_echo.erl Tue Apr 29 17:45:50 2008
@@ -12,20 +12,20 @@
     
 start() ->
     mochiweb_socket_server:start([{name, ?MODULE},
-				  {port, 6789},
-				  {ip, "127.0.0.1"},
-				  {max, 1},
-				  {loop, {?MODULE, loop}}]).
+                                  {port, 6789},
+                                  {ip, "127.0.0.1"},
+                                  {max, 1},
+                                  {loop, {?MODULE, loop}}]).
 
 loop(Socket) ->
     case gen_tcp:recv(Socket, 0, 30000) of
-	{ok, Data} ->
-	    case gen_tcp:send(Socket, Data) of
-		ok ->
-		    loop(Socket);
-		_ ->
-		    exit(normal)
-	    end;
-	_Other ->
-	    exit(normal)
+        {ok, Data} ->
+            case gen_tcp:send(Socket, Data) of
+                ok ->
+                    loop(Socket);
+                _ ->
+                    exit(normal)
+            end;
+        _Other ->
+            exit(normal)
     end.

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_headers.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_headers.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_headers.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_headers.erl Tue Apr 29 17:45:50 2008
@@ -71,11 +71,11 @@
 %%      preserved).
 to_list(T) ->
     F = fun ({K, {array, L}}, Acc) ->
-		L1 = lists:reverse(L),
-		lists:foldl(fun (V, Acc1) -> [{K, V} | Acc1] end, Acc, L1);
-	    (Pair, Acc) ->
-		[Pair | Acc]
-	end,
+                L1 = lists:reverse(L),
+                lists:foldl(fun (V, Acc1) -> [{K, V} | Acc1] end, Acc, L1);
+            (Pair, Acc) ->
+                [Pair | Acc]
+        end,
     lists:reverse(lists:foldl(F, [], gb_trees:values(T))).
 
 %% @spec get_value(key(), headers()) -> string() | undefined
@@ -83,10 +83,10 @@
 %%      undefined will be returned for keys that are not present.
 get_value(K, T) ->
     case lookup(K, T) of
-	{value, {_, V}} ->
-	    expand(V);
-	none ->
-	    undefined
+        {value, {_, V}} ->
+            expand(V);
+        none ->
+            undefined
     end.
 
 %% @spec get_primary_value(key(), headers()) -> string() | undefined
@@ -107,10 +107,10 @@
 %%      not present.
 lookup(K, T) ->
     case gb_trees:lookup(normalize(K), T) of
-	{value, {K0, V}} ->
-	    {value, {K0, expand(V)}};
-	none ->
-	    none
+        {value, {K0, V}} ->
+            {value, {K0, expand(V)}};
+        none ->
+            none
     end.
 
 %% @spec default(key(), value(), headers()) -> headers()
@@ -120,8 +120,8 @@
     V1 = any_to_list(V),
     try gb_trees:insert(K1, {K, V1}, T)
     catch
-	error:{key_exists, _} ->
-	    T
+        error:{key_exists, _} ->
+            T
     end.
 
 %% @spec enter(key(), value(), headers()) -> headers()
@@ -139,10 +139,10 @@
     V1 = any_to_list(V),
     try gb_trees:insert(K1, {K, V1}, T)
     catch
-	error:{key_exists, _} ->
-	    {K0, V0} = gb_trees:get(K1, T),
-	    V2 = merge(K1, V1, V0),
-	    gb_trees:update(K1, {K0, V2}, T)
+        error:{key_exists, _} ->
+            {K0, V0} = gb_trees:get(K1, T),
+            V2 = merge(K1, V1, V0),
+            gb_trees:update(K1, {K0, V2}, T)
     end.
 
 %% Internal API

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_html.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_html.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_html.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_html.erl Tue Apr 29 17:45:50 2008
@@ -31,13 +31,13 @@
         end).
 
 -define(IS_WHITESPACE(C),
- 	(C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).
+        (C =:= $\s orelse C =:= $\t orelse C =:= $\r orelse C =:= $\n)).
 -define(IS_LITERAL_SAFE(C),
         ((C >= $A andalso C =< $Z) orelse (C >= $a andalso C =< $z)
          orelse (C >= $0 andalso C =< $9))).
                                 
 -record(decoder, {line=1,
-		  column=1,
+                  column=1,
                   offset=0}).
 
 %% @type html_node() = {string(), [html_attr()], [html_node() | string()]}

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_http.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_http.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_http.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_http.erl Tue Apr 29 17:45:50 2008
@@ -11,14 +11,14 @@
 -define(IDLE_TIMEOUT, 30000).
 
 -define(DEFAULTS, [{name, ?MODULE},
-		   {port, 8888}]).
+                   {port, 8888}]).
 
 set_default({Prop, Value}, PropList) ->
     case proplists:is_defined(Prop, PropList) of
-	true ->
-	    PropList;
-	false ->
-	    [{Prop, Value} | PropList]
+        true ->
+            PropList;
+        false ->
+            [{Prop, Value} | PropList]
     end.
 
 set_defaults(Defaults, PropList) ->
@@ -27,8 +27,8 @@
 parse_options(Options) ->
     {loop, HttpLoop} = proplists:lookup(loop, Options),
     Loop = fun (S) ->
-		   ?MODULE:loop(S, HttpLoop)
-	   end,
+                   ?MODULE:loop(S, HttpLoop)
+           end,
     Options1 = [{loop, Loop} | proplists:delete(loop, Options)],
     set_defaults(?DEFAULTS, Options1).
 
@@ -40,7 +40,7 @@
     
 start() ->
     start([{ip, "127.0.0.1"},
-	   {loop, {?MODULE, default_body}}]).
+           {loop, {?MODULE, default_body}}]).
 
 start(Options) ->
     mochiweb_socket_server:start(parse_options(Options)).
@@ -69,23 +69,23 @@
     Res:write_chunk("");
 default_body(Req, M, _Path) when M =:= 'GET'; M =:= 'HEAD' ->
     Body = io_lib:format("~p~n", [[{parse_qs, Req:parse_qs()},
-				   {parse_cookie, Req:parse_cookie()},
-				   Req:dump()]]),
+                                   {parse_cookie, Req:parse_cookie()},
+                                   Req:dump()]]),
     Req:ok({"text/html",
-	    [mochiweb_cookies:cookie("mochiweb_http", "test_cookie")],
-	    frm(Body)});
+            [mochiweb_cookies:cookie("mochiweb_http", "test_cookie")],
+            frm(Body)});
 default_body(Req, 'POST', "/multipart") ->
     Body = io_lib:format("~p~n", [[{parse_qs, Req:parse_qs()},
-				   {parse_cookie, Req:parse_cookie()},
-				   {body, Req:recv_body()},
-				   Req:dump()]]),
+                                   {parse_cookie, Req:parse_cookie()},
+                                   {body, Req:recv_body()},
+                                   Req:dump()]]),
     Req:ok({"text/html", [], frm(Body)});
 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)});	    
+                                   {parse_cookie, Req:parse_cookie()},
+                                   {parse_post, Req:parse_post()},
+                                   Req:dump()]]),
+    Req:ok({"text/html", [], frm(Body)});           
 default_body(Req, _Method, _Path) ->
     Req:respond({501, [], []}).
 
@@ -98,35 +98,35 @@
 
 request(Socket, Body) ->
     case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
-	{ok, {http_request, Method, Path, Version}} ->
-	    headers(Socket, {Method, Path, Version}, [], Body);
-	{error, {http_error, "\r\n"}} ->
-	    request(Socket, Body);
-	{error, {http_error, "\n"}} ->
-	    request(Socket, Body);
-	_Other ->
-	    gen_tcp:close(Socket),
-	    exit(normal)
+        {ok, {http_request, Method, Path, Version}} ->
+            headers(Socket, {Method, Path, Version}, [], Body);
+        {error, {http_error, "\r\n"}} ->
+            request(Socket, Body);
+        {error, {http_error, "\n"}} ->
+            request(Socket, Body);
+        _Other ->
+            gen_tcp:close(Socket),
+            exit(normal)
     end.
 
 headers(Socket, Request, Headers, Body) ->
     case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
-	{ok, http_eoh} ->
-	    inet:setopts(Socket, [{packet, raw}]),
-	    Req = mochiweb:new_request({Socket, Request,
-					lists:reverse(Headers)}),
-	    Body(Req),
-	    case Req:should_close() of
-		true ->
-		    gen_tcp:close(Socket),
-		    exit(normal);
-		false ->
-		    Req:cleanup(),
-		    ?MODULE:loop(Socket, Body)
-	    end;
-	{ok, {http_header, _, Name, _, Value}} ->
-	    headers(Socket, Request, [{Name, Value} | Headers], Body);
-	_Other ->
-	    gen_tcp:close(Socket),
-	    exit(normal)
+        {ok, http_eoh} ->
+            inet:setopts(Socket, [{packet, raw}]),
+            Req = mochiweb:new_request({Socket, Request,
+                                        lists:reverse(Headers)}),
+            Body(Req),
+            case Req:should_close() of
+                true ->
+                    gen_tcp:close(Socket),
+                    exit(normal);
+                false ->
+                    Req:cleanup(),
+                    ?MODULE:loop(Socket, Body)
+            end;
+        {ok, {http_header, _, Name, _, Value}} ->
+            headers(Socket, Request, [{Name, Value} | Headers], Body);
+        _Other ->
+            gen_tcp:close(Socket),
+            exit(normal)
     end.

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_multipart.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_multipart.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_multipart.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_multipart.erl Tue Apr 29 17:45:50 2008
@@ -60,17 +60,17 @@
     %% TODO: Support chunked?
     Length = list_to_integer(Req:get_header_value("content-length")),
     Boundary = iolist_to_binary(
-		 get_boundary(Req:get_header_value("content-type"))),
+                 get_boundary(Req:get_header_value("content-type"))),
     Prefix = <<"\r\n--", Boundary/binary>>,
     BS = size(Boundary),
     Chunk = read_chunk(Req, Length),
     Length1 = Length - size(Chunk),
     <<"--", Boundary:BS/binary, "\r\n", Rest/binary>> = Chunk,
     feed_mp(headers, #mp{boundary=Prefix,
-			 length=Length1,
-			 buffer=Rest,
-			 callback=Callback,
-			 req=Req}).
+                         length=Length1,
+                         buffer=Rest,
+                         callback=Callback,
+                         req=Req}).
 
 parse_headers(<<>>) ->
     [];
@@ -79,91 +79,91 @@
 
 parse_headers(Binary, Acc) ->
     case find_in_binary(<<"\r\n">>, Binary) of
-	{exact, N} ->
-	    <<Line:N/binary, "\r\n", Rest/binary>> = Binary,
-	    parse_headers(Rest, [split_header(Line) | Acc]);
-	not_found ->
-	    lists:reverse([split_header(Binary) | Acc])
+        {exact, N} ->
+            <<Line:N/binary, "\r\n", Rest/binary>> = Binary,
+            parse_headers(Rest, [split_header(Line) | Acc]);
+        not_found ->
+            lists:reverse([split_header(Binary) | Acc])
     end.
 
 split_header(Line) ->
     {Name, [$: | Value]} = lists:splitwith(fun (C) -> C =/= $: end,
-					   binary_to_list(Line)),
+                                           binary_to_list(Line)),
     {string:to_lower(string:strip(Name)),
      mochiweb_util:parse_header(Value)}.
 
 read_chunk(Req, Length) when Length > 0 ->
     case Length of
-	Length when Length < ?CHUNKSIZE ->
-	    Req:recv(Length);
-	_ ->
-	    Req:recv(?CHUNKSIZE)
+        Length when Length < ?CHUNKSIZE ->
+            Req:recv(Length);
+        _ ->
+            Req:recv(?CHUNKSIZE)
     end.
 
 read_more(State=#mp{length=Length, buffer=Buffer, req=Req}) ->
     Data = read_chunk(Req, Length),
     Buffer1 = <<Buffer/binary, Data/binary>>,
     State#mp{length=Length - size(Data),
-	     buffer=Buffer1}.
+             buffer=Buffer1}.
 
 feed_mp(headers, State=#mp{buffer=Buffer, callback=Callback}) ->
     {State1, P} = case find_in_binary(<<"\r\n\r\n">>, Buffer) of
-		      {exact, N} ->
-			  {State, N};
-		      _ ->
-			  S1 = read_more(State),
-			  %% Assume headers must be less than ?CHUNKSIZE
-			  {exact, N} = find_in_binary(<<"\r\n\r\n">>,
-						      S1#mp.buffer),
-			  {S1, N}
-		  end,
+                      {exact, N} ->
+                          {State, N};
+                      _ ->
+                          S1 = read_more(State),
+                          %% Assume headers must be less than ?CHUNKSIZE
+                          {exact, N} = find_in_binary(<<"\r\n\r\n">>,
+                                                      S1#mp.buffer),
+                          {S1, N}
+                  end,
     <<Headers:P/binary, "\r\n\r\n", Rest/binary>> = State1#mp.buffer,
     NextCallback = Callback({headers, parse_headers(Headers)}),
     feed_mp(body, State1#mp{buffer=Rest,
-			    callback=NextCallback});
+                            callback=NextCallback});
 feed_mp(body, State=#mp{boundary=Prefix, buffer=Buffer, callback=Callback}) ->
     case find_boundary(Prefix, Buffer) of
-	{end_boundary, Start, Skip} ->
-	    <<Data:Start/binary, _:Skip/binary, Rest/binary>> = Buffer,
-	    C1 = Callback({body, Data}),
-	    C2 = C1(body_end),
-	    {State#mp.length, Rest, C2(eof)};
-	{next_boundary, Start, Skip} ->
-	    <<Data:Start/binary, _:Skip/binary, Rest/binary>> = Buffer,
-	    C1 = Callback({body, Data}),
-	    feed_mp(headers, State#mp{callback=C1(body_end),
-				      buffer=Rest});
-	{maybe, Start} ->
-	    <<Data:Start/binary, Rest/binary>> = Buffer,
-	    feed_mp(body, read_more(State#mp{callback=Callback({body, Data}),
-					     buffer=Rest}));
-	not_found ->
-	    {Data, Rest} = {Buffer, <<>>},
-	    feed_mp(body, read_more(State#mp{callback=Callback({body, Data}),
-					     buffer=Rest}))
+        {end_boundary, Start, Skip} ->
+            <<Data:Start/binary, _:Skip/binary, Rest/binary>> = Buffer,
+            C1 = Callback({body, Data}),
+            C2 = C1(body_end),
+            {State#mp.length, Rest, C2(eof)};
+        {next_boundary, Start, Skip} ->
+            <<Data:Start/binary, _:Skip/binary, Rest/binary>> = Buffer,
+            C1 = Callback({body, Data}),
+            feed_mp(headers, State#mp{callback=C1(body_end),
+                                      buffer=Rest});
+        {maybe, Start} ->
+            <<Data:Start/binary, Rest/binary>> = Buffer,
+            feed_mp(body, read_more(State#mp{callback=Callback({body, Data}),
+                                             buffer=Rest}));
+        not_found ->
+            {Data, Rest} = {Buffer, <<>>},
+            feed_mp(body, read_more(State#mp{callback=Callback({body, Data}),
+                                             buffer=Rest}))
     end.
 
 get_boundary(ContentType) ->
     {"multipart/form-data", Opts} = mochiweb_util:parse_header(ContentType),
     case proplists:get_value("boundary", Opts) of
-	S when is_list(S) ->
-	    S
+        S when is_list(S) ->
+            S
     end.
 
 find_in_binary(B, Data) when size(B) > 0 ->
     case size(Data) - size(B) of
-	Last when Last < 0 ->
-	    partial_find(B, Data, 0, size(Data));
-	Last ->
-	    find_in_binary(B, size(B), Data, 0, Last)
+        Last when Last < 0 ->
+            partial_find(B, Data, 0, size(Data));
+        Last ->
+            find_in_binary(B, size(B), Data, 0, Last)
     end.
 
 find_in_binary(B, BS, D, N, Last) when N =< Last->
     case D of
-	<<_:N/binary, B:BS/binary, _/binary>> ->
-	    {exact, N};
-	_ ->
-	    find_in_binary(B, BS, D, 1 + N, Last)
+        <<_:N/binary, B:BS/binary, _/binary>> ->
+            {exact, N};
+        _ ->
+            find_in_binary(B, BS, D, 1 + N, Last)
     end;
 find_in_binary(B, BS, D, N, Last) when N =:= 1 + Last ->
     partial_find(B, D, N, BS - 1).
@@ -173,92 +173,92 @@
 partial_find(B, D, N, K) ->
     <<B1:K/binary, _/binary>> = B,
     case D of
-	<<_Skip:N/binary, B1:K/binary>> ->
-	    {partial, N, K};
-	_ ->
-	    partial_find(B, D, 1 + N, K - 1)
+        <<_Skip:N/binary, B1:K/binary>> ->
+            {partial, N, K};
+        _ ->
+            partial_find(B, D, 1 + N, K - 1)
     end.
 
 find_boundary(Prefix, Data) ->
     case find_in_binary(Prefix, Data) of
-	{exact, Skip} ->
-	    PrefixSkip = Skip + size(Prefix),
-	    case Data of
-		<<_:PrefixSkip/binary, "\r\n", _/binary>> ->
-		    {next_boundary, Skip, size(Prefix) + 2};
-		<<_:PrefixSkip/binary, "--\r\n", _/binary>> ->
-		    {end_boundary, Skip, size(Prefix) + 4};
-		_ when size(Data) < PrefixSkip + 4 ->
-		    %% Underflow
-		    {maybe, Skip};
-		_ ->
-		    %% False positive
-		    not_found
-	    end;
-	{partial, Skip, Length} when (Skip + Length) =:= size(Data) ->
+        {exact, Skip} ->
+            PrefixSkip = Skip + size(Prefix),
+            case Data of
+                <<_:PrefixSkip/binary, "\r\n", _/binary>> ->
+                    {next_boundary, Skip, size(Prefix) + 2};
+                <<_:PrefixSkip/binary, "--\r\n", _/binary>> ->
+                    {end_boundary, Skip, size(Prefix) + 4};
+                _ when size(Data) < PrefixSkip + 4 ->
+                    %% Underflow
+                    {maybe, Skip};
+                _ ->
+                    %% False positive
+                    not_found
+            end;
+        {partial, Skip, Length} when (Skip + Length) =:= size(Data) ->
             %% Underflow
             {maybe, Skip};
         _ ->
-	    not_found
+            not_found
     end.
 
 with_socket_server(ServerFun, ClientFun) ->
     {ok, Server} = mochiweb_socket_server:start([{ip, "127.0.0.1"},
-						 {port, 0},
-						 {loop, ServerFun}]),
+                                                 {port, 0},
+                                                 {loop, ServerFun}]),
     Port = mochiweb_socket_server:get(Server, port),
     {ok, Client} = gen_tcp:connect("127.0.0.1", Port,
-				   [binary, {active, false}]),
+                                   [binary, {active, false}]),
     Res = (catch ClientFun(Client)),
     mochiweb_socket_server:stop(Server),
     Res.
 
 fake_request(Socket, ContentType, Length) ->
     mochiweb_request:new(Socket,
-			 'POST',
-			 "/multipart",
-			 {1,1},
-			 mochiweb_headers:make(
-			   [{"content-type", ContentType},
-			    {"content-length", Length}])).
+                         'POST',
+                         "/multipart",
+                         {1,1},
+                         mochiweb_headers:make(
+                           [{"content-type", ContentType},
+                            {"content-length", Length}])).
 
 test_callback(Expect, [Expect | Rest]) ->
     case Rest of
-	[] ->
-	    ok;
-	_ ->
-	    fun (Next) -> test_callback(Next, Rest) end
+        [] ->
+            ok;
+        _ ->
+            fun (Next) -> test_callback(Next, Rest) end
     end.
 
 test_parse3() ->
     ContentType = "multipart/form-data; boundary=---------------------------7386909285754635891697677882",
     BinContent = <<"-----------------------------7386909285754635891697677882\r\nContent-Disposition: form-data; name=\"hidden\"\r\n\r\nmultipart message\r\n-----------------------------7386909285754635891697677882\r\nContent-Disposition: form-data; name=\"file\"; filename=\"test_file.txt\"\r\nContent-Type: text/plain\r\n\r\nWoo multiline text file\n\nLa la la\r\n-----------------------------7386909285754635891697677882--\r\n">>,
     Expect = [{headers,
-	       [{"content-disposition",
-		 {"form-data", [{"name", "hidden"}]}}]},
-	      {body, <<"multipart message">>},
-	      body_end,
-	      {headers,
-	       [{"content-disposition",
-		 {"form-data", [{"name", "file"}, {"filename", "test_file.txt"}]}},
-		{"content-type", {"text/plain", []}}]},
-	      {body, <<"Woo multiline text file\n\nLa la la">>},
-	      body_end,
-	      eof],
+               [{"content-disposition",
+                 {"form-data", [{"name", "hidden"}]}}]},
+              {body, <<"multipart message">>},
+              body_end,
+              {headers,
+               [{"content-disposition",
+                 {"form-data", [{"name", "file"}, {"filename", "test_file.txt"}]}},
+                {"content-type", {"text/plain", []}}]},
+              {body, <<"Woo multiline text file\n\nLa la la">>},
+              body_end,
+              eof],
     TestCallback = fun (Next) -> test_callback(Next, Expect) end,
     ServerFun = fun (Socket) ->
-			case gen_tcp:send(Socket, BinContent) of
-			    ok ->
-				exit(normal)
-			end
-		end,
+                        case gen_tcp:send(Socket, BinContent) of
+                            ok ->
+                                exit(normal)
+                        end
+                end,
     ClientFun = fun (Socket) ->
-			Req = fake_request(Socket, ContentType,
-					   size(BinContent)),
-			Res = parse_multipart_request(Req, TestCallback),
-			{0, <<>>, ok} = Res,
-			ok
-		end,
+                        Req = fake_request(Socket, ContentType,
+                                           size(BinContent)),
+                        Res = parse_multipart_request(Req, TestCallback),
+                        {0, <<>>, ok} = Res,
+                        ok
+                end,
     ok = with_socket_server(ServerFun, ClientFun),
     ok.
 
@@ -267,31 +267,31 @@
     ContentType = "multipart/form-data; boundary=---------------------------6072231407570234361599764024",
     BinContent = <<"-----------------------------6072231407570234361599764024\r\nContent-Disposition: form-data; name=\"hidden\"\r\n\r\nmultipart message\r\n-----------------------------6072231407570234361599764024\r\nContent-Disposition: form-data; name=\"file\"; filename=\"\"\r\nContent-Type: application/octet-stream\r\n\r\n\r\n-----------------------------6072231407570234361599764024--\r\n">>,
     Expect = [{headers,
-	       [{"content-disposition",
-		 {"form-data", [{"name", "hidden"}]}}]},
-	      {body, <<"multipart message">>},
-	      body_end,
-	      {headers,
-	       [{"content-disposition",
-		 {"form-data", [{"name", "file"}, {"filename", ""}]}},
-		{"content-type", {"application/octet-stream", []}}]},
-	      {body, <<>>},
-	      body_end,
-	      eof],
+               [{"content-disposition",
+                 {"form-data", [{"name", "hidden"}]}}]},
+              {body, <<"multipart message">>},
+              body_end,
+              {headers,
+               [{"content-disposition",
+                 {"form-data", [{"name", "file"}, {"filename", ""}]}},
+                {"content-type", {"application/octet-stream", []}}]},
+              {body, <<>>},
+              body_end,
+              eof],
     TestCallback = fun (Next) -> test_callback(Next, Expect) end,
     ServerFun = fun (Socket) ->
-			case gen_tcp:send(Socket, BinContent) of
-			    ok ->
-				exit(normal)
-			end
-		end,
+                        case gen_tcp:send(Socket, BinContent) of
+                            ok ->
+                                exit(normal)
+                        end
+                end,
     ClientFun = fun (Socket) ->
-			Req = fake_request(Socket, ContentType,
-					   size(BinContent)),
-			Res = parse_multipart_request(Req, TestCallback),
-			{0, <<>>, ok} = Res,
-			ok
-		end,
+                        Req = fake_request(Socket, ContentType,
+                                           size(BinContent)),
+                        Res = parse_multipart_request(Req, TestCallback),
+                        {0, <<>>, ok} = Res,
+                        ok
+                end,
     ok = with_socket_server(ServerFun, ClientFun),
     ok.
 
@@ -312,35 +312,35 @@
     ContentType = "multipart/form-data; boundary=AaB03x",
     "AaB03x" = get_boundary(ContentType),
     Content = mochiweb_util:join(
-		["--AaB03x",
-		 "Content-Disposition: form-data; name=\"submit-name\"",
-		 "",
-		 "Larry",
-		 "--AaB03x",
-		 "Content-Disposition: form-data; name=\"files\";"
-		 ++ "filename=\"file1.txt\"",
-		 "Content-Type: text/plain",
-		 "",
-		 "... contents of file1.txt ...",
-		 "--AaB03x--",
-		 ""], "\r\n"),
+                ["--AaB03x",
+                 "Content-Disposition: form-data; name=\"submit-name\"",
+                 "",
+                 "Larry",
+                 "--AaB03x",
+                 "Content-Disposition: form-data; name=\"files\";"
+                 ++ "filename=\"file1.txt\"",
+                 "Content-Type: text/plain",
+                 "",
+                 "... contents of file1.txt ...",
+                 "--AaB03x--",
+                 ""], "\r\n"),
     BinContent = iolist_to_binary(Content),
     ServerFun = fun (Socket) ->
-			case gen_tcp:send(Socket, BinContent) of
-			    ok ->
-				exit(normal)
-			end
-		end,
+                        case gen_tcp:send(Socket, BinContent) of
+                            ok ->
+                                exit(normal)
+                        end
+                end,
     ClientFun = fun (Socket) ->
-			Req = fake_request(Socket, ContentType,
-					   size(BinContent)),
-			Res = parse_form(Req, fun handler_test/2),
+                        Req = fake_request(Socket, ContentType,
+                                           size(BinContent)),
+                        Res = parse_form(Req, fun handler_test/2),
                         [{"submit-name", "Larry"},
                          {"files", {"file1.txt", {"text/plain",[]},
                                     <<"... contents of file1.txt ...">>}
                          }] = Res,
-			ok
-		end,
+                        ok
+                end,
     ok = with_socket_server(ServerFun, ClientFun),
     ok.
 
@@ -348,45 +348,45 @@
     ContentType = "multipart/form-data; boundary=AaB03x",
     "AaB03x" = get_boundary(ContentType),
     Content = mochiweb_util:join(
-		["--AaB03x",
-		 "Content-Disposition: form-data; name=\"submit-name\"",
-		 "",
-		 "Larry",
-		 "--AaB03x",
-		 "Content-Disposition: form-data; name=\"files\";"
-		 ++ "filename=\"file1.txt\"",
-		 "Content-Type: text/plain",
-		 "",
-		 "... contents of file1.txt ...",
-		 "--AaB03x--",
-		 ""], "\r\n"),
+                ["--AaB03x",
+                 "Content-Disposition: form-data; name=\"submit-name\"",
+                 "",
+                 "Larry",
+                 "--AaB03x",
+                 "Content-Disposition: form-data; name=\"files\";"
+                 ++ "filename=\"file1.txt\"",
+                 "Content-Type: text/plain",
+                 "",
+                 "... contents of file1.txt ...",
+                 "--AaB03x--",
+                 ""], "\r\n"),
     BinContent = iolist_to_binary(Content),
     Expect = [{headers,
-	       [{"content-disposition",
-		 {"form-data", [{"name", "submit-name"}]}}]},
-	      {body, <<"Larry">>},
-	      body_end,
-	      {headers,
-	       [{"content-disposition",
-		 {"form-data", [{"name", "files"}, {"filename", "file1.txt"}]}},
-		 {"content-type", {"text/plain", []}}]},
-	      {body, <<"... contents of file1.txt ...">>},
-	      body_end,
-	      eof],
+               [{"content-disposition",
+                 {"form-data", [{"name", "submit-name"}]}}]},
+              {body, <<"Larry">>},
+              body_end,
+              {headers,
+               [{"content-disposition",
+                 {"form-data", [{"name", "files"}, {"filename", "file1.txt"}]}},
+                 {"content-type", {"text/plain", []}}]},
+              {body, <<"... contents of file1.txt ...">>},
+              body_end,
+              eof],
     TestCallback = fun (Next) -> test_callback(Next, Expect) end,
     ServerFun = fun (Socket) ->
-			case gen_tcp:send(Socket, BinContent) of
-			    ok ->
-				exit(normal)
-			end
-		end,
+                        case gen_tcp:send(Socket, BinContent) of
+                            ok ->
+                                exit(normal)
+                        end
+                end,
     ClientFun = fun (Socket) ->
-			Req = fake_request(Socket, ContentType,
-					   size(BinContent)),
-			Res = parse_multipart_request(Req, TestCallback),
-			{0, <<>>, ok} = Res,
-			ok
-		end,
+                        Req = fake_request(Socket, ContentType,
+                                           size(BinContent)),
+                        Res = parse_multipart_request(Req, TestCallback),
+                        {0, <<>>, ok} = Res,
+                        ok
+                end,
     ok = with_socket_server(ServerFun, ClientFun),
     ok.
 

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_request.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_request.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_request.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_request.erl Tue Apr 29 17:45:50 2008
@@ -29,6 +29,7 @@
 -define(SAVE_BODY_LENGTH, mochiweb_request_body_length).
 -define(SAVE_POST, mochiweb_request_post).
 -define(SAVE_COOKIE, mochiweb_request_cookie).
+-define(SAVE_FORCE_CLOSE, mochiweb_request_force_close).
 
 %% @type iolist() = [iolist() | binary() | char()].
 %% @type iodata() = binary() | iolist().
@@ -68,32 +69,32 @@
     Headers;
 get(peer) ->
     case inet:peername(Socket) of
-	{ok, {Addr={10, _, _, _}, _Port}} ->
-	    case get_header_value("x-forwarded-for") of
-		undefined ->
-		    inet_parse:ntoa(Addr);
-		Hosts ->
-		    string:strip(lists:last(string:tokens(Hosts, ",")))
-	    end;
-	{ok, {{127, 0, 0, 1}, _Port}} ->
-	    case get_header_value("x-forwarded-for") of
-		undefined ->
-		    "127.0.0.1";
-		Hosts ->
-		    string:strip(lists:last(string:tokens(Hosts, ",")))
-	    end;
-	{ok, {Addr, _Port}} ->
-	    inet_parse:ntoa(Addr)
+        {ok, {Addr={10, _, _, _}, _Port}} ->
+            case get_header_value("x-forwarded-for") of
+                undefined ->
+                    inet_parse:ntoa(Addr);
+                Hosts ->
+                    string:strip(lists:last(string:tokens(Hosts, ",")))
+            end;
+        {ok, {{127, 0, 0, 1}, _Port}} ->
+            case get_header_value("x-forwarded-for") of
+                undefined ->
+                    "127.0.0.1";
+                Hosts ->
+                    string:strip(lists:last(string:tokens(Hosts, ",")))
+            end;
+        {ok, {Addr, _Port}} ->
+            inet_parse:ntoa(Addr)
     end;
 get(path) ->
     case erlang:get(?SAVE_PATH) of
-	undefined ->
-	    {Path0, _, _} = mochiweb_util:urlsplit_path(RawPath),
+        undefined ->
+            {Path0, _, _} = mochiweb_util:urlsplit_path(RawPath),
             Path = mochiweb_util:unquote(Path0),
-	    put(?SAVE_PATH, Path),
-	    Path;
-	Cached ->
-	    Cached
+            put(?SAVE_PATH, Path),
+            Path;
+        Cached ->
+            Cached
     end;
 get(body_length) ->
     erlang:get(?SAVE_BODY_LENGTH);
@@ -110,18 +111,18 @@
 %%      for debugging/inspection purposes.
 dump() ->
     {?MODULE, [{method, Method},
-	       {version, Version},
-	       {raw_path, RawPath},
-	       {headers, mochiweb_headers:to_list(Headers)}]}.
+               {version, Version},
+               {raw_path, RawPath},
+               {headers, mochiweb_headers:to_list(Headers)}]}.
 
 %% @spec send(iodata()) -> ok
 %% @doc Send data over the socket.
 send(Data) ->
     case gen_tcp:send(Socket, Data) of
-	ok ->
-	    ok;
-	_ ->
-	    exit(normal)
+        ok ->
+            ok;
+        _ ->
+            exit(normal)
     end.
 
 %% @spec recv(integer()) -> binary()
@@ -135,11 +136,11 @@
 %%      Timeout in msec.
 recv(Length, Timeout) ->
     case gen_tcp:recv(Socket, Length, Timeout) of
-	{ok, Data} ->
-	    put(?SAVE_RECV, true),
-	    Data;
-	_ ->
-	    exit(normal)
+        {ok, Data} ->
+            put(?SAVE_RECV, true),
+            Data;
+        _ ->
+            exit(normal)
     end.
 
 %% @spec body_length() -> undefined | chunked | unknown_transfer_encoding | integer()
@@ -201,7 +202,7 @@
 start_response({Code, ResponseHeaders}) ->
     HResponse = mochiweb_headers:make(ResponseHeaders),
     HResponse1 = mochiweb_headers:default_from_list(server_headers(),
-						    HResponse),
+                                                    HResponse),
     start_raw_response({Code, HResponse1}).
 
 %% @spec start_raw_response({integer(), headers()}) -> response()
@@ -209,10 +210,10 @@
 %%      ResponseHeaders.
 start_raw_response({Code, ResponseHeaders}) ->
     F = fun ({K, V}, Acc) ->
-		[make_io(K), <<": ">>, V, <<"\r\n">> | Acc]
-	end,
+                [make_io(K), <<": ">>, V, <<"\r\n">> | Acc]
+        end,
     End = lists:foldl(F, [<<"\r\n">>],
-		      mochiweb_headers:to_list(ResponseHeaders)),
+                      mochiweb_headers:to_list(ResponseHeaders)),
     send([make_version(Version), make_code(Code), <<"\r\n">> | End]),
     mochiweb:new_response({THIS, Code, ResponseHeaders}).
 
@@ -245,24 +246,32 @@
 respond({Code, ResponseHeaders, chunked}) ->
     HResponse = mochiweb_headers:make(ResponseHeaders),
     HResponse1 = case Method of
-		     'HEAD' ->
-			 %% This is what Google does, http://www.google.com/
-			 %% is chunked but HEAD gets Content-Length: 0.
-			 %% The RFC is ambiguous so emulating Google is smart.
-			 mochiweb_headers:enter("Content-Length", "0",
-						HResponse);
-		     _ ->
-			 mochiweb_headers:enter("Transfer-Encoding", "chunked",
-						HResponse)
-		 end,
+                     'HEAD' ->
+                         %% This is what Google does, http://www.google.com/
+                         %% is chunked but HEAD gets Content-Length: 0.
+                         %% The RFC is ambiguous so emulating Google is smart.
+                         mochiweb_headers:enter("Content-Length", "0",
+                                                HResponse);
+                     _ when Version >= {1, 1} ->
+                         %% Only use chunked encoding for HTTP/1.1
+                         mochiweb_headers:enter("Transfer-Encoding", "chunked",
+                                                HResponse);
+                     _ ->
+                         %% For pre-1.1 clients we send the data as-is
+                         %% without a Content-Length header and without
+                         %% chunk delimiters. Since the end of the document
+                         %% is now ambiguous we must force a close.
+                         put(?SAVE_FORCE_CLOSE, true),
+                         HResponse
+                 end,
     start_response({Code, HResponse1});
 respond({Code, ResponseHeaders, Body}) ->
     Response = start_response_length({Code, ResponseHeaders, iolist_size(Body)}),
     case Method of
-	'HEAD' ->
-	    ok;
-	_ ->
-	    send(Body)
+        'HEAD' ->
+            ok;
+        _ ->
+            send(Body)
     end,
     Response.
 
@@ -306,40 +315,42 @@
 %% @doc Return true if the connection must be closed. If false, using
 %%      Keep-Alive should be safe.
 should_close() ->
+    ForceClose = erlang:get(mochiweb_request_force_close) =/= undefined,
     DidNotRecv = erlang:get(mochiweb_request_recv) =:= undefined,
-    Version < {1, 0}
-        % Connection: close
-	orelse get_header_value("connection") =:= "close"
-        % HTTP 1.0 requires Connection: Keep-Alive
-	orelse (Version =:= {1, 0}
-		andalso get_header_value("connection") /= "Keep-Alive")
-        % unread data left on the socket, can't safely continue
-	orelse (DidNotRecv
-		andalso get_header_value("content-length") /= undefined).
+    ForceClose orelse Version < {1, 0}
+        %% Connection: close
+        orelse get_header_value("connection") =:= "close"
+        %% HTTP 1.0 requires Connection: Keep-Alive
+        orelse (Version =:= {1, 0}
+                andalso get_header_value("connection") =/= "Keep-Alive")
+        %% unread data left on the socket, can't safely continue
+        orelse (DidNotRecv
+                andalso get_header_value("content-length") =/= undefined).
 
 %% @spec cleanup() -> ok
 %% @doc Clean up any junk in the process dictionary, required before continuing
 %%      a Keep-Alive request.
 cleanup() ->
     [erase(K) || K <- [?SAVE_QS,
-		       ?SAVE_PATH,
-		       ?SAVE_RECV,
-		       ?SAVE_BODY,
-		       ?SAVE_POST,
-		       ?SAVE_COOKIE]],
+                       ?SAVE_PATH,
+                       ?SAVE_RECV,
+                       ?SAVE_BODY,
+                       ?SAVE_POST,
+                       ?SAVE_COOKIE,
+                       ?SAVE_FORCE_CLOSE]],
     ok.
 
 %% @spec parse_qs() -> [{Key::string(), Value::string()}]
 %% @doc Parse the query string of the URL.
 parse_qs() ->
     case erlang:get(?SAVE_QS) of
-	undefined ->
-	    {_, QueryString, _} = mochiweb_util:urlsplit_path(RawPath),
-	    Parsed = mochiweb_util:parse_qs(QueryString),
-	    put(?SAVE_QS, Parsed),
-	    Parsed;
-	Cached ->
-	    Cached
+        undefined ->
+            {_, QueryString, _} = mochiweb_util:urlsplit_path(RawPath),
+            Parsed = mochiweb_util:parse_qs(QueryString),
+            put(?SAVE_QS, Parsed),
+            Parsed;
+        Cached ->
+            Cached
     end.
 
 %% @spec get_cookie_value(Key::string) -> string() | undefined
@@ -351,17 +362,17 @@
 %% @doc Parse the cookie header.
 parse_cookie() ->
     case erlang:get(?SAVE_COOKIE) of
-	undefined ->
-	    Cookies = case get_header_value("cookie") of
-			  undefined ->
-			      [];
-			  Value ->
-			      mochiweb_cookies:parse_cookie(Value)
-		      end,
-	    put(?SAVE_COOKIE, Cookies),
-	    Cookies;
-	Cached ->
-	    Cached
+        undefined ->
+            Cookies = case get_header_value("cookie") of
+                          undefined ->
+                              [];
+                          Value ->
+                              mochiweb_cookies:parse_cookie(Value)
+                      end,
+            put(?SAVE_COOKIE, Cookies),
+            Cookies;
+        Cached ->
+            Cached
     end.
 
 %% @spec parse_post() -> [{Key::string(), Value::string()}]
@@ -369,33 +380,33 @@
 %%      has the side-effect of calling recv_body().
 parse_post() ->
     case erlang:get(?SAVE_POST) of
-	undefined ->
-	    Parsed = case recv_body() of
-			 undefined ->
-			     [];
-			 Binary ->
-			     case get_primary_header_value("content-type") of
-				 "application/x-www-form-urlencoded" ->
-				     mochiweb_util:parse_qs(Binary);
-				 _ ->
-				     []
-			     end
-		     end,
-	    put(?SAVE_POST, Parsed),
-	    Parsed;
-	Cached ->
-	    Cached
+        undefined ->
+            Parsed = case recv_body() of
+                         undefined ->
+                             [];
+                         Binary ->
+                             case get_primary_header_value("content-type") of
+                                 "application/x-www-form-urlencoded" ->
+                                     mochiweb_util:parse_qs(Binary);
+                                 _ ->
+                                     []
+                             end
+                     end,
+            put(?SAVE_POST, Parsed),
+            Parsed;
+        Cached ->
+            Cached
     end.
 
 read_chunked_body(Max, Acc) ->
     case read_chunk_length() of
-	0 ->
-	    read_chunk(0),
-	    iolist_to_binary(lists:reverse(Acc));
-	Length when Length > Max ->
-	    exit({body_too_large, chunked});
-	Length ->
-	    read_chunked_body(Max - Length, [read_chunk(Length) | Acc])
+        0 ->
+            read_chunk(0),
+            iolist_to_binary(lists:reverse(Acc));
+        Length when Length > Max ->
+            exit({body_too_large, chunked});
+        Length ->
+            read_chunked_body(Max - Length, [read_chunk(Length) | Acc])
     end.
 
 %% @spec read_chunk_length() -> integer()
@@ -421,14 +432,14 @@
     inet:setopts(Socket, [{packet, line}]),
     F = fun (F1, Acc) ->
                 case gen_tcp:recv(Socket, 0, ?IDLE_TIMEOUT) of
-		    {ok, <<"\r\n">>} ->
-			Acc;
-		    {ok, Footer} ->
-			F1(F1, [Footer | Acc]);
+                    {ok, <<"\r\n">>} ->
+                        Acc;
+                    {ok, Footer} ->
+                        F1(F1, [Footer | Acc]);
                     _ ->
                         exit(normal)
-		end
-	end,
+                end
+        end,
     Footers = F(F, []),
     inet:setopts(Socket, [{packet, raw}]),
     Footers;
@@ -445,24 +456,35 @@
 serve_file(Path, DocRoot) ->
     FullPath = filename:join([DocRoot, Path]),
     File = case filelib:is_dir(FullPath) of
-	       true ->
-		   filename:join([FullPath, "index.html"]);
-	       false ->
-		   FullPath
-	   end,
+               true ->
+                   filename:join([FullPath, "index.html"]);
+               false ->
+                   FullPath
+           end,
     case lists:prefix(DocRoot, File) of
-	true ->
-	    case file:open(File, [raw, binary]) of
-		{ok, IoDevice} ->
-		    ContentType = mochiweb_util:guess_mime(File),
-		    Res = ok({ContentType, {file, IoDevice}}),
-                    file:close(IoDevice),
-                    Res;
-		_ ->
-		    not_found()
-	    end;
-	false ->
-	    not_found()
+        true ->
+            case file:read_file_info(File) of
+                {ok, FileInfo} ->
+                    LastModified = httpd_util:rfc1123_date(FileInfo#file_info.mtime),
+                    case get_header_value("if-modified-since") of
+                        LastModified ->
+                            respond({304, [], ""});
+                        _ ->
+                            case file:open(File, [raw, binary]) of
+                                {ok, IoDevice} ->
+                                    ContentType = mochiweb_util:guess_mime(File),
+                                    Res = ok({ContentType, [{"last-modified", LastModified}], {file, IoDevice}}),
+                                    file:close(IoDevice),
+                                    Res;
+                                _ ->
+                                    not_found()
+                            end
+                    end;
+                {error, _} ->
+                    not_found()
+            end;
+        false ->
+            not_found()
     end.
 
 

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_response.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_response.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_response.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_response.erl Tue Apr 29 17:45:50 2008
@@ -37,16 +37,21 @@
 %% @doc Send data over the socket if the method is not HEAD.
 send(Data) ->
     case Request:get(method) of
-	'HEAD' ->
-	    ok;
-	_ ->
-	    Request:send(Data)
+        'HEAD' ->
+            ok;
+        _ ->
+            Request:send(Data)
     end.
 
 %% @spec write_chunk(iodata()) -> ok
 %% @doc Write a chunk of a HTTP chunked response. If Data is zero length,
 %%      then the chunked response will be finished.
 write_chunk(Data) ->
-    Length = iolist_size(Data),    
-    send(io_lib:format("~.16b\r\n", [Length])),
-    send([Data, <<"\r\n">>]).
+    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(Data)
+    end.

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_socket_server.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_socket_server.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_socket_server.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_socket_server.erl Tue Apr 29 17:45:50 2008
@@ -9,19 +9,19 @@
 
 -export([start/1, stop/1]).
 -export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
-	 handle_info/2]).
+         handle_info/2]).
 -export([get/2]).
 
 -export([acceptor_loop/1]).
 
 -record(mochiweb_socket_server,
-	{port,
-	 loop,
-	 name=undefined,
-	 max=2048,
-	 ip=any,
-	 listen=null,
-	 acceptor=null,
+        {port,
+         loop,
+         name=undefined,
+         max=2048,
+         ip=any,
+         listen=null,
+         acceptor=null,
          backlog=30}).
 
 start(State=#mochiweb_socket_server{}) ->
@@ -66,14 +66,14 @@
     parse_options(Rest, State#mochiweb_socket_server{port=Port});
 parse_options([{ip, Ip} | Rest], State) ->
     ParsedIp = case Ip of
-		   any ->
-		       any;
-		   Ip when is_tuple(Ip) ->
-		       Ip;
-		   Ip when is_list(Ip) ->
-		       {ok, IpTuple} = inet_parse:address(Ip),
-		       IpTuple
-	       end,
+                   any ->
+                       any;
+                   Ip when is_tuple(Ip) ->
+                       Ip;
+                   Ip when is_list(Ip) ->
+                       {ok, IpTuple} = inet_parse:address(Ip),
+                       IpTuple
+               end,
     parse_options(Rest, State#mochiweb_socket_server{ip=ParsedIp});
 parse_options([{loop, Loop} | Rest], State) ->
     parse_options(Rest, State#mochiweb_socket_server{loop=Loop});
@@ -81,35 +81,35 @@
     parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog});
 parse_options([{max, Max} | Rest], State) ->
     MaxInt = case Max of
-		 Max when is_list(Max) ->
-		     list_to_integer(Max);
-		 Max when is_integer(Max) ->
-		     Max
-	     end,
+                 Max when is_list(Max) ->
+                     list_to_integer(Max);
+                 Max when is_integer(Max) ->
+                     Max
+             end,
     parse_options(Rest, State#mochiweb_socket_server{max=MaxInt}).
 
 start_server(State=#mochiweb_socket_server{name=Name}) ->
     case Name of
-	undefined ->
-	    gen_server:start_link(?MODULE, State, []);
-	_ ->
-	    gen_server:start_link(Name, ?MODULE, State, [])
+        undefined ->
+            gen_server:start_link(?MODULE, State, []);
+        _ ->
+            gen_server:start_link(Name, ?MODULE, State, [])
     end.
 
 init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog}) ->
     process_flag(trap_exit, true),
     BaseOpts = [binary, 
-		{reuseaddr, true},
-		{packet, 0},
-		{backlog, Backlog},
-		{recbuf, 8192},
-		{active, false}],
+                {reuseaddr, true},
+                {packet, 0},
+                {backlog, Backlog},
+                {recbuf, 8192},
+                {active, false}],
     Opts = case Ip of
-	       any ->
-		   BaseOpts;
-	       Ip ->
-		   [{ip, Ip} | BaseOpts]
-	   end,
+               any ->
+                   BaseOpts;
+               Ip ->
+                   [{ip, Ip} | BaseOpts]
+           end,
     case gen_tcp_listen(Port, Opts, State) of
         {stop, eacces} ->
             case Port < 1024 of 
@@ -135,11 +135,11 @@
 gen_tcp_listen(Port, Opts, State) ->
     case gen_tcp:listen(Port, Opts) of
         {ok, Listen} ->
-      	    {ok, ListenPort} = inet:port(Listen),
-       	    {ok, new_acceptor(State#mochiweb_socket_server{listen=Listen, 
+            {ok, ListenPort} = inet:port(Listen),
+            {ok, new_acceptor(State#mochiweb_socket_server{listen=Listen, 
                                                            port=ListenPort})};
-      	{error, Reason} ->
-       	    {stop, Reason}
+        {error, Reason} ->
+            {stop, Reason}
     end.
 
 new_acceptor(State=#mochiweb_socket_server{max=0}) ->
@@ -147,7 +147,7 @@
     State#mochiweb_socket_server{acceptor=null};
 new_acceptor(State=#mochiweb_socket_server{listen=Listen,loop=Loop}) ->
     Pid = proc_lib:spawn_link(?MODULE, acceptor_loop,
-			      [{self(), Listen, Loop}]),
+                              [{self(), Listen, Loop}]),
     State#mochiweb_socket_server{acceptor=Pid}.
 
 call_loop({M, F}, Socket) ->
@@ -157,19 +157,19 @@
 
 acceptor_loop({Server, Listen, Loop}) ->
     case catch gen_tcp:accept(Listen) of
-	{ok, Socket} ->
-	    gen_server:cast(Server, {accepted, self()}),
-	    call_loop(Loop, Socket);
-	{error, closed} ->
-	    exit({error, closed});
-	Other ->
-	    error_logger:error_report(
-	      [{application, mochiweb},
-	       "Accept failed error",
-	       lists:flatten(io_lib:format("~p", [Other]))]),
-	    exit({error, accept_failed})
+        {ok, Socket} ->
+            gen_server:cast(Server, {accepted, self()}),
+            call_loop(Loop, Socket);
+        {error, closed} ->
+            exit({error, closed});
+        Other ->
+            error_logger:error_report(
+              [{application, mochiweb},
+               "Accept failed error",
+               lists:flatten(io_lib:format("~p", [Other]))]),
+            exit({error, accept_failed})
     end.
-	    
+            
 
 do_get(port, #mochiweb_socket_server{port=Port}) ->
     Port.
@@ -182,7 +182,7 @@
     {reply, Res, State}.
 
 handle_cast({accepted, Pid},
-	    State=#mochiweb_socket_server{acceptor=Pid, max=Max}) ->
+            State=#mochiweb_socket_server{acceptor=Pid, max=Max}) ->
     % io:format("accepted ~p~n", [Pid]),
     State1 = State#mochiweb_socket_server{max=Max - 1},
     {noreply, new_acceptor(State1)};
@@ -203,31 +203,31 @@
     State.
 
 handle_info({'EXIT', Pid, normal},
-	    State=#mochiweb_socket_server{acceptor=Pid}) ->
+            State=#mochiweb_socket_server{acceptor=Pid}) ->
     % io:format("normal acceptor down~n"),
     {noreply, new_acceptor(State)};
 handle_info({'EXIT', Pid, Reason},
-	    State=#mochiweb_socket_server{acceptor=Pid}) ->
+            State=#mochiweb_socket_server{acceptor=Pid}) ->
     error_logger:error_report({?MODULE, ?LINE,
-			       {acceptor_error, Reason}}),
+                               {acceptor_error, Reason}}),
     timer:sleep(100),
     {noreply, new_acceptor(State)};
 handle_info({'EXIT', _LoopPid, Reason},
-	    State=#mochiweb_socket_server{acceptor=Pid, max=Max}) ->
+            State=#mochiweb_socket_server{acceptor=Pid, max=Max}) ->
     case Reason of 
-	normal ->
-	    ok;
-	_ ->
-	    error_logger:error_report({?MODULE, ?LINE,
-				       {child_error, Reason}})
+        normal ->
+            ok;
+        _ ->
+            error_logger:error_report({?MODULE, ?LINE,
+                                       {child_error, Reason}})
     end,
     State1 = State#mochiweb_socket_server{max=Max + 1},
     State2 = case Pid of
-		 null ->
-		     new_acceptor(State1);
-		 _ ->
-		     State1
-	     end,
+                 null ->
+                     new_acceptor(State1);
+                 _ ->
+                     State1
+             end,
     {noreply, State2};
 handle_info(Info, State) ->
     error_logger:info_report([{'INFO', Info}, {'State', State}]),

Modified: incubator/couchdb/trunk/src/mochiweb/mochiweb_util.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/mochiweb_util.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/mochiweb_util.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/mochiweb_util.erl Tue Apr 29 17:45:50 2008
@@ -16,13 +16,13 @@
 -define(PERCENT, 37).  % $\%
 -define(FULLSTOP, 46). % $\.
 -define(IS_HEX(C), ((C >= $0 andalso C =< $9) orelse
-		    (C >= $a andalso C =< $f) orelse
-		    (C >= $A andalso C =< $F))).
+                    (C >= $a andalso C =< $f) orelse
+                    (C >= $A andalso C =< $F))).
 -define(QS_SAFE(C), ((C >= $a andalso C =< $z) orelse
-		     (C >= $A andalso C =< $Z) orelse
-		     (C >= $0 andalso C =< $9) orelse
-		     (C =:= ?FULLSTOP orelse C =:= $- orelse C =:= $~ orelse
-		      C =:= $_))).
+                     (C >= $A andalso C =< $Z) orelse
+                     (C >= $0 andalso C =< $9) orelse
+                     (C =:= ?FULLSTOP orelse C =:= $- orelse C =:= $~ orelse
+                      C =:= $_))).
 
 hexdigit(C) when C < 10 -> $0 + C;
 hexdigit(C) when C < 16 -> $A + (C - 10).
@@ -92,8 +92,8 @@
 %% @doc URL encode the property list.
 urlencode(Props) ->
     RevPairs = lists:foldl(fun ({K, V}, Acc) ->
-				   [[quote_plus(K), $=, quote_plus(V)] | Acc]
-			   end, [], Props),
+                                   [[quote_plus(K), $=, quote_plus(V)] | Acc]
+                           end, [], Props),
     lists:flatten(revjoin(RevPairs, $&, [])).
 
 %% @spec parse_qs(string() | binary()) -> [{Key, Value}]
@@ -204,15 +204,15 @@
 %% @doc Assemble a URL from the 5-tuple. Path must be absolute.
 urlunsplit({Scheme, Netloc, Path, Query, Fragment}) ->
     lists:flatten([case Scheme of "" -> "";  _ -> [Scheme, "://"] end,
-		   Netloc,
-		   urlunsplit_path({Path, Query, Fragment})]).
+                   Netloc,
+                   urlunsplit_path({Path, Query, Fragment})]).
 
 %% @spec urlunsplit_path({Path, Query, Fragment}) -> string()
 %% @doc Assemble a URL path from the 3-tuple.
 urlunsplit_path({Path, Query, Fragment}) ->
     lists:flatten([Path,
-		   case Query of "" -> ""; _ -> [$? | Query] end,
-		   case Fragment of "" -> ""; _ -> [$# | Fragment] end]).
+                   case Query of "" -> ""; _ -> [$? | Query] end,
+                   case Fragment of "" -> ""; _ -> [$# | Fragment] end]).
 
 %% @spec urlsplit_path(Url) -> {Path, Query, Fragment}
 %% @doc Return a 3-tuple, does not expand % escapes. Only supports HTTP style
@@ -244,36 +244,36 @@
 %% @doc  Guess the mime type of a file by the extension of its filename.
 guess_mime(File) ->
     case filename:extension(File) of
-	".html" ->
-	    "text/html";
-	".xhtml" ->
-	    "application/xhtml+xml";
-	".xml" ->
-	    "application/xml";
-	".css" ->
-	    "text/css";
-	".js" ->
-	    "application/x-javascript";
-	".jpg" ->
-	    "image/jpeg";
-	".gif" ->
-	    "image/gif";
-	".png" ->
-	    "image/png";
-	".swf" ->
-	    "application/x-shockwave-flash";
-	".zip" ->
-	    "application/zip";
-	".bz2" ->
-	    "application/x-bzip2";
-	".gz" ->
-	    "application/x-gzip";
-	".tar" ->
-	    "application/x-tar";
-	".tgz" ->
-	    "application/x-gzip";
-	".txt" ->
-	    "text/plain";
+        ".html" ->
+            "text/html";
+        ".xhtml" ->
+            "application/xhtml+xml";
+        ".xml" ->
+            "application/xml";
+        ".css" ->
+            "text/css";
+        ".js" ->
+            "application/x-javascript";
+        ".jpg" ->
+            "image/jpeg";
+        ".gif" ->
+            "image/gif";
+        ".png" ->
+            "image/png";
+        ".swf" ->
+            "application/x-shockwave-flash";
+        ".zip" ->
+            "application/zip";
+        ".bz2" ->
+            "application/x-bzip2";
+        ".gz" ->
+            "application/x-gzip";
+        ".tar" ->
+            "application/x-tar";
+        ".tgz" ->
+            "application/x-gzip";
+        ".txt" ->
+            "text/plain";
         ".doc" ->
             "application/msword";
         ".pdf" ->
@@ -314,18 +314,18 @@
     %%       Should parse properly like mochiweb_cookies.
     [Type | Parts] = [string:strip(S) || S <- string:tokens(String, ";")],
     F = fun (S, Acc) ->
-		case lists:splitwith(fun (C) -> C =/= $= end, S) of
-		    {"", _} ->
-			%% Skip anything with no name
-			Acc;
-		    {_, ""} ->
-			%% Skip anything with no value
-			Acc;
-		    {Name, [$\= | Value]} ->
-			[{string:to_lower(string:strip(Name)),
-			  unquote_header(string:strip(Value))} | Acc]
-		end
-	end,
+                case lists:splitwith(fun (C) -> C =/= $= end, S) of
+                    {"", _} ->
+                        %% Skip anything with no name
+                        Acc;
+                    {_, ""} ->
+                        %% Skip anything with no value
+                        Acc;
+                    {Name, [$\= | Value]} ->
+                        [{string:to_lower(string:strip(Name)),
+                          unquote_header(string:strip(Value))} | Acc]
+                end
+        end,
     {string:to_lower(Type),
      lists:foldr(F, [], Parts)}.
 
@@ -401,7 +401,7 @@
 
 test_parse_header() ->
     {"multipart/form-data", [{"boundary", "AaB03x"}]} =
-	parse_header("multipart/form-data; boundary=AaB03x"),
+        parse_header("multipart/form-data; boundary=AaB03x"),
     ok.
 
 test_guess_mime() ->
@@ -422,7 +422,7 @@
 test_urlsplit() ->
     {"", "", "/foo", "", "bar?baz"} = urlsplit("/foo#bar?baz"),
     {"http", "host:port", "/foo", "", "bar?baz"} =
-	urlsplit("http://host:port/foo#bar?baz"),
+        urlsplit("http://host:port/foo#bar?baz"),
     ok.
 
 test_urlsplit_path() ->
@@ -437,7 +437,7 @@
 test_urlunsplit() ->
     "/foo#bar?baz" = urlunsplit({"", "", "/foo", "", "bar?baz"}),
     "http://host:port/foo#bar?baz" =
-	urlunsplit({"http", "host:port", "/foo", "", "bar?baz"}),
+        urlunsplit({"http", "host:port", "/foo", "", "bar?baz"}),
     ok.
 
 test_urlunsplit_path() ->
@@ -476,11 +476,11 @@
 
 test_urlencode() ->
     "foo=bar&baz=wibble+%0D%0A&z=1" = urlencode([{foo, "bar"},
-						 {"baz", "wibble \r\n"},
-						 {z, 1}]),
+                                                 {"baz", "wibble \r\n"},
+                                                 {z, 1}]),
     ok.
 
 test_parse_qs() ->
     [{"foo", "bar"}, {"baz", "wibble \r\n"}, {"z", "1"}] =
-	parse_qs("foo=bar&baz=wibble+%0D%0A&z=1"),
+        parse_qs("foo=bar&baz=wibble+%0D%0A&z=1"),
     ok.

Modified: incubator/couchdb/trunk/src/mochiweb/reloader.erl
URL: http://svn.apache.org/viewvc/incubator/couchdb/trunk/src/mochiweb/reloader.erl?rev=652206&r1=652205&r2=652206&view=diff
==============================================================================
--- incubator/couchdb/trunk/src/mochiweb/reloader.erl (original)
+++ incubator/couchdb/trunk/src/mochiweb/reloader.erl Tue Apr 29 17:45:50 2008
@@ -80,16 +80,7 @@
     [case file:read_file_info(Filename) of
          {ok, FileInfo} when FileInfo#file_info.mtime >= From,
                              FileInfo#file_info.mtime < To ->
-             io:format("Reloading ~p ...", [Module]),
-             code:purge(Module),
-             case code:load_file(Module) of
-                 {module, Module} ->
-                     io:format(" ok.~n"),
-                     reload;
-                 {error, Reason} ->
-                     io:format(" ~p.~n", [Reason]),
-                     error
-             end;
+             reload(Module);
          {ok, _} ->
              unmodified;
          {error, enoent} ->
@@ -103,5 +94,31 @@
              error
      end || {Module, Filename} <- code:all_loaded(), is_list(Filename)].
 
+reload(Module) ->
+    io:format("Reloading ~p ...", [Module]),
+    code:purge(Module),
+    case code:load_file(Module) of
+        {module, Module} ->
+            io:format(" ok.~n"),
+            case erlang:function_exported(Module, test, 0) of
+                true ->
+                    io:format(" - Calling ~p:test() ...", [Module]),
+                    case catch Module:test() of
+                        ok ->
+                            io:format(" ok.~n"),
+                            reload;
+                        Reason ->
+                            io:format(" fail: ~p.~n", [Reason]),
+                            reload_but_test_failed
+                    end;
+                false ->
+                    reload
+            end;
+        {error, Reason} ->
+            io:format(" fail: ~p.~n", [Reason]),
+            error
+    end.
+
+
 stamp() ->
     erlang:localtime().