You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2014/08/07 17:37:54 UTC

[32/50] couch commit: updated refs/heads/windsor-merge to 6e60cbe

Improve responses for bad multipart/mime requests

This changes a number of possible errors in multipart/mime requests to
correctly report a "400 Bad Request" instead of crashing and giving the
client a "500 Internal Server Error". This works by monitoring the
parser process and checking for a host of new exit reasons.


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

Branch: refs/heads/windsor-merge
Commit: a9f5c8303e6efd0b1302a9135740610a6b3ef156
Parents: 5be71f7
Author: Mike Wallace <mi...@googlemail.com>
Authored: Thu Aug 29 15:33:16 2013 +0100
Committer: Robert Newson <rn...@apache.org>
Committed: Wed Aug 6 12:19:11 2014 +0100

----------------------------------------------------------------------
 src/couch_db.erl    |  8 +++++++-
 src/couch_doc.erl   | 19 +++++++++++++++----
 src/couch_httpd.erl | 10 ++++++++--
 3 files changed, 30 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a9f5c830/src/couch_db.erl
----------------------------------------------------------------------
diff --git a/src/couch_db.erl b/src/couch_db.erl
index 836b468..c9dc8e4 100644
--- a/src/couch_db.erl
+++ b/src/couch_db.erl
@@ -1190,8 +1190,14 @@ with_stream(Fd, #att{md5=InMd5,type=Type,encoding=Enc}=Att, Fun) ->
 
 write_streamed_attachment(_Stream, _F, 0) ->
     ok;
+write_streamed_attachment(_Stream, _F, LenLeft) when LenLeft < 0 ->
+    throw({bad_request, <<"attachment longer than expected">>});
 write_streamed_attachment(Stream, F, LenLeft) when LenLeft > 0 ->
-    Bin = read_next_chunk(F, LenLeft),
+    Bin = try read_next_chunk(F, LenLeft)
+    catch
+        {mp_parser_died, normal} ->
+            throw({bad_request, <<"attachment shorter than expected">>})
+    end,
     ok = couch_stream:write(Stream, Bin),
     write_streamed_attachment(Stream, F, LenLeft - size(Bin)).
 

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a9f5c830/src/couch_doc.erl
----------------------------------------------------------------------
diff --git a/src/couch_doc.erl b/src/couch_doc.erl
index 14f6a4f..9263ba3 100644
--- a/src/couch_doc.erl
+++ b/src/couch_doc.erl
@@ -595,7 +595,7 @@ doc_from_multi_part_stream(ContentType, DataFun) ->
 doc_from_multi_part_stream(ContentType, DataFun, Ref) ->
     Parent = self(),
     NumMpWriters = num_mp_writers(),
-    Parser = spawn_link(fun() ->
+    {Parser, ParserRef} = spawn_monitor(fun() ->
         ParentRef = erlang:monitor(process, Parent),
         put(mp_parent_ref, ParentRef),
         put(num_mp_writers, NumMpWriters),
@@ -604,7 +604,6 @@ doc_from_multi_part_stream(ContentType, DataFun, Ref) ->
             fun(Next) -> mp_parse_doc(Next, []) end),
         unlink(Parent)
         end),
-    ParserRef = erlang:monitor(process, Parser),
     Parser ! {get_doc_bytes, Ref, self()},
     receive
     {started_open_doc_revs, NewRef} ->
@@ -623,7 +622,17 @@ doc_from_multi_part_stream(ContentType, DataFun, Ref) ->
             receive {'DOWN', ParserRef, _, _, _} -> ok end,
             erlang:put(mochiweb_request_recv, true)
         end,
-        {ok, Doc#doc{atts=Atts2}, WaitFun, Parser}
+        {ok, Doc#doc{atts=Atts2}, WaitFun, Parser};
+    {'DOWN', ParserRef, _, _, normal} ->
+        ok;
+    {'DOWN', ParserRef, process, Parser, {{nocatch, {Error, Msg}}, _}} ->
+        ?LOG_ERROR("Multipart streamer ~p died with reason ~p",
+                    [ParserRef, Msg]),
+        throw({Error, Msg});
+    {'DOWN', ParserRef, _, _, Reason} ->
+        ?LOG_ERROR("Multipart streamer ~p died with reason ~p",
+                    [ParserRef, Reason]),
+        throw({error, Reason})
     end.
 
 
@@ -632,7 +641,9 @@ mp_parse_doc({headers, H}, []) ->
     {"application/json", _} ->
         fun (Next) ->
             mp_parse_doc(Next, [])
-        end
+        end;
+    _ ->
+        throw({bad_ctype, <<"Content-Type must be application/json">>})
     end;
 mp_parse_doc({body, Bytes}, AccBytes) ->
     fun (Next) ->

http://git-wip-us.apache.org/repos/asf/couchdb-couch/blob/a9f5c830/src/couch_httpd.erl
----------------------------------------------------------------------
diff --git a/src/couch_httpd.erl b/src/couch_httpd.erl
index 437ef08..8022a02 100644
--- a/src/couch_httpd.erl
+++ b/src/couch_httpd.erl
@@ -990,8 +990,14 @@ get_boundary(ContentType) ->
 split_header(<<>>) ->
     [];
 split_header(Line) ->
-    {Name, [$: | Value]} = lists:splitwith(fun (C) -> C =/= $: end,
-                                           binary_to_list(Line)),
+    {Name, Rest} = lists:splitwith(fun (C) -> C =/= $: end,
+                                   binary_to_list(Line)),
+    [$: | Value] = case Rest of
+        [] ->
+            throw({bad_request, <<"bad part header">>});
+        Res ->
+            Res
+    end,
     [{string:to_lower(string:strip(Name)),
      mochiweb_util:parse_header(Value)}].