Updated Branches:
  refs/heads/trunk df877a50d -> 80d59cb8b

Fix a regression introduced in 0.13.0 and make sure to include
Content-Length 0 with PUT and POST requests. Also add test cases for it.

Part of LIBCLOUD-362.


Project: http://git-wip-us.apache.org/repos/asf/libcloud/repo
Commit: http://git-wip-us.apache.org/repos/asf/libcloud/commit/19884f31
Tree: http://git-wip-us.apache.org/repos/asf/libcloud/tree/19884f31
Diff: http://git-wip-us.apache.org/repos/asf/libcloud/diff/19884f31

Branch: refs/heads/trunk
Commit: 19884f31adb727f6c4d4aac58381014acac00647
Parents: df877a5
Author: Tomaz Muraus <[email protected]>
Authored: Thu Aug 8 14:39:13 2013 +0200
Committer: Tomaz Muraus <[email protected]>
Committed: Thu Aug 8 14:39:13 2013 +0200

----------------------------------------------------------------------
 CHANGES                          |  4 ++
 libcloud/common/base.py          |  6 ++-
 libcloud/test/test_connection.py | 88 +++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/libcloud/blob/19884f31/CHANGES
----------------------------------------------------------------------
diff --git a/CHANGES b/CHANGES
index 7e3d59d..819d4b8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -13,6 +13,10 @@ Changes with Apache Libcloud in development
       updating the pricing file.
       [Tomaz Muraus]
 
+    - Fix a regression introduced in 0.13.0 and make sure to include
+      Content-Length 0 with PUT and POST requests. (LIBCLOUD-362)
+      [Tomaz Muraus]
+
  *) Compute
 
     - Modify ElasticHosts drive to store drive UUID in 'extra' field.

http://git-wip-us.apache.org/repos/asf/libcloud/blob/19884f31/libcloud/common/base.py
----------------------------------------------------------------------
diff --git a/libcloud/common/base.py b/libcloud/common/base.py
index 21eef2b..609dd78 100644
--- a/libcloud/common/base.py
+++ b/libcloud/common/base.py
@@ -572,9 +572,11 @@ class Connection(object):
             headers.update({'Host': self.host})
 
         # Encode data if necessary
-        if data:
+        if data is not None:
             data = self.encode_data(data)
-            headers.update({'Content-Length': str(len(data))})
+            # Only send Content-Length 0 with POST and PUT request
+            if len(data) > 0 or (len(data) == 0 and method in ['POST', 'PUT']):
+                headers.update({'Content-Length': str(len(data))})
 
         params, headers = self.pre_connect_hook(params, headers)
 

http://git-wip-us.apache.org/repos/asf/libcloud/blob/19884f31/libcloud/test/test_connection.py
----------------------------------------------------------------------
diff --git a/libcloud/test/test_connection.py b/libcloud/test/test_connection.py
new file mode 100644
index 0000000..938e170
--- /dev/null
+++ b/libcloud/test/test_connection.py
@@ -0,0 +1,88 @@
+# -*- coding: utf-8 -*-
+# Licensed to the Apache Software Foundation (ASF) under one or more§
+# contributor license agreements.  See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+import sys
+import unittest
+
+from mock import Mock
+
+from libcloud.common.base import Connection
+
+
+class ConnectionClassTestCase(unittest.TestCase):
+    def setUp(self):
+        self.originalConnect = Connection.connect
+        self.originalResponseCls = Connection.responseCls
+
+        Connection.connect = Mock()
+        Connection.responseCls = Mock()
+
+    def tearDown(self):
+        Connection.connect = self.originalConnect
+        Connection.responseCls = Connection.responseCls
+
+    def test_content_length(self):
+        con = Connection()
+        con.connection = Mock()
+
+        ## GET method
+        # No data, no content length should be present
+        con.request('/test', method='GET', data=None)
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertTrue('Content-Length' not in call_kwargs['headers'])
+
+        # '' as data, no content length should be present
+        con.request('/test', method='GET', data='')
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertTrue('Content-Length' not in call_kwargs['headers'])
+
+        # 'a' as data, content length should be present (data is GET is not
+        # corect, but anyways)
+        con.request('/test', method='GET', data='a')
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertEqual(call_kwargs['headers']['Content-Length'], '1')
+
+        ## POST, PUT method
+        # No data, no content length should be present
+        con.request('/test', method='POST', data=None)
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertTrue('Content-Length' not in call_kwargs['headers'])
+
+        con.request('/test', method='PUT', data=None)
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertTrue('Content-Length' not in call_kwargs['headers'])
+
+        # '' as data, content length should be present
+        con.request('/test', method='POST', data='')
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertEqual(call_kwargs['headers']['Content-Length'], '0')
+
+        con.request('/test', method='PUT', data='')
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertEqual(call_kwargs['headers']['Content-Length'], '0')
+
+        # 'a' as data, content length should be present
+        con.request('/test', method='POST', data='a')
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertEqual(call_kwargs['headers']['Content-Length'], '1')
+
+        con.request('/test', method='PUT', data='a')
+        call_kwargs = con.connection.request.call_args[1]
+        self.assertEqual(call_kwargs['headers']['Content-Length'], '1')
+
+
+if __name__ == '__main__':
+    sys.exit(unittest.main())

Reply via email to