)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":10,"context_line":"header. S3API previously passed it through while translating"},{"line_number":11,"context_line":"x-amz-copy-source to X-Copy-From. Swift\u0027s server-side copy middleware"},{"line_number":12,"context_line":"then applied the Range to its source GET, allowing CopyObject to create"},{"line_number":13,"context_line":"a truncated destination object."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Reject CopyObject requests containing Range with the same"},{"line_number":16,"context_line":"InvalidArgument response returned by AWS S3."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"f64da421_85822000","line":13,"updated":"2026-07-31 13:35:45.000000000","message":"sounds like a reproducing functional test would be good to have that this patch then fixes","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"46b0cf2540776295f9f39d3d6e2eaccb2bc71628","unresolved":false,"context_lines":[{"line_number":10,"context_line":"header. S3API previously passed it through while translating"},{"line_number":11,"context_line":"x-amz-copy-source to X-Copy-From. Swift\u0027s server-side copy middleware"},{"line_number":12,"context_line":"then applied the Range to its source GET, allowing CopyObject to create"},{"line_number":13,"context_line":"a truncated destination object."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Reject CopyObject requests containing Range with the same"},{"line_number":16,"context_line":"InvalidArgument response returned by AWS S3."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"827d740a_d2a3e378","line":13,"in_reply_to":"66b562cf_3546ed1c","updated":"2026-08-03 21:48:33.000000000","message":"Done","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"8cd17b2d74c8994e788d02820c5485a46e378175","unresolved":true,"context_lines":[{"line_number":10,"context_line":"header. S3API previously passed it through while translating"},{"line_number":11,"context_line":"x-amz-copy-source to X-Copy-From. Swift\u0027s server-side copy middleware"},{"line_number":12,"context_line":"then applied the Range to its source GET, allowing CopyObject to create"},{"line_number":13,"context_line":"a truncated destination object."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Reject CopyObject requests containing Range with the same"},{"line_number":16,"context_line":"InvalidArgument response returned by AWS S3."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"66b562cf_3546ed1c","line":13,"in_reply_to":"f64da421_85822000","updated":"2026-08-03 15:57:43.000000000","message":"I agree with this, I can squash some in.","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":13,"context_line":"a truncated destination object."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Reject CopyObject requests containing Range with the same"},{"line_number":16,"context_line":"InvalidArgument response returned by AWS S3."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Keep x-amz-copy-source-range handling unchanged for UploadPartCopy,"},{"line_number":19,"context_line":"where it is validated and translated into an internal Swift Range."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"2bb150ea_567276fd","line":16,"updated":"2026-07-31 13:35:45.000000000","message":"an s3 compat test would verify this; I think test_input_errors would provide the infrastructure to send bad headers to S3","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"68591e7b21a0495fdd0e954a5a0cbf562e195b76","unresolved":false,"context_lines":[{"line_number":13,"context_line":"a truncated destination object."},{"line_number":14,"context_line":""},{"line_number":15,"context_line":"Reject CopyObject requests containing Range with the same"},{"line_number":16,"context_line":"InvalidArgument response returned by AWS S3."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Keep x-amz-copy-source-range handling unchanged for UploadPartCopy,"},{"line_number":19,"context_line":"where it is validated and translated into an internal Swift Range."}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"c0c1656e_00004bed","line":16,"in_reply_to":"2bb150ea_567276fd","updated":"2026-08-03 22:21:51.000000000","message":"Done","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":20,"context_line":"Also add coverage showing that a client-supplied Range on"},{"line_number":21,"context_line":"UploadPartCopy is rejected by partNumber validation."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"APIImpact"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Change-Id: Ibe6c3a80f3ed0311787b9b0b44d134ae353f4b33"},{"line_number":26,"context_line":"Assisted-by: OpenAI Codex (GPT-5.6)"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"097a88d1_dce42667","line":23,"range":{"start_line":23,"start_character":0,"end_line":23,"end_character":9},"updated":"2026-07-31 13:35:45.000000000","message":"hmmm, not sure I\u0027d flag this as an API impact - we\u0027re not changing the advertised API, just fixing a bug","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"8cd17b2d74c8994e788d02820c5485a46e378175","unresolved":true,"context_lines":[{"line_number":20,"context_line":"Also add coverage showing that a client-supplied Range on"},{"line_number":21,"context_line":"UploadPartCopy is rejected by partNumber validation."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"APIImpact"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Change-Id: Ibe6c3a80f3ed0311787b9b0b44d134ae353f4b33"},{"line_number":26,"context_line":"Assisted-by: OpenAI Codex (GPT-5.6)"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"7d6b9b98_b983084f","line":23,"range":{"start_line":23,"start_character":0,"end_line":23,"end_character":9},"in_reply_to":"097a88d1_dce42667","updated":"2026-08-03 15:57:43.000000000","message":"Yea I agree with this too, though this MIGHT be APIImpact to someone who is for what ever reason using the \u0027Range\u0027 header, we are not changing the API.","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"46b0cf2540776295f9f39d3d6e2eaccb2bc71628","unresolved":false,"context_lines":[{"line_number":20,"context_line":"Also add coverage showing that a client-supplied Range on"},{"line_number":21,"context_line":"UploadPartCopy is rejected by partNumber validation."},{"line_number":22,"context_line":""},{"line_number":23,"context_line":"APIImpact"},{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Change-Id: Ibe6c3a80f3ed0311787b9b0b44d134ae353f4b33"},{"line_number":26,"context_line":"Assisted-by: OpenAI Codex (GPT-5.6)"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"46ba761f_2cb671c4","line":23,"range":{"start_line":23,"start_character":0,"end_line":23,"end_character":9},"in_reply_to":"7d6b9b98_b983084f","updated":"2026-08-03 21:48:33.000000000","message":"Done","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Change-Id: Ibe6c3a80f3ed0311787b9b0b44d134ae353f4b33"},{"line_number":26,"context_line":"Assisted-by: OpenAI Codex (GPT-5.6)"},{"line_number":27,"context_line":"Signed-off-by: Jianjian Huo \u003cjhuo@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"6b93b4c4_bc008798","line":27,"updated":"2026-07-31 13:35:45.000000000","message":"this probably warrants a launchpad bug for anyone trying to understand why their copies were truncated","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"72b9aa9a15ea04ffd0f481fca33ceb56c33af6ef","unresolved":false,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Change-Id: Ibe6c3a80f3ed0311787b9b0b44d134ae353f4b33"},{"line_number":26,"context_line":"Assisted-by: OpenAI Codex (GPT-5.6)"},{"line_number":27,"context_line":"Signed-off-by: Jianjian Huo \u003cjhuo@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"a3a3d5bb_ab2dae96","line":27,"in_reply_to":"05542fc4_37d8c136","updated":"2026-08-03 21:42:39.000000000","message":"https://bugs.launchpad.net/swift/+bug/2162776","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"8cd17b2d74c8994e788d02820c5485a46e378175","unresolved":true,"context_lines":[{"line_number":24,"context_line":""},{"line_number":25,"context_line":"Change-Id: Ibe6c3a80f3ed0311787b9b0b44d134ae353f4b33"},{"line_number":26,"context_line":"Assisted-by: OpenAI Codex (GPT-5.6)"},{"line_number":27,"context_line":"Signed-off-by: Jianjian Huo \u003cjhuo@nvidia.com\u003e"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":1,"id":"05542fc4_37d8c136","line":27,"in_reply_to":"6b93b4c4_bc008798","updated":"2026-08-03 15:57:43.000000000","message":"I concur!","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"}],"/PATCHSET_LEVEL":[{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"8637a3097774da0ff4c0f04cbef16146d144a3ae","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"fc2fea04_b0709494","updated":"2026-07-30 21:01:40.000000000","message":"I think this is pretty straight forward. AWS does not support this so we don\u0027t need this. Thanks!","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":1,"id":"6a99c48d_563e480a","updated":"2026-07-31 13:35:45.000000000","message":"This definitely seems like a bug worth fixing, but I think it would be worth having a functional/s3 compat test that (a) reproduces the problem and (b) verifies the response is compatible with S3","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"7c1627720f7b8210e9796699ed04902c5072cb64","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"66bf1426_5204a495","updated":"2026-08-20 17:40:49.000000000","message":"review in progress, early comments","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"dd08be9a9296f51e71e7c1aee4401f627ae1da29","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"3a7c0122_fe613b24","updated":"2026-08-21 10:23:30.000000000","message":"none of my comments are blockers, this patch closes a gap and is forwards progress.\n\nI have a follow-up here to address my comments s3api: refactor to move Range header check  https://review.opendev.org/c/openstack/swift/+/1001776","commit_id":"d57c078ef2744d0012729bbcb3aaca2c4e5a481d"}],"swift/common/middleware/s3api/controllers/obj.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":172,"context_line":"                                  req.headers[\u0027X-Amz-Copy-Source-Range\u0027],"},{"line_number":173,"context_line":"                                  \u0027Illegal copy header\u0027)"},{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"}],"source_content_type":"text/x-python","patch_set":1,"id":"387a7056_b3014176","line":175,"range":{"start_line":175,"start_character":25,"end_line":175,"end_character":45},"updated":"2026-07-31 13:35:45.000000000","message":"what happens if Range is sent with a PUT *without* X-Amz-Copy-Source? I\u0027d expect that to be an error too?","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"68591e7b21a0495fdd0e954a5a0cbf562e195b76","unresolved":true,"context_lines":[{"line_number":172,"context_line":"                                  req.headers[\u0027X-Amz-Copy-Source-Range\u0027],"},{"line_number":173,"context_line":"                                  \u0027Illegal copy header\u0027)"},{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"}],"source_content_type":"text/x-python","patch_set":1,"id":"a6d8bdf8_5bd00150","line":175,"range":{"start_line":175,"start_character":25,"end_line":175,"end_character":45},"in_reply_to":"387a7056_b3014176","updated":"2026-08-03 22:21:51.000000000","message":"Does not look like it in Swift:\n```\nvagrant@saio:~/swift$ payload_sha256\u003d$(sha256sum ~/.bashrc | cut -d\u0027 \u0027 -f1)\n\ncurl --verbose --include \\\n  --upload-file ~/.bashrc \\\n  --netrc-file \u003c(printf \u0027machine 127.0.0.1\\nlogin test:tester\\npassword testing\\n\u0027) \\\n  --aws-sigv4 \u0027aws:amz:us-east-1:s3\u0027 \\\n  --header \u0027Range: bytes\u003d0-101\u0027 \\\n  --header \"x-amz-content-sha256: $payload_sha256\" \\\n  \u0027http://127.0.0.1:8080/foo/baz\u0027\n*   Trying 127.0.0.1:8080...\n* Connected to 127.0.0.1 (127.0.0.1) port 8080\n* Server auth using AWS_SIGV4 with user \u0027test:tester\u0027\n\u003e PUT /foo/baz HTTP/1.1\n\u003e Host: 127.0.0.1:8080\n\u003e Authorization: AWS4-HMAC-SHA256 Credential\u003dtest:tester/20260803/us-east-1/s3/aws4_request, SignedHeaders\u003dhost;range;x-amz-content-sha256;x-amz-date, Signature\u003dc9dd7e1195d33d13c9f4dfbed05404867fce8e601683c721814818b6b0e1e469\n\u003e X-Amz-Date: 20260803T215944Z\n\u003e User-Agent: curl/8.5.0\n\u003e Accept: */*\n\u003e Range: bytes\u003d0-101\n\u003e x-amz-content-sha256: 342099da4dd28c394d3f8782d90d7465cb2eaa611193f8f378d6918261cb9bb8\n\u003e Content-Length: 3771\n\u003e \n* We are completely uploaded and fine\n\u003c HTTP/1.1 200 OK\nHTTP/1.1 200 OK\n\u003c Content-Type: text/html; charset\u003dUTF-8\nContent-Type: text/html; charset\u003dUTF-8\n\u003c Content-Length: 0\nContent-Length: 0\n\u003c ETag: \"1f98b8f3f3c8f8927eca945d59dcc1c6\"\nETag: \"1f98b8f3f3c8f8927eca945d59dcc1c6\"\n\u003c Last-Modified: Mon, 03 Aug 2026 21:59:45 GMT\nLast-Modified: Mon, 03 Aug 2026 21:59:45 GMT\n\u003c x-amz-id-2: tx34eff9cb46b74095b81a4-006a710f50\nx-amz-id-2: tx34eff9cb46b74095b81a4-006a710f50\n\u003c x-amz-request-id: tx34eff9cb46b74095b81a4-006a710f50\nx-amz-request-id: tx34eff9cb46b74095b81a4-006a710f50\n\u003c X-Trans-Id: tx34eff9cb46b74095b81a4-006a710f50\nX-Trans-Id: tx34eff9cb46b74095b81a4-006a710f50\n\u003c X-Openstack-Request-Id: tx34eff9cb46b74095b81a4-006a710f50\nX-Openstack-Request-Id: tx34eff9cb46b74095b81a4-006a710f50\n\u003c Date: Mon, 03 Aug 2026 21:59:44 GMT\nDate: Mon, 03 Aug 2026 21:59:44 GMT\n\n\u003c \n* Connection #0 to host 127.0.0.1 left intact\n```\n\nThen when we compare, the files are the same still\n```\nvagrant@saio:~/swift$ aws s3api get-object --bucket foo --key baz output.bin\n{\n    \"AcceptRanges\": \"bytes\",\n    \"LastModified\": \"Mon, 03 Aug 2026 21:59:45 GMT\",\n    \"ContentLength\": 3771,\n    \"ETag\": \"\\\"1f98b8f3f3c8f8927eca945d59dcc1c6\\\"\",\n    \"ContentType\": \"binary/octet-stream\",\n    \"Metadata\": {}\n}\nvagrant@saio:~/swift$ diff output.bin ~/.bashrc\n```\n\n\nThough S3 does not care about Range either:\n```\ncurl --silent --show-error --include \\\n  --upload-file \"$payload\" \\\n  --netrc-file \u003c(\n    printf \u0027machine %s\\nlogin %s\\npassword %s\\n\u0027 \\\n      \"${bucket}.s3.${region}.amazonaws.com\" \\\n      \"$access_key\" \\\n      \"$secret_key\"\n  ) \\\n  --aws-sigv4 \"aws:amz:${region}:s3\" \\\n  --header \"x-amz-security-token: $session_token\" \\\n  --header \u0027Range: bytes\u003d0-101\u0027 \\\n  --header \"x-amz-content-sha256: $payload_sha256\" \\\n  \"https://${bucket}.s3.${region}.amazonaws.com/${key}\"\nHTTP/1.1 200 OK\nx-amz-id-2: bcU+NqfdEqS/SwWFS1lL7BAenrBC2/BSl9xy7rxGndx8Elnxh8JRDJXygO97Ll9oS/sq8j10eYzE9KBCYEjNgSmrmwNOXL74\nx-amz-request-id: 4NBS5Z6D9VQTWKYW\nDate: Mon, 03 Aug 2026 22:12:38 GMT\nx-amz-server-side-encryption: AES256\nETag: \"de059f09dd7963c5d65fa24f2df25d38\"\nx-amz-checksum-crc64nvme: wXQgLQkzUU0\u003d\nx-amz-checksum-type: FULL_OBJECT\nContent-Length: 0\nServer: AmazonS3\n```\n\nCopyObject requests does the same thing when you specify some random header\n```\ncurl --silent --show-error --include \\\n  --request PUT \\\n  --data-binary \u0027\u0027 \\\n  --netrc-file \u003c(\n    printf \u0027machine %s\\nlogin %s\\npassword %s\\n\u0027 \\\n      \"${bucket}.s3.${region}.amazonaws.com\" \\\n      \"$access_key\" \\\n      \"$secret_key\"\n  ) \\\n  --aws-sigv4 \"aws:amz:${region}:s3\" \\\n  --header \"x-amz-security-token: $session_token\" \\\n  --header \"x-amz-copy-source: ${bucket}/foo\" \\\n  --header \u0027I-Do-Not-Exist: 42\u0027 \\\n  --header \u0027x-amz-content-sha256: e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855\u0027 \\\n  \"https://${bucket}.s3.${region}.amazonaws.com/${key}\"\nHTTP/1.1 200 OK\nx-amz-id-2: zwyhn1R5rLZbbtvbc+PTk6zvVKsMxUUdfS996ZaZs28Gxn2706b//pl+KoflKSYKa59MdZ43VeSgNkgHfCRv49+8Lhe26H0e\nx-amz-request-id: 34V8E9GEDDSNXRN0\nDate: Mon, 03 Aug 2026 22:18:19 GMT\nx-amz-server-side-encryption: AES256\nContent-Type: application/xml\nContent-Length: 315\nServer: AmazonS3\n\n\u003c?xml version\u003d\"1.0\" encoding\u003d\"UTF-8\"?\u003e\n\u003cCopyObjectResult xmlns\u003d\"http://s3.amazonaws.com/doc/2006-03-01/\"\u003e\u003cLastModified\u003e2026-08-03T22:18:19.000Z\u003c/LastModified\u003e\u003cETag\u003e\"d41d8cd98f00b204e9800998ecf8427e\"\u003c/ETag\u003e\u003cChecksumCRC64NVME\u003eAAAAAAAAAAA\u003d\u003c/ChecksumCRC64NVME\u003e\u003cChecksumType\u003eFULL_OBJECT\u003c/ChecksumType\u003e\u003c/CopyObjectResult\u003e\n```\n\nIt only cares about the RANGE header... strange...","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":false,"context_lines":[{"line_number":172,"context_line":"                                  req.headers[\u0027X-Amz-Copy-Source-Range\u0027],"},{"line_number":173,"context_line":"                                  \u0027Illegal copy header\u0027)"},{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"}],"source_content_type":"text/x-python","patch_set":1,"id":"e4d824d7_2c6dcf2d","line":175,"range":{"start_line":175,"start_character":25,"end_line":175,"end_character":45},"in_reply_to":"a6d8bdf8_5bd00150","updated":"2026-08-21 10:22:16.000000000","message":"Acknowledged","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"},{"line_number":179,"context_line":"        if not req.headers.get(\u0027Content-Type\u0027):"},{"line_number":180,"context_line":"            # can\u0027t setdefault because it can be None for some reason"}],"source_content_type":"text/x-python","patch_set":1,"id":"5dc7a23f_3e8afd04","line":177,"range":{"start_line":177,"start_character":35,"end_line":177,"end_character":40},"updated":"2026-07-31 13:35:45.000000000","message":"all-capitals seems very shouty ;-) what does S3 respond with?","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"8cd17b2d74c8994e788d02820c5485a46e378175","unresolved":true,"context_lines":[{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"},{"line_number":179,"context_line":"        if not req.headers.get(\u0027Content-Type\u0027):"},{"line_number":180,"context_line":"            # can\u0027t setdefault because it can be None for some reason"}],"source_content_type":"text/x-python","patch_set":1,"id":"bb29523a_f0478266","line":177,"range":{"start_line":177,"start_character":35,"end_line":177,"end_character":40},"in_reply_to":"5dc7a23f_3e8afd04","updated":"2026-08-03 15:57:43.000000000","message":"Same thing! S3 is also rude 😉\n\n```\n\"Error\": {\n    \"Code\": \"InvalidArgument\",\n    \"Message\": \"RANGE is not supported in Copy!\",\n    \"ArgumentName\": \"Range\",\n    \"ArgumentValue\": \"bytes\u003d0-5242879\"\n  },\n```","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"7c1627720f7b8210e9796699ed04902c5072cb64","unresolved":true,"context_lines":[{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"},{"line_number":179,"context_line":"        if not req.headers.get(\u0027Content-Type\u0027):"},{"line_number":180,"context_line":"            # can\u0027t setdefault because it can be None for some reason"}],"source_content_type":"text/x-python","patch_set":1,"id":"e7874f9c_6143adfb","line":177,"range":{"start_line":177,"start_character":35,"end_line":177,"end_character":40},"in_reply_to":"bb29523a_f0478266","updated":"2026-08-20 17:40:49.000000000","message":"oh wow, seems like somebody was determined to make the point 😀","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":false,"context_lines":[{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"},{"line_number":178,"context_line":"        req.check_copy_source(self.app)"},{"line_number":179,"context_line":"        if not req.headers.get(\u0027Content-Type\u0027):"},{"line_number":180,"context_line":"            # can\u0027t setdefault because it can be None for some reason"}],"source_content_type":"text/x-python","patch_set":1,"id":"8dda98ac_3b4e221a","line":177,"range":{"start_line":177,"start_character":35,"end_line":177,"end_character":40},"in_reply_to":"e7874f9c_6143adfb","updated":"2026-08-21 10:22:16.000000000","message":"Done","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":true,"context_lines":[{"line_number":171,"context_line":"            raise InvalidArgument(\u0027x-amz-copy-source-range\u0027,"},{"line_number":172,"context_line":"                                  req.headers[\u0027X-Amz-Copy-Source-Range\u0027],"},{"line_number":173,"context_line":"                                  \u0027Illegal copy header\u0027)"},{"line_number":174,"context_line":"        if all(h in req.headers"},{"line_number":175,"context_line":"               for h in (\u0027X-Amz-Copy-Source\u0027, \u0027Range\u0027)):"},{"line_number":176,"context_line":"            raise InvalidArgument(\u0027Range\u0027, req.headers[\u0027Range\u0027],"},{"line_number":177,"context_line":"                                  \u0027RANGE is not supported in Copy!\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"bef78091_6acd85a9","line":174,"updated":"2026-08-21 10:22:16.000000000","message":"minor: this check is generic for all copies and therefore could (should) be in ``check_copy_source`` where it would be a simpler expression; it just happens that ``validate_part_number`` takes care of the UploadPartCopy case and so we don\u0027t rely on ``check_copy_source``.","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"}],"test/s3api/test_input_errors.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":true,"context_lines":[{"line_number":1427,"context_line":"                \u0027x-amz-content-sha256\u0027: _sha256(TEST_BODY)})"},{"line_number":1428,"context_line":"        self.assertOK(resp)"},{"line_number":1429,"context_line":""},{"line_number":1430,"context_line":"    def test_object_copy_with_range_error(self):"},{"line_number":1431,"context_line":"        orig_name \u003d self.create_name(\u0027range-original\u0027)"},{"line_number":1432,"context_line":"        resp \u003d self.conn.make_request("},{"line_number":1433,"context_line":"            self.bucket_name,"}],"source_content_type":"text/x-python","patch_set":3,"id":"6b36718e_9cce1943","line":1430,"updated":"2026-08-21 10:22:16.000000000","message":"I checked this passed against AWS S3","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":true,"context_lines":[{"line_number":1459,"context_line":"            \u0027\u003cMessage\u003eRANGE is not supported in Copy!\u003c/Message\u003e\u0027, respbody)"},{"line_number":1460,"context_line":"        self.assertIn(\u0027\u003cArgumentName\u003eRange\u003c/ArgumentName\u003e\u0027, respbody)"},{"line_number":1461,"context_line":"        self.assertIn("},{"line_number":1462,"context_line":"            \u0027\u003cArgumentValue\u003e%s\u003c/ArgumentValue\u003e\u0027 % req_range, respbody)"},{"line_number":1463,"context_line":""},{"line_number":1464,"context_line":"    def test_get_object_no_sha(self):"},{"line_number":1465,"context_line":"        obj_name \u003d self.create_name(\u0027get-object\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"2df2fe4b_7719f5bc","line":1462,"updated":"2026-08-21 10:22:16.000000000","message":"to be sure, we could check that the copy was not made by doing a GET expecting a 404","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"}],"test/unit/common/middleware/s3api/test_multi_upload.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":2714,"context_line":""},{"line_number":2715,"context_line":"        self.assertEqual(status.split()[0], \u0027400\u0027, body)"},{"line_number":2716,"context_line":""},{"line_number":2717,"context_line":"    def test_upload_part_copy_with_plain_range_is_rejected(self):"},{"line_number":2718,"context_line":"        account \u003d \u0027test:tester\u0027"},{"line_number":2719,"context_line":"        test_headers \u003d ("},{"line_number":2720,"context_line":"            {\u0027Range\u0027: \u0027bytes\u003d0-9\u0027},"}],"source_content_type":"text/x-python","patch_set":1,"id":"8c20c53e_67bb53c8","line":2717,"updated":"2026-07-31 13:35:45.000000000","message":"looks like this is adding coverage for existing behavior?\n\nupdate: yes, the commit message says this :)","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"68591e7b21a0495fdd0e954a5a0cbf562e195b76","unresolved":false,"context_lines":[{"line_number":2714,"context_line":""},{"line_number":2715,"context_line":"        self.assertEqual(status.split()[0], \u0027400\u0027, body)"},{"line_number":2716,"context_line":""},{"line_number":2717,"context_line":"    def test_upload_part_copy_with_plain_range_is_rejected(self):"},{"line_number":2718,"context_line":"        account \u003d \u0027test:tester\u0027"},{"line_number":2719,"context_line":"        test_headers \u003d ("},{"line_number":2720,"context_line":"            {\u0027Range\u0027: \u0027bytes\u003d0-9\u0027},"}],"source_content_type":"text/x-python","patch_set":1,"id":"4660fde0_a53d2b19","line":2717,"in_reply_to":"8c20c53e_67bb53c8","updated":"2026-08-03 22:21:51.000000000","message":"Acknowledged","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":true,"context_lines":[{"line_number":2717,"context_line":"    def test_upload_part_copy_with_plain_range_is_rejected(self):"},{"line_number":2718,"context_line":"        account \u003d \u0027test:tester\u0027"},{"line_number":2719,"context_line":"        test_headers \u003d ("},{"line_number":2720,"context_line":"            {\u0027Range\u0027: \u0027bytes\u003d0-9\u0027},"},{"line_number":2721,"context_line":"            {"},{"line_number":2722,"context_line":"                \u0027Range\u0027: \u0027bytes\u003d10-19\u0027,"},{"line_number":2723,"context_line":"                \u0027X-Amz-Copy-Source-Range\u0027: \u0027bytes\u003d0-9\u0027,"}],"source_content_type":"text/x-python","patch_set":3,"id":"4dbf3097_3a15786c","line":2720,"updated":"2026-08-21 10:22:16.000000000","message":"Claude pointed out that validate_part_number does not catch a malformed Range \n\ntry:\n```\ndiff --git a/test/unit/common/middleware/s3api/test_multi_upload.py b/test/unit/common/middleware/s3api/test_multi_upload.py\nindex dcc549d60..880ce622e 100644\n--- a/test/unit/common/middleware/s3api/test_multi_upload.py\n+++ b/test/unit/common/middleware/s3api/test_multi_upload.py\n@@ -2823,6 +2823,7 @@ class TestS3ApiMultiUpload(BaseS3ApiMultiUpload, S3ApiTestCase):\n         account \u003d \u0027test:tester\u0027\n         test_headers \u003d (\n             {\u0027Range\u0027: \u0027bytes\u003d0-9\u0027},\n+            {\u0027Range\u0027: \u0027bytes\u003da-b\u0027},\n             {\n                 \u0027Range\u0027: \u0027bytes\u003d10-19\u0027,\n                 \u0027X-Amz-Copy-Source-Range\u0027: \u0027bytes\u003d0-9\u0027,\n\n```\n\nthis is caught if the new check is moved to check_copy_resp as suggested in my follow on patch, but with a different error response. so there\u0027s some more work to be done to verify the S3 responses in these cases and align swift\u0027s responses. IMHO that can be follow up work.","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"7c1627720f7b8210e9796699ed04902c5072cb64","unresolved":true,"context_lines":[{"line_number":2737,"context_line":"                self.assertEqual("},{"line_number":2738,"context_line":"                    \u0027Cannot specify both Range header and partNumber \u0027"},{"line_number":2739,"context_line":"                    \u0027query parameter\u0027,"},{"line_number":2740,"context_line":"                    self._get_error_message(body))"},{"line_number":2741,"context_line":"                self.assertNotIn("},{"line_number":2742,"context_line":"                    (\u0027HEAD\u0027, \u0027/v1/AUTH_test/src_bucket/src_obj\u0027),"},{"line_number":2743,"context_line":"                    self.swift.calls)"}],"source_content_type":"text/x-python","patch_set":3,"id":"6769750b_1ec11d22","line":2740,"updated":"2026-08-20 17:40:49.000000000","message":"ok. this is prevented by ``validate_part_number``. I wonder if that is deliberate or accidental i.e. we\u0027d definitely want to check that a GET/HEAD could not have both part_number and range, so wrote the validator function, and then it\u0027s called in the UploadPartCopy where part_number refers to the *destination* part and Range to the source.\n\ngood to have test coverage","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":false,"context_lines":[{"line_number":2737,"context_line":"                self.assertEqual("},{"line_number":2738,"context_line":"                    \u0027Cannot specify both Range header and partNumber \u0027"},{"line_number":2739,"context_line":"                    \u0027query parameter\u0027,"},{"line_number":2740,"context_line":"                    self._get_error_message(body))"},{"line_number":2741,"context_line":"                self.assertNotIn("},{"line_number":2742,"context_line":"                    (\u0027HEAD\u0027, \u0027/v1/AUTH_test/src_bucket/src_obj\u0027),"},{"line_number":2743,"context_line":"                    self.swift.calls)"}],"source_content_type":"text/x-python","patch_set":3,"id":"66fb72c1_e5563e47","line":2740,"in_reply_to":"6769750b_1ec11d22","updated":"2026-08-21 10:22:16.000000000","message":"Acknowledged","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"}],"test/unit/common/middleware/s3api/test_obj.py":[{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"ac296b0c837d3c37641aab9a9a4e50279ef3c309","unresolved":true,"context_lines":[{"line_number":1210,"context_line":"                                       header)"},{"line_number":1211,"context_line":"        self.assertEqual(self._get_error_code(body), \u0027PreconditionFailed\u0027)"},{"line_number":1212,"context_line":""},{"line_number":1213,"context_line":"    def test_object_PUT_copy_range(self):"},{"line_number":1214,"context_line":"        req_range \u003d \u0027bytes\u003d0-2\u0027"},{"line_number":1215,"context_line":""},{"line_number":1216,"context_line":"        status, _headers, body \u003d self._test_object_PUT_copy("}],"source_content_type":"text/x-python","patch_set":1,"id":"9fd2e266_7874ee16","line":1213,"updated":"2026-07-31 13:35:45.000000000","message":"nit: add ``_error`` suffix to test name to match adjacent tests","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":39146,"name":"Nathaniel Martes","display_name":"Nate Martes","email":"nmartes@NVIDIA.com","username":"nmartes"},"change_message_id":"68591e7b21a0495fdd0e954a5a0cbf562e195b76","unresolved":false,"context_lines":[{"line_number":1210,"context_line":"                                       header)"},{"line_number":1211,"context_line":"        self.assertEqual(self._get_error_code(body), \u0027PreconditionFailed\u0027)"},{"line_number":1212,"context_line":""},{"line_number":1213,"context_line":"    def test_object_PUT_copy_range(self):"},{"line_number":1214,"context_line":"        req_range \u003d \u0027bytes\u003d0-2\u0027"},{"line_number":1215,"context_line":""},{"line_number":1216,"context_line":"        status, _headers, body \u003d self._test_object_PUT_copy("}],"source_content_type":"text/x-python","patch_set":1,"id":"24b628ad_c9660370","line":1213,"in_reply_to":"9fd2e266_7874ee16","updated":"2026-08-03 22:21:51.000000000","message":"Done","commit_id":"c6afafb2c0994bc5dd34490212c490b45dba192b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"0afc06a614c7d88bbe170b7e19c387606a16c784","unresolved":true,"context_lines":[{"line_number":1227,"context_line":"        self.assertNotIn("},{"line_number":1228,"context_line":"            (\u0027HEAD\u0027, \u0027/v1/AUTH_test/some/source\u0027), self.swift.calls)"},{"line_number":1229,"context_line":"        self.assertNotIn("},{"line_number":1230,"context_line":"            (\u0027PUT\u0027, \u0027/v1/AUTH_test/bucket/object\u0027), self.swift.calls)"},{"line_number":1231,"context_line":""},{"line_number":1232,"context_line":"    def test_object_POST_error(self):"},{"line_number":1233,"context_line":"        code \u003d self._test_method_error(\u0027POST\u0027, \u0027/bucket/object\u0027, None)"}],"source_content_type":"text/x-python","patch_set":3,"id":"4bc26727_62edfb1a","line":1230,"updated":"2026-08-21 10:22:16.000000000","message":"this would be tighter written as:\n```\n        self.assertFalse(self.swift.calls)\n\n```","commit_id":"2619d40e2c79f596107062efcffaf8c83ba752ce"}]}
