Updated Branches: refs/heads/1368-fix-multipart-header-parts 0a004e573 -> a67308e32 (forced update)
Send attachment headers in multipart responses Closes COUCHDB-1368 Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/a67308e3 Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/a67308e3 Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/a67308e3 Branch: refs/heads/1368-fix-multipart-header-parts Commit: a67308e32f6c686e359026d8ab03855cd1fd0bf2 Parents: d7f2037 Author: Jan Lehnardt <[email protected]> Authored: Wed Nov 14 14:59:58 2012 +0100 Committer: Jan Lehnardt <[email protected]> Committed: Wed Nov 14 22:04:31 2012 +0100 ---------------------------------------------------------------------- share/www/script/test/attachments_multipart.js | 29 ++++++++--- src/couchdb/couch_doc.erl | 52 +++++++++++++++++-- 2 files changed, 69 insertions(+), 12 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/couchdb/blob/a67308e3/share/www/script/test/attachments_multipart.js ---------------------------------------------------------------------- diff --git a/share/www/script/test/attachments_multipart.js b/share/www/script/test/attachments_multipart.js index 9b9ddbd..0b1e19d 100644 --- a/share/www/script/test/attachments_multipart.js +++ b/share/www/script/test/attachments_multipart.js @@ -18,7 +18,7 @@ couchTests.attachments_multipart= function(debug) { // mime multipart - xhr = CouchDB.request("PUT", "/test_suite_db/multipart", { + var xhr = CouchDB.request("PUT", "/test_suite_db/multipart", { headers: {"Content-Type": "multipart/related;boundary=\"abc123\""}, body: "--abc123\r\n" + @@ -177,14 +177,27 @@ couchTests.attachments_multipart= function(debug) { // parse out the multipart var sections = parseMultipart(xhr); - + T(sections.length == 3); - - // The first section is the json doc. Check it's content-type. It contains - // the metadata for all the following attachments - - T(sections[0].headers['content-type'] == "application/json"); - + // The first section is the json doc. Check it's content-type. + // Each part carries their own meta data. + TEquals("application/json", sections[0].headers['content-type'], + "Content-Type should be application/json for section[0]"); + TEquals("application/test", sections[1].headers['Content-Type'], + "Content-Type should be application/test for section[1]"); + TEquals("application/test", sections[2].headers['Content-Type'], + "Content-Type should be application/test for section[2]"); + + TEquals("21", sections[1].headers['Content-Length'], + "Content-Length should be 21 section[1]"); + TEquals("18", sections[2].headers['Content-Length'], + "Content-Length should be 18 section[2]"); + + TEquals("foo.txt", sections[1].headers['Content-Disposition'], + "Content-ID should be foo.txt section[1]"); + TEquals("bar.txt", sections[2].headers['Content-Disposition'], + "Content-ID should be bar.txt section[2]"); + var doc = JSON.parse(sections[0].body); T(doc._attachments['foo.txt'].follows == true); http://git-wip-us.apache.org/repos/asf/couchdb/blob/a67308e3/src/couchdb/couch_doc.erl ---------------------------------------------------------------------- diff --git a/src/couchdb/couch_doc.erl b/src/couchdb/couch_doc.erl index 349df4a..64176b1 100644 --- a/src/couchdb/couch_doc.erl +++ b/src/couchdb/couch_doc.erl @@ -445,7 +445,15 @@ fold_streamed_data(RcvFun, LenLeft, Fun, Acc) when LenLeft > 0-> fold_streamed_data(RcvFun, LenLeft - size(Bin), Fun, ResultAcc). len_doc_to_multi_part_stream(Boundary, JsonBytes, Atts, SendEncodedAtts) -> - AttsSize = lists:foldl(fun(#att{data=Data} = Att, AccAttsSize) -> + AttsSize = lists:foldl(fun(Att, AccAttsSize) -> + #att{ + data=Data, + name=Name, + att_len=AttLen, + disk_len=DiskLen, + type=Type, + encoding=Encoding + } = Att, case Data of stub -> AccAttsSize; @@ -454,12 +462,29 @@ len_doc_to_multi_part_stream(Boundary, JsonBytes, Atts, SendEncodedAtts) -> 4 + % "\r\n\r\n" case SendEncodedAtts of true -> - Att#att.att_len; + % header + length(integer_to_list(AttLen)) + + AttLen; _ -> - Att#att.disk_len + % header + length(integer_to_list(DiskLen)) + + DiskLen end + 4 + % "\r\n--" - size(Boundary) + size(Boundary) + + + % attachment headers + % (the length of the Content-Length has already been set) + case Encoding of + identity -> 4; + _ -> size(list_to_binary(atom_to_list(Encoding))) + end + + size(Name) + + size(Type) + + 23 + % "\r\nContent-Disposition: " + 16 + % "\r\nContent-Type: " + 18 + % "\r\nContent-Length: " + 29 % "\r\nContent-Transfer-Encoding: " end end, 0, Atts), if AttsSize == 0 -> @@ -496,6 +521,25 @@ atts_to_mp([#att{data=stub} | RestAtts], Boundary, WriteFun, atts_to_mp(RestAtts, Boundary, WriteFun, SendEncodedAtts); atts_to_mp([Att | RestAtts], Boundary, WriteFun, SendEncodedAtts) -> + #att{ + name=Name, + att_len=Length, + type=Type, + encoding=Encoding + } = Att, + + % write headers + LengthBin = list_to_binary(integer_to_list(Length)), + TransferEncoding = case Encoding of + identity -> <<"7bit">>; % eh? + _ -> list_to_binary(atom_to_list(Encoding)) % send encoded + end, + WriteFun(<<"\r\nContent-Disposition: ", Name/binary>>), + WriteFun(<<"\r\nContent-Type: ", Type/binary>>), + WriteFun(<<"\r\nContent-Length: ", LengthBin/binary>>), + WriteFun(<<"\r\nContent-Transfer-Encoding: ", TransferEncoding/binary>>), + + % write data WriteFun(<<"\r\n\r\n">>), AttFun = case SendEncodedAtts of false ->
