)]}'
{"etc/proxy-server.conf-sample":[{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"f1b906cafa2a18c09c5eb5ac7afb622beedcd5b4","unresolved":false,"context_lines":[{"line_number":293,"context_line":"# double-quotes around \"strong\" ETags. Some clients have depended on this"},{"line_number":294,"context_line":"# difference, but you may opt in to RFC-compliant behavior by enabling this"},{"line_number":295,"context_line":"# option."},{"line_number":296,"context_line":"# quote_etags \u003d false"},{"line_number":297,"context_line":""},{"line_number":298,"context_line":"# Some proxy-server configuration options may be overridden on a per-policy"},{"line_number":299,"context_line":"# basis by including per-policy config section(s). The value of any option"}],"source_content_type":"application/octet-stream","patch_set":2,"id":"3fa7e38b_ca8dae31","line":296,"range":{"start_line":296,"start_character":16,"end_line":296,"end_character":21},"updated":"2019-11-20 20:17:51.000000000","message":"should we have a plan to eventually default to true? If so, it\u0027s probably worth adding a note about it","commit_id":"c4d98d41548cb72371d4af4f5a5a6f35a4360185"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":293,"context_line":"# double-quotes around \"strong\" ETags. Some clients have depended on this"},{"line_number":294,"context_line":"# difference, but you may opt in to RFC-compliant behavior by enabling this"},{"line_number":295,"context_line":"# option."},{"line_number":296,"context_line":"# quote_etags \u003d false"},{"line_number":297,"context_line":""},{"line_number":298,"context_line":"# Some proxy-server configuration options may be overridden on a per-policy"},{"line_number":299,"context_line":"# basis by including per-policy config section(s). The value of any option"}],"source_content_type":"application/octet-stream","patch_set":2,"id":"3fa7e38b_f151720e","line":296,"range":{"start_line":296,"start_character":16,"end_line":296,"end_character":21},"in_reply_to":"3fa7e38b_ca8dae31","updated":"2019-12-10 18:14:05.000000000","message":"IDK what the default should be long-term... this definitely seems like the sort of thing that\u0027s fairly likely to break clients, though.","commit_id":"c4d98d41548cb72371d4af4f5a5a6f35a4360185"}],"swift/common/middleware/gatekeeper.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3f7371a066fe48783d699a2978008eeed872fa85","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            \u0027swift.leave_relative_location\u0027):"},{"line_number":118,"context_line":"                        hdrs.append((k, relative_path(v)))"},{"line_number":119,"context_line":"                    elif kl \u003d\u003d \u0027etag\u0027 and self.quote_etags and not ("},{"line_number":120,"context_line":"                            v.startswith((\u0027\"\u0027, \u0027W/\"\u0027)) and v.endswith(\u0027\"\u0027)):"},{"line_number":121,"context_line":"                        hdrs.append((k, \u0027\"%s\"\u0027 % v))"},{"line_number":122,"context_line":"                    else:"},{"line_number":123,"context_line":"                        hdrs.append((k, v))"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_4533e813","line":120,"updated":"2019-12-10 17:07:38.000000000","message":"so we quote any unquoted etag on the way out right at the gate.\n\nThe W/ isn\u0027t immediately obvious to me:\n\nhttps://tools.ietf.org/html/rfc7232#section-2.3","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":117,"context_line":"                            \u0027swift.leave_relative_location\u0027):"},{"line_number":118,"context_line":"                        hdrs.append((k, relative_path(v)))"},{"line_number":119,"context_line":"                    elif kl \u003d\u003d \u0027etag\u0027 and self.quote_etags and not ("},{"line_number":120,"context_line":"                            v.startswith((\u0027\"\u0027, \u0027W/\"\u0027)) and v.endswith(\u0027\"\u0027)):"},{"line_number":121,"context_line":"                        hdrs.append((k, \u0027\"%s\"\u0027 % v))"},{"line_number":122,"context_line":"                    else:"},{"line_number":123,"context_line":"                        hdrs.append((k, v))"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_b6b0d08c","line":120,"in_reply_to":"3fa7e38b_4533e813","updated":"2019-12-10 18:14:05.000000000","message":"I\u0027ll add a comment.","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"}],"swift/common/middleware/symlink.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3f7371a066fe48783d699a2978008eeed872fa85","unresolved":false,"context_lines":[{"line_number":282,"context_line":"            body\u003d\u0027Symlink cannot target itself\u0027,"},{"line_number":283,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":284,"context_line":"    etag \u003d req.headers.get(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":285,"context_line":"    if etag and etag.startswith(\u0027\"\u0027) and etag.endswith(\u0027\"\u0027) and etag[1:-1]:"},{"line_number":286,"context_line":"        etag \u003d etag[1:-1]"},{"line_number":287,"context_line":"    if etag and any(c in etag for c in \u0027;\"\\\\\u0027):"},{"line_number":288,"context_line":"        # See cgi.parse_header for why the above chars are problematic"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_454e8896","line":285,"updated":"2019-12-10 17:07:38.000000000","message":"etag \u003d normalize_etag(etag)\n\n???","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":282,"context_line":"            body\u003d\u0027Symlink cannot target itself\u0027,"},{"line_number":283,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":284,"context_line":"    etag \u003d req.headers.get(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":285,"context_line":"    if etag and etag.startswith(\u0027\"\u0027) and etag.endswith(\u0027\"\u0027) and etag[1:-1]:"},{"line_number":286,"context_line":"        etag \u003d etag[1:-1]"},{"line_number":287,"context_line":"    if etag and any(c in etag for c in \u0027;\"\\\\\u0027):"},{"line_number":288,"context_line":"        # See cgi.parse_header for why the above chars are problematic"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_96a1143d","line":285,"in_reply_to":"3fa7e38b_454e8896","updated":"2019-12-10 18:14:05.000000000","message":"Is that a thing we have? That seems like a thing we should have.","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3f7371a066fe48783d699a2978008eeed872fa85","unresolved":false,"context_lines":[{"line_number":469,"context_line":"            found_etag \u003d resp_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":470,"context_line":"            if found_etag and found_etag.startswith(\u0027\"\u0027) and \\"},{"line_number":471,"context_line":"                    found_etag.endswith(\u0027\"\u0027) and found_etag[1:-1]:"},{"line_number":472,"context_line":"                found_etag \u003d found_etag[1:-1]"},{"line_number":473,"context_line":"            if target_etag and target_etag !\u003d found_etag:"},{"line_number":474,"context_line":"                raise HTTPConflict("},{"line_number":475,"context_line":"                    body\u003d\u0027X-Symlink-Target-Etag headers do not match\u0027,"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_85fd600a","line":472,"updated":"2019-12-10 17:07:38.000000000","message":"I don\u0027t understand why this etag would be quoted already - i wouldn\u0027t expect that to happen until gatekeeper","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":469,"context_line":"            found_etag \u003d resp_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":470,"context_line":"            if found_etag and found_etag.startswith(\u0027\"\u0027) and \\"},{"line_number":471,"context_line":"                    found_etag.endswith(\u0027\"\u0027) and found_etag[1:-1]:"},{"line_number":472,"context_line":"                found_etag \u003d found_etag[1:-1]"},{"line_number":473,"context_line":"            if target_etag and target_etag !\u003d found_etag:"},{"line_number":474,"context_line":"                raise HTTPConflict("},{"line_number":475,"context_line":"                    body\u003d\u0027X-Symlink-Target-Etag headers do not match\u0027,"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_d659cc5a","line":472,"in_reply_to":"3fa7e38b_85fd600a","updated":"2019-12-10 18:14:05.000000000","message":"Hold-over from an earlier patchset where I was doing the quote-wrapping in the proxy-server app. I\u0027m kinda tempted to leave it, in case we ever allow the object server to do the wrapping...","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"}],"swift/proxy/server.py":[{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"f1b906cafa2a18c09c5eb5ac7afb622beedcd5b4","unresolved":false,"context_lines":[{"line_number":297,"context_line":"        self.disallowed_sections \u003d list_from_csv("},{"line_number":298,"context_line":"            conf.get(\u0027disallowed_sections\u0027, \u0027swift.valid_api_versions\u0027))"},{"line_number":299,"context_line":"        self.admin_key \u003d conf.get(\u0027admin_key\u0027, None)"},{"line_number":300,"context_line":"        self.quote_etags \u003d config_true_value(conf.get(\u0027quote_etags\u0027, \u0027no\u0027))"},{"line_number":301,"context_line":"        register_swift_info("},{"line_number":302,"context_line":"            version\u003dswift_version,"},{"line_number":303,"context_line":"            strict_cors_mode\u003dself.strict_cors_mode,"},{"line_number":304,"context_line":"            policies\u003dPOLICIES.get_policy_info(),"},{"line_number":305,"context_line":"            allow_account_management\u003dself.allow_account_management,"},{"line_number":306,"context_line":"            account_autocreate\u003dself.account_autocreate,"},{"line_number":307,"context_line":"            **constraints.EFFECTIVE_CONSTRAINTS)"},{"line_number":308,"context_line":""},{"line_number":309,"context_line":"    def _make_policy_override(self, policy, conf, override_conf):"},{"line_number":310,"context_line":"        label_for_policy \u003d _label_for_policy(policy)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_cabb6ec1","line":307,"range":{"start_line":300,"start_character":8,"end_line":307,"end_character":48},"updated":"2019-11-20 20:17:51.000000000","message":"how about adding it to /info?","commit_id":"c4d98d41548cb72371d4af4f5a5a6f35a4360185"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":297,"context_line":"        self.disallowed_sections \u003d list_from_csv("},{"line_number":298,"context_line":"            conf.get(\u0027disallowed_sections\u0027, \u0027swift.valid_api_versions\u0027))"},{"line_number":299,"context_line":"        self.admin_key \u003d conf.get(\u0027admin_key\u0027, None)"},{"line_number":300,"context_line":"        self.quote_etags \u003d config_true_value(conf.get(\u0027quote_etags\u0027, \u0027no\u0027))"},{"line_number":301,"context_line":"        register_swift_info("},{"line_number":302,"context_line":"            version\u003dswift_version,"},{"line_number":303,"context_line":"            strict_cors_mode\u003dself.strict_cors_mode,"},{"line_number":304,"context_line":"            policies\u003dPOLICIES.get_policy_info(),"},{"line_number":305,"context_line":"            allow_account_management\u003dself.allow_account_management,"},{"line_number":306,"context_line":"            account_autocreate\u003dself.account_autocreate,"},{"line_number":307,"context_line":"            **constraints.EFFECTIVE_CONSTRAINTS)"},{"line_number":308,"context_line":""},{"line_number":309,"context_line":"    def _make_policy_override(self, policy, conf, override_conf):"},{"line_number":310,"context_line":"        label_for_policy \u003d _label_for_policy(policy)"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_314cea74","line":307,"range":{"start_line":300,"start_character":8,"end_line":307,"end_character":48},"in_reply_to":"3fa7e38b_cabb6ec1","updated":"2019-12-10 18:14:05.000000000","message":"Done","commit_id":"c4d98d41548cb72371d4af4f5a5a6f35a4360185"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0ed67f98b1e7fda745afe67483943dc3b2662573","unresolved":false,"context_lines":[{"line_number":557,"context_line":"                resp \u003d handler(req)"},{"line_number":558,"context_line":"                if self.quote_etags and resp.etag is not None:"},{"line_number":559,"context_line":"                    resp.etag \u003d resp.etag"},{"line_number":560,"context_line":"                return resp"},{"line_number":561,"context_line":"            finally:"},{"line_number":562,"context_line":"                if old_authorize:"},{"line_number":563,"context_line":"                    req.environ[\u0027swift.authorize\u0027] \u003d old_authorize"}],"source_content_type":"text/x-python","patch_set":2,"id":"3fa7e38b_401d1d0d","line":560,"updated":"2019-11-20 22:38:09.000000000","message":"I\u0027m not actually sure this should happen in the proxy... I think it won\u0027t work well with encryption.\n\nMaybe better in the gatekeeper? In which case, symlink can stay as it was...","commit_id":"c4d98d41548cb72371d4af4f5a5a6f35a4360185"}],"test/functional/__init__.py":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d8d0d2e6fef690757c26442e268b81a82b52834b","unresolved":false,"context_lines":[{"line_number":327,"context_line":"        if not six.PY2:"},{"line_number":328,"context_line":"            root_secret \u003d root_secret.decode(\u0027ascii\u0027)"},{"line_number":329,"context_line":"        conf.set(\u0027filter:keymaster\u0027, \u0027encryption_root_secret\u0027, root_secret)"},{"line_number":330,"context_line":"        conf.set(\u0027app:proxy-server\u0027, \u0027quote_etags\u0027, \u0027true\u0027)"},{"line_number":331,"context_line":"    except NoSectionError as err:"},{"line_number":332,"context_line":"        msg \u003d \u0027Error problem with proxy conf file %s: %s\u0027 % \\"},{"line_number":333,"context_line":"              (proxy_conf_file, err)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_b4b537d2","line":330,"range":{"start_line":330,"start_character":18,"end_line":330,"end_character":34},"updated":"2019-12-10 02:22:56.000000000","message":"Forgot to change this!","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":327,"context_line":"        if not six.PY2:"},{"line_number":328,"context_line":"            root_secret \u003d root_secret.decode(\u0027ascii\u0027)"},{"line_number":329,"context_line":"        conf.set(\u0027filter:keymaster\u0027, \u0027encryption_root_secret\u0027, root_secret)"},{"line_number":330,"context_line":"        conf.set(\u0027app:proxy-server\u0027, \u0027quote_etags\u0027, \u0027true\u0027)"},{"line_number":331,"context_line":"    except NoSectionError as err:"},{"line_number":332,"context_line":"        msg \u003d \u0027Error problem with proxy conf file %s: %s\u0027 % \\"},{"line_number":333,"context_line":"              (proxy_conf_file, err)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_f635e8f6","line":330,"range":{"start_line":330,"start_character":18,"end_line":330,"end_character":34},"in_reply_to":"3fa7e38b_6bdfd5d6","updated":"2019-12-10 18:14:05.000000000","message":"Like I said, I need to change it! Needs to be\n\n filter:gatekeeper\n\nAgain, a hold-over from an earlier patchset where I was doing the quote-wrapping in the proxy-server app.","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3f7371a066fe48783d699a2978008eeed872fa85","unresolved":false,"context_lines":[{"line_number":327,"context_line":"        if not six.PY2:"},{"line_number":328,"context_line":"            root_secret \u003d root_secret.decode(\u0027ascii\u0027)"},{"line_number":329,"context_line":"        conf.set(\u0027filter:keymaster\u0027, \u0027encryption_root_secret\u0027, root_secret)"},{"line_number":330,"context_line":"        conf.set(\u0027app:proxy-server\u0027, \u0027quote_etags\u0027, \u0027true\u0027)"},{"line_number":331,"context_line":"    except NoSectionError as err:"},{"line_number":332,"context_line":"        msg \u003d \u0027Error problem with proxy conf file %s: %s\u0027 % \\"},{"line_number":333,"context_line":"              (proxy_conf_file, err)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_6bdfd5d6","line":330,"range":{"start_line":330,"start_character":18,"end_line":330,"end_character":34},"in_reply_to":"3fa7e38b_b4b537d2","updated":"2019-12-10 17:07:38.000000000","message":"does this mean this change\u0027s gate inprocess functests ran with quote_etags true!?  and they passed?  lots of func tests seem to expect unquoted etags, and don\u0027t seem to work for me when this is option is on...","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"}],"test/functional/test_symlink.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3f7371a066fe48783d699a2978008eeed872fa85","unresolved":false,"context_lines":[{"line_number":1562,"context_line":"                self.env.container2.name, \u0027manifest-abcde\u0027),"},{"line_number":1563,"context_line":"            \u0027X-Symlink-Target-Etag\u0027: slo_etag,"},{"line_number":1564,"context_line":"        })"},{"line_number":1565,"context_line":"        self.assert_status(409)  # quotes OK, but doesn\u0027t match"},{"line_number":1566,"context_line":""},{"line_number":1567,"context_line":"        # try the slo etag w/o the quotes"},{"line_number":1568,"context_line":"        slo_etag \u003d slo_etag.strip(\u0027\"\u0027)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_2b623d17","line":1565,"updated":"2019-12-10 17:07:38.000000000","message":"this client facing api change seems entirely fine to me, i guess because they\u0027re they\u0027re not already handling any 4XX they\u0027re at least already handling 409","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"}],"test/functional/tests.py":[{"author":{"_account_id":597,"name":"Pete Zaitcev","email":"zaitcev@kotori.zaitcev.us","username":"zaitcev"},"change_message_id":"092bcb192c167d074b01e46dbca92b3caf8b6ac3","unresolved":false,"context_lines":[{"line_number":886,"context_line":"                self.assertEqual(expected[name][\u0027etag\u0027],"},{"line_number":887,"context_line":"                                 \u0027\"%s\"\u0027 % actual[\u0027hash\u0027])"},{"line_number":888,"context_line":"            else:"},{"line_number":889,"context_line":"                self.assertEqual(expected[name][\u0027etag\u0027], actual[\u0027hash\u0027])"},{"line_number":890,"context_line":"            self.assertEqual("},{"line_number":891,"context_line":"                expected[name][\u0027content_type\u0027], actual[\u0027content_type\u0027])"},{"line_number":892,"context_line":"            self.assertEqual("}],"source_content_type":"text/x-python","patch_set":10,"id":"ff570b3c_0856015d","line":889,"updated":"2020-06-02 20:38:02.000000000","message":"I\u0027m against this trickery in functional tests. Our functests ought to work in a stable manner against pre-existing clusters -- we agree here. But, IMHO it means that the tests have to be liberal in what they accept, because both quoted and unquoted are acceptable. Therefore, just apply normalize_etag(). This differs from unit tests where you might want an _exact_ test.","commit_id":"99947150dd923ce19112a8f8c35c41f5a1271d72"}],"test/unit/common/middleware/test_gatekeeper.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3f7371a066fe48783d699a2978008eeed872fa85","unresolved":false,"context_lines":[{"line_number":254,"context_line":"        resp \u003d req.get_response(app)"},{"line_number":255,"context_line":"        self.assertEqual(\u0027200 OK\u0027, resp.status)"},{"line_number":256,"context_line":"        if expected_etag is None:"},{"line_number":257,"context_line":"            self.assertNotIn(\u0027ETag\u0027, resp.headers)"},{"line_number":258,"context_line":"        else:"},{"line_number":259,"context_line":"            self.assertIn(\u0027ETag\u0027, resp.headers)"},{"line_number":260,"context_line":"            self.assertEqual(resp.headers[\u0027ETag\u0027], expected_etag)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_509de4b8","line":257,"updated":"2019-12-10 17:07:38.000000000","message":"oic, sometimes app_etag is *also* None... this cofused me given L#249, I find this more obvious:\n\n    -        if expected_etag is None:\n    +        if app_etag is None:","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":254,"context_line":"        resp \u003d req.get_response(app)"},{"line_number":255,"context_line":"        self.assertEqual(\u0027200 OK\u0027, resp.status)"},{"line_number":256,"context_line":"        if expected_etag is None:"},{"line_number":257,"context_line":"            self.assertNotIn(\u0027ETag\u0027, resp.headers)"},{"line_number":258,"context_line":"        else:"},{"line_number":259,"context_line":"            self.assertIn(\u0027ETag\u0027, resp.headers)"},{"line_number":260,"context_line":"            self.assertEqual(resp.headers[\u0027ETag\u0027], expected_etag)"}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_b60c5042","line":257,"in_reply_to":"3fa7e38b_509de4b8","updated":"2019-12-10 18:14:05.000000000","message":"IDK, maybe I should just be more explicit and have a separate test for \"no ETag from app means no ETag for client\".","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"ccf662b755e721bf400e5f7940241127546569a3","unresolved":false,"context_lines":[{"line_number":267,"context_line":"        self._test_etags(False, \u0027W/\"weak-etag\"\u0027)"},{"line_number":268,"context_line":"        self._test_etags(True, None)"},{"line_number":269,"context_line":"        self._test_etags(True, \u0027some-value\u0027, \u0027\"some-value\"\u0027)"},{"line_number":270,"context_line":"        self._test_etags(True, \u0027\"semi-quoted\u0027, \u0027\"\"semi-quoted\"\u0027)"},{"line_number":271,"context_line":"        self._test_etags(True, \u0027\"xlo-etag\"\u0027)"},{"line_number":272,"context_line":"        self._test_etags(True, \u0027W/\"weak-etag\"\u0027)"},{"line_number":273,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"3fa7e38b_96fd940a","line":270,"range":{"start_line":270,"start_character":48,"end_line":270,"end_character":62},"updated":"2019-12-10 18:14:05.000000000","message":"I\u0027m still not sure this is quite the behavior we want; RFC looks like it\u0027d maybe recommend\n\n \"\\\"semi-quoted\"\n\non the wire instead?","commit_id":"90502d13addd8a75bd4e7b6bddd09b861d838bb2"}]}
