)]}'
{"/PATCHSET_LEVEL":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"d9d192c95a25958e9ee21c3ebf8509f4b76d518a","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":3,"id":"0971b908_fc2da67c","updated":"2024-01-19 06:45:11.000000000","message":"From my limited testing it seems the old cgi parse_header doesn\u0027t support qouted semi colons (`\\\\;`) either.\n\n  \u003e\u003e\u003e from cgi import parse_header\n  \u003e\u003e\u003e parse_header(\u0027foobar; param\u003d\"has; semicolons\"\u0027)\n  (\u0027foobar\u0027, {\u0027param\u0027: \u0027has; semicolons\u0027})\n  \u003e\u003e\u003e parse_header(\u0027foobar; param\u003d\"has\\\\; semicolons\"\u0027)\n  (\u0027foobar\u0027, {\u0027param\u0027: \u0027has\\\\; semicolons\u0027})\n\nSo maybe we don\u0027t need to either?","commit_id":"4583d5bed012781ec649860dd21e7906dc2f2d1e"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1c225c215b6c446f322c977f425c88308ec52f6c","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"4d2e107d_4f53aca0","updated":"2024-07-19 03:07:18.000000000","message":"4 test cases from upstream all failed, I am not sure if those test cases exist in our usages, but the generic cgi.parse_header supports them, \"-1\" to raise a concern here.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"e651fbe9c96c5e09b4806f9e7b4a136fccef3dc7","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"54c914bf_5cfe855c","updated":"2024-07-25 02:47:49.000000000","message":"I do like the name change, but also understand Tim\u0027s reluctance. We could do a wrapper.. but this is also python so can\u0027t we just (see inline)?","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5da2b6e4096c2afd36dcce818f17b0867d1de4aa","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"97a990e8_0684d9c0","updated":"2024-07-23 15:55:16.000000000","message":"LGTM, that\u0027ll be great if we can add a new wrapper function like ``parse_header`` in utils.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"edcb4b0ef4205f3772d15382b0cccedf22821207","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"4bcacd56_76618eff","updated":"2024-08-06 22:56:31.000000000","message":"OK, alternate idea: https://review.opendev.org/c/openstack/swift/+/925825","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"000745e1ccf08118652eae845d3a6d3cda851863","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":4,"id":"ed8d80db_955e3123","updated":"2024-06-17 20:22:31.000000000","message":"recheck\n\nPretty sure all those failures were because of .git directory ownership issues that have since been remedied.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"5fbb1eb0737ec5f61fddd95c76522b929a80cb78","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"431070b5_51c87bbc","updated":"2024-10-16 10:49:35.000000000","message":"I added a parse_header wrapper for parse_content_type as per previous comments\n\nNote: there\u0027s an alternative patch here https://review.opendev.org/c/openstack/swift/+/932452","commit_id":"862ef0bdc1a346a557b92af6284e57a94a861a5b"},{"author":{"_account_id":6476,"name":"Thomas Goirand","email":"thomas@goirand.fr","username":"thomas-goirand"},"change_message_id":"75e4c37e6110c79020d38e201d1a7533c0d59378","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":5,"id":"b2d31007_072bb945","updated":"2024-10-29 11:03:21.000000000","message":"Patch added to the Debian package of Swift.","commit_id":"862ef0bdc1a346a557b92af6284e57a94a861a5b"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2bba70914a65039ba2d5d58687031886c7a059ff","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":7,"id":"38613a1a_80c3a5a7","updated":"2025-02-28 22:28:28.000000000","message":"recheck\n\nLooks like some spurious failures, and our gate should be relatively healthy now.","commit_id":"be40ee959590d95840d520181c783c3de530b664"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e919f92883e910aadec8782e2bc8d01c7deeab95","unresolved":false,"context_lines":[],"source_content_type":"","patch_set":8,"id":"e7cb5856_603a4d67","updated":"2025-03-05 15:47:10.000000000","message":"@Tim I have pushed some more test cases and docstring changes. I pushed straight over rather than using a squash to save a round of squashing and re-checking in zuul. But obvs revert anything you\u0027re not happy with.","commit_id":"c390c637d1ab8e93fed4c2ada77e90162373d32f"}],"swift/common/middleware/s3api/s3api.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1c225c215b6c446f322c977f425c88308ec52f6c","unresolved":true,"context_lines":[{"line_number":228,"context_line":"            for item in listing:"},{"line_number":229,"context_line":"                if \u0027subdir\u0027 in item:"},{"line_number":230,"context_line":"                    continue"},{"line_number":231,"context_line":"                value, params \u003d parse_content_type(item[\u0027hash\u0027], strict\u003dFalse)"},{"line_number":232,"context_line":"                params \u003d dict(params)"},{"line_number":233,"context_line":"                if \u0027s3_etag\u0027 in params:"},{"line_number":234,"context_line":"                    item[\u0027s3_etag\u0027] \u003d \u0027\"%s\"\u0027 % params.pop(\u0027s3_etag\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"cd7e90a7_f6c836aa","line":231,"updated":"2024-07-19 03:07:18.000000000","message":"maybe we should give a more generic name to \"parse_content_type\"? and also a wrapper function to return dict?","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"3668ecc19b9a991e633d704beb81fd551b4c1c88","unresolved":true,"context_lines":[{"line_number":228,"context_line":"            for item in listing:"},{"line_number":229,"context_line":"                if \u0027subdir\u0027 in item:"},{"line_number":230,"context_line":"                    continue"},{"line_number":231,"context_line":"                value, params \u003d parse_content_type(item[\u0027hash\u0027], strict\u003dFalse)"},{"line_number":232,"context_line":"                params \u003d dict(params)"},{"line_number":233,"context_line":"                if \u0027s3_etag\u0027 in params:"},{"line_number":234,"context_line":"                    item[\u0027s3_etag\u0027] \u003d \u0027\"%s\"\u0027 % params.pop(\u0027s3_etag\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"fac4d6fe_dcaac801","line":231,"in_reply_to":"25581632_b534fd88","updated":"2024-10-02 14:37:51.000000000","message":"+1 for Jianjian\u0027s suggestion - let\u0027s have a parse_header method so it doesn\u0027t look weird to ``parse_content_type(not-content-type)``\n\nAnd then we can have it return a dict and be backwards compatible with cgi.parse_header","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f40e5fc2d0f38914e3f60a29f5be7d53f5d7d27c","unresolved":false,"context_lines":[{"line_number":228,"context_line":"            for item in listing:"},{"line_number":229,"context_line":"                if \u0027subdir\u0027 in item:"},{"line_number":230,"context_line":"                    continue"},{"line_number":231,"context_line":"                value, params \u003d parse_content_type(item[\u0027hash\u0027], strict\u003dFalse)"},{"line_number":232,"context_line":"                params \u003d dict(params)"},{"line_number":233,"context_line":"                if \u0027s3_etag\u0027 in params:"},{"line_number":234,"context_line":"                    item[\u0027s3_etag\u0027] \u003d \u0027\"%s\"\u0027 % params.pop(\u0027s3_etag\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"ed3cd49c_127e1c45","line":231,"in_reply_to":"3d5c9893_05aba721","updated":"2024-07-22 21:59:44.000000000","message":"Acknowledged","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"8cd59e65d333d41a9a6898d92b9e104645839845","unresolved":true,"context_lines":[{"line_number":228,"context_line":"            for item in listing:"},{"line_number":229,"context_line":"                if \u0027subdir\u0027 in item:"},{"line_number":230,"context_line":"                    continue"},{"line_number":231,"context_line":"                value, params \u003d parse_content_type(item[\u0027hash\u0027], strict\u003dFalse)"},{"line_number":232,"context_line":"                params \u003d dict(params)"},{"line_number":233,"context_line":"                if \u0027s3_etag\u0027 in params:"},{"line_number":234,"context_line":"                    item[\u0027s3_etag\u0027] \u003d \u0027\"%s\"\u0027 % params.pop(\u0027s3_etag\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"3d5c9893_05aba721","line":231,"in_reply_to":"cd7e90a7_f6c836aa","updated":"2024-07-22 18:47:55.000000000","message":"Yeah, we definitely use it for other things than content-type... we\u0027d still need to keep the old name around, though -- being in `utils` I worry a little about potential external users, especially since it\u0027s been there **so** long -- it was introduced [more than ten years ago](https://github.com/openstack/swift/commit/53345da70e3c969168e7192c3098540ba642ea09) and hasn\u0027t changed much in that time.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5da2b6e4096c2afd36dcce818f17b0867d1de4aa","unresolved":true,"context_lines":[{"line_number":228,"context_line":"            for item in listing:"},{"line_number":229,"context_line":"                if \u0027subdir\u0027 in item:"},{"line_number":230,"context_line":"                    continue"},{"line_number":231,"context_line":"                value, params \u003d parse_content_type(item[\u0027hash\u0027], strict\u003dFalse)"},{"line_number":232,"context_line":"                params \u003d dict(params)"},{"line_number":233,"context_line":"                if \u0027s3_etag\u0027 in params:"},{"line_number":234,"context_line":"                    item[\u0027s3_etag\u0027] \u003d \u0027\"%s\"\u0027 % params.pop(\u0027s3_etag\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"25581632_b534fd88","line":231,"in_reply_to":"ed3cd49c_127e1c45","updated":"2024-07-23 15:55:16.000000000","message":"I would advocate adding a wrapper function like ``parse_header`` in utils to call ``parse_content_type`` and return a dictionary.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e919f92883e910aadec8782e2bc8d01c7deeab95","unresolved":false,"context_lines":[{"line_number":228,"context_line":"            for item in listing:"},{"line_number":229,"context_line":"                if \u0027subdir\u0027 in item:"},{"line_number":230,"context_line":"                    continue"},{"line_number":231,"context_line":"                value, params \u003d parse_content_type(item[\u0027hash\u0027], strict\u003dFalse)"},{"line_number":232,"context_line":"                params \u003d dict(params)"},{"line_number":233,"context_line":"                if \u0027s3_etag\u0027 in params:"},{"line_number":234,"context_line":"                    item[\u0027s3_etag\u0027] \u003d \u0027\"%s\"\u0027 % params.pop(\u0027s3_etag\u0027)"}],"source_content_type":"text/x-python","patch_set":4,"id":"5e9c24e2_ed9a0291","line":231,"in_reply_to":"fac4d6fe_dcaac801","updated":"2025-03-05 15:47:10.000000000","message":"Done","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"}],"swift/common/request_helpers.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"8659f9394b977127ac7feefdd6297e0d5d971885","unresolved":true,"context_lines":[{"line_number":62,"context_line":"# so https://peps.python.org/pep-0594/#cgi recommends using email.message"},{"line_number":63,"context_line":"# as a replacement, but we\u0027ve seen trouble before when treating HTTP headers"},{"line_number":64,"context_line":"# as though they were email headers, and it doesn\u0027t handle multiple params"},{"line_number":65,"context_line":"def parse_header(header):"},{"line_number":66,"context_line":"    header_value, _, params \u003d header.partition(\u0027;\u0027)"},{"line_number":67,"context_line":"    param_dict \u003d {}"},{"line_number":68,"context_line":"    for part in params.split(\u0027;\u0027):"}],"source_content_type":"text/x-python","patch_set":1,"id":"e1e23704_eae17e8e","line":65,"updated":"2023-07-06 23:58:31.000000000","message":"how about copy it from cgi.py then you don\u0027t need to write test cases? https://github.com/python/cpython/blob/v3.11.4/Lib/cgi.py#L238\nor you can copy unit tests for your implementations too.","commit_id":"872a6c334b4cd8c076a731bff520fb155c701631"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"25fff2ec876a117b60858008363ccc3fe8f0b577","unresolved":true,"context_lines":[{"line_number":62,"context_line":"# so https://peps.python.org/pep-0594/#cgi recommends using email.message"},{"line_number":63,"context_line":"# as a replacement, but we\u0027ve seen trouble before when treating HTTP headers"},{"line_number":64,"context_line":"# as though they were email headers, and it doesn\u0027t handle multiple params"},{"line_number":65,"context_line":"def parse_header(header):"},{"line_number":66,"context_line":"    header_value, _, params \u003d header.partition(\u0027;\u0027)"},{"line_number":67,"context_line":"    param_dict \u003d {}"},{"line_number":68,"context_line":"    for part in params.split(\u0027;\u0027):"}],"source_content_type":"text/x-python","patch_set":1,"id":"00e7f3a3_9c6fa7c9","line":65,"in_reply_to":"e1e23704_eae17e8e","updated":"2023-07-07 20:02:49.000000000","message":"Yeah, I *should* write some tests -- just realized this doesn\u0027t handle quoted semicolons properly.\n\nI think I prefer my implementation (or one like it) over upstream\u0027s, though -- doing char-by-char string processing in python seems less than ideal; (I suspect) doing something with `partition` or even (precompiled) regexes will be more performant. Correctness needs to come first, though!","commit_id":"872a6c334b4cd8c076a731bff520fb155c701631"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"d9d192c95a25958e9ee21c3ebf8509f4b76d518a","unresolved":true,"context_lines":[{"line_number":76,"context_line":"                continue"},{"line_number":77,"context_line":"            yield param"},{"line_number":78,"context_line":"            param \u003d \u0027\u0027"},{"line_number":79,"context_line":"        if param:"},{"line_number":80,"context_line":"            yield param"},{"line_number":81,"context_line":""},{"line_number":82,"context_line":"    param_dict \u003d {}"}],"source_content_type":"text/x-python","patch_set":3,"id":"823ef96c_df9a60e2","line":79,"updated":"2024-01-19 06:45:11.000000000","message":"OK so this is only called when the last part has an uneven number of \u0027\"\u0027. Then it drops into the continue, falls out of the loop and then can still get yielded.\nDamn parsing can be confusing (at least on a Friday arvo) :P\n\nYeah is quoted semi-colons a possibility and anything else possibly quoted. Extra equals, although that will get trhough the partition below so might be ok (not that that is supported).","commit_id":"4583d5bed012781ec649860dd21e7906dc2f2d1e"}],"swift/common/utils/__init__.py":[{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"e651fbe9c96c5e09b4806f9e7b4a136fccef3dc7","unresolved":true,"context_lines":[{"line_number":2751,"context_line":"    return tuple(int(x) for x in found.groups())"},{"line_number":2752,"context_line":""},{"line_number":2753,"context_line":""},{"line_number":2754,"context_line":"def parse_content_type(content_type, strict\u003dTrue):"},{"line_number":2755,"context_line":"    \"\"\""},{"line_number":2756,"context_line":"    Parse a content-type and its parameters into values."},{"line_number":2757,"context_line":"    RFC 2616 sec 14.17 and 3.7 are pertinent."}],"source_content_type":"text/x-python","patch_set":4,"id":"7c1ede66_248c925d","line":2754,"updated":"2024-07-25 02:47:49.000000000","message":"As Jian was saying, maybe we rename this but keep it backward compatable?\n\n    def parse_header_params(header, strict\u003dTrue):\n        ....\n   \n    # For backward compatibility of this utils interface.\n    parse_content_type \u003d parse_header_params","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e919f92883e910aadec8782e2bc8d01c7deeab95","unresolved":false,"context_lines":[{"line_number":2751,"context_line":"    return tuple(int(x) for x in found.groups())"},{"line_number":2752,"context_line":""},{"line_number":2753,"context_line":""},{"line_number":2754,"context_line":"def parse_content_type(content_type, strict\u003dTrue):"},{"line_number":2755,"context_line":"    \"\"\""},{"line_number":2756,"context_line":"    Parse a content-type and its parameters into values."},{"line_number":2757,"context_line":"    RFC 2616 sec 14.17 and 3.7 are pertinent."}],"source_content_type":"text/x-python","patch_set":4,"id":"1f55d2c0_e3a02669","line":2754,"in_reply_to":"7c1ede66_248c925d","updated":"2025-03-05 15:47:10.000000000","message":"Done","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"5fbb1eb0737ec5f61fddd95c76522b929a80cb78","unresolved":true,"context_lines":[{"line_number":2766,"context_line":"    :param strict: ignore ``/`` and any following characters in parameter"},{"line_number":2767,"context_line":"        tokens. If ``strict`` is True a parameter such as ``x\u003da/b`` will be"},{"line_number":2768,"context_line":"        parsed as ``x\u003da``. If ``strict`` is False a parameter such as ``x\u003da/b``"},{"line_number":2769,"context_line":"        will be parsed as ``x\u003da/b``. The default is True."},{"line_number":2770,"context_line":"    :returns: a tuple containing (content type, list of k, v parameter tuples)"},{"line_number":2771,"context_line":"    \"\"\""},{"line_number":2772,"context_line":"    parm_list \u003d []"}],"source_content_type":"text/x-python","patch_set":5,"id":"1b8ef99b_1bb90457","line":2769,"updated":"2024-10-16 10:49:35.000000000","message":"I\u0027m not sure I fully understand what\u0027s going loose vs strict mode? I can see (below) that cgi.parse_header behaves like loose mode, but is that not rfc-compliant, and parse_content_type is compliant?\n\n```\ncgi.parse_header(\u0027x;a\u003db/c\u0027)\n(\u0027x\u0027, {\u0027a\u0027: \u0027b/c\u0027})\n```","commit_id":"862ef0bdc1a346a557b92af6284e57a94a861a5b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"84b3c877afd687823a559b49640fb9085a121c3a","unresolved":true,"context_lines":[{"line_number":2790,"context_line":"    :return: a tuple (first token, dict(params))."},{"line_number":2791,"context_line":"    \"\"\""},{"line_number":2792,"context_line":"    token, params \u003d parse_content_type(value, strict\u003dFalse)"},{"line_number":2793,"context_line":"    return token, dict(params)"},{"line_number":2794,"context_line":""},{"line_number":2795,"context_line":""},{"line_number":2796,"context_line":"def extract_swift_bytes(content_type):"}],"source_content_type":"text/x-python","patch_set":5,"id":"1c278f9f_d318c376","line":2793,"updated":"2024-12-03 10:38:22.000000000","message":"I cherry-picked this patch onto feature/mpu and discovered that this implementation is NOT the same as cgi.parse_header w.r.t. the null character:\n\n```\nimport swift.common.utils as u\nu.parse_header(\u0027foo;x\u003dy/z\u0027)\n(\u0027foo\u0027, {\u0027x\u0027: \u0027y/z\u0027})\nu.parse_header(\u0027foo;x\u003d\\x00y/z\u0027)\n(\u0027foo\u0027, {\u0027x\u0027: \u0027\u0027})\n\nimport cgi\ncgi.parse_header(\u0027foo;x\u003dy/z\u0027)\n(\u0027foo\u0027, {\u0027x\u0027: \u0027y/z\u0027})\ncgi.parse_header(\u0027foo;x\u003d\\x00y/z\u0027)\n(\u0027foo\u0027, {\u0027x\u0027: \u0027\\x00y/z\u0027})\n\n```\n\nWe use the null character to delimit hidden namespaces, and those are included in etag params (``symlink_target\u003d\u003chidden namespace path\u003e``) ... but it\u0027s ok because the hidden namespace path has been wsgi_quote\u0027d which removed the null character.\n\nBut I though it was worth noting as a difference.","commit_id":"862ef0bdc1a346a557b92af6284e57a94a861a5b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e919f92883e910aadec8782e2bc8d01c7deeab95","unresolved":false,"context_lines":[{"line_number":2790,"context_line":"    :return: a tuple (first token, dict(params))."},{"line_number":2791,"context_line":"    \"\"\""},{"line_number":2792,"context_line":"    token, params \u003d parse_content_type(value, strict\u003dFalse)"},{"line_number":2793,"context_line":"    return token, dict(params)"},{"line_number":2794,"context_line":""},{"line_number":2795,"context_line":""},{"line_number":2796,"context_line":"def extract_swift_bytes(content_type):"}],"source_content_type":"text/x-python","patch_set":5,"id":"308f291f_1c42a247","line":2793,"in_reply_to":"1c278f9f_d318c376","updated":"2025-03-05 15:47:10.000000000","message":"Acknowledged","commit_id":"862ef0bdc1a346a557b92af6284e57a94a861a5b"},{"author":{"_account_id":7847,"name":"Alistair Coles","email":"alistairncoles@gmail.com","username":"acoles"},"change_message_id":"e919f92883e910aadec8782e2bc8d01c7deeab95","unresolved":true,"context_lines":[{"line_number":2898,"context_line":""},{"line_number":2899,"context_line":"def parse_header(value):"},{"line_number":2900,"context_line":"    \"\"\""},{"line_number":2901,"context_line":"    Parse a header value to extract the first token and a dict of any"},{"line_number":2902,"context_line":"    following parameters."},{"line_number":2903,"context_line":""},{"line_number":2904,"context_line":"    :param value: the header value to parse."}],"source_content_type":"text/x-python","patch_set":7,"id":"6e78cca6_ea5a2889","line":2901,"range":{"start_line":2901,"start_character":46,"end_line":2901,"end_character":51},"updated":"2025-03-05 15:47:10.000000000","message":"\u0027token\u0027 is best avoided given its specific meaning in RFC schema","commit_id":"be40ee959590d95840d520181c783c3de530b664"}],"test/unit/common/test_request_helpers.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"32dcd257dfbc422e7cb0749f01804f2fc06226ad","unresolved":true,"context_lines":[{"line_number":471,"context_line":"        self.assertEqual(str(ctx.exception),"},{"line_number":472,"context_line":"                         \u0027Invalid reserved name\u0027)"},{"line_number":473,"context_line":""},{"line_number":474,"context_line":"    def test_parse_header(self):"},{"line_number":475,"context_line":"        self.assertEqual(rh.parse_header(\u0027text/html; charset\u003dUTF-8\u0027), ("},{"line_number":476,"context_line":"            \u0027text/html\u0027,"},{"line_number":477,"context_line":"            {\u0027charset\u0027: \u0027UTF-8\u0027}))"}],"source_content_type":"text/x-python","patch_set":2,"id":"743a654e_1dc2e74b","line":474,"updated":"2023-08-04 22:26:01.000000000","message":"I saw upstream has two test cases to cover that dict is empty.\n        self.assertEqual(\n            cgi.parse_header(\"text/plain\"),\n            (\"text/plain\", {}))\n        self.assertEqual(\n            cgi.parse_header(\"text/vnd.just.made.this.up ; \"),\n            (\"text/vnd.just.made.this.up\", {}))\n            \nhttps://github.com/python/cpython/blob/v3.11.4/Lib/test/test_cgi.py#L549","commit_id":"a74bf46db44e38cf598c4e84fd674b58fbe38296"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f96e4f98d2a07b90e63d3448100aedce993f9fc2","unresolved":false,"context_lines":[{"line_number":471,"context_line":"        self.assertEqual(str(ctx.exception),"},{"line_number":472,"context_line":"                         \u0027Invalid reserved name\u0027)"},{"line_number":473,"context_line":""},{"line_number":474,"context_line":"    def test_parse_header(self):"},{"line_number":475,"context_line":"        self.assertEqual(rh.parse_header(\u0027text/html; charset\u003dUTF-8\u0027), ("},{"line_number":476,"context_line":"            \u0027text/html\u0027,"},{"line_number":477,"context_line":"            {\u0027charset\u0027: \u0027UTF-8\u0027}))"}],"source_content_type":"text/x-python","patch_set":2,"id":"426a1377_9dbe1b33","line":474,"in_reply_to":"743a654e_1dc2e74b","updated":"2024-01-04 17:09:29.000000000","message":"Added -- good call.","commit_id":"a74bf46db44e38cf598c4e84fd674b58fbe38296"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"32dcd257dfbc422e7cb0749f01804f2fc06226ad","unresolved":true,"context_lines":[{"line_number":514,"context_line":""},{"line_number":515,"context_line":"        self.assertEqual("},{"line_number":516,"context_line":"            rh.parse_header("},{"line_number":517,"context_line":"                \u0027params; need\u003dto; have; an\u003d\u003dsign\u0027"},{"line_number":518,"context_line":"            ), ("},{"line_number":519,"context_line":"                \u0027params\u0027,"},{"line_number":520,"context_line":"                {\u0027need\u0027: \u0027to\u0027, \u0027an\u0027: \u0027\u003dsign\u0027}"}],"source_content_type":"text/x-python","patch_set":2,"id":"44a680e9_e13d212f","line":517,"updated":"2023-08-04 22:26:01.000000000","message":"so the expected output for \"\u003d\u003dsign\" is \"\u003dsign\". From upstream implementation, seems it\u0027s the case. I wonder if there is any protocol for parsing.","commit_id":"a74bf46db44e38cf598c4e84fd674b58fbe38296"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"f96e4f98d2a07b90e63d3448100aedce993f9fc2","unresolved":true,"context_lines":[{"line_number":514,"context_line":""},{"line_number":515,"context_line":"        self.assertEqual("},{"line_number":516,"context_line":"            rh.parse_header("},{"line_number":517,"context_line":"                \u0027params; need\u003dto; have; an\u003d\u003dsign\u0027"},{"line_number":518,"context_line":"            ), ("},{"line_number":519,"context_line":"                \u0027params\u0027,"},{"line_number":520,"context_line":"                {\u0027need\u0027: \u0027to\u0027, \u0027an\u0027: \u0027\u003dsign\u0027}"}],"source_content_type":"text/x-python","patch_set":2,"id":"b146da12_540d98c2","line":517,"in_reply_to":"44a680e9_e13d212f","updated":"2024-01-04 17:09:29.000000000","message":"https://www.rfc-editor.org/rfc/rfc2616#section-3.6 is probably the earliest reference we would have been looking at, but you can see similar things in https://www.rfc-editor.org/rfc/rfc7230#section-4 and https://www.rfc-editor.org/rfc/rfc9110#section-5.6.6 -- you find lots of similar things if you search any of those (or https://www.rfc-editor.org/rfc/rfc7231) for `\";\"`","commit_id":"a74bf46db44e38cf598c4e84fd674b58fbe38296"}],"test/unit/common/test_utils.py":[{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"1c225c215b6c446f322c977f425c88308ec52f6c","unresolved":true,"context_lines":[{"line_number":2669,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2670,"context_line":"        self.assertEqual("},{"line_number":2671,"context_line":"            utils.parse_content_type(r\u0027text/plain; x\u003da/b; y\u0027, strict\u003dFalse),"},{"line_number":2672,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a/b\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2673,"context_line":""},{"line_number":2674,"context_line":"    def test_override_bytes_from_content_type(self):"},{"line_number":2675,"context_line":"        listing_dict \u003d {"}],"source_content_type":"text/x-python","patch_set":4,"id":"258ff0b2_b4714863","line":2672,"updated":"2024-07-19 03:07:18.000000000","message":"I added 4 test cases from upstream https://github.com/python/cpython/blob/v3.11.4/Lib/test/test_cgi.py#L549\n\nand they all failed.\n\n        self.assertEqual(\n            utils.parse_content_type(\u0027attachment; filename\u003d\"silly.txt\"\u0027),\n            (\"attachment\", [(\"filename\", \"silly.txt\")]))\n        self.assertEqual(\n            utils.parse_content_type(\u0027attachment; filename\u003d\"strange;name\"\u0027),\n            (\"attachment\", [(\"filename\", \"strange;name\")]))\n        self.assertEqual(\n            utils.parse_content_type(\n                \u0027attachment; filename\u003d\"strange;name\";size\u003d123;\u0027),\n            (\"attachment\", [(\"filename\", \"strange;name\"), (\"size\", \"123\")]))\n        self.assertEqual(\n            utils.parse_content_type(\n                \u0027form-data; name\u003d\"files\"; filename\u003d\"fo\\\\\"o;bar\"\u0027),\n            (\"form-data\", [(\"name\", \"files\"), (\"filename\", \u0027fo\"o;bar\u0027)]))\n\nfor example, the last one fails with:\nE       AssertionError: Tuples differ: (\u0027form-data\u0027, [(\u0027name\u0027, \u0027\"files\"\u0027), (\u0027filename\u0027, \u0027\"fo\\\\\"o;bar\"\u0027)]) !\u003d (\u0027form-data\u0027, [(\u0027name\u0027, \u0027files\u0027), (\u0027filename\u0027, \u0027fo\"o;bar\u0027)])\n\nit seems the current parse_content_type does not strip the quotes from the parameter value when it parses it, and also does not strip \"\\\\\" as expected.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"8cd59e65d333d41a9a6898d92b9e104645839845","unresolved":true,"context_lines":[{"line_number":2669,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2670,"context_line":"        self.assertEqual("},{"line_number":2671,"context_line":"            utils.parse_content_type(r\u0027text/plain; x\u003da/b; y\u0027, strict\u003dFalse),"},{"line_number":2672,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a/b\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2673,"context_line":""},{"line_number":2674,"context_line":"    def test_override_bytes_from_content_type(self):"},{"line_number":2675,"context_line":"        listing_dict \u003d {"}],"source_content_type":"text/x-python","patch_set":4,"id":"b860a228_484c6fcc","line":2672,"in_reply_to":"258ff0b2_b4714863","updated":"2024-07-22 18:47:55.000000000","message":"I\u0027m not really trying to reimplement `cgi.parse_header` -- I\u0027m just trying to do the smallest thing to get rid of our use of it. Fixing the `\\`-escaping will mean needing to consider how every caller re-constitutes the header... and again we need to worry about the potential for external users...\n\nIf we did it all again, I suppose what we *really* want is some `extract_header_param(header: str, param: str) -\u003e tuple[str, Optional[str]]` -- maybe even pair it with an `append_header_param(header: str, param: str, value: str) -\u003e str`. If we were *really* ambitious, maybe even have\n```\nextract_header_params(header: str, *params: str) -\u003e tuple[str, dict[str, str]]\nappend_header_params(header: str, params: dict[str, str]) -\u003e str\n```","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"5da2b6e4096c2afd36dcce818f17b0867d1de4aa","unresolved":false,"context_lines":[{"line_number":2669,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2670,"context_line":"        self.assertEqual("},{"line_number":2671,"context_line":"            utils.parse_content_type(r\u0027text/plain; x\u003da/b; y\u0027, strict\u003dFalse),"},{"line_number":2672,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a/b\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2673,"context_line":""},{"line_number":2674,"context_line":"    def test_override_bytes_from_content_type(self):"},{"line_number":2675,"context_line":"        listing_dict \u003d {"}],"source_content_type":"text/x-python","patch_set":4,"id":"046b7e90_a35af41b","line":2672,"in_reply_to":"b6a77c2a_466c37f3","updated":"2024-07-23 15:55:16.000000000","message":"yeah, ``symlink`` doesn\u0027t have a test case like that either. okay, it\u0027s not a concern to me anymore.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":34930,"name":"Jianjian Huo","email":"jhuo@nvidia.com","username":"jhuo"},"change_message_id":"f40e5fc2d0f38914e3f60a29f5be7d53f5d7d27c","unresolved":true,"context_lines":[{"line_number":2669,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2670,"context_line":"        self.assertEqual("},{"line_number":2671,"context_line":"            utils.parse_content_type(r\u0027text/plain; x\u003da/b; y\u0027, strict\u003dFalse),"},{"line_number":2672,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a/b\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2673,"context_line":""},{"line_number":2674,"context_line":"    def test_override_bytes_from_content_type(self):"},{"line_number":2675,"context_line":"        listing_dict \u003d {"}],"source_content_type":"text/x-python","patch_set":4,"id":"c624f452_36377c04","line":2672,"in_reply_to":"b860a228_484c6fcc","updated":"2024-07-22 21:59:44.000000000","message":"I see. but with ``cgi.parse_header``, users can set ``filename\u003d\"silly.txt\" `` or ``filename\u003d\"fo\\\\\"o;bar\"`` in their header and we support them already, do we need to be backward compatible? if there are no such use cases, then it\u0027s not a concern.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0e60776bb25eae87a3efabde324f0b71da908c83","unresolved":true,"context_lines":[{"line_number":2669,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2670,"context_line":"        self.assertEqual("},{"line_number":2671,"context_line":"            utils.parse_content_type(r\u0027text/plain; x\u003da/b; y\u0027, strict\u003dFalse),"},{"line_number":2672,"context_line":"            (\u0027text/plain\u0027, [(\u0027x\u0027, \u0027a/b\u0027), (\u0027y\u0027, \u0027\u0027)]))"},{"line_number":2673,"context_line":""},{"line_number":2674,"context_line":"    def test_override_bytes_from_content_type(self):"},{"line_number":2675,"context_line":"        listing_dict \u003d {"}],"source_content_type":"text/x-python","patch_set":4,"id":"b6a77c2a_466c37f3","line":2672,"in_reply_to":"c624f452_36377c04","updated":"2024-07-23 00:39:06.000000000","message":"All the old uses of `cgi.parse_header` were either looking at `hash` entries from container listings, or transient sysmeta for encryption -- both of those are tightly controlled and assumed to be written only by Swift. I don\u0027t think we need to worry about the `\"` case in practice -- `symlink` is the only place that lets user input in, and it\u0027s going to be `quote`d first.","commit_id":"b4a50d57832d6b1a9fd96df1ced69836f1cc8dc5"}]}
