couchdb-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From j..@apache.org
Subject svn commit: r750695 - in /couchdb/trunk: share/www/script/couch_tests.js share/www/script/test/attachment_names.js src/couchdb/couch_httpd_db.erl
Date Fri, 06 Mar 2009 00:12:16 GMT
Author: jan
Date: Fri Mar  6 00:12:15 2009
New Revision: 750695

URL: http://svn.apache.org/viewvc?rev=750695&view=rev
Log:
Verify attachment names. They must be utf-8 (closes COUCHDB-280) and must not start with an
underscore.

Added:
    couchdb/trunk/share/www/script/test/attachment_names.js
Modified:
    couchdb/trunk/share/www/script/couch_tests.js
    couchdb/trunk/src/couchdb/couch_httpd_db.erl

Modified: couchdb/trunk/share/www/script/couch_tests.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_tests.js?rev=750695&r1=750694&r2=750695&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch_tests.js [utf-8] (original)
+++ couchdb/trunk/share/www/script/couch_tests.js [utf-8] Fri Mar  6 00:12:15 2009
@@ -41,6 +41,7 @@
 loadTest("large_docs.js");
 loadTest("utf8.js");
 loadTest("attachments.js");
+loadTest("attachment_names.js");
 loadTest("attachment_paths.js");
 loadTest("attachment_views.js");
 loadTest("design_paths.js");

Added: couchdb/trunk/share/www/script/test/attachment_names.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/attachment_names.js?rev=750695&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/attachment_names.js (added)
+++ couchdb/trunk/share/www/script/test/attachment_names.js Fri Mar  6 00:12:15 2009
@@ -0,0 +1,87 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License.  You may obtain a copy
+// of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+couchTests.attatchment_names = function(debug) { 
+  var db = new CouchDB("test_suite_db"); 
+  db.deleteDb(); 
+  db.createDb(); 
+  if (debug) debugger; 
+
+  var binAttDoc = { 
+    _id: "bin_doc", 
+    _attachments:{ 
+      "foo\x80txt": { 
+        content_type:"text/plain", 
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=" 
+      } 
+    } 
+  } 
+
+  // inline attachments
+  try {
+    db.save(binAttDoc);
+    TEquals(1, 2, "Attachment name with non UTF-8 encoding saved. Should never show!");
+  } catch (e) {
+    TEquals("bad_request", e.error, "attachment_name: inline attachments");
+    TEquals("Attachment name is not UTF-8 encoded", e.reason, "attachment_name: inline attachments");
+  }
+
+
+  // standalone docs
+  var bin_data = "JHAPDO*AU£PN ){(3u[d 93DQ9¡€])}    ææøo'∂ƒæ≤çæππ•¥∫¶®#†π¶®¥π€ª®˙π8np";
+  
+  var xhr = (CouchDB.request("PUT", "/test_suite_db/bin_doc3/attachment\x80txt", {
+    headers:{"Content-Type":"text/plain;charset=utf-8"},
+    body:bin_data
+  }));
+
+  var resp = JSON.parse(xhr.responseText);
+  TEquals(400, xhr.status, "attachment_name: standalone API");
+  TEquals("bad_request", resp.error, "attachment_name: standalone API");
+  TEquals("Attachment name is not UTF-8 encoded", resp.reason, "attachment_name: standalone
API");
+
+
+  // bulk docs
+  var docs = { docs: [binAttDoc] };
+
+  var xhr = CouchDB.request("POST", "/test_suite_db/_bulk_docs", {
+    body: JSON.stringify(docs)
+  });
+
+  var resp = JSON.parse(xhr.responseText);
+  TEquals(400, xhr.status, "attachment_name: bulk docs");
+  TEquals("bad_request", resp.error, "attachment_name: bulk docs");
+  TEquals("Attachment name is not UTF-8 encoded", resp.reason, "attachment_name: bulk docs");
+
+
+  // leading underscores
+  var binAttDoc = { 
+    _id: "bin_doc2", 
+    _attachments:{ 
+      "_foo.txt": { 
+        content_type:"text/plain", 
+        data: "VGhpcyBpcyBhIGJhc2U2NCBlbmNvZGVkIHRleHQ=" 
+      } 
+    } 
+  } 
+
+  try {
+    db.save(binAttDoc);
+    TEquals(1, 2, "Attachment name with leading underscore saved. Should never show!");
+  } catch (e) {
+    TEquals("bad_request", e.error, "attachment_name: leading underscore");
+    TEquals("Attachment name can't start with '_'", e.reason, "attachment_name: leading underscore");
+  }  
+  
+  // todo: form uploads, waiting for cmlenz' test case for form uploads
+
+};

