You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by ko...@apache.org on 2010/04/15 18:40:36 UTC

svn commit: r934481 - in /couchdb/trunk: src/couchdb/couch_db.erl src/couchdb/couch_httpd_db.erl test/etap/140-attachment-comp.t

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")