Return-Path: Delivered-To: apmail-couchdb-commits-archive@www.apache.org Received: (qmail 80656 invoked from network); 15 Apr 2010 16:40:58 -0000 Received: from unknown (HELO mail.apache.org) (140.211.11.3) by 140.211.11.9 with SMTP; 15 Apr 2010 16:40:58 -0000 Received: (qmail 2187 invoked by uid 500); 15 Apr 2010 16:40:58 -0000 Delivered-To: apmail-couchdb-commits-archive@couchdb.apache.org Received: (qmail 2152 invoked by uid 500); 15 Apr 2010 16:40:58 -0000 Mailing-List: contact commits-help@couchdb.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@couchdb.apache.org Delivered-To: mailing list commits@couchdb.apache.org Received: (qmail 2145 invoked by uid 99); 15 Apr 2010 16:40:58 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 15 Apr 2010 16:40:58 +0000 X-ASF-Spam-Status: No, hits=-1060.0 required=10.0 tests=ALL_TRUSTED,AWL X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 15 Apr 2010 16:40:57 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id D4EE12388A64; Thu, 15 Apr 2010 16:40:36 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r934481 - in /couchdb/trunk: src/couchdb/couch_db.erl src/couchdb/couch_httpd_db.erl test/etap/140-attachment-comp.t Date: Thu, 15 Apr 2010 16:40:36 -0000 To: commits@couchdb.apache.org From: kocolosk@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20100415164036.D4EE12388A64@eris.apache.org> Author: kocolosk Date: Thu Apr 15 16:40:36 2010 New Revision: 934481 URL: http://svn.apache.org/viewvc?rev=934481&view=rev Log: accept gzipped attachments w/ standalone api. thx fdmanana. COUCHDB-712 Modified: couchdb/trunk/src/couchdb/couch_db.erl couchdb/trunk/src/couchdb/couch_httpd_db.erl couchdb/trunk/test/etap/140-attachment-comp.t Modified: couchdb/trunk/src/couchdb/couch_db.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.erl?rev=934481&r1=934480&r2=934481&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_db.erl (original) +++ couchdb/trunk/src/couchdb/couch_db.erl Thu Apr 15 16:40:36 2010 @@ -850,7 +850,16 @@ with_stream(Fd, #att{md5=InMd5,type=Type {Len, IdentityLen, gzip} end; gzip -> - {Att#att.att_len, Att#att.disk_len, Enc} + case {Att#att.att_len, Att#att.disk_len} of + {AL, DL} when AL =:= undefined orelse DL =:= undefined -> + % Compressed attachment uploaded through the standalone API. + {Len, Len, gzip}; + {AL, DL} -> + % This case is used for efficient push-replication, where a + % compressed attachment is located in the body of multipart + % content-type request. + {AL, DL, gzip} + end end, Att#att{ data={Fd,StreamInfo}, Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=934481&r1=934480&r2=934481&view=diff ============================================================================== --- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original) +++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Thu Apr 15 16:40:36 2010 @@ -945,7 +945,20 @@ db_attachment_req(#httpd{method=Method,m Length -> list_to_integer(Length) end, - md5 = get_md5_header(Req) + md5 = get_md5_header(Req), + encoding = case string:to_lower(string:strip( + couch_httpd:header_value(Req,"Content-Encoding","identity") + )) of + "identity" -> + identity; + "gzip" -> + gzip; + _ -> + throw({ + bad_ctype, + "Only gzip and identity content-encodings are supported" + }) + end }] end, Modified: couchdb/trunk/test/etap/140-attachment-comp.t URL: http://svn.apache.org/viewvc/couchdb/trunk/test/etap/140-attachment-comp.t?rev=934481&r1=934480&r2=934481&view=diff ============================================================================== --- couchdb/trunk/test/etap/140-attachment-comp.t (original) +++ couchdb/trunk/test/etap/140-attachment-comp.t Thu Apr 15 16:40:36 2010 @@ -22,7 +22,7 @@ test_db_name() -> main(_) -> test_util:init_code_path(), - etap:plan(65), + etap:plan(78), case (catch test()) of ok -> etap:end_tests(); @@ -54,6 +54,27 @@ test() -> tests_for_2nd_text_att(), tests_for_2nd_png_att(), + create_already_compressed_att(db_url() ++ "/doc_comp_att", "readme.txt"), + test_already_compressed_att(db_url() ++ "/doc_comp_att", "readme.txt"), + + test_create_already_compressed_att_with_invalid_content_encoding( + db_url() ++ "/doc_att_deflate", + "readme.txt", + zlib:compress(test_text_data()), + "deflate" + ), + + test_create_already_compressed_att_with_invalid_content_encoding( + db_url() ++ "/doc_att_compress", + "readme.txt", + % Note: As of OTP R13B04, it seems there's no LZW compression + % (i.e. UNIX compress utility implementation) lib in OTP. + % However there's a simple working Erlang implementation at: + % http://scienceblogs.com/goodmath/2008/01/simple_lempelziv_compression_i.php + test_text_data(), + "compress" + ), + timer:sleep(3000), % to avoid mochiweb socket closed exceptions couch_server:delete(test_db_name(), []), couch_server_sup:stop(), @@ -121,6 +142,20 @@ create_2nd_png_att() -> etap:is(Code, 201, "Created png attachment using the non-standalone api"), ok. +create_already_compressed_att(DocUri, AttName) -> + {ok, {{_, Code, _}, _Headers, _Body}} = http:request( + put, + {DocUri ++ "/" ++ AttName, [{"Content-Encoding", "gzip"}], + "text/plain", zlib:gzip(test_text_data())}, + [], + [{sync, true}]), + etap:is( + Code, + 201, + "Created already compressed attachment using the standalone api" + ), + ok. + tests_for_1st_text_att() -> test_get_1st_text_att_with_accept_encoding_gzip(), test_get_1st_text_att_without_accept_encoding_header(), @@ -576,6 +611,93 @@ test_2nd_png_att_stub() -> ), ok. +test_already_compressed_att(DocUri, AttName) -> + test_get_already_compressed_att_with_accept_gzip(DocUri, AttName), + test_get_already_compressed_att_without_accept(DocUri, AttName), + test_get_already_compressed_att_stub(DocUri, AttName). + +test_get_already_compressed_att_with_accept_gzip(DocUri, AttName) -> + {ok, {{_, Code, _}, Headers, Body}} = http:request( + get, + {DocUri ++ "/" ++ AttName, [{"Accept-Encoding", "gzip"}]}, + [], + [{sync, true}]), + etap:is(Code, 200, "HTTP response code is 200"), + Gziped = lists:member({"content-encoding", "gzip"}, Headers), + etap:is(Gziped, true, "received body is gziped"), + etap:is( + iolist_to_binary(Body), + iolist_to_binary(zlib:gzip(test_text_data())), + "received data for the already compressed attachment is ok" + ), + ok. + +test_get_already_compressed_att_without_accept(DocUri, AttName) -> + {ok, {{_, Code, _}, Headers, Body}} = http:request( + get, + {DocUri ++ "/" ++ AttName, []}, + [], + [{sync, true}]), + etap:is(Code, 200, "HTTP response code is 200"), + Gziped = lists:member({"content-encoding", "gzip"}, Headers), + etap:is(Gziped, false, "received body is not gziped"), + etap:is( + iolist_to_binary(Body), + iolist_to_binary(test_text_data()), + "received data for the already compressed attachment is ok" + ), + ok. + +test_get_already_compressed_att_stub(DocUri, AttName) -> + {ok, {{_, Code, _}, _Headers, Body}} = http:request( + get, + {DocUri ++ "?att_encoding_info=true", []}, + [], + [{sync, true}]), + etap:is(Code, 200, "HTTP response code is 200"), + Json = couch_util:json_decode(Body), + {AttJson} = couch_util:get_nested_json_value( + Json, + [<<"_attachments">>, iolist_to_binary(AttName)] + ), + AttLength = proplists:get_value(<<"length">>, AttJson), + etap:is( + AttLength, + iolist_size((zlib:gzip(test_text_data()))), + "Already compressed attachment stub length matches the " + "compressed length" + ), + Encoding = proplists:get_value(<<"encoding">>, AttJson), + etap:is( + Encoding, + <<"gzip">>, + "Already compressed attachment stub has the encoding field set to gzip" + ), + EncLength = proplists:get_value(<<"encoded_length">>, AttJson), + etap:is( + EncLength, + AttLength, + "Already compressed attachment stub encoded_length matches the " + "length field value" + ), + ok. + +test_create_already_compressed_att_with_invalid_content_encoding( + DocUri, AttName, AttData, Encoding) -> + {ok, {{_, Code, _}, _Headers, _Body}} = http:request( + put, + {DocUri ++ "/" ++ AttName, [{"Content-Encoding", Encoding}], + "text/plain", AttData}, + [], + [{sync, true}]), + etap:is( + Code, + 415, + "Couldn't create an already compressed attachment using the " + "unsupported encoding '" ++ Encoding ++ "'" + ), + ok. + test_png_data() -> {ok, Data} = file:read_file( test_util:source_file("share/www/image/logo.png")