)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"ebefd4cf_9ce61dd0","updated":"2023-08-17 15:33:58.000000000","message":"pi","commit_id":"cfdf2ae59b4a20b98dd986ec3d6aa33265accc8f"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":23,"id":"e779cc27_c443ccce","updated":"2023-08-11 01:15:00.000000000","message":"there\u0027s some things I like here - but the test failures and pep8 errors are annoying\n\nit took me awhile to even get it working well enough to start to functional test:\n\nhttps://review.opendev.org/c/openstack/swift/+/891141\n\nplease get into better shape before you push up another revision; feel free to squash in my functional tests if that will help.\n\nI\u0027m starting to question if the SLO API should re-use s3api \"part-number\" or if we should keep it consistent with API docs:\n\nhttps://docs.openstack.org/swift/latest/overview_large_objects.html#module-swift.common.middleware.slo\n\nmaybe Swift API should be multipart-segment\u003dX, and possibly even zero-indexed\n\nI\u0027m not sure when we started responding with the X-Manifest-Etag to all SLO responses, but adding X-Segment-Count to metadata and stashing it on manifest create is probably a good idea to come in with this new API","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"53182890086124f4499de4cbb6c8542bcae2b841","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"bfce1f6a_75435087","updated":"2023-08-21 23:29:46.000000000","message":"I\u0027m only just glancing at this, I have some previous comments that may deserve a response - there\u0027s minor stuff like calling _get_part_num twice right after another that could probably be refactored or cleaned-up a little.\n\nOverall I think the updates to better handle HEAD ?part-num requests seem quite reasonable!  I think the GET path was mostly working, so that\u0027s the last blocker I was really aware of.\n\nI think there may be room for some additional testing, particularlly the combination of the various \"types\" of segments (w/ range, in-line data, sub-slo) that we should at least not error.","commit_id":"6791e8420c07a129040a3186ea5f609af1782af0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0a039ac636a08f38981efebbdffd6d8ea7464b5a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":38,"id":"815ad0ed_06ccaec8","updated":"2023-08-22 14:42:00.000000000","message":"test failures look legit - there was an missing request for HEAD on legacy manifest and we returned the wrong etag.","commit_id":"6791e8420c07a129040a3186ea5f609af1782af0"}],"swift/common/constraints.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"c4260b9b77c760b423b53f44b435bf730f85888b","unresolved":true,"context_lines":[{"line_number":34,"context_line":"MAX_HEADER_SIZE \u003d 8192"},{"line_number":35,"context_line":"MAX_OBJECT_NAME_LENGTH \u003d 1024"},{"line_number":36,"context_line":"CONTAINER_LISTING_LIMIT \u003d 10000"},{"line_number":37,"context_line":"DEFAULT_MAX_MANIFEST_SEGMENTS \u003d 1000"},{"line_number":38,"context_line":"ACCOUNT_LISTING_LIMIT \u003d 10000"},{"line_number":39,"context_line":"MAX_ACCOUNT_NAME_LENGTH \u003d 256"},{"line_number":40,"context_line":"MAX_CONTAINER_NAME_LENGTH \u003d 256"}],"source_content_type":"text/x-python","patch_set":19,"id":"f0a7c2fd_27be2c1d","line":37,"updated":"2023-08-07 22:42:24.000000000","message":"This feels really out of place here:\n\n- Most of these are configured in the `[swift-constraints]` section of /etc/swift/swift.conf, but `max_manifest_segments` comes out of proxy-server.conf.\n- The `DEFAULT_` prefix is awkward; we\u0027d usually indicate the default-ness by updating `DEFAULT_CONSTRAINTS`.","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":34,"context_line":"MAX_HEADER_SIZE \u003d 8192"},{"line_number":35,"context_line":"MAX_OBJECT_NAME_LENGTH \u003d 1024"},{"line_number":36,"context_line":"CONTAINER_LISTING_LIMIT \u003d 10000"},{"line_number":37,"context_line":"DEFAULT_MAX_MANIFEST_SEGMENTS \u003d 1000"},{"line_number":38,"context_line":"ACCOUNT_LISTING_LIMIT \u003d 10000"},{"line_number":39,"context_line":"MAX_ACCOUNT_NAME_LENGTH \u003d 256"},{"line_number":40,"context_line":"MAX_CONTAINER_NAME_LENGTH \u003d 256"}],"source_content_type":"text/x-python","patch_set":19,"id":"a5833ea1_bea9d3f7","line":37,"in_reply_to":"f0a7c2fd_27be2c1d","updated":"2023-08-17 15:33:58.000000000","message":"Ack","commit_id":"99e272a7346e8a6862530607abc1b73286849077"}],"swift/common/middleware/slo.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"e7660ea712599a737e1c38f136e5ea1d047f2fb0","unresolved":true,"context_lines":[{"line_number":1061,"context_line":"                raise HTTPBadRequest(req\u003dreq,"},{"line_number":1062,"context_line":"                                     body\u003d\u0027Invalid part-number query param,\u0027"},{"line_number":1063,"context_line":"                                          \u0027 must be \u0027"},{"line_number":1064,"context_line":"                                          \u0027between 0 and 1000\u0027)"},{"line_number":1065,"context_line":"            byteranges \u003d ["},{"line_number":1066,"context_line":"                # For some reason, swob.Range.ranges_for_length adds 1 to the"},{"line_number":1067,"context_line":"                # last byte\u0027s position."}],"source_content_type":"text/x-python","patch_set":12,"id":"0d800d77_1babfa18","line":1064,"updated":"2023-08-04 22:26:00.000000000","message":"Eh? This doesn\u0027t seem to be the problem -- we want something more like\n\n\u003e Range requests are not supported with part-number queries\n\nyeah? But it\u0027s not clear to me _why_ that would have to be -- why wouldn\u0027t the range slice into the single part? It is mainly for the difficulty/annoyance of dealing with multi-range requests?\n\nAssuming we keep this restriction, do we drop the `Accept-Ranges: bytes` for `?part-number` requests?","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"e7660ea712599a737e1c38f136e5ea1d047f2fb0","unresolved":true,"context_lines":[{"line_number":1069,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1070,"context_line":"        elif req.params.get(\u0027part-number\u0027) is not None:"},{"line_number":1071,"context_line":"            start \u003d 0"},{"line_number":1072,"context_line":"            if 0 \u003c int(req.params.get(\u0027part-number\u0027)) \u003c\u003d \\"},{"line_number":1073,"context_line":"                    DEFAULT_MAX_MANIFEST_SEGMENTS:"},{"line_number":1074,"context_line":"                part_num \u003d int(req.params.get(\u0027part-number\u0027))"},{"line_number":1075,"context_line":"                for seg in segments[:part_num - 1]:"}],"source_content_type":"text/x-python","patch_set":12,"id":"ffe4a64f_08e5d2dd","line":1072,"range":{"start_line":1072,"start_character":19,"end_line":1072,"end_character":22},"updated":"2023-08-04 22:26:00.000000000","message":"Potential `TypeError`","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":1069,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1070,"context_line":"        elif req.params.get(\u0027part-number\u0027) is not None:"},{"line_number":1071,"context_line":"            start \u003d 0"},{"line_number":1072,"context_line":"            if 0 \u003c int(req.params.get(\u0027part-number\u0027)) \u003c\u003d \\"},{"line_number":1073,"context_line":"                    DEFAULT_MAX_MANIFEST_SEGMENTS:"},{"line_number":1074,"context_line":"                part_num \u003d int(req.params.get(\u0027part-number\u0027))"},{"line_number":1075,"context_line":"                for seg in segments[:part_num - 1]:"}],"source_content_type":"text/x-python","patch_set":12,"id":"58a06b40_1dad49ad","line":1072,"range":{"start_line":1072,"start_character":19,"end_line":1072,"end_character":22},"in_reply_to":"ffe4a64f_08e5d2dd","updated":"2023-08-17 15:33:58.000000000","message":"Ack","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"c4260b9b77c760b423b53f44b435bf730f85888b","unresolved":false,"context_lines":[{"line_number":1069,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1070,"context_line":"        elif req.params.get(\u0027part-number\u0027) is not None:"},{"line_number":1071,"context_line":"            start \u003d 0"},{"line_number":1072,"context_line":"            if 0 \u003c int(req.params.get(\u0027part-number\u0027)) \u003c\u003d \\"},{"line_number":1073,"context_line":"                    DEFAULT_MAX_MANIFEST_SEGMENTS:"},{"line_number":1074,"context_line":"                part_num \u003d int(req.params.get(\u0027part-number\u0027))"},{"line_number":1075,"context_line":"                for seg in segments[:part_num - 1]:"}],"source_content_type":"text/x-python","patch_set":12,"id":"7047cea0_3381fec3","line":1072,"range":{"start_line":1072,"start_character":19,"end_line":1072,"end_character":22},"in_reply_to":"ffe4a64f_08e5d2dd","updated":"2023-08-07 22:42:24.000000000","message":"Bah, I meant `ValueError` -- but you got what I meant 😊","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"e7660ea712599a737e1c38f136e5ea1d047f2fb0","unresolved":true,"context_lines":[{"line_number":1070,"context_line":"        elif req.params.get(\u0027part-number\u0027) is not None:"},{"line_number":1071,"context_line":"            start \u003d 0"},{"line_number":1072,"context_line":"            if 0 \u003c int(req.params.get(\u0027part-number\u0027)) \u003c\u003d \\"},{"line_number":1073,"context_line":"                    DEFAULT_MAX_MANIFEST_SEGMENTS:"},{"line_number":1074,"context_line":"                part_num \u003d int(req.params.get(\u0027part-number\u0027))"},{"line_number":1075,"context_line":"                for seg in segments[:part_num - 1]:"},{"line_number":1076,"context_line":"                    start +\u003d seg[\u0027segment-length\u0027]"}],"source_content_type":"text/x-python","patch_set":12,"id":"60e5da8e_ab1802f0","line":1073,"range":{"start_line":1073,"start_character":20,"end_line":1073,"end_character":49},"updated":"2023-08-04 22:26:00.000000000","message":"What if someone\u0027s got their cluster configured with `max_manifest_segments \u003d 10000` (i.e., 10x the default)? They can use `?part-number\u003d0` through `?part-number\u003d999`, but any segments after that are out of luck?\n\nIf a client asks for `?part-number\u003d999` but there are only 10 segments, say, won\u0027t we `IndexError` on L1082?","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":1070,"context_line":"        elif req.params.get(\u0027part-number\u0027) is not None:"},{"line_number":1071,"context_line":"            start \u003d 0"},{"line_number":1072,"context_line":"            if 0 \u003c int(req.params.get(\u0027part-number\u0027)) \u003c\u003d \\"},{"line_number":1073,"context_line":"                    DEFAULT_MAX_MANIFEST_SEGMENTS:"},{"line_number":1074,"context_line":"                part_num \u003d int(req.params.get(\u0027part-number\u0027))"},{"line_number":1075,"context_line":"                for seg in segments[:part_num - 1]:"},{"line_number":1076,"context_line":"                    start +\u003d seg[\u0027segment-length\u0027]"}],"source_content_type":"text/x-python","patch_set":12,"id":"da8b99c5_80403767","line":1073,"range":{"start_line":1073,"start_character":20,"end_line":1073,"end_character":49},"in_reply_to":"60e5da8e_ab1802f0","updated":"2023-08-17 15:33:58.000000000","message":"Yes, your correct maybe adding a criteria for an upper bound to the object size could potentially be a right move and err other wise with a 400 saying part-num param exceeds no. of parts","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"e7660ea712599a737e1c38f136e5ea1d047f2fb0","unresolved":true,"context_lines":[{"line_number":1084,"context_line":"        else:"},{"line_number":1085,"context_line":"            total_length \u003d sum(self._segment_length(seg)"},{"line_number":1086,"context_line":"                               for seg in segments)"},{"line_number":1087,"context_line":"            byteranges \u003d [(0, total_length - 1)]"},{"line_number":1088,"context_line":""},{"line_number":1089,"context_line":"        ver, account, _junk \u003d req.split_path(3, 3, rest_with_last\u003dTrue)"},{"line_number":1090,"context_line":"        account \u003d wsgi_to_str(account)"}],"source_content_type":"text/x-python","patch_set":12,"id":"ef7e4845_6c7181a2","line":1087,"updated":"2023-08-04 22:26:00.000000000","message":"Good call; I like pulling this out of `_segment_listing_iterator` 👍","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":1084,"context_line":"        else:"},{"line_number":1085,"context_line":"            total_length \u003d sum(self._segment_length(seg)"},{"line_number":1086,"context_line":"                               for seg in segments)"},{"line_number":1087,"context_line":"            byteranges \u003d [(0, total_length - 1)]"},{"line_number":1088,"context_line":""},{"line_number":1089,"context_line":"        ver, account, _junk \u003d req.split_path(3, 3, rest_with_last\u003dTrue)"},{"line_number":1090,"context_line":"        account \u003d wsgi_to_str(account)"}],"source_content_type":"text/x-python","patch_set":12,"id":"e626f82b_145cf6ba","line":1087,"in_reply_to":"ef7e4845_6c7181a2","updated":"2023-08-17 15:33:58.000000000","message":"Ack","commit_id":"f2fa6b15c249662408839c5600f2af6b6c0349c1"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"c4260b9b77c760b423b53f44b435bf730f85888b","unresolved":true,"context_lines":[{"line_number":1061,"context_line":"                # last byte\u0027s position."},{"line_number":1062,"context_line":"                (start, end - 1) for start, end"},{"line_number":1063,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1064,"context_line":"        elif get_part_num(req) is not None:"},{"line_number":1065,"context_line":"            part_num \u003d get_part_num(req, len(segments))"},{"line_number":1066,"context_line":"            start \u003d 0"},{"line_number":1067,"context_line":"            for seg in segments[:part_num - 1]:"}],"source_content_type":"text/x-python","patch_set":19,"id":"2ba5d3df_b15d66cf","line":1064,"range":{"start_line":1064,"start_character":13,"end_line":1064,"end_character":25},"updated":"2023-08-07 22:42:24.000000000","message":"This is the only call where we don\u0027t pass in `len(segments)`, and we\u0027ve already got `segments` in hand -- we should probably just make `parts_count` required.","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":1061,"context_line":"                # last byte\u0027s position."},{"line_number":1062,"context_line":"                (start, end - 1) for start, end"},{"line_number":1063,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1064,"context_line":"        elif get_part_num(req) is not None:"},{"line_number":1065,"context_line":"            part_num \u003d get_part_num(req, len(segments))"},{"line_number":1066,"context_line":"            start \u003d 0"},{"line_number":1067,"context_line":"            for seg in segments[:part_num - 1]:"}],"source_content_type":"text/x-python","patch_set":19,"id":"a854ba11_08d9ec49","line":1064,"range":{"start_line":1064,"start_character":13,"end_line":1064,"end_character":25},"in_reply_to":"2ba5d3df_b15d66cf","updated":"2023-08-17 15:33:58.000000000","message":"Done","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":790,"context_line":"                calculated_slo_object_size \u003d \\"},{"line_number":791,"context_line":"                    segments[part_number - 1].get(\u0027segment-length\u0027)"},{"line_number":792,"context_line":"                client_response_headers.append((\u0027X-Parts-Count\u0027,"},{"line_number":793,"context_line":"                                                len(segments)))"},{"line_number":794,"context_line":""},{"line_number":795,"context_line":"        if slo_etag is None:"},{"line_number":796,"context_line":"            slo_etag \u003d calculated_etag.hexdigest()"}],"source_content_type":"text/x-python","patch_set":23,"id":"656d5378_2fd7afe8","line":793,"updated":"2023-08-11 01:15:00.000000000","message":"Why are we doing this for every segment in the segments loop?  this header is getting added multiple times.\n\n\nthis function is getting called for every segment, and every time it\u0027s adding this header\n\nAug 11 00:39:41 saio proxy-server: headers: [(\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027, \u0027d0e4503aace9e8718151efef6390eba6; slo_etag\u003da0f1d4803ad2fe6cc92d8aca910d792d\u0027), (\u0027Content-Type\u0027, \u0027application/octet-stream\u0027), (\u0027X-Object-Sysmeta-Slo-Etag\u0027, \u0027a0f1d4803ad2fe6cc92d8aca910d792d\u0027), (\u0027X-Object-Sysmeta-Slo-Size\u0027, \u00274194305\u0027), (\u0027X-Static-Large-Object\u0027, \u0027True\u0027), (\u0027X-Manifest-Etag\u0027, \u0027d0e4503aace9e8718151efef6390eba6\u0027), (\u0027Last-Modified\u0027, \u0027Fri, 11 Aug 2023 00:31:09 GMT\u0027), (\u0027X-Timestamp\u0027, \u00271691713868.18645\u0027), (\u0027X-Backend-Timestamp\u0027, \u00271691713868.18645\u0027), (\u0027X-Backend-Data-Timestamp\u0027, \u00271691713868.18645\u0027), (\u0027X-Backend-Durable-Timestamp\u0027, \u00271691713868.18645\u0027), (\u0027Accept-Ranges\u0027, \u0027bytes\u0027), (\u0027X-Parts-Count\u0027, 5), (\u0027X-Parts-Count\u0027, 5), (\u0027X-Parts-Count\u0027, 5), (\u0027X-Parts-Count\u0027, 5), (\u0027X-Parts-Count\u0027, 5), (\u0027Content-Length\u0027, \u00274194305\u0027), (\u0027Etag\u0027, \u0027\"a0f1d4803ad2fe6cc92d8aca910d792d\"\u0027)] (txn: tx2b70bce9419e498aa9aa7-0064d5834d) (client_ip: 127.0.0.1)","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":true,"context_lines":[{"line_number":790,"context_line":"                calculated_slo_object_size \u003d \\"},{"line_number":791,"context_line":"                    segments[part_number - 1].get(\u0027segment-length\u0027)"},{"line_number":792,"context_line":"                client_response_headers.append((\u0027X-Parts-Count\u0027,"},{"line_number":793,"context_line":"                                                len(segments)))"},{"line_number":794,"context_line":""},{"line_number":795,"context_line":"        if slo_etag is None:"},{"line_number":796,"context_line":"            slo_etag \u003d calculated_etag.hexdigest()"}],"source_content_type":"text/x-python","patch_set":23,"id":"f1deeb9f_971b45d6","line":793,"in_reply_to":"656d5378_2fd7afe8","updated":"2023-08-17 15:33:58.000000000","message":"My understanding was that the metadata \"X-Parts-Count\" will be a new metadata header that will be associated with an object for all object API calls, I realized that @Tim Burke  wanted it exposed only for part-num apis","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":794,"context_line":""},{"line_number":795,"context_line":"        if slo_etag is None:"},{"line_number":796,"context_line":"            slo_etag \u003d calculated_etag.hexdigest()"},{"line_number":797,"context_line":"        if slo_object_size is None:"},{"line_number":798,"context_line":"            slo_object_size \u003d calculated_slo_object_size"},{"line_number":799,"context_line":""},{"line_number":800,"context_line":"        return slo_etag, slo_object_size, client_response_headers"}],"source_content_type":"text/x-python","patch_set":23,"id":"d56e7de4_48cc04a6","line":797,"updated":"2023-08-11 01:15:00.000000000","message":"i think this is only rarely going to be None, specifically in the case for legacy SLO written w/o the size in the metadata headers","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":926,"context_line":"            resp.headers.update({"},{"line_number":927,"context_line":"                \u0027Etag\u0027: \u0027\"%s\"\u0027 % slo_etag,"},{"line_number":928,"context_line":"                \u0027X-Manifest-Etag\u0027: self._response_header_value(\u0027etag\u0027),"},{"line_number":929,"context_line":"                \u0027Content-Length\u0027: slo_size,"},{"line_number":930,"context_line":"            })"},{"line_number":931,"context_line":"            return resp(req.environ, start_response)"},{"line_number":932,"context_line":""}],"source_content_type":"text/x-python","patch_set":23,"id":"95a2d2be_67aececb","line":929,"updated":"2023-08-11 01:15:00.000000000","message":"in my testing this early return is very common for HEAD responses and gets the content-length wrong for part-number requests\n\nI think your unittests that are testing HEADs aren\u0027t registering the slo manifest responses with the slo etag/size metadata like you\u0027d expect to see on newly created slo manifests.\n\nWe have a bunch of SLO sysmeta we don\u0027t expose to swift slo api responses, we might want to add X-Object-Sysmeta-Slo-Segment-Count on create too\n\nSystem Metadata:\n  X-Object-Sysmeta-Container-Update-Override-Etag: 659ce1e4bac075db45ccacd17d2939ac; slo_etag\u003da0f1d4803ad2fe6cc92d8aca910d792d\n  X-Object-Sysmeta-Slo-Etag: a0f1d4803ad2fe6cc92d8aca910d792d\n  X-Object-Sysmeta-Slo-Size: 4194305","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":1030,"context_line":"        \"\"\""},{"line_number":1031,"context_line":"        resp_headers \u003d self._response_headers"},{"line_number":1032,"context_line":"        try:"},{"line_number":1033,"context_line":"            part_number \u003d int(get_param(req, \u0027part-number\u0027))"},{"line_number":1034,"context_line":"            resp_headers.append((\u0027X-Parts-Count\u0027, parts_count))"},{"line_number":1035,"context_line":"            if part_number \u003d\u003d 0:"},{"line_number":1036,"context_line":"                resp_headers.append((\u0027Content-Range\u0027, \u0027bytes */%d\u0027 % ("}],"source_content_type":"text/x-python","patch_set":23,"id":"9683d722_156ad171","line":1033,"updated":"2023-08-11 01:15:00.000000000","message":"a bunch of slo func tests failed for me with a traceback here:\n\n\tAug 10 22:08:53 saio proxy-server: Error: An error occurred: \n\tTraceback (most recent call last):\n\t  File \"/vagrant/swift/swift/common/middleware/catch_errors.py\", line 75, in handle_request\n\t    resp \u003d self._app_call(env)\n\t  File \"/vagrant/swift/swift/common/wsgi.py\", line 1126, in _app_call\n\t    resp \u003d self.app(env, self._start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/gatekeeper.py\", line 129, in __call__\n\t    return self.app(env, gatekeeper_response)\n\t  File \"/vagrant/swift/swift/common/middleware/healthcheck.py\", line 52, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/proxy_logging.py\", line 463, in __call__\n\t    iterable \u003d self.app(env, my_start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/domain_remap.py\", line 199, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/memcache.py\", line 32, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/listing_formats.py\", line 157, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/etag_quoter.py\", line 107, in __call__\n\t    status, headers, resp_iter \u003d req.call_application(self.app)\n\t  File \"/vagrant/swift/swift/common/swob.py\", line 1149, in call_application\n\t    app_iter \u003d application(self.environ, start_response)\n\t  File \"/vagrant/swift/swift/common/swob.py\", line 1576, in _wsgify\n\t    return func(*new_args)(env, start_response)\n\t  File \"/vagrant/swift/swift/common/swob.py\", line 1576, in _wsgify\n\t    return func(*new_args)(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/tempurl.py\", line 502, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/s3api/s3api.py\", line 369, in __call__\n\t    return resp(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/s3api/s3api.py\", line 195, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/tempauth.py\", line 349, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/copy.py\", line 253, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/ratelimit.py\", line 322, in __call__\n\t    return self.app(env, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/slo.py\", line 1793, in __call__\n\t    return self.handle_multipart_get_or_head(req, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/slo.py\", line 1236, in handle_multipart_get_or_head\n\t    return SloGetContext(self).handle_slo_get_or_head(req, start_response)\n\t  File \"/vagrant/swift/swift/common/middleware/slo.py\", line 978, in handle_slo_get_or_head\n\t    response \u003d self.get_or_head_response(\n\t  File \"/vagrant/swift/swift/common/middleware/slo.py\", line 1068, in get_or_head_response\n\t    self._calculate_slo_attributes(req, resp_headers, segments)\n\t  File \"/vagrant/swift/swift/common/middleware/slo.py\", line 786, in _calculate_slo_attributes\n\t    part_number \u003d self._get_part_num(request, len(segments))\n\t  File \"/vagrant/swift/swift/common/middleware/slo.py\", line 1033, in _get_part_num\n\t    part_number \u003d int(get_param(req, \u0027part-number\u0027))\n\tTypeError: int() argument must be a string, a bytes-like object or a real number, not \u0027NoneType\u0027 (txn: tx93ae5da3a9cb4164845e8-0064d55ff5) (client_ip: 127.0.0.1)\n\t\n... which makes sense to me not all requests are going to have part-number param and `int(None)` is going to `TypeError`","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"1ac12f86592ff3a416cbc749cf79c876931c45da","unresolved":false,"context_lines":[{"line_number":1030,"context_line":"        \"\"\""},{"line_number":1031,"context_line":"        resp_headers \u003d self._response_headers"},{"line_number":1032,"context_line":"        try:"},{"line_number":1033,"context_line":"            part_number \u003d int(get_param(req, \u0027part-number\u0027))"},{"line_number":1034,"context_line":"            resp_headers.append((\u0027X-Parts-Count\u0027, parts_count))"},{"line_number":1035,"context_line":"            if part_number \u003d\u003d 0:"},{"line_number":1036,"context_line":"                resp_headers.append((\u0027Content-Range\u0027, \u0027bytes */%d\u0027 % ("}],"source_content_type":"text/x-python","patch_set":23,"id":"46c96944_f9bf2d56","line":1033,"in_reply_to":"9683d722_156ad171","updated":"2023-08-30 17:28:02.000000000","message":"Ack","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":1031,"context_line":"        resp_headers \u003d self._response_headers"},{"line_number":1032,"context_line":"        try:"},{"line_number":1033,"context_line":"            part_number \u003d int(get_param(req, \u0027part-number\u0027))"},{"line_number":1034,"context_line":"            resp_headers.append((\u0027X-Parts-Count\u0027, parts_count))"},{"line_number":1035,"context_line":"            if part_number \u003d\u003d 0:"},{"line_number":1036,"context_line":"                resp_headers.append((\u0027Content-Range\u0027, \u0027bytes */%d\u0027 % ("},{"line_number":1037,"context_line":"                            part_number, )))"}],"source_content_type":"text/x-python","patch_set":23,"id":"4d960e17_7e4d7e96","line":1034,"updated":"2023-08-11 01:15:00.000000000","message":"these are the manifest request response headers, these aren\u0027t the client_response_headers, there\u0027s no point to annotate them the client client will never see them.","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"1ac12f86592ff3a416cbc749cf79c876931c45da","unresolved":false,"context_lines":[{"line_number":1031,"context_line":"        resp_headers \u003d self._response_headers"},{"line_number":1032,"context_line":"        try:"},{"line_number":1033,"context_line":"            part_number \u003d int(get_param(req, \u0027part-number\u0027))"},{"line_number":1034,"context_line":"            resp_headers.append((\u0027X-Parts-Count\u0027, parts_count))"},{"line_number":1035,"context_line":"            if part_number \u003d\u003d 0:"},{"line_number":1036,"context_line":"                resp_headers.append((\u0027Content-Range\u0027, \u0027bytes */%d\u0027 % ("},{"line_number":1037,"context_line":"                            part_number, )))"}],"source_content_type":"text/x-python","patch_set":23,"id":"7731b00c_ea891314","line":1034,"in_reply_to":"4d960e17_7e4d7e96","updated":"2023-08-30 17:28:02.000000000","message":"Ack","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":1067,"context_line":"        slo_etag, slo_content_length, response_headers \u003d \\"},{"line_number":1068,"context_line":"            self._calculate_slo_attributes(req, resp_headers, segments)"},{"line_number":1069,"context_line":""},{"line_number":1070,"context_line":"        response_headers.append((\u0027Content-Length\u0027, str(slo_content_length)))"},{"line_number":1071,"context_line":"        response_headers.append((\u0027Etag\u0027, \u0027\"%s\"\u0027 % slo_etag))"},{"line_number":1072,"context_line":""},{"line_number":1073,"context_line":"        if req.method \u003d\u003d \u0027HEAD\u0027:"}],"source_content_type":"text/x-python","patch_set":23,"id":"c928bc34_0a1a7e7f","line":1070,"updated":"2023-08-11 01:15:00.000000000","message":"ok, so slo_object_size/slo_content_length is actually just the resp content-length\n\n... so that\u0027s why it gets modified for part-number requests.\n\nI don\u0027t like that slo_content_length means different things depending on the request params, but then we pass it around.  If we could move this response_headers manipulatoin inside _annotate_segments_and_calculate_response_headers and just have it return the response_headers then at least we\u0027d have everything in one method.","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":1093,"context_line":"                # For some reason, swob.Range.ranges_for_length adds 1 to the"},{"line_number":1094,"context_line":"                # last byte\u0027s position."},{"line_number":1095,"context_line":"                (start, end - 1) for start, end"},{"line_number":1096,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1097,"context_line":"        elif self._get_part_num(req, len(segments)) is not None:"},{"line_number":1098,"context_line":"            part_num \u003d self._get_part_num(req, len(segments))"},{"line_number":1099,"context_line":"            start \u003d 0"}],"source_content_type":"text/x-python","patch_set":23,"id":"5c0516a3_f011e02a","line":1096,"updated":"2023-08-11 01:15:00.000000000","message":"ugh, yeah it bugs me that content_length passed to this method not actually be the size of the SLO, but at least the name here is more obvious\n\nmaybe move this byteranges calculation above _manifest_get_response","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"316b345e328060b5849be24a8146635f4156d2be","unresolved":true,"context_lines":[{"line_number":1095,"context_line":"                (start, end - 1) for start, end"},{"line_number":1096,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1097,"context_line":"        elif self._get_part_num(req, len(segments)) is not None:"},{"line_number":1098,"context_line":"            part_num \u003d self._get_part_num(req, len(segments))"},{"line_number":1099,"context_line":"            start \u003d 0"},{"line_number":1100,"context_line":"            for seg in segments[:part_num - 1]:"},{"line_number":1101,"context_line":"                start +\u003d seg[\u0027segment-length\u0027]"}],"source_content_type":"text/x-python","patch_set":23,"id":"0c5f7080_1dbf28d9","line":1098,"updated":"2023-08-11 01:15:00.000000000","message":"it\u0027s kinda gross to call _get_part_num twice here","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"1ac12f86592ff3a416cbc749cf79c876931c45da","unresolved":false,"context_lines":[{"line_number":1095,"context_line":"                (start, end - 1) for start, end"},{"line_number":1096,"context_line":"                in req.range.ranges_for_length(content_length)]"},{"line_number":1097,"context_line":"        elif self._get_part_num(req, len(segments)) is not None:"},{"line_number":1098,"context_line":"            part_num \u003d self._get_part_num(req, len(segments))"},{"line_number":1099,"context_line":"            start \u003d 0"},{"line_number":1100,"context_line":"            for seg in segments[:part_num - 1]:"},{"line_number":1101,"context_line":"                start +\u003d seg[\u0027segment-length\u0027]"}],"source_content_type":"text/x-python","patch_set":23,"id":"c750e30b_16388a20","line":1098,"in_reply_to":"0c5f7080_1dbf28d9","updated":"2023-08-30 17:28:02.000000000","message":"Done","commit_id":"e2ca3c48a7bcf03ffc98ea81c3025db2d3972c51"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"53182890086124f4499de4cbb6c8542bcae2b841","unresolved":true,"context_lines":[{"line_number":772,"context_line":"            req.environ, method\u003d\u0027GET\u0027,"},{"line_number":773,"context_line":"            headers\u003d{\u0027x-auth-token\u0027: req.headers.get(\u0027x-auth-token\u0027)},"},{"line_number":774,"context_line":"            agent\u003d\u0027%(orig)s SLO MultipartGET\u0027, swift_source\u003d\u0027SLO\u0027)"},{"line_number":775,"context_line":"        return self._app_call(get_req.environ)"},{"line_number":776,"context_line":""},{"line_number":777,"context_line":"    def handle_slo_get_or_head(self, req, start_response):"},{"line_number":778,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":38,"id":"9c750b90_5ec83589","side":"PARENT","line":775,"updated":"2023-08-21 23:29:46.000000000","message":"oic, this just got moved to up earlier; around L583\n\nit\u0027s still part of the SloGETContext class","commit_id":"d8c802c9d384d2f5a78da92036bbd06a8fef21cf"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"1ac12f86592ff3a416cbc749cf79c876931c45da","unresolved":false,"context_lines":[{"line_number":772,"context_line":"            req.environ, method\u003d\u0027GET\u0027,"},{"line_number":773,"context_line":"            headers\u003d{\u0027x-auth-token\u0027: req.headers.get(\u0027x-auth-token\u0027)},"},{"line_number":774,"context_line":"            agent\u003d\u0027%(orig)s SLO MultipartGET\u0027, swift_source\u003d\u0027SLO\u0027)"},{"line_number":775,"context_line":"        return self._app_call(get_req.environ)"},{"line_number":776,"context_line":""},{"line_number":777,"context_line":"    def handle_slo_get_or_head(self, req, start_response):"},{"line_number":778,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":38,"id":"03dcd7ed_97b69f5f","side":"PARENT","line":775,"in_reply_to":"9c750b90_5ec83589","updated":"2023-08-30 17:28:02.000000000","message":"Ack","commit_id":"d8c802c9d384d2f5a78da92036bbd06a8fef21cf"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"53182890086124f4499de4cbb6c8542bcae2b841","unresolved":true,"context_lines":[{"line_number":955,"context_line":"                \u0027X-Manifest-Etag\u0027: self._response_header_value(\u0027etag\u0027),"},{"line_number":956,"context_line":"                \u0027Content-Length\u0027: slo_content_length,"},{"line_number":957,"context_line":"            })"},{"line_number":958,"context_line":"            return resp(req.environ, start_response)"},{"line_number":959,"context_line":"        if slo_etag and slo_size and ("},{"line_number":960,"context_line":"                req.method \u003d\u003d \u0027HEAD\u0027 or is_conditional):"},{"line_number":961,"context_line":"            # Since we have length and etag, we can respond immediately"}],"source_content_type":"text/x-python","patch_set":38,"id":"87ca35dd_3d8659ca","line":958,"updated":"2023-08-21 23:29:46.000000000","message":"this method is pretty long and has some cyclomatic complexity - it\u0027s perhaps not ideal to add another \"special case\" with an early return - but definately an existing problem with how this code is currently factored.","commit_id":"6791e8420c07a129040a3186ea5f609af1782af0"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"1ac12f86592ff3a416cbc749cf79c876931c45da","unresolved":false,"context_lines":[{"line_number":955,"context_line":"                \u0027X-Manifest-Etag\u0027: self._response_header_value(\u0027etag\u0027),"},{"line_number":956,"context_line":"                \u0027Content-Length\u0027: slo_content_length,"},{"line_number":957,"context_line":"            })"},{"line_number":958,"context_line":"            return resp(req.environ, start_response)"},{"line_number":959,"context_line":"        if slo_etag and slo_size and ("},{"line_number":960,"context_line":"                req.method \u003d\u003d \u0027HEAD\u0027 or is_conditional):"},{"line_number":961,"context_line":"            # Since we have length and etag, we can respond immediately"}],"source_content_type":"text/x-python","patch_set":38,"id":"12688e2f_a09a4f0e","line":958,"in_reply_to":"87ca35dd_3d8659ca","updated":"2023-08-30 17:28:02.000000000","message":"Ack","commit_id":"6791e8420c07a129040a3186ea5f609af1782af0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"53182890086124f4499de4cbb6c8542bcae2b841","unresolved":true,"context_lines":[{"line_number":1116,"context_line":"        response_headers.append((\u0027Content-Length\u0027, str(slo_content_length)))"},{"line_number":1117,"context_line":""},{"line_number":1118,"context_line":"        if req.method \u003d\u003d \u0027HEAD\u0027:"},{"line_number":1119,"context_line":"            return self._manifest_head_response(req, response_headers)"},{"line_number":1120,"context_line":"        else:"},{"line_number":1121,"context_line":"            return self._manifest_get_response("},{"line_number":1122,"context_line":"                req, slo_content_length, response_headers, segments)"}],"source_content_type":"text/x-python","patch_set":38,"id":"ddee882f_4fbac162","line":1119,"updated":"2023-08-21 23:29:46.000000000","message":"so lots of HEAD responses might result in a refetch and early response - but i think this case is still needed in some cases.","commit_id":"6791e8420c07a129040a3186ea5f609af1782af0"}],"swift/common/request_helpers.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"c4260b9b77c760b423b53f44b435bf730f85888b","unresolved":true,"context_lines":[{"line_number":94,"context_line":"    return value"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"def get_part_num(req, parts_count\u003dNone):"},{"line_number":98,"context_line":"    \"\"\""},{"line_number":99,"context_line":"     Parses the part num param from request and raises"},{"line_number":100,"context_line":"     HTTPBadRequest if missing or invalid."}],"source_content_type":"text/x-python","patch_set":19,"id":"dfcb6914_696bc322","line":97,"updated":"2023-08-07 22:42:24.000000000","message":"Do we foresee a use for this outside of SLO? Feels a little out of place to have this here.","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":94,"context_line":"    return value"},{"line_number":95,"context_line":""},{"line_number":96,"context_line":""},{"line_number":97,"context_line":"def get_part_num(req, parts_count\u003dNone):"},{"line_number":98,"context_line":"    \"\"\""},{"line_number":99,"context_line":"     Parses the part num param from request and raises"},{"line_number":100,"context_line":"     HTTPBadRequest if missing or invalid."}],"source_content_type":"text/x-python","patch_set":19,"id":"eef61583_9b008648","line":97,"in_reply_to":"dfcb6914_696bc322","updated":"2023-08-17 15:33:58.000000000","message":"I do not really, I will move it into slo.py","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"c4260b9b77c760b423b53f44b435bf730f85888b","unresolved":true,"context_lines":[{"line_number":108,"context_line":"        part_number \u003d int(get_param(req, \u0027part-number\u0027))"},{"line_number":109,"context_line":"        parts_count \u003d DEFAULT_MAX_MANIFEST_SEGMENTS if parts_count is None \\"},{"line_number":110,"context_line":"            else parts_count"},{"line_number":111,"context_line":"        if part_number \u003c 1 or parts_count \u003c part_number:"},{"line_number":112,"context_line":"            raise Exception()"},{"line_number":113,"context_line":"    except Exception:"},{"line_number":114,"context_line":"        err_msg \u003d \u0027Invalid part-number query param\u0027"}],"source_content_type":"text/x-python","patch_set":19,"id":"c09a0be1_43d41b43","line":111,"updated":"2023-08-07 22:42:24.000000000","message":"We might want to distinguish these two cases, similar to how we behave differently for a malformed `Range` header vs one that specifies a range beyond the size of the object. In particular, I\u0027d say that a client specifying `part_number \u003e parts_count` probably deserves to know how many parts there *are* somewhere in the headers.\n\nThe main edge case where I could see this coming up is with an empty manifest. Seems better to send back a 416 with `Content-Range: bytes */0` and `X-Parts-Count: 0` than 400 and making the user wonder whether there\u0027s some client bug that\u0027s causing it to send a malformed param.","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":108,"context_line":"        part_number \u003d int(get_param(req, \u0027part-number\u0027))"},{"line_number":109,"context_line":"        parts_count \u003d DEFAULT_MAX_MANIFEST_SEGMENTS if parts_count is None \\"},{"line_number":110,"context_line":"            else parts_count"},{"line_number":111,"context_line":"        if part_number \u003c 1 or parts_count \u003c part_number:"},{"line_number":112,"context_line":"            raise Exception()"},{"line_number":113,"context_line":"    except Exception:"},{"line_number":114,"context_line":"        err_msg \u003d \u0027Invalid part-number query param\u0027"}],"source_content_type":"text/x-python","patch_set":19,"id":"b74faa23_e021a037","line":111,"in_reply_to":"c09a0be1_43d41b43","updated":"2023-08-17 15:33:58.000000000","message":"Ack","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"c4260b9b77c760b423b53f44b435bf730f85888b","unresolved":true,"context_lines":[{"line_number":110,"context_line":"            else parts_count"},{"line_number":111,"context_line":"        if part_number \u003c 1 or parts_count \u003c part_number:"},{"line_number":112,"context_line":"            raise Exception()"},{"line_number":113,"context_line":"    except Exception:"},{"line_number":114,"context_line":"        err_msg \u003d \u0027Invalid part-number query param\u0027"},{"line_number":115,"context_line":"        raise HTTPBadRequest("},{"line_number":116,"context_line":"            request\u003dreq,"}],"source_content_type":"text/x-python","patch_set":19,"id":"cb7ce22e_3f30891a","line":113,"updated":"2023-08-07 22:42:24.000000000","message":"Rather broad -- why not just `ValueError`, and `raise ValueError` on the line above?","commit_id":"99e272a7346e8a6862530607abc1b73286849077"},{"author":{"_account_id":34892,"name":"ASHWIN A NAIR","display_name":"indianwhocodes","email":"nairashwin952013@gmail.com","username":"indianwhocodes","status":"Nvidia"},"change_message_id":"d74e5f6b6145e67ef7e19ac452dab8049e6be147","unresolved":false,"context_lines":[{"line_number":110,"context_line":"            else parts_count"},{"line_number":111,"context_line":"        if part_number \u003c 1 or parts_count \u003c part_number:"},{"line_number":112,"context_line":"            raise Exception()"},{"line_number":113,"context_line":"    except Exception:"},{"line_number":114,"context_line":"        err_msg \u003d \u0027Invalid part-number query param\u0027"},{"line_number":115,"context_line":"        raise HTTPBadRequest("},{"line_number":116,"context_line":"            request\u003dreq,"}],"source_content_type":"text/x-python","patch_set":19,"id":"ac28970f_68afdfc8","line":113,"in_reply_to":"cb7ce22e_3f30891a","updated":"2023-08-17 15:33:58.000000000","message":"Understood.","commit_id":"99e272a7346e8a6862530607abc1b73286849077"}],"test/unit/common/middleware/test_slo.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"0a039ac636a08f38981efebbdffd6d8ea7464b5a","unresolved":true,"context_lines":[{"line_number":2453,"context_line":"        manifest_etag \u003d md5hex(md5hex(\"b\" * 10) + md5hex(\"c\" * 15))"},{"line_number":2454,"context_line":"        self.assertEqual(status, \u0027200 OK\u0027)"},{"line_number":2455,"context_line":"        self.assertEqual(headers[\u0027Content-Length\u0027], \u002725\u0027)"},{"line_number":2456,"context_line":"        self.assertEqual(headers[\u0027Etag\u0027], \u0027\"%s\"\u0027 % manifest_etag)"},{"line_number":2457,"context_line":"        self.assertEqual(headers[\u0027X-Object-Meta-Plant\u0027], \u0027Ficus\u0027)"},{"line_number":2458,"context_line":"        self.assertEqual(body, b\u0027bbbbbbbbbbccccccccccccccc\u0027)"},{"line_number":2459,"context_line":""}],"source_content_type":"text/x-python","patch_set":38,"id":"3c09cc1f_557fcf3f","side":"PARENT","line":2456,"updated":"2023-08-22 14:42:00.000000000","message":"hopefully some reviewer would have noticed this change doesn\u0027t make sense\n\nthis is a conditional HEAD on the large object (no ?multipart-manifest\u003dget param); so it\u0027s only reasonable that it return the large object etag (not the etag of the manifest)\n\nfixed:\n\nhttps://review.opendev.org/c/openstack/swift/+/892361","commit_id":"d8c802c9d384d2f5a78da92036bbd06a8fef21cf"}]}