Modified: couchdb/trunk/src/couchdb/couch_httpd_db.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_db.erl?rev=750695&r1=750694&r2=750695&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_db.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_db.erl Fri Mar  6 00:12:15 2009
@@ -116,6 +116,7 @@
         Docs = lists:map(
             fun({ObjProps} = JsonObj) ->
                 Doc = couch_doc:from_json_obj(JsonObj),
+                validate_attachment_names(Doc),
                 Id = case Doc#doc.id of
                     <<>> -> couch_util:new_uuid();
                     Id0 -> Id0
@@ -436,7 +437,7 @@
     end,
 
     NewAttachments = [
-        {list_to_binary(Name), {list_to_binary(ContentType), Content}} ||
+        {validate_attachment_name(Name), {list_to_binary(ContentType), Content}} ||
         {Name, {ContentType, _}, Content} <-
         proplists:get_all_values("_attachments", Form)
     ],
@@ -460,6 +461,7 @@
         [Rev0|_] -> Rev0;
         [] -> undefined
     end,
+    validate_attachment_names(Doc),
     case couch_httpd:header_value(Req, "X-Couch-Full-Commit", "false") of
     "true" ->
         Options = [full_commit];
@@ -591,8 +593,11 @@
 
 db_attachment_req(#httpd{method=Method}=Req, Db, DocId, FileNameParts)
         when (Method == 'PUT') or (Method == 'DELETE') ->
-    FileName = list_to_binary(mochiweb_util:join(lists:map(fun binary_to_list/1, 
-        FileNameParts),"/")),
+    FileName = validate_attachment_name(
+                    mochiweb_util:join(
+                        lists:map(fun binary_to_list/1, 
+                            FileNameParts),"/")),
+    
     NewAttachment = case Method of
         'DELETE' ->
             [];
@@ -708,3 +713,46 @@
         {list_to_binary(DocId), [list_to_binary(Rev)]}
     end.
 
+validate_attachment_names(Doc) ->
+    lists:foreach(fun({Name, _}) -> 
+        validate_attachment_name(Name)
+    end, Doc#doc.attachments).
+
+validate_attachment_name(Name) when is_list(Name) ->
+    validate_attachment_name(list_to_binary(Name));
+validate_attachment_name(Name) ->
+    case is_valid_utf8(Name) of
+        true -> 
+            case Name of
+                <<"_",_/binary>>=Name -> throw({bad_request, <<"Attachment
name can't start with '_'">>});
+                _ -> Name
+            end;
+        false -> throw({bad_request, <<"Attachment name is not UTF-8 encoded">>})
+    end.
+
+%% borrowed from mochijson2:json_bin_is_safe()
+is_valid_utf8(<<>>) ->
+    true;
+is_valid_utf8(<<C, Rest/binary>>) ->
+    case C of
+        $\" ->
+            false;
+        $\\ ->
+            false;
+        $\b ->
+            false;
+        $\f ->
+            false;
+        $\n ->
+            false;
+        $\r ->
+            false;
+        $\t ->
+            false;
+        C when C >= 0, C < $\s; C >= 16#7f, C =< 16#10FFFF ->
+            false;
+        C when C < 16#7f ->
+            is_valid_utf8(Rest);
+        _ ->
+            false
+    end.



Mime
View raw message