From a1455b3a3566a1a0d5680e540d19ba6dc417b1db Mon Sep 17 00:00:00 2001 From: Tim Burke Date: Fri, 26 Jul 2019 21:29:42 -0700 Subject: [PATCH] symlink: Allow symlinks to be created via chunk-encoded PUTs ... provided they're still zero bytes. Change-Id: I66f2f16d7cf0b9cb0888e3b9b1a17b9112233d21 --- swift/common/middleware/symlink.py | 6 +++++- test/unit/common/middleware/test_symlink.py | 16 ++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/swift/common/middleware/symlink.py b/swift/common/middleware/symlink.py index a7d82b1540..e6cdccc2f4 100644 --- a/swift/common/middleware/symlink.py +++ b/swift/common/middleware/symlink.py @@ -425,7 +425,11 @@ class SymlinkObjectContext(WSGIContext): :param req: HTTP PUT object request :returns: Response Iterator """ - if req.content_length != 0: + if req.content_length is None: + has_body = (req.body_file.read(1) != b'') + else: + has_body = (req.content_length != 0) + if has_body: raise HTTPBadRequest( body='Symlink requests require a zero byte body', request=req, diff --git a/test/unit/common/middleware/test_symlink.py b/test/unit/common/middleware/test_symlink.py index faa2114ffd..e510de9155 100644 --- a/test/unit/common/middleware/test_symlink.py +++ b/test/unit/common/middleware/test_symlink.py @@ -15,6 +15,7 @@ # limitations under the License. import unittest +import io import json import mock @@ -91,6 +92,21 @@ class TestSymlinkMiddleware(TestSymlinkMiddlewareBase): val = hdrs.get('X-Object-Sysmeta-Container-Update-Override-Etag') self.assertEqual(val, '%s; symlink_target=c1/o' % MD5_OF_EMPTY_STRING) + def test_symlink_chunked_put(self): + self.app.register('PUT', '/v1/a/c/symlink', swob.HTTPCreated, {}) + req = Request.blank('/v1/a/c/symlink', method='PUT', + headers={'X-Symlink-Target': 'c1/o'}, + environ={'wsgi.input': io.BytesIO(b'')}) + self.assertIsNone(req.content_length) # sanity + status, headers, body = self.call_sym(req) + self.assertEqual(status, '201 Created') + method, path, hdrs = self.app.calls_with_headers[0] + val = hdrs.get('X-Object-Sysmeta-Symlink-Target') + self.assertEqual(val, 'c1/o') + self.assertNotIn('X-Object-Sysmeta-Symlink-Target-Account', hdrs) + val = hdrs.get('X-Object-Sysmeta-Container-Update-Override-Etag') + self.assertEqual(val, '%s; symlink_target=c1/o' % MD5_OF_EMPTY_STRING) + def test_symlink_put_different_account(self): self.app.register('PUT', '/v1/a/c/symlink', swob.HTTPCreated, {}) req = Request.blank('/v1/a/c/symlink', method='PUT',