)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":22,"context_line":"Bonus goodness:"},{"line_number":23,"context_line":""},{"line_number":24,"context_line":"- Tighten assertions on Content-Location"},{"line_number":25,"context_line":"- Get rid of source.source-sniffing by making versioned_writes"},{"line_number":26,"context_line":"  symlink-aware (\u0027cause I\u0027m going to want to make it symlink-aware"},{"line_number":27,"context_line":"  later anyway)"},{"line_number":28,"context_line":"- Allow middlewares left of symlink set their own"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"9fdfeff1_109c5468","line":25,"range":{"start_line":25,"start_character":13,"end_line":25,"end_character":26},"updated":"2019-01-30 19:21:46.000000000","message":"swift.source, dumb-dumb.","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ecd5490b63a6e33fbd3dc07a33022817ccd027f2","unresolved":false,"context_lines":[{"line_number":24,"context_line":"- Tighten assertions on Content-Location"},{"line_number":25,"context_line":"- Get rid of source.source-sniffing by making versioned_writes"},{"line_number":26,"context_line":"  symlink-aware (\u0027cause I\u0027m going to want to make it symlink-aware"},{"line_number":27,"context_line":"  later anyway)"},{"line_number":28,"context_line":"- Allow middlewares left of symlink set their own"},{"line_number":29,"context_line":"  Container-Update-Override-Etag when creating a symlink"},{"line_number":30,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"9fdfeff1_4511b351","line":27,"updated":"2019-01-30 14:58:32.000000000","message":"Can you point me at more of what\u0027s going on with this - I don\u0027t think I understood how versioned_writes and symlinks interacted.  What is source.source-sniffing -it\u0027s only referenced here in the commit?","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":24,"context_line":"- Tighten assertions on Content-Location"},{"line_number":25,"context_line":"- Get rid of source.source-sniffing by making versioned_writes"},{"line_number":26,"context_line":"  symlink-aware (\u0027cause I\u0027m going to want to make it symlink-aware"},{"line_number":27,"context_line":"  later anyway)"},{"line_number":28,"context_line":"- Allow middlewares left of symlink set their own"},{"line_number":29,"context_line":"  Container-Update-Override-Etag when creating a symlink"},{"line_number":30,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"9fdfeff1_da9d790a","line":27,"in_reply_to":"9fdfeff1_4511b351","updated":"2019-01-30 19:21:46.000000000","message":"See https://github.com/openstack/swift/blob/2.20.0/swift/common/middleware/symlink.py#L508-L511 -- we carve out an exception just for versioned_writes","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":25,"context_line":"- Get rid of source.source-sniffing by making versioned_writes"},{"line_number":26,"context_line":"  symlink-aware (\u0027cause I\u0027m going to want to make it symlink-aware"},{"line_number":27,"context_line":"  later anyway)"},{"line_number":28,"context_line":"- Allow middlewares left of symlink set their own"},{"line_number":29,"context_line":"  Container-Update-Override-Etag when creating a symlink"},{"line_number":30,"context_line":""},{"line_number":31,"context_line":"Change-Id: I179ea6180d31146bb947061c69b1807c59529ac8"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"9fdfeff1_dd5573fb","line":28,"range":{"start_line":28,"start_character":36,"end_line":28,"end_character":39},"updated":"2019-01-30 19:21:46.000000000","message":"\"to set\"","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"2d245a3b024d5db40e0bc8891ed52b70a6a154d9","unresolved":false,"context_lines":[{"line_number":16,"context_line":"the client. If multiple symlinks are chained together, each symlink must"},{"line_number":17,"context_line":"either use the same X-Symlink-Target-Etag or omit the header."},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"Note that, unlink \"softer\" symlink behavior, the target object must"},{"line_number":20,"context_line":"exist with the matching Etag for the \"hardlink\" to be created."},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Since we\u0027re validating the Etag anyway, we also force the content-type"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":5,"id":"5fc1f717_4a479678","line":19,"range":{"start_line":19,"start_character":11,"end_line":19,"end_character":17},"updated":"2019-03-25 23:21:32.000000000","message":"unlike","commit_id":"573ad41a9eadae9480b4a0405b92e6d031a8ced9"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"3a468508adf77c4a98bba83cb135ef8a71aabce2","unresolved":false,"context_lines":[{"line_number":19,"context_line":"Note that, unlike \"softer\" symlink behavior, the target object must"},{"line_number":20,"context_line":"exist with the matching Etag for the \"hardlink\" to be created."},{"line_number":21,"context_line":""},{"line_number":22,"context_line":"Since we\u0027re validating the Etag anyway, we also force the content-type"},{"line_number":23,"context_line":"to match and send the content-length along to the container listing as"},{"line_number":24,"context_line":"well."},{"line_number":25,"context_line":""},{"line_number":26,"context_line":"Bonus goodness:"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":10,"id":"9fb8cfa7_5a2b742f","line":23,"range":{"start_line":22,"start_character":40,"end_line":23,"end_character":8},"updated":"2019-06-19 13:21:30.000000000","message":"interesting, this is a change in direction since we use to document a suggestion to users how they should set content-type","commit_id":"1e1a9d0967c1357aeecbb098543cef39c30552ca"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":16,"context_line":"the client."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Note that, unlike \"softer\" symlink behavior, the target object must"},{"line_number":19,"context_line":"exist with the matching Etag for the \"hardlink\" to be created."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Since we\u0027re validating the Etag anyway, we also set the content-type of"},{"line_number":22,"context_line":"the symlink to match if the client didn\u0027t otherwise specifiy and send"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":25,"id":"7faddb67_d5af117b","line":19,"range":{"start_line":19,"start_character":38,"end_line":19,"end_character":46},"updated":"2019-08-09 22:13:02.000000000","message":"This is my own failing, but I wonder if we should call it a static symlink in the commit message, too.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":16,"context_line":"the client."},{"line_number":17,"context_line":""},{"line_number":18,"context_line":"Note that, unlike \"softer\" symlink behavior, the target object must"},{"line_number":19,"context_line":"exist with the matching Etag for the \"hardlink\" to be created."},{"line_number":20,"context_line":""},{"line_number":21,"context_line":"Since we\u0027re validating the Etag anyway, we also set the content-type of"},{"line_number":22,"context_line":"the symlink to match if the client didn\u0027t otherwise specifiy and send"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":25,"id":"7faddb67_4bc5a709","line":19,"range":{"start_line":19,"start_character":38,"end_line":19,"end_character":46},"in_reply_to":"7faddb67_d5af117b","updated":"2019-08-12 18:30:15.000000000","message":"#willfix","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"}],"swift/common/middleware/symlink.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ecd5490b63a6e33fbd3dc07a33022817ccd027f2","unresolved":false,"context_lines":[{"line_number":40,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":41,"context_line":"during the PUT. If present, this will be used duing GETs to verify that the"},{"line_number":42,"context_line":"object matches the given ETag. Note that no verification is performed at"},{"line_number":43,"context_line":"symlink creation time."},{"line_number":44,"context_line":""},{"line_number":45,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"},{"line_number":46,"context_line":"object referenced by the symlink\u0027s ``X-Symlink-Target-Account`` and"}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_ea7d14b2","line":43,"updated":"2019-01-30 14:58:32.000000000","message":"yay docs!","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ecd5490b63a6e33fbd3dc07a33022817ccd027f2","unresolved":false,"context_lines":[{"line_number":102,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":103,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":104,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":105,"context_line":"listings will include that value in a ``symlink_etag`` key."},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"Errors"},{"line_number":108,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_ea56742a","line":105,"updated":"2019-01-30 14:58:32.000000000","message":"this is a **really** cool feature - does it fix bytes in the listing as well!?","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":102,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":103,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":104,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":105,"context_line":"listings will include that value in a ``symlink_etag`` key."},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"Errors"},{"line_number":108,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_7a7a4dba","line":105,"in_reply_to":"9fdfeff1_ea56742a","updated":"2019-01-30 19:21:46.000000000","message":"I debated about also adding a X-Symlink-Target-Size and shoving symlink_size into listings... but my gut reaction would\u0027ve been to make all of these requirements orthogonal, so you could have\n\n- symlink with no etag/size restrictions\n- symlink with just etag restriction\n- symlink with both etag \u0026 size restrictions\n- symlink with just size restriction\n\nand that last one felt weird to me. \"If you do a GET here, I\u0027ll go give you this other object, but only if it\u0027s exactly N bytes.\" seems kinda arbitrary -- it makes more sense if there\u0027s *also* and etag restriction... but it *also* seemed weird to make the size requirement only be valid if there\u0027s an etag requirement... so I just punted that part of the listing problem to versioned_writes in the next patch in the chain.","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":116,"context_line":"  produce a 409 Conflict error."},{"line_number":117,"context_line":""},{"line_number":118,"context_line":"* GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header that"},{"line_number":119,"context_line":"  does not match the target will poduce a 412 Precondition Failed error."},{"line_number":120,"context_line":""},{"line_number":121,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."},{"line_number":122,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_7a280d96","line":119,"range":{"start_line":119,"start_character":42,"end_line":119,"end_character":65},"updated":"2019-01-30 19:21:46.000000000","message":"Is this a reasonable response status? It\u0027s not really a client error... and to the degree that it *is*, 412 is kinda misleading... the client didn\u0027t (necessarily) include any If-Match/If-None-Match/If-Modified-Since/If-Unmodified-Since headers...\n\nBut then, we abuse the hell out of 412 *already*, using it for things like \"this path isn\u0027t UTF-8\"...\n\nMaybe 409 Conflict would be better, though? That\u0027d match what you get from a busted SLO...","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"0c32844dc30a5efe7a785eb77d961c874a41d729","unresolved":false,"context_lines":[{"line_number":38,"context_line":"``application/symlink``."},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":41,"context_line":"during the PUT. If present, this will be used duing GETs to verify that the"},{"line_number":42,"context_line":"object matches the given ETag. Note that no verification is performed at"},{"line_number":43,"context_line":"symlink creation time."},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_47a512a1","line":41,"range":{"start_line":41,"start_character":46,"end_line":41,"end_character":51},"updated":"2019-02-01 10:47:31.000000000","message":"during","commit_id":"8c2cbe5044ed7f4776c46002c2ff3a3a1d228a25"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"447317f0789e5db66c5d264c15d05028bb90be88","unresolved":false,"context_lines":[{"line_number":38,"context_line":"``application/symlink``."},{"line_number":39,"context_line":""},{"line_number":40,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":41,"context_line":"during the PUT. If present, this will be used duing GETs to verify that the"},{"line_number":42,"context_line":"object matches the given ETag. Note that no verification is performed at"},{"line_number":43,"context_line":"symlink creation time."},{"line_number":44,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_b552df11","line":41,"range":{"start_line":41,"start_character":46,"end_line":41,"end_character":51},"in_reply_to":"9fdfeff1_47a512a1","updated":"2019-02-01 22:19:45.000000000","message":"My keyboa\u0027s been having a lot of troubles with \"r\" an \"d\" lately :-(\n\nThanks.","commit_id":"8c2cbe5044ed7f4776c46002c2ff3a3a1d228a25"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"0c32844dc30a5efe7a785eb77d961c874a41d729","unresolved":false,"context_lines":[{"line_number":199,"context_line":""},{"line_number":200,"context_line":"def _check_symlink_header(req):"},{"line_number":201,"context_line":"    \"\"\""},{"line_number":202,"context_line":"    Validate that the value from x-symlink-target header is"},{"line_number":203,"context_line":"    well formatted. We assume the caller ensures that"},{"line_number":204,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":205,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_67f7f68c","line":202,"range":{"start_line":202,"start_character":4,"end_line":202,"end_character":12},"updated":"2019-02-01 10:47:31.000000000","message":"update docstring: function now validates x-symlink-target-etag too\n\nsame for symlink_usermeta_to_sysmeta and symlink_sysmeta_to_usermeta","commit_id":"8c2cbe5044ed7f4776c46002c2ff3a3a1d228a25"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"447317f0789e5db66c5d264c15d05028bb90be88","unresolved":false,"context_lines":[{"line_number":199,"context_line":""},{"line_number":200,"context_line":"def _check_symlink_header(req):"},{"line_number":201,"context_line":"    \"\"\""},{"line_number":202,"context_line":"    Validate that the value from x-symlink-target header is"},{"line_number":203,"context_line":"    well formatted. We assume the caller ensures that"},{"line_number":204,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":205,"context_line":""}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_e8b16945","line":202,"range":{"start_line":202,"start_character":4,"end_line":202,"end_character":12},"in_reply_to":"9fdfeff1_67f7f68c","updated":"2019-02-01 22:19:45.000000000","message":"Done","commit_id":"8c2cbe5044ed7f4776c46002c2ff3a3a1d228a25"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"0c32844dc30a5efe7a785eb77d961c874a41d729","unresolved":false,"context_lines":[{"line_number":485,"context_line":"        # info can appear as the suffix in the hash value of object"},{"line_number":486,"context_line":"        # listing result for clients."},{"line_number":487,"context_line":"        # To create override etag easily, we have a constraint that the symlink"},{"line_number":488,"context_line":"        # must be 0 byte so we can add etag of the empty string + symlink info"},{"line_number":489,"context_line":"        # here, simply. Note that this override etag may be encrypted in the"},{"line_number":490,"context_line":"        # container db by encryption middleware."},{"line_number":491,"context_line":"        etag_override \u003d ["}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_47067254","line":488,"range":{"start_line":488,"start_character":25,"end_line":488,"end_character":63},"updated":"2019-02-01 10:47:31.000000000","message":"if \u0027override-etag\u0027 doesn\u0027t already exist","commit_id":"8c2cbe5044ed7f4776c46002c2ff3a3a1d228a25"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"447317f0789e5db66c5d264c15d05028bb90be88","unresolved":false,"context_lines":[{"line_number":485,"context_line":"        # info can appear as the suffix in the hash value of object"},{"line_number":486,"context_line":"        # listing result for clients."},{"line_number":487,"context_line":"        # To create override etag easily, we have a constraint that the symlink"},{"line_number":488,"context_line":"        # must be 0 byte so we can add etag of the empty string + symlink info"},{"line_number":489,"context_line":"        # here, simply. Note that this override etag may be encrypted in the"},{"line_number":490,"context_line":"        # container db by encryption middleware."},{"line_number":491,"context_line":"        etag_override \u003d ["}],"source_content_type":"text/x-python","patch_set":3,"id":"9fdfeff1_089aadb7","line":488,"range":{"start_line":488,"start_character":25,"end_line":488,"end_character":63},"in_reply_to":"9fdfeff1_47067254","updated":"2019-02-01 22:19:45.000000000","message":"Done","commit_id":"8c2cbe5044ed7f4776c46002c2ff3a3a1d228a25"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c161211474a71c76e7712df0cf1606b5de5c9c38","unresolved":false,"context_lines":[{"line_number":56,"context_line":"`proxy-server.conf`. If not specified, the default ``symloop_max`` value is 2."},{"line_number":57,"context_line":"If a value less than 1 is specified, the default value will be used. If"},{"line_number":58,"context_line":"multiple symlinks in the chain include a ``X-Symlink-Target-Etag`` header,"},{"line_number":59,"context_line":"they must all match for the GET to succeed."},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"A HEAD/GET request to a symlink object behaves as a normal HEAD/GET request"},{"line_number":62,"context_line":"to the target object. Therefore issuing a HEAD request to the symlink will"}],"source_content_type":"text/x-python","patch_set":7,"id":"5fc1f717_4c48e45a","line":59,"updated":"2019-03-27 17:53:57.000000000","message":"This behavior should probably be functest\u0027d","commit_id":"450d9c98cc520519d3ac870ab3a61fdd2229cf72"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c161211474a71c76e7712df0cf1606b5de5c9c38","unresolved":false,"context_lines":[{"line_number":102,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":103,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":104,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":105,"context_line":"listings will include that value in a ``symlink_etag`` key."},{"line_number":106,"context_line":""},{"line_number":107,"context_line":"Errors"},{"line_number":108,"context_line":""}],"source_content_type":"text/x-python","patch_set":7,"id":"5fc1f717_ac0f082c","line":105,"updated":"2019-03-27 17:53:57.000000000","message":"and also symlink_bytes :\u0027(","commit_id":"450d9c98cc520519d3ac870ab3a61fdd2229cf72"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c161211474a71c76e7712df0cf1606b5de5c9c38","unresolved":false,"context_lines":[{"line_number":540,"context_line":"                    \u0027symlink_target_etag\u003d%s\u0027 %"},{"line_number":541,"context_line":"                    req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR],"},{"line_number":542,"context_line":"                    \u0027symlink_target_bytes\u003d%s\u0027 %"},{"line_number":543,"context_line":"                    req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR],"},{"line_number":544,"context_line":"                ])"},{"line_number":545,"context_line":"                req.headers[\u0027Content-Type\u0027] \u003d \\"},{"line_number":546,"context_line":"                    req.headers[TGT_CONTENT_TYPE_SYSMETA_SYMLINK_HDR]"}],"source_content_type":"text/x-python","patch_set":7,"id":"5fc1f717_ac3dc8bb","line":543,"updated":"2019-03-27 17:53:57.000000000","message":"I wonder if these should be prefixed with `swift_`\n\nhttps://github.com/openstack/swift/blob/master/swift/proxy/controllers/obj.py#L78","commit_id":"450d9c98cc520519d3ac870ab3a61fdd2229cf72"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"3a468508adf77c4a98bba83cb135ef8a71aabce2","unresolved":false,"context_lines":[{"line_number":206,"context_line":"def _check_symlink_header(req):"},{"line_number":207,"context_line":"    \"\"\""},{"line_number":208,"context_line":"    Validate that the value from x-symlink-target header is well formatted"},{"line_number":209,"context_line":"    and that the x-symlink-target-etag header (if present) does not contain"},{"line_number":210,"context_line":"    problematic characters. We assume the caller ensures that"},{"line_number":211,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":212,"context_line":""},{"line_number":213,"context_line":"    :param req: HTTP request object"}],"source_content_type":"text/x-python","patch_set":10,"id":"9fb8cfa7_552587aa","line":210,"range":{"start_line":209,"start_character":4,"end_line":210,"end_character":26},"updated":"2019-06-19 13:21:30.000000000","message":"I think this is now being checked in _validate_etag_and_update_sysmeta().","commit_id":"1e1a9d0967c1357aeecbb098543cef39c30552ca"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"3a468508adf77c4a98bba83cb135ef8a71aabce2","unresolved":false,"context_lines":[{"line_number":328,"context_line":"        self.update_content_length(len(new_body))"},{"line_number":329,"context_line":"        return [new_body]"},{"line_number":330,"context_line":""},{"line_number":331,"context_line":"    def _extract_symlink_path_json(self, obj_dict, swift_version, account):"},{"line_number":332,"context_line":"        \"\"\""},{"line_number":333,"context_line":"        Extract the symlink path from the hash value"},{"line_number":334,"context_line":"        :return: object dictionary with additional key:value pair if object"}],"source_content_type":"text/x-python","patch_set":10,"id":"9fb8cfa7_7ac5180a","line":331,"range":{"start_line":331,"start_character":8,"end_line":331,"end_character":34},"updated":"2019-06-19 13:21:30.000000000","message":"suggestion to update method name and docstring to reflect changes","commit_id":"1e1a9d0967c1357aeecbb098543cef39c30552ca"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"3a468508adf77c4a98bba83cb135ef8a71aabce2","unresolved":false,"context_lines":[{"line_number":470,"context_line":""},{"line_number":471,"context_line":"    def _validate_etag_and_update_sysmeta("},{"line_number":472,"context_line":"            self, req, symlink_target_path, etag):"},{"line_number":473,"context_line":"        if any(c in etag for c in \u0027;\"\\\\\u0027):"},{"line_number":474,"context_line":"            # See cgi.parse_header for why the above chars are problematic"},{"line_number":475,"context_line":"            raise HTTPBadRequest("},{"line_number":476,"context_line":"                body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"}],"source_content_type":"text/x-python","patch_set":10,"id":"9fb8cfa7_98379de4","line":473,"range":{"start_line":473,"start_character":36,"end_line":473,"end_character":37},"updated":"2019-06-19 13:21:30.000000000","message":"The \" check causes an issue for creating symlinks to xLO objects: http://paste.openstack.org/show/753186/","commit_id":"1e1a9d0967c1357aeecbb098543cef39c30552ca"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"3a468508adf77c4a98bba83cb135ef8a71aabce2","unresolved":false,"context_lines":[{"line_number":510,"context_line":"        symlink_target_path \u003d _check_symlink_header(req)"},{"line_number":511,"context_line":"        etag \u003d req.headers.pop(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":512,"context_line":"        if etag:"},{"line_number":513,"context_line":"            resp \u003d self._validate_etag_and_update_sysmeta("},{"line_number":514,"context_line":"                req, symlink_target_path, etag)"},{"line_number":515,"context_line":"            if resp is not None:"},{"line_number":516,"context_line":"                return resp"}],"source_content_type":"text/x-python","patch_set":10,"id":"9fb8cfa7_ca6f6d90","line":513,"range":{"start_line":513,"start_character":24,"end_line":513,"end_character":57},"updated":"2019-06-19 13:21:30.000000000","message":"wondering why was this call not kept in _check_symlink_header? From the docstring it seems like it was intended to be there at some point...","commit_id":"1e1a9d0967c1357aeecbb098543cef39c30552ca"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"a8f76c37648654bd3028483d0a19c646a42a5ed3","unresolved":false,"context_lines":[{"line_number":263,"context_line":"            body\u003d\u0027Symlink cannot target itself\u0027,"},{"line_number":264,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":265,"context_line":"    etag \u003d req.headers.pop(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":266,"context_line":"    if etag and any(c in etag for c in \u0027;\"\\\\\u0027):"},{"line_number":267,"context_line":"        # See cgi.parse_header for why the above chars are problematic"},{"line_number":268,"context_line":"        raise HTTPBadRequest("},{"line_number":269,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"}],"source_content_type":"text/x-python","patch_set":12,"id":"7faddb67_983df7c5","line":266,"range":{"start_line":266,"start_character":41,"end_line":266,"end_character":42},"updated":"2019-07-12 22:31:42.000000000","message":"I\u0027m still a little concerned about this check and I think it would make it fail for slo objects: \n\ndiff --git a/test/functional/test_symlink.py b/test/functional/test_symlink.py\nindex 99fe7acb2..53783aaee 100755\n--- a/test/functional/test_symlink.py\n+++ b/test/functional/test_symlink.py\n@@ -1321,9 +1321,13 @@ class TestSymlinkSlo(Base):\n         self.file_symlink \u003d self.env.container.file(uuid4().hex)\n \n     def test_symlink_target_slo_manifest(self):\n-        self.file_symlink.write(hdrs\u003d{\u0027X-Symlink-Target\u0027:\n-                                \u0027%s/%s\u0027 % (self.env.container.name,\n-                                           \u0027manifest-abcde\u0027)})\n+        file_item \u003d self.env.container.file(\u0027manifest-abcde\u0027)\n+        etag \u003d file_item.info()[\u0027etag\u0027]\n+        hdrs \u003d {\n+            \u0027X-Symlink-Target\u0027: \u0027%s/%s\u0027 % (self.env.container.name,\n+                                           \u0027manifest-abcde\u0027),\n+            \u0027X-Symlink-Target-Etag\u0027: etag}\n+        self.file_symlink.write(hdrs\u003dhdrs)\n         self.assertEqual([\n             (b\u0027a\u0027, 1024 * 1024),\n             (b\u0027b\u0027, 1024 * 1024),\n\n\n\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\u003d\nERROR: test_symlink_target_slo_manifest (test.functional.test_symlink.TestSymlinkSlo)\n----------------------------------------------------------------------\nTraceback (most recent call last):\n  File \"/vagrant/source/swift/test/functional/test_symlink.py\", line 1330, in test_symlink_target_slo_manifest\n    self.file_symlink.write(hdrs\u003dhdrs)\n  File \"/vagrant/source/swift/test/functional/swift_test_client.py\", line 1158, in write\n    raise ResponseError(self.conn.response, \u0027PUT\u0027,\nResponseError: 400: \u0027Bad Request\u0027 (\u0027PUT\u0027 \u0027/v1/AUTH_test/17cad61c380a43569bab4f7e47474d28/79ab13855c3441c4ae1d55915ed32092\u0027) txid\u003dtx24a400c5b21b4d2282e50-005d290944","commit_id":"50ab20d8f7b91f7f2ddf722ddae4a3ffe51e475f"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":38,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":39,"context_line":"during the PUT. If present, this will be used during GETs to verify that the"},{"line_number":40,"context_line":"object matches the given ETag.  The target object must exist and the ETag must"},{"line_number":41,"context_line":"match or the symlink creation will return an client error."},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"It is generally suggested to set the ``Content-Type`` of symlink objects to a"},{"line_number":44,"context_line":"distinct value such as ``application/symlink`` unless the application has"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_825536fc","line":41,"range":{"start_line":41,"start_character":42,"end_line":41,"end_character":51},"updated":"2019-07-18 15:48:36.000000000","message":"nit: a client","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":38,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":39,"context_line":"during the PUT. If present, this will be used during GETs to verify that the"},{"line_number":40,"context_line":"object matches the given ETag.  The target object must exist and the ETag must"},{"line_number":41,"context_line":"match or the symlink creation will return an client error."},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"It is generally suggested to set the ``Content-Type`` of symlink objects to a"},{"line_number":44,"context_line":"distinct value such as ``application/symlink`` unless the application has"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_cb910949","line":41,"range":{"start_line":41,"start_character":42,"end_line":41,"end_character":51},"in_reply_to":"7faddb67_825536fc","updated":"2019-07-18 16:44:30.000000000","message":"Done","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":43,"context_line":"It is generally suggested to set the ``Content-Type`` of symlink objects to a"},{"line_number":44,"context_line":"distinct value such as ``application/symlink`` unless the application has"},{"line_number":45,"context_line":"reason to set it to something else.  For example, when creating a symlink with"},{"line_number":46,"context_line":"a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header the ``Content-Type`` will"},{"line_number":47,"context_line":"automatically be set to match the target object."},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"},{"line_number":50,"context_line":"object referenced by the symlink\u0027s ``X-Symlink-Target-Account`` and"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_803c5c2f","line":47,"range":{"start_line":46,"start_character":43,"end_line":47,"end_character":47},"updated":"2019-07-18 01:37:27.000000000","message":"Always? All the time, regardless of what the client may have sent? It seems incongruous when we say \"unless the application has reason\" immediately before -- it sure seems like *swift* is the one with a reason...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"d4099ac74eac7e4959072ac25dec1280e2ceeeaf","unresolved":false,"context_lines":[{"line_number":43,"context_line":"It is generally suggested to set the ``Content-Type`` of symlink objects to a"},{"line_number":44,"context_line":"distinct value such as ``application/symlink`` unless the application has"},{"line_number":45,"context_line":"reason to set it to something else.  For example, when creating a symlink with"},{"line_number":46,"context_line":"a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header the ``Content-Type`` will"},{"line_number":47,"context_line":"automatically be set to match the target object."},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"},{"line_number":50,"context_line":"object referenced by the symlink\u0027s ``X-Symlink-Target-Account`` and"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_1c9d2965","line":47,"range":{"start_line":46,"start_character":43,"end_line":47,"end_character":47},"in_reply_to":"7faddb67_45ce6863","updated":"2019-07-18 18:58:30.000000000","message":"Perhaps:\n  A symlink\u0027s ``Content-Type`` is completely independent from it\u0027s target.  As a\n  convenience we will automatically set the ``Content-Type`` on a symlink PUT if\n  not explicitly set by the client.  If the client sends a\n  ``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of\n  the target, otherwise it will be set to ``application/symlink``.  You can\n  review a symlink\u0027s ``Content-Type`` using the ``?symlink\u003dget`` interface.  You\n  can change a symlink\u0027s ``Content-Type`` using a POST request.  The symlink\u0027s\n  ``Content-Type`` will appear in the container listing.\n  \n  \n\n???","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb646c373b38f8d57a2b4b8e5191a85020ea5d08","unresolved":false,"context_lines":[{"line_number":43,"context_line":"It is generally suggested to set the ``Content-Type`` of symlink objects to a"},{"line_number":44,"context_line":"distinct value such as ``application/symlink`` unless the application has"},{"line_number":45,"context_line":"reason to set it to something else.  For example, when creating a symlink with"},{"line_number":46,"context_line":"a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header the ``Content-Type`` will"},{"line_number":47,"context_line":"automatically be set to match the target object."},{"line_number":48,"context_line":""},{"line_number":49,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"},{"line_number":50,"context_line":"object referenced by the symlink\u0027s ``X-Symlink-Target-Account`` and"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_45ce6863","line":47,"range":{"start_line":46,"start_character":43,"end_line":47,"end_character":47},"in_reply_to":"7faddb67_803c5c2f","updated":"2019-07-18 16:17:15.000000000","message":"yes, hardlinks set content-type regardless of what the client set - it seems like it\u0027d be really easy to create a hardlink with the wrong content-type in the container listing otherwise... You could probably change it with a POST/307.\n\nI\u0027d be happy to see this reworded if you have a concrete suggestion - I was trying to honor the original recommendation of using \"application/symlink\" but honestly I\u0027m not sure the sentiment there.","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":111,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":112,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":113,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"},{"line_number":114,"context_line":"object\u0027s ``Content-Length`` will be included in the key ``symlink_bytes``."},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"Errors"},{"line_number":117,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_c24ece95","line":114,"updated":"2019-07-18 15:48:36.000000000","message":"wondering if these values are also included in a object HEAD request with the qp `?symlink\u003dget`","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":111,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":112,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":113,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"},{"line_number":114,"context_line":"object\u0027s ``Content-Length`` will be included in the key ``symlink_bytes``."},{"line_number":115,"context_line":""},{"line_number":116,"context_line":"Errors"},{"line_number":117,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_0baba174","line":114,"in_reply_to":"7faddb67_c24ece95","updated":"2019-07-18 16:44:30.000000000","message":"They\u0027re not, which sure makes it questionable why i\u0027m *storing* them on the object in sysmeta....\n\nThe bytes at least seems like it might be informative... potentially...\n\n\tdiff --git a/swift/common/middleware/symlink.py b/swift/common/middleware/symlink.py\n\tindex 9464f6304..505aa39c1 100644\n\t--- a/swift/common/middleware/symlink.py\n\t+++ b/swift/common/middleware/symlink.py\n\t@@ -200,6 +200,7 @@ DEFAULT_SYMLOOP_MAX \u003d 2\n\t TGT_OBJ_SYMLINK_HDR \u003d \u0027x-symlink-target\u0027\n\t TGT_ACCT_SYMLINK_HDR \u003d \u0027x-symlink-target-account\u0027\n\t TGT_ETAG_SYMLINK_HDR \u003d \u0027x-symlink-target-etag\u0027\n\t+TGT_BYTES_SYMLINK_HDR \u003d \u0027x-symlink-target-bytes\u0027\n\t TGT_OBJ_SYSMETA_SYMLINK_HDR \u003d get_sys_meta_prefix(\u0027object\u0027) + \u0027symlink-target\u0027\n\t TGT_ACCT_SYSMETA_SYMLINK_HDR \u003d \\\n\t     get_sys_meta_prefix(\u0027object\u0027) + \u0027symlink-target-account\u0027\n\t@@ -300,7 +301,8 @@ def symlink_sysmeta_to_usermeta(headers):\n\t     for user_hdr, sysmeta_hdr in (\n\t\t     (TGT_OBJ_SYMLINK_HDR, TGT_OBJ_SYSMETA_SYMLINK_HDR),\n\t\t     (TGT_ACCT_SYMLINK_HDR, TGT_ACCT_SYSMETA_SYMLINK_HDR),\n\t-            (TGT_ETAG_SYMLINK_HDR, TGT_ETAG_SYSMETA_SYMLINK_HDR)):\n\t+            (TGT_ETAG_SYMLINK_HDR, TGT_ETAG_SYSMETA_SYMLINK_HDR),\n\t+            (TGT_BYTES_SYMLINK_HDR, TGT_BYTES_SYSMETA_SYMLINK_HDR)):\n\t\t if sysmeta_hdr in headers:\n\t\t     headers[user_hdr] \u003d headers.pop(sysmeta_hdr)","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":300,"context_line":"    for user_hdr, sysmeta_hdr in ("},{"line_number":301,"context_line":"            (TGT_OBJ_SYMLINK_HDR, TGT_OBJ_SYSMETA_SYMLINK_HDR),"},{"line_number":302,"context_line":"            (TGT_ACCT_SYMLINK_HDR, TGT_ACCT_SYSMETA_SYMLINK_HDR),"},{"line_number":303,"context_line":"            (TGT_ETAG_SYMLINK_HDR, TGT_ETAG_SYSMETA_SYMLINK_HDR)):"},{"line_number":304,"context_line":"        if sysmeta_hdr in headers:"},{"line_number":305,"context_line":"            headers[user_hdr] \u003d headers.pop(sysmeta_hdr)"},{"line_number":306,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_a08158c5","line":303,"range":{"start_line":303,"start_character":13,"end_line":303,"end_character":63},"updated":"2019-07-18 01:37:27.000000000","message":"Wait, so we *don\u0027t* handle this pair in symlink_usermeta_to_sysmeta()?\n\nIs there value in translating TGT_BYTES_SYSMETA_SYMLINK_HDR and TGT_CONTENT_TYPE_SYSMETA_SYMLINK_HDR to something user-accessible here?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb646c373b38f8d57a2b4b8e5191a85020ea5d08","unresolved":false,"context_lines":[{"line_number":300,"context_line":"    for user_hdr, sysmeta_hdr in ("},{"line_number":301,"context_line":"            (TGT_OBJ_SYMLINK_HDR, TGT_OBJ_SYSMETA_SYMLINK_HDR),"},{"line_number":302,"context_line":"            (TGT_ACCT_SYMLINK_HDR, TGT_ACCT_SYSMETA_SYMLINK_HDR),"},{"line_number":303,"context_line":"            (TGT_ETAG_SYMLINK_HDR, TGT_ETAG_SYSMETA_SYMLINK_HDR)):"},{"line_number":304,"context_line":"        if sysmeta_hdr in headers:"},{"line_number":305,"context_line":"            headers[user_hdr] \u003d headers.pop(sysmeta_hdr)"},{"line_number":306,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_45fc286f","line":303,"range":{"start_line":303,"start_character":13,"end_line":303,"end_character":63},"in_reply_to":"7faddb67_a08158c5","updated":"2019-07-18 16:17:15.000000000","message":"I could see the value of having the etag in the response of a symlink\u003dget request #willfix\n\nI\u0027m not really sure why I\u0027m persisting the bytes \u0026 content-type in sysmeta - an x-backend header would be entirely sufficient to pass the values over from versioned writes; what do you think?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":367,"context_line":"                else:"},{"line_number":368,"context_line":"                    # make sure to add all other (key, values) back in place"},{"line_number":369,"context_line":"                    obj_dict[\u0027hash\u0027] +\u003d \u0027; %s\u003d%s\u0027 % (key, meta[key])"},{"line_number":370,"context_line":"            else:"},{"line_number":371,"context_line":"                if target:"},{"line_number":372,"context_line":"                    obj_dict[\u0027symlink_path\u0027] \u003d os.path.join("},{"line_number":373,"context_line":"                        \u0027/\u0027, swift_version, account, target)"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_c08494d5","line":370,"range":{"start_line":370,"start_character":12,"end_line":370,"end_character":17},"updated":"2019-07-18 01:37:27.000000000","message":"Off-topic: since there\u0027s no break, the else is always executed.","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":397,"context_line":"        \"\"\""},{"line_number":398,"context_line":"        resp \u003d self._app_call(req.environ)"},{"line_number":399,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":400,"context_line":"        symlink_sysmeta_to_usermeta(response_header_dict)"},{"line_number":401,"context_line":"        self._response_headers \u003d response_header_dict.items()"},{"line_number":402,"context_line":"        return resp"},{"line_number":403,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_68533b6c","line":400,"range":{"start_line":400,"start_character":8,"end_line":400,"end_character":35},"updated":"2019-07-18 15:48:36.000000000","message":"similar question as Tim, since we are returning symlink target bytes and content in the container listing, would it make sense to also return as part of a symlink HEAD request?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"a4d519538a50c16da554aa0b22521b01cbb61ec5","unresolved":false,"context_lines":[{"line_number":397,"context_line":"        \"\"\""},{"line_number":398,"context_line":"        resp \u003d self._app_call(req.environ)"},{"line_number":399,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":400,"context_line":"        symlink_sysmeta_to_usermeta(response_header_dict)"},{"line_number":401,"context_line":"        self._response_headers \u003d response_header_dict.items()"},{"line_number":402,"context_line":"        return resp"},{"line_number":403,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_b63c34e1","line":400,"range":{"start_line":400,"start_character":8,"end_line":400,"end_character":35},"in_reply_to":"7faddb67_566f002a","updated":"2019-07-18 17:37:02.000000000","message":"yeah, let\u0027s figure out how we WANT it to work - try and validate the code does THAT - and then make sure it\u0027s documented!  :+1:","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":397,"context_line":"        \"\"\""},{"line_number":398,"context_line":"        resp \u003d self._app_call(req.environ)"},{"line_number":399,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":400,"context_line":"        symlink_sysmeta_to_usermeta(response_header_dict)"},{"line_number":401,"context_line":"        self._response_headers \u003d response_header_dict.items()"},{"line_number":402,"context_line":"        return resp"},{"line_number":403,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_6b53356c","line":400,"range":{"start_line":400,"start_character":8,"end_line":400,"end_character":35},"in_reply_to":"7faddb67_68533b6c","updated":"2019-07-18 16:44:30.000000000","message":"well, it wouldn\u0027t hurt... storing it on the object in sysmeta gives us that option, so maybe I was just think \"might be useful some day\"\n\nThe content-type of the symlink *is* the content type of the target object - and I think it almost HAS to be because of the way we allow you to update content-type.  Maybe more clear if we drop that from sysmeta entirely?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5514807dcaba0f0cefa10660d59ee167e0e7aa00","unresolved":false,"context_lines":[{"line_number":397,"context_line":"        \"\"\""},{"line_number":398,"context_line":"        resp \u003d self._app_call(req.environ)"},{"line_number":399,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":400,"context_line":"        symlink_sysmeta_to_usermeta(response_header_dict)"},{"line_number":401,"context_line":"        self._response_headers \u003d response_header_dict.items()"},{"line_number":402,"context_line":"        return resp"},{"line_number":403,"context_line":""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_566f002a","line":400,"range":{"start_line":400,"start_character":8,"end_line":400,"end_character":35},"in_reply_to":"7faddb67_6b53356c","updated":"2019-07-18 17:26:08.000000000","message":"yes, you are correct! even the content-length is set to the target object so nevermind...\n\nOTOH, where I\u0027m seeing an issue (and I think you already identified this from reading your other comments) is when the user updates the content-type of a target object. In this scenario, a HEAD to the hardlink correctly shows the updated content-type, but a container listing, incorrectly shows the old (saved in sysmeta) content-type.\n\nI guess this would also be true of the etag and bytes, only that in the case of a HEAD/GET on the hardlink would return an error, but the container listing would continue showing the wrong info until a new hardlink PUT was issued. If this is desirable behavior, maybe we should just mention it in the docs, wdyt?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":441,"context_line":"        symlink_target \u003d self._response_header_value("},{"line_number":442,"context_line":"            TGT_OBJ_SYSMETA_SYMLINK_HDR)"},{"line_number":443,"context_line":"        if symlink_target:"},{"line_number":444,"context_line":"            close_if_possible(resp)"},{"line_number":445,"context_line":"            target_etag \u003d self._response_header_value("},{"line_number":446,"context_line":"                TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":447,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_e064304c","line":444,"updated":"2019-07-18 01:37:27.000000000","message":"Since it\u0027s zero-bytes, this gets logged as a 200 rather than 499, yeah?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"4765b6a852a45562b7e3c2285fa1bba40a1f204c","unresolved":false,"context_lines":[{"line_number":441,"context_line":"        symlink_target \u003d self._response_header_value("},{"line_number":442,"context_line":"            TGT_OBJ_SYSMETA_SYMLINK_HDR)"},{"line_number":443,"context_line":"        if symlink_target:"},{"line_number":444,"context_line":"            close_if_possible(resp)"},{"line_number":445,"context_line":"            target_etag \u003d self._response_header_value("},{"line_number":446,"context_line":"                TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":447,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_5b8d6b2f","line":444,"in_reply_to":"7faddb67_85330062","updated":"2019-07-27 05:36:51.000000000","message":"As much as anything, I wanted this as a reminder to myself. I\u0027m not sure how best to test it, either, but experimentally, yes, this\u0027ll be logged as a 200.","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb646c373b38f8d57a2b4b8e5191a85020ea5d08","unresolved":false,"context_lines":[{"line_number":441,"context_line":"        symlink_target \u003d self._response_header_value("},{"line_number":442,"context_line":"            TGT_OBJ_SYSMETA_SYMLINK_HDR)"},{"line_number":443,"context_line":"        if symlink_target:"},{"line_number":444,"context_line":"            close_if_possible(resp)"},{"line_number":445,"context_line":"            target_etag \u003d self._response_header_value("},{"line_number":446,"context_line":"                TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":447,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_85330062","line":444,"in_reply_to":"7faddb67_e064304c","updated":"2019-07-18 16:17:15.000000000","message":"not sure, what would a test case look like?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":460,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":461,"context_line":"        else:"},{"line_number":462,"context_line":"            # N.B. SLO is to the left of symlink, so we have to leak"},{"line_number":463,"context_line":"            slo_etag \u003d self._response_header_value(SYSMETA_SLO_ETAG)"},{"line_number":464,"context_line":"            if slo_etag:"},{"line_number":465,"context_line":"                final_etag \u003d \u0027\"%s\"\u0027 % slo_etag"},{"line_number":466,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_60584087","line":463,"range":{"start_line":463,"start_character":51,"end_line":463,"end_character":67},"updated":"2019-07-18 01:37:27.000000000","message":"Hmm... so what about the S3-etag for MPUs? This leaking sucks...\n\nIs there anything we can do with X-Backend-Etag-Is-At?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb646c373b38f8d57a2b4b8e5191a85020ea5d08","unresolved":false,"context_lines":[{"line_number":460,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":461,"context_line":"        else:"},{"line_number":462,"context_line":"            # N.B. SLO is to the left of symlink, so we have to leak"},{"line_number":463,"context_line":"            slo_etag \u003d self._response_header_value(SYSMETA_SLO_ETAG)"},{"line_number":464,"context_line":"            if slo_etag:"},{"line_number":465,"context_line":"                final_etag \u003d \u0027\"%s\"\u0027 % slo_etag"},{"line_number":466,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_c57b38f2","line":463,"range":{"start_line":463,"start_character":51,"end_line":463,"end_character":67},"in_reply_to":"7faddb67_60584087","updated":"2019-07-18 16:17:15.000000000","message":"can you make a swift hardlink to a s3 mpu?\n\nI\u0027m not familiar with X-Backend-Etag-Is-At; if it\u0027s in the response sysmeta that might be useful.  Encryption I guess avoids the problem because it\u0027s to the right of symlink.","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"4765b6a852a45562b7e3c2285fa1bba40a1f204c","unresolved":false,"context_lines":[{"line_number":460,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":461,"context_line":"        else:"},{"line_number":462,"context_line":"            # N.B. SLO is to the left of symlink, so we have to leak"},{"line_number":463,"context_line":"            slo_etag \u003d self._response_header_value(SYSMETA_SLO_ETAG)"},{"line_number":464,"context_line":"            if slo_etag:"},{"line_number":465,"context_line":"                final_etag \u003d \u0027\"%s\"\u0027 % slo_etag"},{"line_number":466,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_1bae1398","line":463,"range":{"start_line":463,"start_character":51,"end_line":463,"end_character":67},"in_reply_to":"7faddb67_c57b38f2","updated":"2019-07-27 05:36:51.000000000","message":"Sure, why not? So, supposing I\u0027ve already made my bucket, I make some data big enough to trip awscli\u0027s default MPU handling:\n\n vagrant@saio:~/swift$ truncate -s 50M 50M\n vagrant@saio:~/swift$ aws s3 cp 50M s3://bucket\n upload: ./50M to s3://bucket/50M\n\nAt this point, my listing looks something like\n\n[\n  {\n    \"bytes\": 52428800,\n    \"hash\": \"a53e3fbf3316b36366b877ee2f00c6ad\",\n    \"name\": \"50M\",\n    \"content_type\": \"application/octet-stream\",\n    \"last_modified\": \"2019-07-27T05:08:04.765860\",\n    \"slo_etag\": \"\\\"1415e594539c74a84ce1f1263c7ba860\\\"\",\n    \"s3_etag\": \"\\\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\\\"\"\n  }\n]\n\nSo, let\u0027s make a hardlink!\n\n $ curl -H x-auth-token:$OS_AUTH_TOKEN http://saio:8080/v1/AUTH_test/bucket/link -X PUT -d \u0027\u0027 -H x-symlink-target:bucket/50M -H x-symlink-target-etag:a53e3fbf3316b36366b877ee2f00c6ad -v\n*   Trying 192.168.8.80:8080...\n* TCP_NODELAY set\n* Connected to saio (192.168.8.80) port 8080 (#0)\n\u003e PUT /v1/AUTH_test/bucket/link HTTP/1.1\n\u003e Host: saio:8080\n\u003e User-Agent: curl/7.65.3\n\u003e Accept: */*\n\u003e x-auth-token:AUTH_tkdfb13f78186f495baa45d9cfa2d807c1\n\u003e x-symlink-target:bucket/50M\n\u003e x-symlink-target-etag:a53e3fbf3316b36366b877ee2f00c6ad\n\u003e Content-Length: 0\n\u003e Content-Type: application/x-www-form-urlencoded\n\u003e \n* Mark bundle as not supporting multiuse\n\u003c HTTP/1.1 201 Created\n\u003c Content-Type: text/html; charset\u003dUTF-8\n\u003c Content-Length: 0\n\u003c Etag: d41d8cd98f00b204e9800998ecf8427e\n\u003c Last-Modified: Sat, 27 Jul 2019 05:13:46 GMT\n\u003c X-Trans-Id: tx0d5a68ad3e5b412789d6c-005d3bdd89\n\u003c X-Openstack-Request-Id: tx0d5a68ad3e5b412789d6c-005d3bdd89\n\u003c Date: Sat, 27 Jul 2019 05:13:45 GMT\n\u003c \n* Connection #0 to host saio left intact\n\nAnd if we like how I hacked up _validate_etag_and_update_sysmeta() in patchset 17, our listing now looks like\n\n[\n  {\n    \"bytes\": 52428800,\n    \"hash\": \"a53e3fbf3316b36366b877ee2f00c6ad\",\n    \"name\": \"50M\",\n    \"content_type\": \"application/octet-stream\",\n    \"last_modified\": \"2019-07-27T05:08:04.765860\",\n    \"slo_etag\": \"\\\"1415e594539c74a84ce1f1263c7ba860\\\"\",\n    \"s3_etag\": \"\\\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\\\"\"\n  },\n  {\n    \"bytes\": 0,\n    \"hash\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"name\": \"link\",\n    \"content_type\": \"application/x-www-form-urlencoded\",\n    \"last_modified\": \"2019-07-27T05:13:45.361950\",\n    \"symlink_etag\": \"a53e3fbf3316b36366b877ee2f00c6ad\",\n    \"symlink_bytes\": 52428800,\n    \"symlink_path\": \"/v1/AUTH_test/bucket/50M\",\n    \"slo_etag\": \"\\\"1415e594539c74a84ce1f1263c7ba860\\\"\",\n    \"s3_etag\": \"\\\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\\\"\"\n  }\n]\n\n(with the content-type sucking just \u0027cause I was using -d \u0027\u0027)\n\nShows up \"fine\" from s3:\n\n vagrant@saio:~/swift$ aws s3 ls s3://bucket\n 2019-07-27 05:08:04   52428800 50M\n 2019-07-27 05:13:45          0 link\n vagrant@saio:~/swift$ aws s3api head-object --bucket bucket --key link\n {\n     \"LastModified\": \"Sat, 27 Jul 2019 05:08:05 GMT\",\n     \"ContentLength\": 52428800,\n     \"ETag\": \"\\\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\\\"\",\n     \"ContentType\": \"application/octet-stream\",\n     \"Metadata\": {}\n }\n\nListing size is off, but HEAD works fine. In fact, as of that patchset, it even works with if-match/if-none-match!\n\n vagrant@saio:~/swift$ aws s3api head-object --bucket bucket --key link --if-match \u0027\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\"\u0027\n {\n     \"LastModified\": \"Sat, 27 Jul 2019 05:08:05 GMT\",\n     \"ContentLength\": 52428800,\n     \"ETag\": \"\\\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\\\"\",\n     \"ContentType\": \"application/octet-stream\",\n     \"Metadata\": {}\n }\n vagrant@saio:~/swift$ aws s3api head-object --bucket bucket --key link --if-none-match \u0027\"73d8a713f6f80a5e82a0ea8c92f0cab1-7\"\u0027\n \n An error occurred (304) when calling the HeadObject operation: Not Modified\n\nSweet!","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":467,"context_line":"                final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":468,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":469,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":470,"context_line":"                close_if_possible(resp)"},{"line_number":471,"context_line":"                body \u003d (\u0027Object Etag %r does not match \u0027"},{"line_number":472,"context_line":"                        \u0027X-Symlink-Target-Etag header %r\u0027)"},{"line_number":473,"context_line":"                raise HTTPConflict("}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_40f7445a","line":470,"updated":"2019-07-18 01:37:27.000000000","message":"This one, on the other hand, in all likelihood *would* log a 499, right? Seems appropriate, just checking my mental model.","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"4765b6a852a45562b7e3c2285fa1bba40a1f204c","unresolved":false,"context_lines":[{"line_number":467,"context_line":"                final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":468,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":469,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":470,"context_line":"                close_if_possible(resp)"},{"line_number":471,"context_line":"                body \u003d (\u0027Object Etag %r does not match \u0027"},{"line_number":472,"context_line":"                        \u0027X-Symlink-Target-Etag header %r\u0027)"},{"line_number":473,"context_line":"                raise HTTPConflict("}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_5b924b4d","line":470,"in_reply_to":"7faddb67_08aac717","updated":"2019-07-27 05:36:51.000000000","message":"Confirmed experimentally: this will be a 499 (with SYM swift source), followed by a 409 (with no swift source).","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb646c373b38f8d57a2b4b8e5191a85020ea5d08","unresolved":false,"context_lines":[{"line_number":467,"context_line":"                final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":468,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":469,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":470,"context_line":"                close_if_possible(resp)"},{"line_number":471,"context_line":"                body \u003d (\u0027Object Etag %r does not match \u0027"},{"line_number":472,"context_line":"                        \u0027X-Symlink-Target-Etag header %r\u0027)"},{"line_number":473,"context_line":"                raise HTTPConflict("}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_08aac717","line":470,"in_reply_to":"7faddb67_40f7445a","updated":"2019-07-18 16:17:15.000000000","message":"I\u0027m really not sure on the logging.","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"7bf6fe9d380a1ca2d55628d743ba86e1f09a8c6c","unresolved":false,"context_lines":[{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":505,"context_line":"            response_header_dict[\u0027Content-Length\u0027]"},{"line_number":506,"context_line":"        req.headers[TGT_CONTENT_TYPE_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":507,"context_line":"            response_header_dict[\u0027Content-Type\u0027]"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"    def handle_put(self, req):"},{"line_number":510,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_00f62c64","line":507,"updated":"2019-07-18 01:37:27.000000000","message":"I wonder if this should maybe default *our* X-Object-Sysmeta-Container-Update-Override-Etag to the *target\u0027s* override if it has one...\n\nMight be a way to improve on the SLO/MPU situation? Then we\u0027d still track any slo_etag/s3_etag data present in the target\u0027s container info...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"4765b6a852a45562b7e3c2285fa1bba40a1f204c","unresolved":false,"context_lines":[{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":505,"context_line":"            response_header_dict[\u0027Content-Length\u0027]"},{"line_number":506,"context_line":"        req.headers[TGT_CONTENT_TYPE_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":507,"context_line":"            response_header_dict[\u0027Content-Type\u0027]"},{"line_number":508,"context_line":""},{"line_number":509,"context_line":"    def handle_put(self, req):"},{"line_number":510,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_bba25f99","line":507,"in_reply_to":"7faddb67_00f62c64","updated":"2019-07-27 05:36:51.000000000","message":"Played around with this idea in a later patchset -- seems intriguing?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":527,"context_line":"            if resp is not None:"},{"line_number":528,"context_line":"                return resp"},{"line_number":529,"context_line":"        # N.B. TGT_ETAG_SYMLINK_HDR was converted as part of verifying it"},{"line_number":530,"context_line":"        symlink_usermeta_to_sysmeta(req.headers)"},{"line_number":531,"context_line":"        # Store info in container update that this object is a symlink."},{"line_number":532,"context_line":"        # We have a design decision to use etag space to store symlink info for"},{"line_number":533,"context_line":"        # object listing because it\u0027s immutable unless the object is"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_885557fc","line":530,"range":{"start_line":530,"start_character":8,"end_line":530,"end_character":48},"updated":"2019-07-18 15:48:36.000000000","message":"I\u0027d suggest calling from _validate_etag_and_update_sysmeta, or even just moving the code there if not used else where...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":527,"context_line":"            if resp is not None:"},{"line_number":528,"context_line":"                return resp"},{"line_number":529,"context_line":"        # N.B. TGT_ETAG_SYMLINK_HDR was converted as part of verifying it"},{"line_number":530,"context_line":"        symlink_usermeta_to_sysmeta(req.headers)"},{"line_number":531,"context_line":"        # Store info in container update that this object is a symlink."},{"line_number":532,"context_line":"        # We have a design decision to use etag space to store symlink info for"},{"line_number":533,"context_line":"        # object listing because it\u0027s immutable unless the object is"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_cbf26970","line":530,"range":{"start_line":530,"start_character":8,"end_line":530,"end_character":48},"in_reply_to":"7faddb67_885557fc","updated":"2019-07-18 16:44:30.000000000","message":"I\u0027m not sure I follow - a diff might make it more clear.\n\nMy thinking is both symlinks and hardlinks need to traslate usermeta to sysmeta - but we only need to call _validate_etag for hardlinks...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5514807dcaba0f0cefa10660d59ee167e0e7aa00","unresolved":false,"context_lines":[{"line_number":527,"context_line":"            if resp is not None:"},{"line_number":528,"context_line":"                return resp"},{"line_number":529,"context_line":"        # N.B. TGT_ETAG_SYMLINK_HDR was converted as part of verifying it"},{"line_number":530,"context_line":"        symlink_usermeta_to_sysmeta(req.headers)"},{"line_number":531,"context_line":"        # Store info in container update that this object is a symlink."},{"line_number":532,"context_line":"        # We have a design decision to use etag space to store symlink info for"},{"line_number":533,"context_line":"        # object listing because it\u0027s immutable unless the object is"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_f67b8c88","line":530,"range":{"start_line":530,"start_character":8,"end_line":530,"end_character":48},"in_reply_to":"7faddb67_cbf26970","updated":"2019-07-18 17:26:08.000000000","message":"sorry, my mistake. I didn\u0027t like the fact that the code is updating from user meta to sysmeta in two different places, but overlooked that `_validate_etag_and_update_sysmeta` is only called for hardlinks (duh), let me think more about this...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"a4d519538a50c16da554aa0b22521b01cbb61ec5","unresolved":false,"context_lines":[{"line_number":527,"context_line":"            if resp is not None:"},{"line_number":528,"context_line":"                return resp"},{"line_number":529,"context_line":"        # N.B. TGT_ETAG_SYMLINK_HDR was converted as part of verifying it"},{"line_number":530,"context_line":"        symlink_usermeta_to_sysmeta(req.headers)"},{"line_number":531,"context_line":"        # Store info in container update that this object is a symlink."},{"line_number":532,"context_line":"        # We have a design decision to use etag space to store symlink info for"},{"line_number":533,"context_line":"        # object listing because it\u0027s immutable unless the object is"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_b6475477","line":530,"range":{"start_line":530,"start_character":8,"end_line":530,"end_character":48},"in_reply_to":"7faddb67_f67b8c88","updated":"2019-07-18 17:37:02.000000000","message":"thanks for thinking about it!\n\nWhat\u0027d I\u0027d like to have done is consolidate _check_symlink_header and _validate_etag_and_update_sysmeta - but the `if resp; return resp` thing is tricky!\n\nI wish we could `raise resp` but I can\u0027t seem to make it work that way...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":564,"context_line":"                # TGT_BYTES_SYSMETA_SYMLINK_HDR and"},{"line_number":565,"context_line":"                # TGT_CONTENT_TYPE_SYSMETA_SYMLINK_HDR"},{"line_number":566,"context_line":"                raise HTTPBadRequest("},{"line_number":567,"context_line":"                    body\u003d\u0027Incomplete Hardlink Sysmeta\u0027,"},{"line_number":568,"context_line":"                    request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":569,"context_line":"        req.headers[\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027] \u003d \\"},{"line_number":570,"context_line":"            \u0027; \u0027.join(etag_override)"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_e8896b74","line":567,"range":{"start_line":567,"start_character":26,"end_line":567,"end_character":53},"updated":"2019-07-18 15:48:36.000000000","message":"This is a bad error to return to API users, they probably don\u0027t know (didn\u0027t see it used anywhere in the docs) \u0027hardlink\u0027 or even \u0027sysmeta\u0027, or even if they did, there\u0027s nothing they can do about it. It looks to me more like a 500 error than a 400, thoughts?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":564,"context_line":"                # TGT_BYTES_SYSMETA_SYMLINK_HDR and"},{"line_number":565,"context_line":"                # TGT_CONTENT_TYPE_SYSMETA_SYMLINK_HDR"},{"line_number":566,"context_line":"                raise HTTPBadRequest("},{"line_number":567,"context_line":"                    body\u003d\u0027Incomplete Hardlink Sysmeta\u0027,"},{"line_number":568,"context_line":"                    request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":569,"context_line":"        req.headers[\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027] \u003d \\"},{"line_number":570,"context_line":"            \u0027; \u0027.join(etag_override)"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_2bf77d5b","line":567,"range":{"start_line":567,"start_character":26,"end_line":567,"end_character":53},"in_reply_to":"7faddb67_e8896b74","updated":"2019-07-18 16:44:30.000000000","message":"Only middleware can hit can this error - but point taken about accidentally leaking it... maybe it would be better to let the KeyError traceback?  Do we have any prior art for something like this?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0b1481eddbf61371d31c01e73f6ccf5d21c75e93","unresolved":false,"context_lines":[{"line_number":58,"context_line":"with a ``X-Symlink-Target-Etag`` header they must both match for the GET to"},{"line_number":59,"context_line":"succeed.  If a symlink with a ``X-Symlink-Target-Etag`` header targets a"},{"line_number":60,"context_line":"symlink without a ``X-Symlink-Target-Etag`` header the"},{"line_number":61,"context_line":"``X-Symlink-Target-Etag`` header must be the Etag of the zero-byte object.  If"},{"line_number":62,"context_line":"a symlink with a ``X-Symlink-Target-Etag`` targets a large object manifest it"},{"line_number":63,"context_line":"must match the ETag of the manifest as returned by ``multipart-manifest\u003dget``."},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"A HEAD/GET request to a symlink object behaves as a normal HEAD/GET request"},{"line_number":66,"context_line":"to the target object. Therefore issuing a HEAD request to the symlink will"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_3b050fc3","line":63,"range":{"start_line":61,"start_character":76,"end_line":63,"end_character":78},"updated":"2019-07-27 04:55:24.000000000","message":"Is this going to give more urgency to https://review.opendev.org/#/c/635040/ ?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":58,"context_line":"with a ``X-Symlink-Target-Etag`` header they must both match for the GET to"},{"line_number":59,"context_line":"succeed.  If a symlink with a ``X-Symlink-Target-Etag`` header targets a"},{"line_number":60,"context_line":"symlink without a ``X-Symlink-Target-Etag`` header the"},{"line_number":61,"context_line":"``X-Symlink-Target-Etag`` header must be the Etag of the zero-byte object.  If"},{"line_number":62,"context_line":"a symlink with a ``X-Symlink-Target-Etag`` targets a large object manifest it"},{"line_number":63,"context_line":"must match the ETag of the manifest as returned by ``multipart-manifest\u003dget``."},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"A HEAD/GET request to a symlink object behaves as a normal HEAD/GET request"},{"line_number":66,"context_line":"to the target object. Therefore issuing a HEAD request to the symlink will"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_a142f7a9","line":63,"range":{"start_line":61,"start_character":76,"end_line":63,"end_character":78},"in_reply_to":"7faddb67_3b050fc3","updated":"2019-07-31 16:40:25.000000000","message":"I don\u0027t think continued dependence on correct pipeline ordering gives any more *urgency* to that change, no.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0b1481eddbf61371d31c01e73f6ccf5d21c75e93","unresolved":false,"context_lines":[{"line_number":130,"context_line":"  produce a 409 Conflict error."},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"* GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header that"},{"line_number":133,"context_line":"  does not match the target will poduce a 409 Conflict error."},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_5b3a4b98","line":133,"updated":"2019-07-27 04:55:24.000000000","message":"I\u0027m torn about saying we should maybe do this when the target no longer exists, too...\n\nOn the one hand, we include the Content-Location, so a smart client can figure out that they hit a symlink. On the other hand, the response looks no different from a \"soft\" link pointing at a missing object.\n\nIf we take our cue from If-Match semantics, the 404\u0027s fine and appropriate. If we look to SLO, the 409 makes sense. Hmm... :-/","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":130,"context_line":"  produce a 409 Conflict error."},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"* GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header that"},{"line_number":133,"context_line":"  does not match the target will poduce a 409 Conflict error."},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_3fd38262","line":133,"in_reply_to":"7faddb67_5b3a4b98","updated":"2019-07-31 16:40:25.000000000","message":"in my test both symlinks and hardlinks return 404 when the target doesn\u0027t exist and that seems fine.\n\nCan you clarify if you think the wording here should change to be more clear or that the behavior should change?  Or something else?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":267,"context_line":"            body\u003d\u0027Symlink cannot target itself\u0027,"},{"line_number":268,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":269,"context_line":"    etag \u003d req.headers.pop(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":270,"context_line":"    if etag and any(c in etag.strip(\u0027\"\u0027) for c in \u0027;\"\\\\\u0027):"},{"line_number":271,"context_line":"        # See cgi.parse_header for why the above chars are problematic"},{"line_number":272,"context_line":"        raise HTTPBadRequest("},{"line_number":273,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_e8ad6eea","line":270,"range":{"start_line":270,"start_character":30,"end_line":270,"end_character":35},"updated":"2019-07-26 21:37:38.000000000","message":"Interesting... so we strip(\u0027\"\u0027) before doing the validation, but then we return the unstripped version?\n\nI\u0027ve got this feeling like a quote-wrapped etag wouldn\u0027t ever be useful (given the current state of the code) so we may as well fail it early if we\u0027re going to return the unstripped version...","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":267,"context_line":"            body\u003d\u0027Symlink cannot target itself\u0027,"},{"line_number":268,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":269,"context_line":"    etag \u003d req.headers.pop(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":270,"context_line":"    if etag and any(c in etag.strip(\u0027\"\u0027) for c in \u0027;\"\\\\\u0027):"},{"line_number":271,"context_line":"        # See cgi.parse_header for why the above chars are problematic"},{"line_number":272,"context_line":"        raise HTTPBadRequest("},{"line_number":273,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_ff564ace","line":270,"range":{"start_line":270,"start_character":30,"end_line":270,"end_character":35},"in_reply_to":"7faddb67_e8ad6eea","updated":"2019-07-31 16:40:25.000000000","message":"Honestly I think this was left over from when I was requiring that hardlinks to SLO use the quoted SLO etag instead of the manifest etag.\n\nI\u0027m going to try and pull this out.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":305,"context_line":"            (TGT_OBJ_SYMLINK_HDR, TGT_OBJ_SYSMETA_SYMLINK_HDR),"},{"line_number":306,"context_line":"            (TGT_ACCT_SYMLINK_HDR, TGT_ACCT_SYSMETA_SYMLINK_HDR),"},{"line_number":307,"context_line":"            (TGT_ETAG_SYMLINK_HDR, TGT_ETAG_SYSMETA_SYMLINK_HDR),"},{"line_number":308,"context_line":"            (TGT_BYTES_SYMLINK_HDR, TGT_BYTES_SYSMETA_SYMLINK_HDR)):"},{"line_number":309,"context_line":"        if sysmeta_hdr in headers:"},{"line_number":310,"context_line":"            headers[user_hdr] \u003d headers.pop(sysmeta_hdr)"},{"line_number":311,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_e826ce16","line":308,"updated":"2019-07-26 21:37:38.000000000","message":"Since we return X-Symlink-Target-Bytes on GET, I wonder if we ought to support clients passing it (and us validating it) on PUT...","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":305,"context_line":"            (TGT_OBJ_SYMLINK_HDR, TGT_OBJ_SYSMETA_SYMLINK_HDR),"},{"line_number":306,"context_line":"            (TGT_ACCT_SYMLINK_HDR, TGT_ACCT_SYSMETA_SYMLINK_HDR),"},{"line_number":307,"context_line":"            (TGT_ETAG_SYMLINK_HDR, TGT_ETAG_SYSMETA_SYMLINK_HDR),"},{"line_number":308,"context_line":"            (TGT_BYTES_SYMLINK_HDR, TGT_BYTES_SYSMETA_SYMLINK_HDR)):"},{"line_number":309,"context_line":"        if sysmeta_hdr in headers:"},{"line_number":310,"context_line":"            headers[user_hdr] \u003d headers.pop(sysmeta_hdr)"},{"line_number":311,"context_line":""}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_ffb2ca05","line":308,"in_reply_to":"7faddb67_e826ce16","updated":"2019-07-31 16:40:25.000000000","message":"The only use-case I can imagine there is to prevent a client accidentally hardlinks to an object that has the same ETag but a different # of bytes... which seems somewhat niche.  Surely if we make the validation on PUT it would only make sense to also do it on GET.\n\nI think it\u0027d be an additive feature that would that would look best as a follow on patch.  I\u0027m against expanding the scope of this change to include that validation, tests, and reviewer cognitive load.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":449,"context_line":"            close_if_possible(resp)"},{"line_number":450,"context_line":"            target_etag \u003d self._response_header_value("},{"line_number":451,"context_line":"                TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":452,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":453,"context_line":"            if self._target_etag and self._target_etag !\u003d expected_etag:"},{"line_number":454,"context_line":"                raise HTTPConflict("},{"line_number":455,"context_line":"                    body\u003d\u0027X-Symlink-Target-Etag headers do not match\u0027,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_c86752b7","line":452,"range":{"start_line":452,"start_character":43,"end_line":452,"end_character":78},"updated":"2019-07-26 21:37:38.000000000","message":"Given our pipeline positioning, this should *never* be quoted, yeah?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":449,"context_line":"            close_if_possible(resp)"},{"line_number":450,"context_line":"            target_etag \u003d self._response_header_value("},{"line_number":451,"context_line":"                TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":452,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":453,"context_line":"            if self._target_etag and self._target_etag !\u003d expected_etag:"},{"line_number":454,"context_line":"                raise HTTPConflict("},{"line_number":455,"context_line":"                    body\u003d\u0027X-Symlink-Target-Etag headers do not match\u0027,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_7f9b3a72","line":452,"range":{"start_line":452,"start_character":43,"end_line":452,"end_character":78},"in_reply_to":"7faddb67_c86752b7","updated":"2019-07-31 16:40:25.000000000","message":"that matches my understanding of the current state of the code, yes.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":456,"context_line":"                    headers\u003d{"},{"line_number":457,"context_line":"                        \u0027Content-Type\u0027: \u0027text/plain\u0027,"},{"line_number":458,"context_line":"                        \u0027Content-Location\u0027: self._last_target_path})"},{"line_number":459,"context_line":"            self._target_etag \u003d target_etag"},{"line_number":460,"context_line":"            if self._loop_count \u003e\u003d self.symloop_max:"},{"line_number":461,"context_line":"                raise LinkIterError()"},{"line_number":462,"context_line":"            # format: /\u003caccount name\u003e/\u003ccontainer name\u003e/\u003cobject name\u003e"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_28aaa684","line":459,"updated":"2019-07-26 21:37:38.000000000","message":"Interesting... so if we\u0027re making a hardlink (so self._target_etag was set) that points to a symlink (so target_etag *is not*), we clear the target and continue validation all the way down to the base object?\n\nSo you can get somewhat curious listings like\n\n[\n  {\n    \"bytes\": 0,\n    \"hash\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"name\": \"hardlink\",\n    \"content_type\": \"application/octet-stream\",\n    \"last_modified\": \"2019-07-26T19:57:46.057300\",\n    \"symlink_etag\": \"ac01d90af8657663a2b0474a4032547e\",\n    \"symlink_bytes\": 1832,\n    \"symlink_path\": \"/v1/AUTH_test/c/tox.ini\"\n  },\n  {\n    \"bytes\": 0,\n    \"hash\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"name\": \"link-to-hardlink\",\n    \"content_type\": \"application/octet-stream\",\n    \"last_modified\": \"2019-07-26T20:09:24.650740\",\n    \"symlink_etag\": \"ac01d90af8657663a2b0474a4032547e\",\n    \"symlink_bytes\": 1832,\n    \"symlink_path\": \"/v1/AUTH_test/c/hardlink\"\n  },\n  {\n    \"bytes\": 0,\n    \"hash\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"name\": \"link-to-symlink\",\n    \"content_type\": \"application/octet-stream\",\n    \"last_modified\": \"2019-07-26T20:28:23.760750\",\n    \"symlink_etag\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"symlink_bytes\": 1832,\n    \"symlink_path\": \"/v1/AUTH_test/c/symlink\"\n  },\n  {\n    \"bytes\": 0,\n    \"hash\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"name\": \"symlink\",\n    \"content_type\": \"application/symlink\",\n    \"last_modified\": \"2019-07-26T19:47:05.264800\",\n    \"symlink_path\": \"/v1/AUTH_test/c/tox.ini\"\n  },\n  {\n    \"bytes\": 3952,\n    \"hash\": \"ac01d90af8657663a2b0474a4032547e\",\n    \"name\": \"tox.ini\",\n    \"content_type\": \"application/octet-stream\",\n    \"last_modified\": \"2019-07-26T19:56:01.417420\",\n    \"slo_etag\": \"\\\"6e63ff34889640a03faa1a606c982634\\\"\"\n  }\n]\n\nwhere link-to-hardlink very clearly looks like hardlink, but link-to-symlink looks... a little odd. symlink_etag is recognizable as MD5-of-empty-string, but symlink_bytes is the size of the thing that the symlink *happened to point to* at the time of creation...\n\nI wonder if it\u0027d be better to just *not include* symlink_bytes if we\u0027re pointing to a symlink? I\u0027m having a hard time thinking of a better way to convey that information...","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":456,"context_line":"                    headers\u003d{"},{"line_number":457,"context_line":"                        \u0027Content-Type\u0027: \u0027text/plain\u0027,"},{"line_number":458,"context_line":"                        \u0027Content-Location\u0027: self._last_target_path})"},{"line_number":459,"context_line":"            self._target_etag \u003d target_etag"},{"line_number":460,"context_line":"            if self._loop_count \u003e\u003d self.symloop_max:"},{"line_number":461,"context_line":"                raise LinkIterError()"},{"line_number":462,"context_line":"            # format: /\u003caccount name\u003e/\u003ccontainer name\u003e/\u003cobject name\u003e"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_bfcc526a","line":459,"in_reply_to":"7faddb67_28aaa684","updated":"2019-07-31 16:40:25.000000000","message":"Yes, I\u0027d say that\u0027s a bug - a hardlink to a symlink should probably have symlink_bytes \u003d\u003d 0\n\nI\u0027ll work on a failing test.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":464,"context_line":"            self._loop_count +\u003d 1"},{"line_number":465,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":466,"context_line":"        else:"},{"line_number":467,"context_line":"            final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":468,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":469,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":470,"context_line":"                close_if_possible(resp)"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_48860216","line":467,"updated":"2019-07-26 21:37:38.000000000","message":"How crazy would it be to look at the container update override header here, if present? It occurs to me that it\u0027d be nice if we had the ability to see that we were pointing to an slo, say...","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":464,"context_line":"            self._loop_count +\u003d 1"},{"line_number":465,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":466,"context_line":"        else:"},{"line_number":467,"context_line":"            final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":468,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":469,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":470,"context_line":"                close_if_possible(resp)"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_ff316a5a","line":467,"in_reply_to":"7faddb67_48860216","updated":"2019-07-31 16:40:25.000000000","message":"look at it ... to what ends?  \"ability to see\" in what context?  for the client?  in container listings?  on a symlink\u003dget?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"aa1fbe8bce690a4e81f3ec17089e93672374a5ee","unresolved":false,"context_lines":[{"line_number":474,"context_line":"                    body\u003dbody % (final_etag, self._target_etag),"},{"line_number":475,"context_line":"                    headers\u003d{"},{"line_number":476,"context_line":"                        \u0027Content-Type\u0027: \u0027text/plain\u0027,"},{"line_number":477,"context_line":"                        \u0027Content-Location\u0027: self._last_target_path})"},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"            if self._last_target_path:"},{"line_number":480,"context_line":"                # Content-Location will be applied only when one or more"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_d91baec7","line":477,"updated":"2019-07-26 17:35:20.000000000","message":"wondering if it would be helpful to client apps to also include the target etag as a header, thoughts?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":474,"context_line":"                    body\u003dbody % (final_etag, self._target_etag),"},{"line_number":475,"context_line":"                    headers\u003d{"},{"line_number":476,"context_line":"                        \u0027Content-Type\u0027: \u0027text/plain\u0027,"},{"line_number":477,"context_line":"                        \u0027Content-Location\u0027: self._last_target_path})"},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"            if self._last_target_path:"},{"line_number":480,"context_line":"                # Content-Location will be applied only when one or more"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_c84e7237","line":477,"in_reply_to":"7faddb67_17ca6d6d","updated":"2019-07-26 21:37:38.000000000","message":"I think the idea would be to have a way to get *just* the etag they should\u0027ve sent, without having to parse the body (the exact wording of which we may update over time).","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":474,"context_line":"                    body\u003dbody % (final_etag, self._target_etag),"},{"line_number":475,"context_line":"                    headers\u003d{"},{"line_number":476,"context_line":"                        \u0027Content-Type\u0027: \u0027text/plain\u0027,"},{"line_number":477,"context_line":"                        \u0027Content-Location\u0027: self._last_target_path})"},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"            if self._last_target_path:"},{"line_number":480,"context_line":"                # Content-Location will be applied only when one or more"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_5f7f5edf","line":477,"in_reply_to":"7faddb67_c84e7237","updated":"2019-07-31 16:40:25.000000000","message":"so that they can build their own error messages without making another request?  Ok, I\u0027m not against it... is there a particular diff anyone is advocating for?\n\nTo me it seems only marginally useful unless it\u0027s applied very consistently and well documented and maintained.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"3db53aaf0e1ac13b07f02b3044c4142358fdc3ec","unresolved":false,"context_lines":[{"line_number":474,"context_line":"                    body\u003dbody % (final_etag, self._target_etag),"},{"line_number":475,"context_line":"                    headers\u003d{"},{"line_number":476,"context_line":"                        \u0027Content-Type\u0027: \u0027text/plain\u0027,"},{"line_number":477,"context_line":"                        \u0027Content-Location\u0027: self._last_target_path})"},{"line_number":478,"context_line":""},{"line_number":479,"context_line":"            if self._last_target_path:"},{"line_number":480,"context_line":"                # Content-Location will be applied only when one or more"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_17ca6d6d","line":477,"in_reply_to":"7faddb67_d91baec7","updated":"2019-07-26 17:45:01.000000000","message":"it\u0027s in the body","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":496,"context_line":"        new_req \u003d make_subrequest("},{"line_number":497,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":498,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_48ba826e","line":499,"range":{"start_line":499,"start_character":20,"end_line":499,"end_character":39},"updated":"2019-07-26 21:37:38.000000000","message":"Oh, cool -- so if we\u0027re hardlinking to a hardlink, we\u0027ll validate that the link we\u0027re pointing to was valid at the time of creation -- I think I like that.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fe710aebb0927b90a4c2877780f06d47d44ffe57","unresolved":false,"context_lines":[{"line_number":498,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":503,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_f53a26e5","line":501,"updated":"2019-07-27 00:45:17.000000000","message":"So if the target doesn\u0027t exist when we do the PUT... we return a 404? IDK, I\u0027d kinda prefer to 409 like we would if the etag didn\u0027t match... particularly since there\u0027s no indication that this *wasn\u0027t* a 404 because the container doesn\u0027t exist (which is the normal reason I\u0027d expect a 404 on PUT).\n\nIIRC, a 409 would also match what you\u0027d get if there was a 404 during SLO validation.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":498,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":503,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_5fcd1e2f","line":501,"in_reply_to":"7faddb67_2a4842ca","updated":"2019-07-31 16:40:25.000000000","message":"I\u0027m not sure about the 409 vs 404 on GET where I think the 404 might provide more relevant and useful context, but I definitely appreciate the ambiguity of the 404 on PUT.\n\nI think we discussed the hardlink to symlink on IRC, so I\u0027d like to work on that change and maybe the correct answer for the status code on PUT will become more obvious.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"09b980090770437cfa09e613ab4149605a1fef79","unresolved":false,"context_lines":[{"line_number":498,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":503,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_2a4842ca","line":501,"in_reply_to":"7faddb67_f53a26e5","updated":"2019-07-29 21:17:21.000000000","message":"Note that this gets particularly strange when hardlinking to a symlink -- the symlink *must* point to actual data at the time of the linking, otherwise the PUT will 404 here! And that extra validation doesn\u0027t actually improve our guarantees on GET -- the validation only gets as far as the symlink :-/","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":503,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":505,"context_line":"            response_header_dict[\u0027Content-Length\u0027]"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_e8ca4e4d","line":502,"updated":"2019-07-26 21:37:38.000000000","message":"Or maybe we\u0027d want to be looking at the override header down around here or something... I\u0027ll play with it a little... see what I can come up with.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":503,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":505,"context_line":"            response_header_dict[\u0027Content-Length\u0027]"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_5af68c65","line":502,"in_reply_to":"7faddb67_b8dca574","updated":"2019-07-31 16:40:25.000000000","message":"I can\u0027t seem to copy this diff out of this comment from my browser in order to apply it to my tree :\u0027(\n\nBut my experience leads me to assume once I get it applied it\u0027ll be great!","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"fe710aebb0927b90a4c2877780f06d47d44ffe57","unresolved":false,"context_lines":[{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_header_dict \u003d HeaderKeyDict(self._response_headers)"},{"line_number":503,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":504,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":505,"context_line":"            response_header_dict[\u0027Content-Length\u0027]"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_b8dca574","line":502,"in_reply_to":"7faddb67_e8ca4e4d","updated":"2019-07-27 00:45:17.000000000","message":"Here\u0027s what I got:\n\ndiff --git a/swift/common/middleware/symlink.py b/swift/common/middleware/symlink.py\nindex 91e437523..008dc5039 100644\n--- a/swift/common/middleware/symlink.py\n+++ b/swift/common/middleware/symlink.py\n@@ -501,12 +501,22 @@ class SymlinkObjectContext(WSGIContext):\n         resp \u003d self._recursive_get_head(new_req)\n         if not is_success(self._get_status_int()):\n             return resp\n-        response_header_dict \u003d HeaderKeyDict(self._response_headers)\n+        response_headers \u003d HeaderKeyDict(self._response_headers)\n+        override_header \u003d \u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027\n+        if override_header in response_headers and \\\n+                override_header not in req.headers:\n+            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]\n+            req.headers[override_header] \u003d MD5_OF_EMPTY_STRING + sep + params\n         req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag\n-        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\\n-            response_header_dict[\u0027Content-Length\u0027]\n+        slo_size \u003d response_headers.get(\u0027x-object-sysmeta-slo-size\u0027)\n+        if slo_size:\n+            # :-/ well this sucks\n+            req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d slo_size\n+        else:\n+            req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\\n+                response_headers[\u0027Content-Length\u0027]\n         if not req.headers.get(\u0027Content-Type\u0027):\n-            req.headers[\u0027Content-Type\u0027] \u003d response_header_dict[\u0027Content-Type\u0027]\n+            req.headers[\u0027Content-Type\u0027] \u003d response_headers[\u0027Content-Type\u0027]\n \n     def handle_put(self, req):\n         \"\"\"\n\nGets us both slo_etag and the slo size, like\n\n[\n  {\n    \"bytes\": 0,\n    \"hash\": \"d41d8cd98f00b204e9800998ecf8427e\",\n    \"name\": \"hardlink\",\n    \"content_type\": \"text/plain\",\n    \"last_modified\": \"2019-07-27T00:42:04.218080\",\n    \"symlink_etag\": \"299915f50ae74ae19ec5b3cad4f84513\",\n    \"symlink_bytes\": 3952,\n    \"symlink_path\": \"/v1/AUTH_test/c/tox.ini\",\n    \"slo_etag\": \"\\\"ba233eb3581190adc23514ebbf894072\\\"\"\n  },\n  {\n    \"bytes\": 3952,\n    \"hash\": \"299915f50ae74ae19ec5b3cad4f84513\",\n    \"name\": \"tox.ini\",\n    \"content_type\": \"text/plain\",\n    \"last_modified\": \"2019-07-27T00:01:57.792310\",\n    \"slo_etag\": \"\\\"ba233eb3581190adc23514ebbf894072\\\"\"\n  }\n]","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f9f98e87fc5f15c57107ac0f2f9ffbd8f4ed7ddd","unresolved":false,"context_lines":[{"line_number":267,"context_line":"            body\u003d\u0027Symlink cannot target itself\u0027,"},{"line_number":268,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":269,"context_line":"    etag \u003d req.headers.pop(TGT_ETAG_SYMLINK_HDR, None)"},{"line_number":270,"context_line":"    if etag and any(c in etag.strip(\u0027\"\u0027) for c in \u0027;\"\\\\\u0027):"},{"line_number":271,"context_line":"        # See cgi.parse_header for why the above chars are problematic"},{"line_number":272,"context_line":"        raise HTTPBadRequest("},{"line_number":273,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_86e25bd4","line":270,"updated":"2019-08-01 14:28:47.000000000","message":"I forgot to put \"fix the quote thing\" on my todo list!  :disappointed:\n\n#willfix","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"021ccfdeec2f1879717ba5f8d3d95e6ede1ca8e5","unresolved":false,"context_lines":[{"line_number":512,"context_line":"            req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d slo_size"},{"line_number":513,"context_line":"        else:"},{"line_number":514,"context_line":"            req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\"},{"line_number":515,"context_line":"                response_headers[\u0027Content-Length\u0027]"},{"line_number":516,"context_line":"        if not req.headers.get(\u0027Content-Type\u0027):"},{"line_number":517,"context_line":"            req.headers[\u0027Content-Type\u0027] \u003d response_headers[\u0027Content-Type\u0027]"},{"line_number":518,"context_line":""}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_e32eac8a","line":515,"updated":"2019-07-31 20:47:15.000000000","message":"I don\u0027t think we should be doing this with slo\u0027s sysmeta.  I think this would look better as just:\n\n\tdiff --git a/swift/common/middleware/symlink.py b/swift/common/middleware/symlink.py\n\tindex 410a05d37..2ab4def38 100644\n\t--- a/swift/common/middleware/symlink.py\n\t+++ b/swift/common/middleware/symlink.py\n\t@@ -506,13 +506,8 @@ class SymlinkObjectContext(WSGIContext):\n\t\t     sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]\n\t\t     req.headers[override_header] \u003d MD5_OF_EMPTY_STRING + sep + params\n\t\t req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag\n\t-        slo_size \u003d response_headers.get(\u0027x-object-sysmeta-slo-size\u0027)\n\t-        if slo_size:\n\t-            # :-/ well this sucks\n\t-            req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d slo_size\n\t-        else:\n\t-            req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\\n\t-                response_headers[\u0027Content-Length\u0027]\n\t+        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \\\n\t+            response_headers[\u0027Content-Length\u0027]\n\t\t if not req.headers.get(\u0027Content-Type\u0027):\n\t\t     req.headers[\u0027Content-Type\u0027] \u003d response_headers[\u0027Content-Type\u0027]\n\t \n\nthe symlink_bytes should go with the symlink_etag","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"52ae84d07fe742f4d2b7c1223ab809adfb4882eb","unresolved":false,"context_lines":[{"line_number":496,"context_line":"        new_req \u003d make_subrequest("},{"line_number":497,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":498,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":499,"context_line":"        resp \u003d self._recursive_get_head(new_req, stop_at_softlink\u003dTrue)"},{"line_number":500,"context_line":"        if not is_success(self._get_status_int()):"},{"line_number":501,"context_line":"            return resp"},{"line_number":502,"context_line":"        response_headers \u003d HeaderKeyDict(self._response_headers)"}],"source_content_type":"text/x-python","patch_set":19,"id":"7faddb67_f811595e","line":499,"updated":"2019-08-02 19:46:35.000000000","message":"stop_at_softlink, how clever.","commit_id":"a83a7692af11c49ecda4152e0bf857cc19b8832a"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5e6b3fe5507118c0fe1a46f98926309812775112","unresolved":false,"context_lines":[{"line_number":80,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":81,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":82,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"},{"line_number":83,"context_line":"the target, otherwise it will be set to ``application/symlink``.  You can"},{"line_number":84,"context_line":"review a symlink\u0027s ``Content-Type`` using the ``?symlink\u003dget`` interface.  You"},{"line_number":85,"context_line":"can change a symlink\u0027s ``Content-Type`` using a POST request.  The symlink\u0027s"},{"line_number":86,"context_line":"``Content-Type`` will appear in the container listing."}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_8c7812c4","line":83,"range":{"start_line":83,"start_character":42,"end_line":83,"end_character":61},"updated":"2019-08-05 14:22:04.000000000","message":"I think we might be missing this...","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":80,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":81,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":82,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"},{"line_number":83,"context_line":"the target, otherwise it will be set to ``application/symlink``.  You can"},{"line_number":84,"context_line":"review a symlink\u0027s ``Content-Type`` using the ``?symlink\u003dget`` interface.  You"},{"line_number":85,"context_line":"can change a symlink\u0027s ``Content-Type`` using a POST request.  The symlink\u0027s"},{"line_number":86,"context_line":"``Content-Type`` will appear in the container listing."}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_b8c988ac","line":83,"range":{"start_line":83,"start_character":42,"end_line":83,"end_character":61},"in_reply_to":"7faddb67_8c7812c4","updated":"2019-08-05 19:37:22.000000000","message":"I don\u0027t know what you mean.  Can you more clearly formulate a recommendation for what you think will improve this change?","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5f78fc880e2de0aa4b7394193756987c5cfd1d77","unresolved":false,"context_lines":[{"line_number":80,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":81,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":82,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"},{"line_number":83,"context_line":"the target, otherwise it will be set to ``application/symlink``.  You can"},{"line_number":84,"context_line":"review a symlink\u0027s ``Content-Type`` using the ``?symlink\u003dget`` interface.  You"},{"line_number":85,"context_line":"can change a symlink\u0027s ``Content-Type`` using a POST request.  The symlink\u0027s"},{"line_number":86,"context_line":"``Content-Type`` will appear in the container listing."}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_2bb70bf8","line":83,"range":{"start_line":83,"start_character":42,"end_line":83,"end_character":61},"in_reply_to":"7faddb67_b8c988ac","updated":"2019-08-12 16:50:49.000000000","message":"sorry, I just missed the change in line 278.","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5e6b3fe5507118c0fe1a46f98926309812775112","unresolved":false,"context_lines":[{"line_number":129,"context_line":"* GET/HEAD traversing more than ``symloop_max`` chained symlinks will"},{"line_number":130,"context_line":"  produce a 409 Conflict error."},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"* GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header that"},{"line_number":133,"context_line":"  does not match the target will poduce a 409 Conflict error."},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_562cebaa","line":132,"range":{"start_line":132,"start_character":2,"end_line":132,"end_character":10},"updated":"2019-08-05 14:22:04.000000000","message":"PUT/GET/HEAD","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":129,"context_line":"* GET/HEAD traversing more than ``symloop_max`` chained symlinks will"},{"line_number":130,"context_line":"  produce a 409 Conflict error."},{"line_number":131,"context_line":""},{"line_number":132,"context_line":"* GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header that"},{"line_number":133,"context_line":"  does not match the target will poduce a 409 Conflict error."},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_b85748ca","line":132,"range":{"start_line":132,"start_character":2,"end_line":132,"end_character":10},"in_reply_to":"7faddb67_562cebaa","updated":"2019-08-05 19:37:22.000000000","message":"Ha good point!  #willfix","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":275,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"},{"line_number":276,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":277,"context_line":"    if not (etag or req.headers.get(\u0027Content-Type\u0027)):"},{"line_number":278,"context_line":"        req.headers[\u0027Content-Type\u0027] \u003d \u0027application/symlink\u0027"},{"line_number":279,"context_line":"    return \u0027/v1/%s/%s/%s\u0027 % (account, container, obj), etag"},{"line_number":280,"context_line":""},{"line_number":281,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_f885c05a","line":278,"updated":"2019-08-05 19:37:22.000000000","message":"just want to draw attention to this change here","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5e6b3fe5507118c0fe1a46f98926309812775112","unresolved":false,"context_lines":[{"line_number":449,"context_line":"            TGT_OBJ_SYSMETA_SYMLINK_HDR)"},{"line_number":450,"context_line":"        target_etag \u003d self._response_header_value("},{"line_number":451,"context_line":"            TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":452,"context_line":"        if symlink_target and (target_etag or not stop_at_softlink):"},{"line_number":453,"context_line":"            close_if_possible(resp)"},{"line_number":454,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":455,"context_line":"            if self._target_etag and self._target_etag !\u003d expected_etag:"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_29bd50b6","line":452,"range":{"start_line":452,"start_character":50,"end_line":452,"end_character":66},"updated":"2019-08-05 14:22:04.000000000","message":"could we change `stop_at_softlink` to `follow_softlink`, i think we would then endup with:\n\n  if symlink_target and (target_etag or follow_softlink):\n\n\nwhich i think is easier to understand...","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":449,"context_line":"            TGT_OBJ_SYSMETA_SYMLINK_HDR)"},{"line_number":450,"context_line":"        target_etag \u003d self._response_header_value("},{"line_number":451,"context_line":"            TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":452,"context_line":"        if symlink_target and (target_etag or not stop_at_softlink):"},{"line_number":453,"context_line":"            close_if_possible(resp)"},{"line_number":454,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":455,"context_line":"            if self._target_etag and self._target_etag !\u003d expected_etag:"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_98f5accd","line":452,"range":{"start_line":452,"start_character":50,"end_line":452,"end_character":66},"in_reply_to":"7faddb67_29bd50b6","updated":"2019-08-05 19:37:22.000000000","message":"Yes, changing the name and flipping the boolean seems to work.  I agree it\u0027s a little easier to read (I think \"not stop\" is almost a double-negative)","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5e6b3fe5507118c0fe1a46f98926309812775112","unresolved":false,"context_lines":[{"line_number":513,"context_line":"        if override_header in response_headers and \\"},{"line_number":514,"context_line":"                override_header not in req.headers:"},{"line_number":515,"context_line":"            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]"},{"line_number":516,"context_line":"            req.headers[override_header] \u003d MD5_OF_EMPTY_STRING + sep + params"},{"line_number":517,"context_line":""},{"line_number":518,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":519,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_eceae671","line":516,"range":{"start_line":516,"start_character":12,"end_line":516,"end_character":77},"updated":"2019-08-05 14:22:04.000000000","message":"Please add a comment as to why we are doing this here, at first glance it is not obvious. It\u0027s to get the slo_etag on the symlink listing, correct?","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":513,"context_line":"        if override_header in response_headers and \\"},{"line_number":514,"context_line":"                override_header not in req.headers:"},{"line_number":515,"context_line":"            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]"},{"line_number":516,"context_line":"            req.headers[override_header] \u003d MD5_OF_EMPTY_STRING + sep + params"},{"line_number":517,"context_line":""},{"line_number":518,"context_line":"        req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR] \u003d etag"},{"line_number":519,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_1833fcac","line":516,"range":{"start_line":516,"start_character":12,"end_line":516,"end_character":77},"in_reply_to":"7faddb67_eceae671","updated":"2019-08-05 19:37:22.000000000","message":"This behavior was missing a unittest - but a functional test failure confirmed the slo_etag was missing from the container without it; so your intuition is correct at least...\n\nI updated the unittest based on Tim\u0027s suggestion and add a (hopefully clarifying) comment.","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d26c73962383108fc1c7c1274aa2c9dd640f0061","unresolved":false,"context_lines":[{"line_number":523,"context_line":"        size \u003d response_headers[\u0027Content-Length\u0027]"},{"line_number":524,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":525,"context_line":"        slo_size \u003d response_headers.get(\u0027x-object-sysmeta-slo-size\u0027)"},{"line_number":526,"context_line":"        if slo_size:"},{"line_number":527,"context_line":"            size \u003d slo_size"},{"line_number":528,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d size"},{"line_number":529,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_5ea652c3","line":526,"updated":"2019-08-02 22:54:41.000000000","message":"nit: I might reduce all this to\n\n req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d \n     slo_size or response_headers[\u0027Content-Length\u0027]\n\nbut w/e","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":523,"context_line":"        size \u003d response_headers[\u0027Content-Length\u0027]"},{"line_number":524,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":525,"context_line":"        slo_size \u003d response_headers.get(\u0027x-object-sysmeta-slo-size\u0027)"},{"line_number":526,"context_line":"        if slo_size:"},{"line_number":527,"context_line":"            size \u003d slo_size"},{"line_number":528,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d size"},{"line_number":529,"context_line":""}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_786eb02f","line":526,"in_reply_to":"7faddb67_5ea652c3","updated":"2019-08-05 19:37:22.000000000","message":"oh, i like it!","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ae795e1061a4d6006553e7e3f00f9890a50a6c4c","unresolved":false,"context_lines":[{"line_number":525,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":526,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d ("},{"line_number":527,"context_line":"            response_headers.get(\u0027x-object-sysmeta-slo-size\u0027) or"},{"line_number":528,"context_line":"            response_headers[\u0027Content-Length\u0027])"},{"line_number":529,"context_line":""},{"line_number":530,"context_line":"    def handle_put(self, req):"},{"line_number":531,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":23,"id":"7faddb67_5642a03f","line":528,"updated":"2019-08-05 21:45:57.000000000","message":"this coupling with SLO is worse than we imagined, since legacy SLOs on disk won\u0027t have the slo-size or container-update-override headers set\n\nit\u0027s possible hardlinks shouldn\u0027t be trying to carry forward the special target container update keys w/o the actual request that created the target object in the request path (i.e. versioned writes can do whatever it wants to the versioned container listing when creating hardlinks to objects it just wrote into the versions container)","commit_id":"c1da067a26593ba98669a5b1a702099c7f8ece53"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":525,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":526,"context_line":"        req.headers[TGT_BYTES_SYSMETA_SYMLINK_HDR] \u003d ("},{"line_number":527,"context_line":"            response_headers.get(\u0027x-object-sysmeta-slo-size\u0027) or"},{"line_number":528,"context_line":"            response_headers[\u0027Content-Length\u0027])"},{"line_number":529,"context_line":""},{"line_number":530,"context_line":"    def handle_put(self, req):"},{"line_number":531,"context_line":"        \"\"\""}],"source_content_type":"text/x-python","patch_set":23,"id":"7faddb67_e352c568","line":528,"in_reply_to":"7faddb67_5642a03f","updated":"2019-08-09 22:13:02.000000000","message":"IDK -- I\u0027d like to hope that the set of all SLOs that have been or will be written *with* the sysmeta and override headers is orders of maginitude larger than the set of all SLOs written *without* one or more of those headers...","commit_id":"c1da067a26593ba98669a5b1a702099c7f8ece53"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9de3fb75aa7c99a41a76322cf290b14cd579e11e","unresolved":false,"context_lines":[{"line_number":37,"context_line":""},{"line_number":38,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":39,"context_line":"during the PUT. If present, this will be used during GETs to verify that the"},{"line_number":40,"context_line":"object matches the given ETag.  The target object must exist and the ETag must"},{"line_number":41,"context_line":"match or the symlink creation will return a client error."},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_233692e9","line":40,"range":{"start_line":40,"start_character":32,"end_line":40,"end_character":60},"updated":"2019-08-08 07:17:59.000000000","message":"This is contradicting the last paragraph. I understand why, but I wonder if that means we need to word this better?","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c0d1f8851fc4d51666cee55d3b177b30ba697a0a","unresolved":false,"context_lines":[{"line_number":37,"context_line":""},{"line_number":38,"context_line":"Clients may optionally include a ``X-Symlink-Target-Etag: \u003cetag\u003e`` header"},{"line_number":39,"context_line":"during the PUT. If present, this will be used during GETs to verify that the"},{"line_number":40,"context_line":"object matches the given ETag.  The target object must exist and the ETag must"},{"line_number":41,"context_line":"match or the symlink creation will return a client error."},{"line_number":42,"context_line":""},{"line_number":43,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_700be42a","line":40,"range":{"start_line":40,"start_character":32,"end_line":40,"end_character":60},"in_reply_to":"7faddb67_233692e9","updated":"2019-08-08 16:49:23.000000000","message":"maybe we can attach it to the preceding sentence with a conjunction so the \"If present\" qualifier more clearly applies to both new behaviors.\n\nAlternatively we could might define a \"Hardlink\" as an officially documented noun that has different behavior than a Symlink.\n\nThoughts?","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9de3fb75aa7c99a41a76322cf290b14cd579e11e","unresolved":false,"context_lines":[{"line_number":58,"context_line":"with a ``X-Symlink-Target-Etag`` header they must both match for the GET to"},{"line_number":59,"context_line":"succeed.  If a symlink with a ``X-Symlink-Target-Etag`` header targets a"},{"line_number":60,"context_line":"symlink without a ``X-Symlink-Target-Etag`` header the"},{"line_number":61,"context_line":"``X-Symlink-Target-Etag`` header must be the Etag of the zero-byte object.  If"},{"line_number":62,"context_line":"a symlink with a ``X-Symlink-Target-Etag`` targets a large object manifest it"},{"line_number":63,"context_line":"must match the ETag of the manifest as returned by ``multipart-manifest\u003dget``."},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_a34fe268","line":61,"updated":"2019-08-08 07:17:59.000000000","message":"Wait.. what. OK. When would we ever need that?\n\nedit: Further reading in the code we have tests for hardlinks to symlinks.. ok, fair enough. We may want hard link to somewhere that must always be a symlink. I guess it could happen. Or does this open up to hardlinks to DLOs too? Which may be something people may want.","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c0d1f8851fc4d51666cee55d3b177b30ba697a0a","unresolved":false,"context_lines":[{"line_number":58,"context_line":"with a ``X-Symlink-Target-Etag`` header they must both match for the GET to"},{"line_number":59,"context_line":"succeed.  If a symlink with a ``X-Symlink-Target-Etag`` header targets a"},{"line_number":60,"context_line":"symlink without a ``X-Symlink-Target-Etag`` header the"},{"line_number":61,"context_line":"``X-Symlink-Target-Etag`` header must be the Etag of the zero-byte object.  If"},{"line_number":62,"context_line":"a symlink with a ``X-Symlink-Target-Etag`` targets a large object manifest it"},{"line_number":63,"context_line":"must match the ETag of the manifest as returned by ``multipart-manifest\u003dget``."},{"line_number":64,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_d3598235","line":61,"in_reply_to":"7faddb67_a34fe268","updated":"2019-08-08 16:49:23.000000000","message":"You can hardlink to a symlink or a DLO, in both cases the ETag on the hardlink would be the zero-byte object.\n\nhardlinks to real objects and SLO manifests have much stronger guarantees about the integrity of the target.\n\nhardlinks to symlinks \u0026 DLOs offer little in the way of integrity and carry no useful information about the dynamic entity referenced *thorough* their target\n\nThis paragraph might also become more clear with an officially documented noun.","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9de3fb75aa7c99a41a76322cf290b14cd579e11e","unresolved":false,"context_lines":[{"line_number":118,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"},{"line_number":119,"context_line":"object\u0027s ``Content-Length`` will be included in the key ``symlink_bytes``."},{"line_number":120,"context_line":""},{"line_number":121,"context_line":"If a symlink with a ``X-Symlink-Target-Etag`` targets a static large object"},{"line_number":122,"context_line":"manifest it will carry forward the SLO size and etag in the container listing"},{"line_number":123,"context_line":"the ``symlink_bytes`` and ``slo_etag`` keys.  However, manifests created before"},{"line_number":124,"context_line":"swift v2.12.0 (released Dec 2016) do not contain enough metadata to propogate"},{"line_number":125,"context_line":"the extra SLO information to the listing."},{"line_number":126,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_83818650","line":123,"range":{"start_line":121,"start_character":0,"end_line":123,"end_character":44},"updated":"2019-08-08 07:17:59.000000000","message":"This sentence is missing some words and doesn\u0027t make sense.\n\nMaybe it\u0027s missing an \"along with\" or something similar:\n\n  If a symlink with a ``X-Symlink-Target-Etag`` targets a static large object manifest it will carry forward the SLO size and etag in the container listing along with the ``symlink_bytes`` and ``slo_etag`` keys.","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c0d1f8851fc4d51666cee55d3b177b30ba697a0a","unresolved":false,"context_lines":[{"line_number":118,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"},{"line_number":119,"context_line":"object\u0027s ``Content-Length`` will be included in the key ``symlink_bytes``."},{"line_number":120,"context_line":""},{"line_number":121,"context_line":"If a symlink with a ``X-Symlink-Target-Etag`` targets a static large object"},{"line_number":122,"context_line":"manifest it will carry forward the SLO size and etag in the container listing"},{"line_number":123,"context_line":"the ``symlink_bytes`` and ``slo_etag`` keys.  However, manifests created before"},{"line_number":124,"context_line":"swift v2.12.0 (released Dec 2016) do not contain enough metadata to propogate"},{"line_number":125,"context_line":"the extra SLO information to the listing."},{"line_number":126,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_33b6d640","line":123,"range":{"start_line":121,"start_character":0,"end_line":123,"end_character":44},"in_reply_to":"7faddb67_83818650","updated":"2019-08-08 16:49:23.000000000","message":"Agreed.\n\nI think I was trying to say:\n\nIf a symlink with a X-Symlink-Target-Etag (a hardlink) targets a static large object manifest it will carry forwards the SLO size and etag in it\u0027s container listing *via* the symlink_bytes and slo_bytes keys.","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9de3fb75aa7c99a41a76322cf290b14cd579e11e","unresolved":false,"context_lines":[{"line_number":517,"context_line":"        response_headers \u003d HeaderKeyDict(self._response_headers)"},{"line_number":518,"context_line":"        # carry forward any etag update params (e.g. \"slo_etag\"), we\u0027ll append"},{"line_number":519,"context_line":"        # symlink_target_* params to this header after this method returns"},{"line_number":520,"context_line":"        override_header \u003d \u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027"},{"line_number":521,"context_line":"        if override_header in response_headers and \\"},{"line_number":522,"context_line":"                override_header not in req.headers:"},{"line_number":523,"context_line":"            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]"}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_ae9d89bc","line":520,"updated":"2019-08-08 07:17:59.000000000","message":"NIT: The middleware goes to the effort of generating sysmeta headers using the helper method. I wonder if it should be used for this as well, or even a const used?","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"c0d1f8851fc4d51666cee55d3b177b30ba697a0a","unresolved":false,"context_lines":[{"line_number":517,"context_line":"        response_headers \u003d HeaderKeyDict(self._response_headers)"},{"line_number":518,"context_line":"        # carry forward any etag update params (e.g. \"slo_etag\"), we\u0027ll append"},{"line_number":519,"context_line":"        # symlink_target_* params to this header after this method returns"},{"line_number":520,"context_line":"        override_header \u003d \u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027"},{"line_number":521,"context_line":"        if override_header in response_headers and \\"},{"line_number":522,"context_line":"                override_header not in req.headers:"},{"line_number":523,"context_line":"            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]"}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_b38166fe","line":520,"in_reply_to":"7faddb67_ae9d89bc","updated":"2019-08-08 16:49:23.000000000","message":"oh it definitely would\n#willfix\n\nOh except that symbol is defined all over the place... I\u0027ll look into doing a prefactor.","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":42,"context_line":"``X-Symlink-Target-Etag`` header when created to verify it still matches the"},{"line_number":43,"context_line":"ETag of the object they\u0027re pointing at on a GET.  In contrast to a dynamic"},{"line_number":44,"context_line":"symlink the target object referenced in the ``X-Symlink-Target`` header must"},{"line_number":45,"context_line":"exist and it\u0027s ETag must match the ``X-Symlink-Target-Etag`` or the symlink"},{"line_number":46,"context_line":"creation will return a client error."},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_24d51144","line":45,"range":{"start_line":45,"start_character":10,"end_line":45,"end_character":14},"updated":"2019-08-10 00:05:32.000000000","message":"its","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":42,"context_line":"``X-Symlink-Target-Etag`` header when created to verify it still matches the"},{"line_number":43,"context_line":"ETag of the object they\u0027re pointing at on a GET.  In contrast to a dynamic"},{"line_number":44,"context_line":"symlink the target object referenced in the ``X-Symlink-Target`` header must"},{"line_number":45,"context_line":"exist and it\u0027s ETag must match the ``X-Symlink-Target-Etag`` or the symlink"},{"line_number":46,"context_line":"creation will return a client error."},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_966186d6","line":45,"range":{"start_line":45,"start_character":10,"end_line":45,"end_character":14},"in_reply_to":"7faddb67_24d51144","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5f78fc880e2de0aa4b7394193756987c5cfd1d77","unresolved":false,"context_lines":[{"line_number":59,"context_line":"`proxy-server.conf`. If not specified, the default ``symloop_max`` value is 2."},{"line_number":60,"context_line":"If a value less than 1 is specified, the default value will be used."},{"line_number":61,"context_line":""},{"line_number":62,"context_line":"If a static symlink (i.e. a symlink created with a ``X-Symlink-Target-Etag``"},{"line_number":63,"context_line":"header) targets another static symlink, both of the ``X-Symlink-Target-Etag``"},{"line_number":64,"context_line":"headers must both match the target object for the GET to succeed.  If a static"},{"line_number":65,"context_line":"symlink targets a dynamic symlink (i.e. a symlink created without a"},{"line_number":66,"context_line":"``X-Symlink-Target-Etag`` header) then the ``X-Symlink-Target-Etag`` header of"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_ab153b3f","line":63,"range":{"start_line":62,"start_character":21,"end_line":63,"end_character":6},"updated":"2019-08-12 16:50:49.000000000","message":"Nice changes to doc! The distinction between static and dynamic links really helps. I\u0027d might even consider removing some of the \"i.e.,\" to reduce verbosity and just leave it at \"dynamic link\" or \"static link\" since it was well defined early on.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":59,"context_line":"`proxy-server.conf`. If not specified, the default ``symloop_max`` value is 2."},{"line_number":60,"context_line":"If a value less than 1 is specified, the default value will be used."},{"line_number":61,"context_line":""},{"line_number":62,"context_line":"If a static symlink (i.e. a symlink created with a ``X-Symlink-Target-Etag``"},{"line_number":63,"context_line":"header) targets another static symlink, both of the ``X-Symlink-Target-Etag``"},{"line_number":64,"context_line":"headers must both match the target object for the GET to succeed.  If a static"},{"line_number":65,"context_line":"symlink targets a dynamic symlink (i.e. a symlink created without a"},{"line_number":66,"context_line":"``X-Symlink-Target-Etag`` header) then the ``X-Symlink-Target-Etag`` header of"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_968f4674","line":63,"range":{"start_line":62,"start_character":21,"end_line":63,"end_character":6},"in_reply_to":"7faddb67_ab153b3f","updated":"2019-08-12 18:30:15.000000000","message":"I think this is the first time we make reference back to a \"static symlink\" - I think I\u0027d like to leave it","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":60,"context_line":"If a value less than 1 is specified, the default value will be used."},{"line_number":61,"context_line":""},{"line_number":62,"context_line":"If a static symlink (i.e. a symlink created with a ``X-Symlink-Target-Etag``"},{"line_number":63,"context_line":"header) targets another static symlink, both of the ``X-Symlink-Target-Etag``"},{"line_number":64,"context_line":"headers must both match the target object for the GET to succeed.  If a static"},{"line_number":65,"context_line":"symlink targets a dynamic symlink (i.e. a symlink created without a"},{"line_number":66,"context_line":"``X-Symlink-Target-Etag`` header) then the ``X-Symlink-Target-Etag`` header of"},{"line_number":67,"context_line":"the static symlink must be the Etag of the zero-byte object.  If a symlink with"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_c4575dca","line":64,"range":{"start_line":63,"start_character":40,"end_line":64,"end_character":23},"updated":"2019-08-10 00:05:32.000000000","message":"nit:\n\n\u003e both ... must both match\n\nThe double-both reads a little funny to me.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":60,"context_line":"If a value less than 1 is specified, the default value will be used."},{"line_number":61,"context_line":""},{"line_number":62,"context_line":"If a static symlink (i.e. a symlink created with a ``X-Symlink-Target-Etag``"},{"line_number":63,"context_line":"header) targets another static symlink, both of the ``X-Symlink-Target-Etag``"},{"line_number":64,"context_line":"headers must both match the target object for the GET to succeed.  If a static"},{"line_number":65,"context_line":"symlink targets a dynamic symlink (i.e. a symlink created without a"},{"line_number":66,"context_line":"``X-Symlink-Target-Etag`` header) then the ``X-Symlink-Target-Etag`` header of"},{"line_number":67,"context_line":"the static symlink must be the Etag of the zero-byte object.  If a symlink with"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_96bd0604","line":64,"range":{"start_line":63,"start_character":40,"end_line":64,"end_character":23},"in_reply_to":"7faddb67_c4575dca","updated":"2019-08-12 18:30:15.000000000","message":"reads fine to me, but I\u0027ll remove the second both","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":63,"context_line":"header) targets another static symlink, both of the ``X-Symlink-Target-Etag``"},{"line_number":64,"context_line":"headers must both match the target object for the GET to succeed.  If a static"},{"line_number":65,"context_line":"symlink targets a dynamic symlink (i.e. a symlink created without a"},{"line_number":66,"context_line":"``X-Symlink-Target-Etag`` header) then the ``X-Symlink-Target-Etag`` header of"},{"line_number":67,"context_line":"the static symlink must be the Etag of the zero-byte object.  If a symlink with"},{"line_number":68,"context_line":"a ``X-Symlink-Target-Etag`` targets a large object manifest it must match the"},{"line_number":69,"context_line":"ETag of the manifest (e.g. the ETag as returned by ``multipart-manifest\u003dget``"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_83d06355","line":66,"updated":"2019-08-12 18:30:15.000000000","message":"this is the first time we back reference a dynamic link...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":67,"context_line":"the static symlink must be the Etag of the zero-byte object.  If a symlink with"},{"line_number":68,"context_line":"a ``X-Symlink-Target-Etag`` targets a large object manifest it must match the"},{"line_number":69,"context_line":"ETag of the manifest (e.g. the ETag as returned by ``multipart-manifest\u003dget``"},{"line_number":70,"context_line":"or value in the ``X-Manifest-Etag`` header)."},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"A HEAD/GET request to a symlink object behaves as a normal HEAD/GET request"},{"line_number":73,"context_line":"to the target object. Therefore issuing a HEAD request to the symlink will"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_e45cd9ee","line":70,"range":{"start_line":70,"start_character":3,"end_line":70,"end_character":42},"updated":"2019-08-10 00:05:32.000000000","message":"Hm. I should probably add that for DLO, too...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":76,"context_line":"metadata (with its empty body) a GET/HEAD request with the ``?symlink\u003dget``"},{"line_number":77,"context_line":"query parameter must be sent to a symlink object."},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"A POST request to a symlink will result in a 307 TemporaryRedirect response."},{"line_number":80,"context_line":"The response will contain a ``Location`` header with the path of the target"},{"line_number":81,"context_line":"object as the value. The request is never redirected to the target object by"},{"line_number":82,"context_line":"Swift. Nevertheless, the metadata in the POST request will be applied to the"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_a46ee193","line":79,"range":{"start_line":79,"start_character":49,"end_line":79,"end_character":66},"updated":"2019-08-10 00:05:32.000000000","message":"Off-topic: this needs a space.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":76,"context_line":"metadata (with its empty body) a GET/HEAD request with the ``?symlink\u003dget``"},{"line_number":77,"context_line":"query parameter must be sent to a symlink object."},{"line_number":78,"context_line":""},{"line_number":79,"context_line":"A POST request to a symlink will result in a 307 TemporaryRedirect response."},{"line_number":80,"context_line":"The response will contain a ``Location`` header with the path of the target"},{"line_number":81,"context_line":"object as the value. The request is never redirected to the target object by"},{"line_number":82,"context_line":"Swift. Nevertheless, the metadata in the POST request will be applied to the"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_56354ea7","line":79,"range":{"start_line":79,"start_character":49,"end_line":79,"end_character":66},"in_reply_to":"7faddb67_a46ee193","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":83,"context_line":"symlink because object servers cannot know for sure if the current object is a"},{"line_number":84,"context_line":"symlink or not in eventual consistency."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"A symlink\u0027s ``Content-Type`` is completely independent from it\u0027s target.  As a"},{"line_number":87,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":88,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":89,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_6468e986","line":86,"range":{"start_line":86,"start_character":60,"end_line":86,"end_character":64},"updated":"2019-08-10 00:05:32.000000000","message":"its","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":83,"context_line":"symlink because object servers cannot know for sure if the current object is a"},{"line_number":84,"context_line":"symlink or not in eventual consistency."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"A symlink\u0027s ``Content-Type`` is completely independent from it\u0027s target.  As a"},{"line_number":87,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":88,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":89,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_163fd687","line":86,"range":{"start_line":86,"start_character":60,"end_line":86,"end_character":64},"in_reply_to":"7faddb67_6468e986","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":84,"context_line":"symlink or not in eventual consistency."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"A symlink\u0027s ``Content-Type`` is completely independent from it\u0027s target.  As a"},{"line_number":87,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":88,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":89,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"},{"line_number":90,"context_line":"the target, otherwise it will be set to ``application/symlink``.  You can"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_c40c3dee","line":87,"range":{"start_line":87,"start_character":12,"end_line":87,"end_character":14},"updated":"2019-08-10 00:05:32.000000000","message":"This (and the \"we\" on L89) is a change in tone from the rest of our docs, I think. \"Swift\" would be more consistent.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":84,"context_line":"symlink or not in eventual consistency."},{"line_number":85,"context_line":""},{"line_number":86,"context_line":"A symlink\u0027s ``Content-Type`` is completely independent from it\u0027s target.  As a"},{"line_number":87,"context_line":"convenience we will automatically set the ``Content-Type`` on a symlink PUT if"},{"line_number":88,"context_line":"not explicitly set by the client.  If the client sends a"},{"line_number":89,"context_line":"``X-Symlink-Target-Etag`` we will set the symlink\u0027s ``Content-Type`` to that of"},{"line_number":90,"context_line":"the target, otherwise it will be set to ``application/symlink``.  You can"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_9652e6dd","line":87,"range":{"start_line":87,"start_character":12,"end_line":87,"end_character":14},"in_reply_to":"7faddb67_c40c3dee","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":100,"context_line":"parameter ``?symlink\u003dget`` will copy the symlink itself."},{"line_number":101,"context_line":""},{"line_number":102,"context_line":"An OPTIONS request to a symlink will respond with the options for the symlink"},{"line_number":103,"context_line":"only, the request will not be redirected to the target object. Please note that"},{"line_number":104,"context_line":"if the symlink\u0027s target object is in another container with CORS settings, the"},{"line_number":105,"context_line":"response will not reflect the settings."},{"line_number":106,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_84f645d8","line":103,"range":{"start_line":103,"start_character":4,"end_line":103,"end_character":5},"updated":"2019-08-10 00:05:32.000000000","message":"Off-topic: should be a semicolon.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":100,"context_line":"parameter ``?symlink\u003dget`` will copy the symlink itself."},{"line_number":101,"context_line":""},{"line_number":102,"context_line":"An OPTIONS request to a symlink will respond with the options for the symlink"},{"line_number":103,"context_line":"only, the request will not be redirected to the target object. Please note that"},{"line_number":104,"context_line":"if the symlink\u0027s target object is in another container with CORS settings, the"},{"line_number":105,"context_line":"response will not reflect the settings."},{"line_number":106,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_b64da23c","line":103,"range":{"start_line":103,"start_character":4,"end_line":103,"end_character":5},"in_reply_to":"7faddb67_84f645d8","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":115,"context_line":"If a symlink object is overwritten while it is in a versioned container, the"},{"line_number":116,"context_line":"symlink object itself is versioned, not the referenced object."},{"line_number":117,"context_line":""},{"line_number":118,"context_line":"A GET request with query parameter ``?format\u003djson`` to a container which"},{"line_number":119,"context_line":"contains symlinks will respond with additional information ``symlink_path``"},{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_6416a9f4","line":118,"range":{"start_line":118,"start_character":14,"end_line":118,"end_character":51},"updated":"2019-08-10 00:05:32.000000000","message":"Off-topic: or with ``Accept: application/json`` header; w/e, a JSON listing","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":115,"context_line":"If a symlink object is overwritten while it is in a versioned container, the"},{"line_number":116,"context_line":"symlink object itself is versioned, not the referenced object."},{"line_number":117,"context_line":""},{"line_number":118,"context_line":"A GET request with query parameter ``?format\u003djson`` to a container which"},{"line_number":119,"context_line":"contains symlinks will respond with additional information ``symlink_path``"},{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_165836f8","line":118,"range":{"start_line":118,"start_character":14,"end_line":118,"end_character":51},"in_reply_to":"7faddb67_6416a9f4","updated":"2019-08-12 18:30:15.000000000","message":"I\u0027m not sure how to link to other docs - diff?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":118,"context_line":"A GET request with query parameter ``?format\u003djson`` to a container which"},{"line_number":119,"context_line":"contains symlinks will respond with additional information ``symlink_path``"},{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"},{"line_number":122,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":123,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":124,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_44ee0dee","line":121,"range":{"start_line":121,"start_character":7,"end_line":121,"end_character":18},"updated":"2019-08-10 00:05:32.000000000","message":"Off-topic: we should probably mention that it\u0027s quoted...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":118,"context_line":"A GET request with query parameter ``?format\u003djson`` to a container which"},{"line_number":119,"context_line":"contains symlinks will respond with additional information ``symlink_path``"},{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"},{"line_number":122,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":123,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":124,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_d6713e79","line":121,"range":{"start_line":121,"start_character":7,"end_line":121,"end_character":18},"in_reply_to":"7faddb67_44ee0dee","updated":"2019-08-12 18:30:15.000000000","message":"yes, that would be great - diff?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":119,"context_line":"contains symlinks will respond with additional information ``symlink_path``"},{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"},{"line_number":122,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":123,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":124,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":125,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_64eb09dc","line":122,"range":{"start_line":122,"start_character":52,"end_line":122,"end_character":54},"updated":"2019-08-10 00:05:32.000000000","message":"Off-topic: better as \"in\"","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":119,"context_line":"contains symlinks will respond with additional information ``symlink_path``"},{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"},{"line_number":122,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":123,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":124,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":125,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_565eaee9","line":122,"range":{"start_line":122,"start_character":52,"end_line":122,"end_character":54},"in_reply_to":"7faddb67_64eb09dc","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"},{"line_number":122,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":123,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":124,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":125,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"},{"line_number":126,"context_line":"object\u0027s ``Content-Length`` will be included in the key ``symlink_bytes``."}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_e4dff937","line":123,"range":{"start_line":123,"start_character":5,"end_line":123,"end_character":20},"updated":"2019-08-10 00:05:32.000000000","message":"Off-topic: This doesn\u0027t render right :-(\n\nMaybe just needs a space between e.g. and ``?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":120,"context_line":"for each symlink object in the container listing. The ``symlink_path`` value"},{"line_number":121,"context_line":"is the target path of the symlink. Clients can differentiate symlinks and"},{"line_number":122,"context_line":"other objects by this function. Note that responses of any other format"},{"line_number":123,"context_line":"(e.g.``?format\u003dxml``) won\u0027t include ``symlink_path`` info.  If a"},{"line_number":124,"context_line":"``X-Symlink-Target-Etag`` header was included on the symlink, JSON container"},{"line_number":125,"context_line":"listings will include that value in a ``symlink_etag`` key and the target"},{"line_number":126,"context_line":"object\u0027s ``Content-Length`` will be included in the key ``symlink_bytes``."}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_56030ebf","line":123,"range":{"start_line":123,"start_character":5,"end_line":123,"end_character":20},"in_reply_to":"7faddb67_e4dff937","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":129,"context_line":"forward the SLO\u0027s size and slo_etag in the container listing using the"},{"line_number":130,"context_line":"``symlink_bytes`` and ``slo_etag`` keys.  However, manifests created before"},{"line_number":131,"context_line":"swift v2.12.0 (released Dec 2016) do not contain enough metadata to propagate"},{"line_number":132,"context_line":"the extra SLO information to the listing.  Clients may recreate the manifest"},{"line_number":133,"context_line":"(COPY w/ ?multipart-manfiest\u003dget) before creating a static symlink."},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"Errors"},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_04ba55e0","line":133,"range":{"start_line":132,"start_character":43,"end_line":133,"end_character":66},"updated":"2019-08-10 00:05:32.000000000","message":"... to add the requisite metadata.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":129,"context_line":"forward the SLO\u0027s size and slo_etag in the container listing using the"},{"line_number":130,"context_line":"``symlink_bytes`` and ``slo_etag`` keys.  However, manifests created before"},{"line_number":131,"context_line":"swift v2.12.0 (released Dec 2016) do not contain enough metadata to propagate"},{"line_number":132,"context_line":"the extra SLO information to the listing.  Clients may recreate the manifest"},{"line_number":133,"context_line":"(COPY w/ ?multipart-manfiest\u003dget) before creating a static symlink."},{"line_number":134,"context_line":""},{"line_number":135,"context_line":"Errors"},{"line_number":136,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_56ba2ee1","line":133,"range":{"start_line":132,"start_character":43,"end_line":133,"end_character":66},"in_reply_to":"7faddb67_04ba55e0","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":143,"context_line":"* GET/HEAD traversing more than ``symloop_max`` chained symlinks will"},{"line_number":144,"context_line":"  produce a 409 Conflict error."},{"line_number":145,"context_line":""},{"line_number":146,"context_line":"* PUT/GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header"},{"line_number":147,"context_line":"  that does not match the target will poduce a 409 Conflict error."},{"line_number":148,"context_line":""},{"line_number":149,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."},{"line_number":150,"context_line":""},{"line_number":151,"context_line":"----------"},{"line_number":152,"context_line":"Deployment"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_a4ca616b","line":149,"range":{"start_line":146,"start_character":0,"end_line":149,"end_character":51},"updated":"2019-08-10 00:05:32.000000000","message":"Well here\u0027s an interesting question... how should we and/or clients handle POSTing to busted static links? As things stand, I don\u0027t think clients get any indication that the things busted... swift just sends back the 307 -- I\u0027m not even sure that they get a hint that the thing\u0027s a static link!","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":143,"context_line":"* GET/HEAD traversing more than ``symloop_max`` chained symlinks will"},{"line_number":144,"context_line":"  produce a 409 Conflict error."},{"line_number":145,"context_line":""},{"line_number":146,"context_line":"* PUT/GET/HEAD on a symlink that inclues a ``X-Symlink-Target-Etag`` header"},{"line_number":147,"context_line":"  that does not match the target will poduce a 409 Conflict error."},{"line_number":148,"context_line":""},{"line_number":149,"context_line":"* POSTs will produce a 307 TemporaryRedirect error."},{"line_number":150,"context_line":""},{"line_number":151,"context_line":"----------"},{"line_number":152,"context_line":"Deployment"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_96d8a61e","line":149,"range":{"start_line":146,"start_character":0,"end_line":149,"end_character":51},"in_reply_to":"7faddb67_a4ca616b","updated":"2019-08-12 18:30:15.000000000","message":"Good thinking, I\u0027ll try to at least make sure we have func tests for both static \u0026 dynamic POST for good \u0026 broken","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":236,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":237,"context_line":""},{"line_number":238,"context_line":"    :param req: HTTP request object"},{"line_number":239,"context_line":"    :returns: a tuple, the full versioned path to the object and the value of"},{"line_number":240,"context_line":"              the X-Symlink-Target-Etag header which may be None"},{"line_number":241,"context_line":"    :raise: HTTPPreconditionFailed if x-symlink-target value"},{"line_number":242,"context_line":"            is not well formatted."}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_d58071c2","line":239,"range":{"start_line":239,"start_character":23,"end_line":239,"end_character":60},"updated":"2019-08-09 22:13:02.000000000","message":"WSGI, native, or some other string? Looks like... WSGI?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":236,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":237,"context_line":""},{"line_number":238,"context_line":"    :param req: HTTP request object"},{"line_number":239,"context_line":"    :returns: a tuple, the full versioned path to the object and the value of"},{"line_number":240,"context_line":"              the X-Symlink-Target-Etag header which may be None"},{"line_number":241,"context_line":"    :raise: HTTPPreconditionFailed if x-symlink-target value"},{"line_number":242,"context_line":"            is not well formatted."}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_16335664","line":239,"range":{"start_line":239,"start_character":23,"end_line":239,"end_character":60},"in_reply_to":"7faddb67_d58071c2","updated":"2019-08-12 18:30:15.000000000","message":"#willfix (docstring)","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5f78fc880e2de0aa4b7394193756987c5cfd1d77","unresolved":false,"context_lines":[{"line_number":288,"context_line":"        raise HTTPBadRequest("},{"line_number":289,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"},{"line_number":290,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":291,"context_line":"    if not (etag or req.headers.get(\u0027Content-Type\u0027)):"},{"line_number":292,"context_line":"        req.headers[\u0027Content-Type\u0027] \u003d \u0027application/symlink\u0027"},{"line_number":293,"context_line":"    return \u0027/v1/%s/%s/%s\u0027 % (account, container, obj), etag"},{"line_number":294,"context_line":""},{"line_number":295,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_6b9663f2","line":292,"range":{"start_line":291,"start_character":4,"end_line":292,"end_character":59},"updated":"2019-08-12 16:50:49.000000000","message":"just nit picking here, but I\u0027d move this to handle_put. I\u0027m bothered that we make this change in a check method.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":288,"context_line":"        raise HTTPBadRequest("},{"line_number":289,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"},{"line_number":290,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":291,"context_line":"    if not (etag or req.headers.get(\u0027Content-Type\u0027)):"},{"line_number":292,"context_line":"        req.headers[\u0027Content-Type\u0027] \u003d \u0027application/symlink\u0027"},{"line_number":293,"context_line":"    return \u0027/v1/%s/%s/%s\u0027 % (account, container, obj), etag"},{"line_number":294,"context_line":""},{"line_number":295,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_a6c43761","line":292,"range":{"start_line":291,"start_character":4,"end_line":292,"end_character":59},"in_reply_to":"7faddb67_56c54e09","updated":"2019-08-16 22:21:47.000000000","message":"We haven\u0027t addressed this yet, yeah?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":288,"context_line":"        raise HTTPBadRequest("},{"line_number":289,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"},{"line_number":290,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":291,"context_line":"    if not (etag or req.headers.get(\u0027Content-Type\u0027)):"},{"line_number":292,"context_line":"        req.headers[\u0027Content-Type\u0027] \u003d \u0027application/symlink\u0027"},{"line_number":293,"context_line":"    return \u0027/v1/%s/%s/%s\u0027 % (account, container, obj), etag"},{"line_number":294,"context_line":""},{"line_number":295,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_56c54e09","line":292,"range":{"start_line":291,"start_character":4,"end_line":292,"end_character":59},"in_reply_to":"7faddb67_6b9663f2","updated":"2019-08-12 18:30:15.000000000","message":"no, that\u0027s reasonable - we should move the code or rename the method.  #willfix","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"2cd8b169fe90f3b8ec4b5bdf3d4727f20dd636d0","unresolved":false,"context_lines":[{"line_number":288,"context_line":"        raise HTTPBadRequest("},{"line_number":289,"context_line":"            body\u003d\u0027Bad %s format\u0027 % TGT_ETAG_SYMLINK_HDR,"},{"line_number":290,"context_line":"            request\u003dreq, content_type\u003d\u0027text/plain\u0027)"},{"line_number":291,"context_line":"    if not (etag or req.headers.get(\u0027Content-Type\u0027)):"},{"line_number":292,"context_line":"        req.headers[\u0027Content-Type\u0027] \u003d \u0027application/symlink\u0027"},{"line_number":293,"context_line":"    return \u0027/v1/%s/%s/%s\u0027 % (account, container, obj), etag"},{"line_number":294,"context_line":""},{"line_number":295,"context_line":""}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_3e8e012e","line":292,"range":{"start_line":291,"start_character":4,"end_line":292,"end_character":59},"in_reply_to":"7faddb67_a6c43761","updated":"2019-08-19 16:08:27.000000000","message":"Upon closer inspection the request mangling was already happening (see TGT_ACCT_SYMLINK_HDR) and doing the new content-type fixing inline looked out of place to me.  There\u0027s like three method interacting here seemed like a big ball of mud to untangle them with no obviously correct separation I could find.\n\nWe could rename the method fairly cheaply, but I couldn\u0027t come up with a good name for everything that\u0027s going on here besides maybe...\n\nhttps://review.opendev.org/#/c/677247/","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":296,"context_line":"def symlink_usermeta_to_sysmeta(headers):"},{"line_number":297,"context_line":"    \"\"\""},{"line_number":298,"context_line":"    Helper function to translate from client-facing X-Symlink-* headers"},{"line_number":299,"context_line":"    to cluster-facing X-Object-Sysmeta-Symlink-* headers."},{"line_number":300,"context_line":""},{"line_number":301,"context_line":"    :param headers: request headers dict. Note that the headers dict"},{"line_number":302,"context_line":"        will be updated directly."}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_559001ee","line":299,"updated":"2019-08-09 22:13:02.000000000","message":"Given the docstring update, it feels weird that we don\u0027t do anything with etag/bytes... meh, w/e","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":296,"context_line":"def symlink_usermeta_to_sysmeta(headers):"},{"line_number":297,"context_line":"    \"\"\""},{"line_number":298,"context_line":"    Helper function to translate from client-facing X-Symlink-* headers"},{"line_number":299,"context_line":"    to cluster-facing X-Object-Sysmeta-Symlink-* headers."},{"line_number":300,"context_line":""},{"line_number":301,"context_line":"    :param headers: request headers dict. Note that the headers dict"},{"line_number":302,"context_line":"        will be updated directly."}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_5174789c","line":299,"in_reply_to":"7faddb67_559001ee","updated":"2019-08-12 18:30:15.000000000","message":"For symmetry with sysmeta_to_usermeta it would be nice if the impl matched the docstring better - but I think that\u0027s not convenient w/o some refactor.\n\nSince, I find the loop code easier to maintain, I\u0027m not planning to revert.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":436,"context_line":"            errmsg \u003d \u0027Too many levels of symbolic links, \u0027 \\"},{"line_number":437,"context_line":"                     \u0027maximum allowed is %d\u0027 % self.symloop_max"},{"line_number":438,"context_line":"            raise HTTPConflict(body\u003derrmsg, request\u003dreq, headers\u003d{"},{"line_number":439,"context_line":"                \u0027Content-Type\u0027: \u0027text/plain\u0027})"},{"line_number":440,"context_line":""},{"line_number":441,"context_line":"    def _recursive_get_head(self, req, follow_softlinks\u003dTrue):"},{"line_number":442,"context_line":"        resp \u003d self._app_call(req.environ)"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_b51ff56e","line":439,"updated":"2019-08-09 22:13:02.000000000","message":"Does this actually do anything different? IDK which way I prefer... *shrug*","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":436,"context_line":"            errmsg \u003d \u0027Too many levels of symbolic links, \u0027 \\"},{"line_number":437,"context_line":"                     \u0027maximum allowed is %d\u0027 % self.symloop_max"},{"line_number":438,"context_line":"            raise HTTPConflict(body\u003derrmsg, request\u003dreq, headers\u003d{"},{"line_number":439,"context_line":"                \u0027Content-Type\u0027: \u0027text/plain\u0027})"},{"line_number":440,"context_line":""},{"line_number":441,"context_line":"    def _recursive_get_head(self, req, follow_softlinks\u003dTrue):"},{"line_number":442,"context_line":"        resp \u003d self._app_call(req.environ)"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_16b6f68b","line":439,"in_reply_to":"7faddb67_b51ff56e","updated":"2019-08-12 18:30:15.000000000","message":"no obvious difference in behavior to me, unittests don\u0027t seem to care, if functests are happy I\u0027ll revert","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":465,"context_line":"            TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":466,"context_line":"        if symlink_target and (target_etag or follow_softlinks):"},{"line_number":467,"context_line":"            close_if_possible(resp)"},{"line_number":468,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":469,"context_line":"            if self._target_etag and self._target_etag !\u003d expected_etag:"},{"line_number":470,"context_line":"                raise HTTPConflict("},{"line_number":471,"context_line":"                    body\u003d\u0027X-Symlink-Target-Etag headers do not match\u0027,"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_950bd929","line":468,"range":{"start_line":468,"start_character":12,"end_line":468,"end_character":25},"updated":"2019-08-09 22:13:02.000000000","message":"nit: I feel like self._target_etag is the \"expected\" one -- and this one is \"found\" or something...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":465,"context_line":"            TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":466,"context_line":"        if symlink_target and (target_etag or follow_softlinks):"},{"line_number":467,"context_line":"            close_if_possible(resp)"},{"line_number":468,"context_line":"            expected_etag \u003d target_etag or self._response_header_value(\u0027etag\u0027)"},{"line_number":469,"context_line":"            if self._target_etag and self._target_etag !\u003d expected_etag:"},{"line_number":470,"context_line":"                raise HTTPConflict("},{"line_number":471,"context_line":"                    body\u003d\u0027X-Symlink-Target-Etag headers do not match\u0027,"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_f1f1e4df","line":468,"range":{"start_line":468,"start_character":12,"end_line":468,"end_character":25},"in_reply_to":"7faddb67_950bd929","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":481,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":482,"context_line":"        else:"},{"line_number":483,"context_line":"            final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":484,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":485,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":486,"context_line":"                close_if_possible(resp)"},{"line_number":487,"context_line":"                body \u003d (\u0027Object Etag %r does not match \u0027"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_f82484b1","line":484,"range":{"start_line":484,"start_character":12,"end_line":484,"end_character":26},"updated":"2019-08-09 22:13:02.000000000","message":"Huh. Can we really *not have* a final_etag?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":481,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":482,"context_line":"        else:"},{"line_number":483,"context_line":"            final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":484,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":485,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":486,"context_line":"                close_if_possible(resp)"},{"line_number":487,"context_line":"                body \u003d (\u0027Object Etag %r does not match \u0027"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_46ab0387","line":484,"range":{"start_line":484,"start_character":12,"end_line":484,"end_character":26},"in_reply_to":"7faddb67_3129bc36","updated":"2019-08-16 22:21:47.000000000","message":"Oh yeah, failures, good call...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":481,"context_line":"            return self._recursive_get_head(new_req)"},{"line_number":482,"context_line":"        else:"},{"line_number":483,"context_line":"            final_etag \u003d self._response_header_value(\u0027etag\u0027)"},{"line_number":484,"context_line":"            if (final_etag and self._target_etag and"},{"line_number":485,"context_line":"                    self._target_etag !\u003d final_etag):"},{"line_number":486,"context_line":"                close_if_possible(resp)"},{"line_number":487,"context_line":"                body \u003d (\u0027Object Etag %r does not match \u0027"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_3129bc36","line":484,"range":{"start_line":484,"start_character":12,"end_line":484,"end_character":26},"in_reply_to":"7faddb67_f82484b1","updated":"2019-08-12 18:30:15.000000000","message":"so tests defiantly hit \"if not final_etag\"\n\nsome are \"200 OK\" (which I guess is bogus, but they\u0027re dynamic symlink tests?)\n\nIn one test it was 404, which is probably expected...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5f78fc880e2de0aa4b7394193756987c5cfd1d77","unresolved":false,"context_lines":[{"line_number":508,"context_line":"    def _validate_etag_and_update_sysmeta("},{"line_number":509,"context_line":"            self, req, symlink_target_path, etag):"},{"line_number":510,"context_line":"        # next we\u0027ll make sure the E-Tag matches a real object"},{"line_number":511,"context_line":"        self._target_etag \u003d etag"},{"line_number":512,"context_line":"        new_req \u003d make_subrequest("},{"line_number":513,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":514,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_eb6c939e","line":511,"range":{"start_line":511,"start_character":8,"end_line":511,"end_character":32},"updated":"2019-08-12 16:50:49.000000000","message":"I\u0027m not a big fan of this global variable, so I took a chance at a small clean-up: http://paste.openstack.org/show/756347/\nwdyt? I don\u0027t think it is urgent and could be done as a follow-on patch","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":508,"context_line":"    def _validate_etag_and_update_sysmeta("},{"line_number":509,"context_line":"            self, req, symlink_target_path, etag):"},{"line_number":510,"context_line":"        # next we\u0027ll make sure the E-Tag matches a real object"},{"line_number":511,"context_line":"        self._target_etag \u003d etag"},{"line_number":512,"context_line":"        new_req \u003d make_subrequest("},{"line_number":513,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":514,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_914d10c6","line":511,"range":{"start_line":511,"start_character":8,"end_line":511,"end_character":32},"in_reply_to":"7faddb67_eb6c939e","updated":"2019-08-12 18:30:15.000000000","message":"I think it\u0027s fine, tests pass.\n\nIt looks equally good to me, so I\u0027ll include it in the next rev.\n\nI\u0027m curious tho: why just this attribute?  I thought these \"Context\" things are per-request and are reasonable to stick some state onto?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":511,"context_line":"        self._target_etag \u003d etag"},{"line_number":512,"context_line":"        new_req \u003d make_subrequest("},{"line_number":513,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":514,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":515,"context_line":"        self._last_target_path \u003d symlink_target_path"},{"line_number":516,"context_line":"        resp \u003d self._recursive_get_head(new_req, follow_softlinks\u003dFalse)"},{"line_number":517,"context_line":"        if self._get_status_int() \u003d\u003d HTTP_NOT_FOUND:"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_b8a92cde","line":514,"range":{"start_line":514,"start_character":12,"end_line":514,"end_character":31},"updated":"2019-08-09 22:13:02.000000000","message":"This part surprises me a little... I need to think through why we want this and what implications it may have...\n\nMaybe it was to carry our auth token to the subreq? Or something? But I think it means you can get different behavior for PUTs with/without X-Newest, for example...\n\nProbably fine, though?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":511,"context_line":"        self._target_etag \u003d etag"},{"line_number":512,"context_line":"        new_req \u003d make_subrequest("},{"line_number":513,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":514,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":515,"context_line":"        self._last_target_path \u003d symlink_target_path"},{"line_number":516,"context_line":"        resp \u003d self._recursive_get_head(new_req, follow_softlinks\u003dFalse)"},{"line_number":517,"context_line":"        if self._get_status_int() \u003d\u003d HTTP_NOT_FOUND:"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_067aeb22","line":514,"range":{"start_line":514,"start_character":12,"end_line":514,"end_character":31},"in_reply_to":"7faddb67_91fbd045","updated":"2019-08-16 22:21:47.000000000","message":"Yeah, it was the headers... I\u0027m not entirely sure how it results in a bug, it just seems off. Thanks for taking them out.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":511,"context_line":"        self._target_etag \u003d etag"},{"line_number":512,"context_line":"        new_req \u003d make_subrequest("},{"line_number":513,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"},{"line_number":514,"context_line":"            headers\u003dreq.headers, swift_source\u003d\u0027SYM\u0027)"},{"line_number":515,"context_line":"        self._last_target_path \u003d symlink_target_path"},{"line_number":516,"context_line":"        resp \u003d self._recursive_get_head(new_req, follow_softlinks\u003dFalse)"},{"line_number":517,"context_line":"        if self._get_status_int() \u003d\u003d HTTP_NOT_FOUND:"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_91fbd045","line":514,"range":{"start_line":514,"start_character":12,"end_line":514,"end_character":31},"in_reply_to":"7faddb67_b8a92cde","updated":"2019-08-12 18:30:15.000000000","message":"I\u0027m sorry, what surprises you?  the make_subrequest?  the *headers*???\n\nunittests \u0026 functests pass w/o forwarding headers - so if it *is* a an auth-token thing it\u0027s either unnecessary or untested\n\nIf your spider sense is tingling there\u0027s probably a bug here waiting to be found.  Any ideas where to look?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":525,"context_line":"        response_headers \u003d HeaderKeyDict(self._response_headers)"},{"line_number":526,"context_line":"        # carry forward any etag update params (e.g. \"slo_etag\"), we\u0027ll append"},{"line_number":527,"context_line":"        # symlink_target_* params to this header after this method returns"},{"line_number":528,"context_line":"        override_header \u003d \u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027"},{"line_number":529,"context_line":"        if override_header in response_headers and \\"},{"line_number":530,"context_line":"                override_header not in req.headers:"},{"line_number":531,"context_line":"            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_09883020","line":528,"updated":"2019-08-09 22:13:02.000000000","message":"Worth using our new\n\n get_container_update_override_key(\u0027etag\u0027)\n\n?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":525,"context_line":"        response_headers \u003d HeaderKeyDict(self._response_headers)"},{"line_number":526,"context_line":"        # carry forward any etag update params (e.g. \"slo_etag\"), we\u0027ll append"},{"line_number":527,"context_line":"        # symlink_target_* params to this header after this method returns"},{"line_number":528,"context_line":"        override_header \u003d \u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027"},{"line_number":529,"context_line":"        if override_header in response_headers and \\"},{"line_number":530,"context_line":"                override_header not in req.headers:"},{"line_number":531,"context_line":"            sep, params \u003d response_headers[override_header].partition(\u0027;\u0027)[1:]"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_9190b0ef","line":528,"in_reply_to":"7faddb67_09883020","updated":"2019-08-12 18:30:15.000000000","message":"well *yeah* duh that was the whole point :faceplam:\n\n#willfix","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":533,"context_line":""},{"line_number":534,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":535,"context_line":"        if \u0027X-Object-Sysmeta-Slo-Etag\u0027 in response_headers and \\"},{"line_number":536,"context_line":"                override_header not in req.headers:"},{"line_number":537,"context_line":"            req.headers[override_header] \u003d \u0027%s; slo_etag\u003d%s\u0027 % ("},{"line_number":538,"context_line":"                MD5_OF_EMPTY_STRING,"},{"line_number":539,"context_line":"                response_headers[\u0027X-Object-Sysmeta-Slo-Etag\u0027])"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_6972044c","line":536,"range":{"start_line":536,"start_character":16,"end_line":536,"end_character":51},"updated":"2019-08-09 22:13:02.000000000","message":":barf:\n\nGood catch though! May as well help out with old data when we can.\n\nAnd the s3_etag came in https://github.com/openstack/swift/commit/84b85f03b46278325e8f4fdd04d915960697cbb9, so *after* slo_etag.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":533,"context_line":""},{"line_number":534,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":535,"context_line":"        if \u0027X-Object-Sysmeta-Slo-Etag\u0027 in response_headers and \\"},{"line_number":536,"context_line":"                override_header not in req.headers:"},{"line_number":537,"context_line":"            req.headers[override_header] \u003d \u0027%s; slo_etag\u003d%s\u0027 % ("},{"line_number":538,"context_line":"                MD5_OF_EMPTY_STRING,"},{"line_number":539,"context_line":"                response_headers[\u0027X-Object-Sysmeta-Slo-Etag\u0027])"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_71641422","line":536,"range":{"start_line":536,"start_character":16,"end_line":536,"end_character":51},"in_reply_to":"7faddb67_6972044c","updated":"2019-08-12 18:30:15.000000000","message":"I don\u0027t understand.  this code is good or bad?  Should it change?  In what way?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":533,"context_line":""},{"line_number":534,"context_line":"        # It\u0027s troublesome that there\u0027s so much leakage with SLO"},{"line_number":535,"context_line":"        if \u0027X-Object-Sysmeta-Slo-Etag\u0027 in response_headers and \\"},{"line_number":536,"context_line":"                override_header not in req.headers:"},{"line_number":537,"context_line":"            req.headers[override_header] \u003d \u0027%s; slo_etag\u003d%s\u0027 % ("},{"line_number":538,"context_line":"                MD5_OF_EMPTY_STRING,"},{"line_number":539,"context_line":"                response_headers[\u0027X-Object-Sysmeta-Slo-Etag\u0027])"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_2694c735","line":536,"range":{"start_line":536,"start_character":16,"end_line":536,"end_character":51},"in_reply_to":"7faddb67_71641422","updated":"2019-08-16 22:21:47.000000000","message":"Good code, definitely. Sorry, that was just my gut reaction to legacy data formats ;-)","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":570,"context_line":"                req, symlink_target_path, etag)"},{"line_number":571,"context_line":"            if resp is not None:"},{"line_number":572,"context_line":"                return resp"},{"line_number":573,"context_line":"        # N.B. TGT_ETAG_SYMLINK_HDR was converted as part of verifying it"},{"line_number":574,"context_line":"        symlink_usermeta_to_sysmeta(req.headers)"},{"line_number":575,"context_line":"        # Store info in container update that this object is a symlink."},{"line_number":576,"context_line":"        # We have a design decision to use etag space to store symlink info for"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_c9da184a","line":573,"updated":"2019-08-09 22:13:02.000000000","message":"So we pop() it in _check_symlink_header(), and shift it to sysmeta in _validate_etag_and_update_sysmeta()...\n\nI wonder if it\u0027d be better/more obvious to just leave it in place until here and do the transform in symlink_usermeta_to_sysmeta() :-/","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":570,"context_line":"                req, symlink_target_path, etag)"},{"line_number":571,"context_line":"            if resp is not None:"},{"line_number":572,"context_line":"                return resp"},{"line_number":573,"context_line":"        # N.B. TGT_ETAG_SYMLINK_HDR was converted as part of verifying it"},{"line_number":574,"context_line":"        symlink_usermeta_to_sysmeta(req.headers)"},{"line_number":575,"context_line":"        # Store info in container update that this object is a symlink."},{"line_number":576,"context_line":"        # We have a design decision to use etag space to store symlink info for"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_f106c421","line":573,"in_reply_to":"7faddb67_c9da184a","updated":"2019-08-12 18:30:15.000000000","message":"Pretty sure I inherited some of these methods\n\nSo I think it would be ideal if _check could avoid modifying the request.  I know it *is* digging the etag out to check quoting.  #willfix\n\nI like keeping the usermeta-\u003esysmeta translation in the same method as the verification - the goal is to make it very difficult to accidentally move unverified data into sysmeta where there\u0027s a risk it could be stored.\n\nI struggled wit how to get the client error responses that can come out of _validate - We\u0027d have more flexibility if we could do a \"raise_error_from_response\"","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":584,"context_line":"        # override etag may be encrypted in the container db by encryption"},{"line_number":585,"context_line":"        # middleware."},{"line_number":586,"context_line":"        etag_override \u003d ["},{"line_number":587,"context_line":"            req.headers.get(\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027,"},{"line_number":588,"context_line":"                            MD5_OF_EMPTY_STRING),"},{"line_number":589,"context_line":"            \u0027symlink_target\u003d%s\u0027 % req.headers[TGT_OBJ_SYSMETA_SYMLINK_HDR]"},{"line_number":590,"context_line":"        ]"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_6999a477","line":587,"updated":"2019-08-09 22:13:02.000000000","message":"Worth using our new\n\n get_container_update_override_key(\u0027etag\u0027)\n\n?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":584,"context_line":"        # override etag may be encrypted in the container db by encryption"},{"line_number":585,"context_line":"        # middleware."},{"line_number":586,"context_line":"        etag_override \u003d ["},{"line_number":587,"context_line":"            req.headers.get(\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027,"},{"line_number":588,"context_line":"                            MD5_OF_EMPTY_STRING),"},{"line_number":589,"context_line":"            \u0027symlink_target\u003d%s\u0027 % req.headers[TGT_OBJ_SYSMETA_SYMLINK_HDR]"},{"line_number":590,"context_line":"        ]"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_43a34b01","line":587,"in_reply_to":"7faddb67_6999a477","updated":"2019-08-12 18:30:15.000000000","message":"Done","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"cc904ad109c22663f531e981f4b583060a418190","unresolved":false,"context_lines":[{"line_number":596,"context_line":"            # if _validate_etag_and_update_sysmeta or a middleware sets"},{"line_number":597,"context_line":"            # TGT_ETAG_SYSMETA_SYMLINK_HDR then they need to also set"},{"line_number":598,"context_line":"            # TGT_BYTES_SYSMETA_SYMLINK_HDR.  If they forget, they get a"},{"line_number":599,"context_line":"            # KeyError traceback and client gets a ServerError"},{"line_number":600,"context_line":"            etag_override.extend(["},{"line_number":601,"context_line":"                \u0027symlink_target_etag\u003d%s\u0027 %"},{"line_number":602,"context_line":"                req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR],"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_e9ad949b","line":599,"updated":"2019-08-09 22:13:02.000000000","message":"This feels weird, almost a little dev-hostile. Why not do something like\n\n for header, param in [\n     (TGT_ACCT_SYSMETA_SYMLINK_HDR, \u0027symlink_target_account\u0027),\n     (TGT_ETAG_SYSMETA_SYMLINK_HDR, \u0027symlink_target_etag\u0027),\n     (TGT_BYTES_SYSMETA_SYMLINK_HDR, \u0027symlink_target_bytes\u0027),\n ]:\n     if header in req.headers:\n         etag_override.append(\u0027%s\u003d%s\u0027 % (param, req.headers[header]))\n\n?","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":596,"context_line":"            # if _validate_etag_and_update_sysmeta or a middleware sets"},{"line_number":597,"context_line":"            # TGT_ETAG_SYSMETA_SYMLINK_HDR then they need to also set"},{"line_number":598,"context_line":"            # TGT_BYTES_SYSMETA_SYMLINK_HDR.  If they forget, they get a"},{"line_number":599,"context_line":"            # KeyError traceback and client gets a ServerError"},{"line_number":600,"context_line":"            etag_override.extend(["},{"line_number":601,"context_line":"                \u0027symlink_target_etag\u003d%s\u0027 %"},{"line_number":602,"context_line":"                req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR],"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_86bc9bbb","line":599,"in_reply_to":"7faddb67_437cab71","updated":"2019-08-16 22:21:47.000000000","message":"I\u0027m still debating about whether it ought to be an error ;-)\n\nbytes-without-etag, probbaly. etag-without-bytes seems like it could still be a decent indicator that you\u0027re pointing to a dynamic symlink...\n\nMeh. The subtlety in that distinction probably isn\u0027t worth it -- and this is as good a way to blow up as any.","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":596,"context_line":"            # if _validate_etag_and_update_sysmeta or a middleware sets"},{"line_number":597,"context_line":"            # TGT_ETAG_SYSMETA_SYMLINK_HDR then they need to also set"},{"line_number":598,"context_line":"            # TGT_BYTES_SYSMETA_SYMLINK_HDR.  If they forget, they get a"},{"line_number":599,"context_line":"            # KeyError traceback and client gets a ServerError"},{"line_number":600,"context_line":"            etag_override.extend(["},{"line_number":601,"context_line":"                \u0027symlink_target_etag\u003d%s\u0027 %"},{"line_number":602,"context_line":"                req.headers[TGT_ETAG_SYSMETA_SYMLINK_HDR],"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_437cab71","line":599,"in_reply_to":"7faddb67_e9ad949b","updated":"2019-08-12 18:30:15.000000000","message":"Because that wouldn\u0027t blow up if you provide incomplete headers?\n\n\u003e Errors should never pass silently","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"0eb97d129749b357beb630016090af15f52ac95f","unresolved":false,"context_lines":[{"line_number":727,"context_line":"    symloop_max \u003d int(conf.get(\u0027symloop_max\u0027, DEFAULT_SYMLOOP_MAX))"},{"line_number":728,"context_line":"    if symloop_max \u003c 1:"},{"line_number":729,"context_line":"        symloop_max \u003d int(DEFAULT_SYMLOOP_MAX)"},{"line_number":730,"context_line":"    register_swift_info(\u0027symlink\u0027, symloop_max\u003dsymloop_max)"},{"line_number":731,"context_line":""},{"line_number":732,"context_line":"    def symlink_mw(app):"},{"line_number":733,"context_line":"        return SymlinkMiddleware(app, conf, symloop_max)"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_a4d7c14f","line":730,"updated":"2019-08-10 00:05:32.000000000","message":"I wonder if we should add a\n\n allow_static_links\u003dTrue\n\nhere, so clients don\u0027t have to know which Swift version introduced this...","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"27ba1b4a29b501a4957ea8b8ea570a4735b38ad9","unresolved":false,"context_lines":[{"line_number":727,"context_line":"    symloop_max \u003d int(conf.get(\u0027symloop_max\u0027, DEFAULT_SYMLOOP_MAX))"},{"line_number":728,"context_line":"    if symloop_max \u003c 1:"},{"line_number":729,"context_line":"        symloop_max \u003d int(DEFAULT_SYMLOOP_MAX)"},{"line_number":730,"context_line":"    register_swift_info(\u0027symlink\u0027, symloop_max\u003dsymloop_max)"},{"line_number":731,"context_line":""},{"line_number":732,"context_line":"    def symlink_mw(app):"},{"line_number":733,"context_line":"        return SymlinkMiddleware(app, conf, symloop_max)"}],"source_content_type":"text/x-python","patch_set":25,"id":"7faddb67_e38a7762","line":730,"in_reply_to":"7faddb67_a4d7c14f","updated":"2019-08-12 18:30:15.000000000","message":"I think better exposure is in the spirit of client discover-ability - is there a better way to communicate it than \"allow\" because I don\u0027t want to make it toggle-able. #willfix","commit_id":"3dc775e35fbe4ffd6b7c779086036e5a27fb498a"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"292758fa7f3372c627f414195ccbb7c0a4f2be02","unresolved":false,"context_lines":[{"line_number":43,"context_line":"ETag of the object they\u0027re pointing at on a GET.  In contrast to a dynamic"},{"line_number":44,"context_line":"symlink the target object referenced in the ``X-Symlink-Target`` header must"},{"line_number":45,"context_line":"exist and its ETag must match the ``X-Symlink-Target-Etag`` or the symlink"},{"line_number":46,"context_line":"creation will return a client error."},{"line_number":47,"context_line":""},{"line_number":48,"context_line":"A GET/HEAD request to a symlink will result in a request to the target"},{"line_number":49,"context_line":"object referenced by the symlink\u0027s ``X-Symlink-Target-Account`` and"}],"source_content_type":"text/x-python","patch_set":26,"id":"7faddb67_72888f21","line":46,"updated":"2019-08-14 07:24:05.000000000","message":"Yes, much better! Now it doesn\u0027t sound like a contradiction.","commit_id":"9cb1c064b1554f46e44bf3fb5816079714c2e20d"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"84ca26eb8a43fce8d7da95e38bcc1ed7354a2a6d","unresolved":false,"context_lines":[{"line_number":503,"context_line":"            return resp"},{"line_number":504,"context_line":""},{"line_number":505,"context_line":"    def _validate_etag_and_update_sysmeta("},{"line_number":506,"context_line":"            self, req, symlink_target_path, etag):"},{"line_number":507,"context_line":"        # next we\u0027ll make sure the E-Tag matches a real object"},{"line_number":508,"context_line":"        new_req \u003d make_subrequest("},{"line_number":509,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"}],"source_content_type":"text/x-python","patch_set":27,"id":"7faddb67_319ae713","line":506,"updated":"2019-08-15 07:14:28.000000000","message":"NIT: On a method definition we don\u0027t usually push all the params to the next line. I\u0027d only expect this if the method name was really long.\n\n  def _validate_etag_and_update_sysmeta(self, req, symlink_target_path,\n                                        etag):\n      ...","commit_id":"a7857ab076671a1ef1e91fc3ec3af2ac7f845396"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"2cd8b169fe90f3b8ec4b5bdf3d4727f20dd636d0","unresolved":false,"context_lines":[{"line_number":503,"context_line":"            return resp"},{"line_number":504,"context_line":""},{"line_number":505,"context_line":"    def _validate_etag_and_update_sysmeta("},{"line_number":506,"context_line":"            self, req, symlink_target_path, etag):"},{"line_number":507,"context_line":"        # next we\u0027ll make sure the E-Tag matches a real object"},{"line_number":508,"context_line":"        new_req \u003d make_subrequest("},{"line_number":509,"context_line":"            req.environ, path\u003dwsgi_quote(symlink_target_path), method\u003d\u0027HEAD\u0027,"}],"source_content_type":"text/x-python","patch_set":27,"id":"7faddb67_17ee9f20","line":506,"in_reply_to":"7faddb67_319ae713","updated":"2019-08-19 16:08:27.000000000","message":"Done","commit_id":"a7857ab076671a1ef1e91fc3ec3af2ac7f845396"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"512eb9cf8c4d5887dc81f3d09a9968a433e91ad2","unresolved":false,"context_lines":[{"line_number":730,"context_line":"    symloop_max \u003d int(conf.get(\u0027symloop_max\u0027, DEFAULT_SYMLOOP_MAX))"},{"line_number":731,"context_line":"    if symloop_max \u003c 1:"},{"line_number":732,"context_line":"        symloop_max \u003d int(DEFAULT_SYMLOOP_MAX)"},{"line_number":733,"context_line":"    register_swift_info(\u0027symlink\u0027, symloop_max\u003dsymloop_max)"},{"line_number":734,"context_line":""},{"line_number":735,"context_line":"    def symlink_mw(app):"},{"line_number":736,"context_line":"        return SymlinkMiddleware(app, conf, symloop_max)"}],"source_content_type":"text/x-python","patch_set":27,"id":"7faddb67_2ab7e23c","line":733,"range":{"start_line":733,"start_character":4,"end_line":733,"end_character":59},"updated":"2019-08-14 10:12:09.000000000","message":"for the question about /info, how about `static_link\u003dTrue`, similar to what\u0027s done here: https://github.com/openstack/swift/blob/master/swift/common/middleware/tempauth.py#L844\n\nI think in a future patch we might also need to use this flag in our func_tests.","commit_id":"a7857ab076671a1ef1e91fc3ec3af2ac7f845396"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"84ca26eb8a43fce8d7da95e38bcc1ed7354a2a6d","unresolved":false,"context_lines":[{"line_number":730,"context_line":"    symloop_max \u003d int(conf.get(\u0027symloop_max\u0027, DEFAULT_SYMLOOP_MAX))"},{"line_number":731,"context_line":"    if symloop_max \u003c 1:"},{"line_number":732,"context_line":"        symloop_max \u003d int(DEFAULT_SYMLOOP_MAX)"},{"line_number":733,"context_line":"    register_swift_info(\u0027symlink\u0027, symloop_max\u003dsymloop_max)"},{"line_number":734,"context_line":""},{"line_number":735,"context_line":"    def symlink_mw(app):"},{"line_number":736,"context_line":"        return SymlinkMiddleware(app, conf, symloop_max)"}],"source_content_type":"text/x-python","patch_set":27,"id":"7faddb67_4cb4a836","line":733,"range":{"start_line":733,"start_character":4,"end_line":733,"end_character":59},"in_reply_to":"7faddb67_2ab7e23c","updated":"2019-08-15 07:14:28.000000000","message":"Great idea!","commit_id":"a7857ab076671a1ef1e91fc3ec3af2ac7f845396"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":237,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"    :param req: HTTP request object"},{"line_number":240,"context_line":"    :returns: a tuple, the full versioned WSGI quoted path to the object and"},{"line_number":241,"context_line":"              the value of the X-Symlink-Target-Etag header which may be None"},{"line_number":242,"context_line":"    :raise: HTTPPreconditionFailed if x-symlink-target value"},{"line_number":243,"context_line":"            is not well formatted."}],"source_content_type":"text/x-python","patch_set":29,"id":"7faddb67_46b6a3fb","line":240,"range":{"start_line":240,"start_character":47,"end_line":240,"end_character":53},"updated":"2019-08-16 22:21:47.000000000","message":"Not actually quoted, right? That\u0027s why we need to quote() below when we\u0027re putting things into headers, but then we don\u0027t for the return. Maybe\n\n\u003e the full versioned path to the object (as a WSGI string) and ...\n\n?","commit_id":"1abc9c4f9d4c2f9d8ac996cca489b0ec65660a05"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"2cd8b169fe90f3b8ec4b5bdf3d4727f20dd636d0","unresolved":false,"context_lines":[{"line_number":237,"context_line":"    x-symlink-target header is present in req.headers."},{"line_number":238,"context_line":""},{"line_number":239,"context_line":"    :param req: HTTP request object"},{"line_number":240,"context_line":"    :returns: a tuple, the full versioned WSGI quoted path to the object and"},{"line_number":241,"context_line":"              the value of the X-Symlink-Target-Etag header which may be None"},{"line_number":242,"context_line":"    :raise: HTTPPreconditionFailed if x-symlink-target value"},{"line_number":243,"context_line":"            is not well formatted."}],"source_content_type":"text/x-python","patch_set":29,"id":"7faddb67_9efa9572","line":240,"range":{"start_line":240,"start_character":47,"end_line":240,"end_character":53},"in_reply_to":"7faddb67_46b6a3fb","updated":"2019-08-19 16:08:27.000000000","message":"Love it!\n\nhttps://review.opendev.org/#/c/677244/","commit_id":"1abc9c4f9d4c2f9d8ac996cca489b0ec65660a05"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":645,"context_line":"            tgt_etag \u003d self._response_header_value("},{"line_number":646,"context_line":"                TGT_ETAG_SYSMETA_SYMLINK_HDR)"},{"line_number":647,"context_line":"            if tgt_etag:"},{"line_number":648,"context_line":"                headers[TGT_ETAG_SYMLINK_HDR] \u003d tgt_etag"},{"line_number":649,"context_line":"            req.environ[\u0027swift.leave_relative_location\u0027] \u003d True"},{"line_number":650,"context_line":"            errmsg \u003d \u0027The requested POST was applied to a symlink. POST \u0027 +\\"},{"line_number":651,"context_line":"                     \u0027directly to the target to apply requested metadata.\u0027"}],"source_content_type":"text/x-python","patch_set":29,"id":"7faddb67_c6bdb3b1","line":648,"updated":"2019-08-16 22:21:47.000000000","message":"I vaguely wonder if we should do something more like symlink_sysmeta_to_usermeta() to get (for example) bytes...\n\nMeh. This is probably fine as-is.","commit_id":"1abc9c4f9d4c2f9d8ac996cca489b0ec65660a05"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d3e814115bee27a18bd7dcba35585d9bb86c4b88","unresolved":false,"context_lines":[{"line_number":730,"context_line":"    symloop_max \u003d int(conf.get(\u0027symloop_max\u0027, DEFAULT_SYMLOOP_MAX))"},{"line_number":731,"context_line":"    if symloop_max \u003c 1:"},{"line_number":732,"context_line":"        symloop_max \u003d int(DEFAULT_SYMLOOP_MAX)"},{"line_number":733,"context_line":"    register_swift_info(\u0027symlink\u0027, symloop_max\u003dsymloop_max, static_links\u003dTrue)"},{"line_number":734,"context_line":""},{"line_number":735,"context_line":"    def symlink_mw(app):"},{"line_number":736,"context_line":"        return SymlinkMiddleware(app, conf, symloop_max)"}],"source_content_type":"text/x-python","patch_set":29,"id":"7faddb67_86e1fbd2","line":733,"updated":"2019-08-16 22:21:47.000000000","message":":+1:","commit_id":"1abc9c4f9d4c2f9d8ac996cca489b0ec65660a05"}],"swift/common/middleware/versioned_writes.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ecd5490b63a6e33fbd3dc07a33022817ccd027f2","unresolved":false,"context_lines":[{"line_number":372,"context_line":"        # to container, but not READ. This was allowed in previous version"},{"line_number":373,"context_line":"        # (i.e., before middleware) so keeping the same behavior here"},{"line_number":374,"context_line":"        get_req \u003d make_pre_authed_request("},{"line_number":375,"context_line":"            req.environ, path\u003dquote(path_info) + \u0027?symlink\u003dget\u0027,"},{"line_number":376,"context_line":"            headers\u003d{\u0027X-Newest\u0027: \u0027True\u0027}, method\u003d\u0027GET\u0027, swift_source\u003d\u0027VW\u0027)"},{"line_number":377,"context_line":"        source_resp \u003d get_req.get_response(self.app)"},{"line_number":378,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_8a6fa8fa","line":375,"updated":"2019-01-30 14:58:32.000000000","message":"this makes me think we don\u0027t have strong assertions in existing tests around the behavior of symlinks + versioned_writes\n\nThis seems like a significant change - can you elaborate on it more to get me pointed in the right direction?","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":372,"context_line":"        # to container, but not READ. This was allowed in previous version"},{"line_number":373,"context_line":"        # (i.e., before middleware) so keeping the same behavior here"},{"line_number":374,"context_line":"        get_req \u003d make_pre_authed_request("},{"line_number":375,"context_line":"            req.environ, path\u003dquote(path_info) + \u0027?symlink\u003dget\u0027,"},{"line_number":376,"context_line":"            headers\u003d{\u0027X-Newest\u0027: \u0027True\u0027}, method\u003d\u0027GET\u0027, swift_source\u003d\u0027VW\u0027)"},{"line_number":377,"context_line":"        source_resp \u003d get_req.get_response(self.app)"},{"line_number":378,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_9d3e0bbf","line":375,"in_reply_to":"9fdfeff1_8a6fa8fa","updated":"2019-01-30 19:21:46.000000000","message":"No, it\u0027s actually really well-defined: https://github.com/openstack/swift/blob/2.20.0/test/functional/test_versioned_writes.py#L640-L757\n\nThis addition is to counteract the removal of https://github.com/openstack/swift/blob/2.20.0/swift/common/middleware/symlink.py#L511 -- I did it because if I\u0027m going to make versioned_writes know the ins and outs of symlinks *anyway*, I ought to at least get symlinks out of the business of knowing how versioned_writes works.\n\nBasically, (user-defined) symlinks are just another version. Which makes the follow-on patch that introduces system-defined symlinks rather interesting -- and once those func tests actually pass, I\u0027ll feel much better about the state of the patch :-)","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":7233,"name":"Matthew Oliver","email":"matt@oliver.net.au","username":"mattoliverau"},"change_message_id":"9de3fb75aa7c99a41a76322cf290b14cd579e11e","unresolved":false,"context_lines":[{"line_number":371,"context_line":"        # to container, but not READ. This was allowed in previous version"},{"line_number":372,"context_line":"        # (i.e., before middleware) so keeping the same behavior here"},{"line_number":373,"context_line":"        get_req \u003d make_pre_authed_request("},{"line_number":374,"context_line":"            req.environ, path\u003dwsgi_quote(path_info) + \u0027?symlink\u003dget\u0027,"},{"line_number":375,"context_line":"            headers\u003d{\u0027X-Newest\u0027: \u0027True\u0027}, method\u003d\u0027GET\u0027, swift_source\u003d\u0027VW\u0027)"},{"line_number":376,"context_line":"        source_resp \u003d get_req.get_response(self.app)"},{"line_number":377,"context_line":""}],"source_content_type":"text/x-python","patch_set":24,"id":"7faddb67_8e176d55","line":374,"updated":"2019-08-08 07:17:59.000000000","message":"I get it. And cleans up the VW source craziness. We\u0027ll now see alot of symlink\u003dgets when using versioned_writes.\n\nNot against this per say, but what happens when we add new \u0027get\u0027s. But OK to worry about that when it happens, alot of params passed by VW?\n\nAnyway we can cross that bridge when we get to it. This is better then what we had :)","commit_id":"6791906ae119e734ada90becbfd98d0996df8893"}],"test/functional/test_symlink.py":[{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ecd5490b63a6e33fbd3dc07a33022817ccd027f2","unresolved":false,"context_lines":[{"line_number":350,"context_line":"            headers\u003d{\u0027If-Match\u0027: self.env.tgt_etag})"},{"line_number":351,"context_line":"        self.assertEqual(resp.status, 412)"},{"line_number":352,"context_line":"        self.assertEqual(resp.getheader(\u0027content-location\u0027),"},{"line_number":353,"context_line":"                         self.env.target_content_location())"},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"        resp \u003d retry("},{"line_number":356,"context_line":"            self._make_request, method\u003d\u0027GET\u0027,"}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_0adf38d6","line":353,"updated":"2019-01-30 14:58:32.000000000","message":"might be redundant, would it look good to repeat this assertion in the happy path?\n\n    diff --git a/test/functional/test_symlink.py b/test/functional/test_symlink.py\n    index 07f9f58b6..96fff4d0f 100755\n    --- a/test/functional/test_symlink.py\n    +++ b/test/functional/test_symlink.py\n    @@ -306,6 +306,22 @@ class TestSymlink(Base):\n     \n             self._assertSymlink(self.env.link_cont, link_obj)\n     \n    +        resp \u003d retry(\n    +            self._make_request, method\u003d\u0027GET\u0027,\n    +            container\u003dself.env.link_cont, obj\u003dlink_obj,\n    +            headers\u003d{\u0027If-Match\u0027: self.env.tgt_etag})\n    +        self.assertEqual(resp.status, 200)\n    +        self.assertEqual(resp.getheader(\u0027content-location\u0027),\n    +                         self.env.target_content_location())\n    +\n    +        resp \u003d retry(\n    +            self._make_request, method\u003d\u0027GET\u0027,\n    +            container\u003dself.env.link_cont, obj\u003dlink_obj,\n    +            headers\u003d{\u0027If-Match\u0027: \u0027not-the-etag\u0027})\n    +        self.assertEqual(resp.status, 412)\n    +        self.assertEqual(resp.getheader(\u0027content-location\u0027),\n    +                         self.env.target_content_location())\n    +\n         def test_symlink_with_etag_put_head_get(self):\n             link_obj \u003d uuid4().hex","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"a7634f04925d6bda00d74f6826cc33a2454e8a8f","unresolved":false,"context_lines":[{"line_number":350,"context_line":"            headers\u003d{\u0027If-Match\u0027: self.env.tgt_etag})"},{"line_number":351,"context_line":"        self.assertEqual(resp.status, 412)"},{"line_number":352,"context_line":"        self.assertEqual(resp.getheader(\u0027content-location\u0027),"},{"line_number":353,"context_line":"                         self.env.target_content_location())"},{"line_number":354,"context_line":""},{"line_number":355,"context_line":"        resp \u003d retry("},{"line_number":356,"context_line":"            self._make_request, method\u003d\u0027GET\u0027,"}],"source_content_type":"text/x-python","patch_set":2,"id":"9fdfeff1_5d3423de","line":353,"in_reply_to":"9fdfeff1_0adf38d6","updated":"2019-01-30 19:21:46.000000000","message":"*shrug*\n\nSure. Why not.","commit_id":"c831e51342870b3b884edc7765e858b4dee12844"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":1168,"context_line":"                     body\u003d\u0027some other content\u0027)"},{"line_number":1169,"context_line":"        self.assertEqual(resp.status, 201)"},{"line_number":1170,"context_line":""},{"line_number":1171,"context_line":"        # link is now broken"},{"line_number":1172,"context_line":"        resp \u003d retry("},{"line_number":1173,"context_line":"            self._make_request, method\u003d\u0027GET\u0027,"},{"line_number":1174,"context_line":"            container\u003dself.env.link_cont, obj\u003dlink_obj, use_account\u003d2)"},{"line_number":1175,"context_line":"        self.assertEqual(resp.status, 409)"},{"line_number":1176,"context_line":""},{"line_number":1177,"context_line":"        # but we still know where it points"},{"line_number":1178,"context_line":"        self.assertEqual(resp.getheader(\u0027content-location\u0027),"},{"line_number":1179,"context_line":"                         self.env.target_content_location())"},{"line_number":1180,"context_line":""},{"line_number":1181,"context_line":"        # sanity test, remove permissions"},{"line_number":1182,"context_line":"        headers \u003d {\u0027X-Remove-Container-Read\u0027: \u0027remove\u0027}"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_c8626fae","line":1179,"range":{"start_line":1171,"start_character":8,"end_line":1179,"end_character":60},"updated":"2019-07-18 15:48:36.000000000","message":"nice!!","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":1191,"context_line":"            container\u003dself.env.link_cont, obj\u003dlink_obj, use_account\u003d2)"},{"line_number":1192,"context_line":"        self.assertEqual(resp.status, 403)"},{"line_number":1193,"context_line":"        # Still know where it is, though"},{"line_number":1194,"context_line":"        self.assertEqual(resp.getheader(\u0027content-location\u0027),"},{"line_number":1195,"context_line":"                         self.env.target_content_location())"},{"line_number":1196,"context_line":""},{"line_number":1197,"context_line":"    def test_symlink_invalid_etag(self):"},{"line_number":1198,"context_line":"        link_obj \u003d uuid4().hex"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_086c079a","line":1195,"range":{"start_line":1194,"start_character":8,"end_line":1195,"end_character":58},"updated":"2019-07-18 15:48:36.000000000","message":"mmm...this sounds like a security hole, no?\n\nor maybe not, this is not saying anything about the existence of the target object, only where the symlink is pointing to, which is ok since the user does have read access to the symlink itself","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":1191,"context_line":"            container\u003dself.env.link_cont, obj\u003dlink_obj, use_account\u003d2)"},{"line_number":1192,"context_line":"        self.assertEqual(resp.status, 403)"},{"line_number":1193,"context_line":"        # Still know where it is, though"},{"line_number":1194,"context_line":"        self.assertEqual(resp.getheader(\u0027content-location\u0027),"},{"line_number":1195,"context_line":"                         self.env.target_content_location())"},{"line_number":1196,"context_line":""},{"line_number":1197,"context_line":"    def test_symlink_invalid_etag(self):"},{"line_number":1198,"context_line":"        link_obj \u003d uuid4().hex"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_6bafb529","line":1195,"range":{"start_line":1194,"start_character":8,"end_line":1195,"end_character":58},"in_reply_to":"7faddb67_086c079a","updated":"2019-07-18 16:44:30.000000000","message":"not sure, I don\u0027t think this part of the api is a new behavior... I think a symlink\u003dget would also show the target...","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"babf1091c59d53e8f4b0a0e0c6ff7fec04f33c3a","unresolved":false,"context_lines":[{"line_number":1247,"context_line":"        self.assertEqual(self.env.tgt_etag,"},{"line_number":1248,"context_line":"                         obj_info[\u0027symlink_etag\u0027])"},{"line_number":1249,"context_line":"        self.assertEqual(int(self.env.tgt_length),"},{"line_number":1250,"context_line":"                         obj_info[\u0027symlink_bytes\u0027])"},{"line_number":1251,"context_line":""},{"line_number":1252,"context_line":""},{"line_number":1253,"context_line":"class TestCrossPolicySymlinkEnv(TestSymlinkEnv):"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_281543e5","line":1250,"updated":"2019-07-18 15:48:36.000000000","message":"what about content-type?","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"cb6730319b13cf32021ed99594c116ceeba2e0a9","unresolved":false,"context_lines":[{"line_number":1247,"context_line":"        self.assertEqual(self.env.tgt_etag,"},{"line_number":1248,"context_line":"                         obj_info[\u0027symlink_etag\u0027])"},{"line_number":1249,"context_line":"        self.assertEqual(int(self.env.tgt_length),"},{"line_number":1250,"context_line":"                         obj_info[\u0027symlink_bytes\u0027])"},{"line_number":1251,"context_line":""},{"line_number":1252,"context_line":""},{"line_number":1253,"context_line":"class TestCrossPolicySymlinkEnv(TestSymlinkEnv):"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_cb4ee995","line":1250,"in_reply_to":"7faddb67_281543e5","updated":"2019-07-18 16:44:30.000000000","message":"maybe like...\n\n\tdiff --git a/test/functional/test_symlink.py b/test/functional/test_symlink.py\n\tindex d55fcd62f..62deb8989 100755\n\t--- a/test/functional/test_symlink.py\n\t+++ b/test/functional/test_symlink.py\n\t@@ -106,6 +106,7 @@ class TestSymlinkEnv(BaseEnv):\n\t     @classmethod\n\t     def _create_tgt_object(cls, body\u003dTARGET_BODY):\n\t\t resp \u003d retry(cls._make_request, method\u003d\u0027PUT\u0027,\n\t+                     headers\u003d{\u0027Content-Type\u0027: \u0027application/target\u0027},\n\t\t\t      container\u003dcls.tgt_cont, obj\u003dcls.tgt_obj,\n\t\t\t      body\u003dbody)\n\t\t if resp.status !\u003d 201:\n\t@@ -1248,6 +1249,7 @@ class TestSymlink(Base):\n\t\t\t\t  obj_info[\u0027symlink_etag\u0027])\n\t\t self.assertEqual(int(self.env.tgt_length),\n\t\t\t\t  obj_info[\u0027symlink_bytes\u0027])\n\t+        self.assertEqual(obj_info[\u0027content_type\u0027], \u0027application/target\u0027)\n\t \n\t \n\t class TestCrossPolicySymlinkEnv(TestSymlinkEnv):\n\n\n???","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"a4d519538a50c16da554aa0b22521b01cbb61ec5","unresolved":false,"context_lines":[{"line_number":1247,"context_line":"        self.assertEqual(self.env.tgt_etag,"},{"line_number":1248,"context_line":"                         obj_info[\u0027symlink_etag\u0027])"},{"line_number":1249,"context_line":"        self.assertEqual(int(self.env.tgt_length),"},{"line_number":1250,"context_line":"                         obj_info[\u0027symlink_bytes\u0027])"},{"line_number":1251,"context_line":""},{"line_number":1252,"context_line":""},{"line_number":1253,"context_line":"class TestCrossPolicySymlinkEnv(TestSymlinkEnv):"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_56b4e07f","line":1250,"in_reply_to":"7faddb67_9697b83a","updated":"2019-07-18 17:37:02.000000000","message":"Done","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5514807dcaba0f0cefa10660d59ee167e0e7aa00","unresolved":false,"context_lines":[{"line_number":1247,"context_line":"        self.assertEqual(self.env.tgt_etag,"},{"line_number":1248,"context_line":"                         obj_info[\u0027symlink_etag\u0027])"},{"line_number":1249,"context_line":"        self.assertEqual(int(self.env.tgt_length),"},{"line_number":1250,"context_line":"                         obj_info[\u0027symlink_bytes\u0027])"},{"line_number":1251,"context_line":""},{"line_number":1252,"context_line":""},{"line_number":1253,"context_line":"class TestCrossPolicySymlinkEnv(TestSymlinkEnv):"}],"source_content_type":"text/x-python","patch_set":14,"id":"7faddb67_9697b83a","line":1250,"in_reply_to":"7faddb67_cb4ee995","updated":"2019-07-18 17:26:08.000000000","message":"yep","commit_id":"5311ab490d04ae24d2899f94be28dc77df1561a0"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":1253,"context_line":"                         obj_info[\u0027symlink_etag\u0027])"},{"line_number":1254,"context_line":"        self.assertEqual(int(self.env.tgt_length),"},{"line_number":1255,"context_line":"                         obj_info[\u0027symlink_bytes\u0027])"},{"line_number":1256,"context_line":"        self.assertEqual(obj_info[\u0027content_type\u0027], \u0027application/target\u0027)"},{"line_number":1257,"context_line":""},{"line_number":1258,"context_line":"        # POSTing to a hardlink can change the listing Content-Type"},{"line_number":1259,"context_line":"        headers \u003d {\u0027Content-Type\u0027: \u0027application/foo\u0027}"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_e8680ebb","line":1256,"updated":"2019-07-26 21:37:38.000000000","message":"Do we have any existing tests exploring what listings look like for links-to-links?\n\nShould we have some tests about listings and links-to-slos?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":1253,"context_line":"                         obj_info[\u0027symlink_etag\u0027])"},{"line_number":1254,"context_line":"        self.assertEqual(int(self.env.tgt_length),"},{"line_number":1255,"context_line":"                         obj_info[\u0027symlink_bytes\u0027])"},{"line_number":1256,"context_line":"        self.assertEqual(obj_info[\u0027content_type\u0027], \u0027application/target\u0027)"},{"line_number":1257,"context_line":""},{"line_number":1258,"context_line":"        # POSTing to a hardlink can change the listing Content-Type"},{"line_number":1259,"context_line":"        headers \u003d {\u0027Content-Type\u0027: \u0027application/foo\u0027}"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_3a64f021","line":1256,"in_reply_to":"7faddb67_e8680ebb","updated":"2019-07-31 16:40:25.000000000","message":"\u003e Do we have any existing tests exploring what listings look like for\n \u003e links-to-links?\n\nI\u0027m not sure, i\u0027ll try to introduce some changes and see if any functests catch them\n\n \u003e \n \u003e Should we have some tests about listings and links-to-slos?\n\nyes, I think we should expand some of the new tests to cover listings","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":1381,"context_line":"            \u0027multipart-manifest\u0027: \u0027get\u0027})"},{"line_number":1382,"context_line":"        self.assertEqual("},{"line_number":1383,"context_line":"            [seg[\u0027hash\u0027] for seg in json.loads(manifest_body)],"},{"line_number":1384,"context_line":"            [self.env.seg_info[\u0027seg_%s\u0027 % c][\u0027etag\u0027] for c in \u0027abcde\u0027])"},{"line_number":1385,"context_line":""},{"line_number":1386,"context_line":"    def test_hardlink_target_slo_manifest_wrong_etag(self):"},{"line_number":1387,"context_line":"        # try the slo \"etag\""}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_9a8c04d8","line":1384,"updated":"2019-07-31 16:40:25.000000000","message":"this is a link to an SLO, I think it should definitely be expanded to check listings.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"021ccfdeec2f1879717ba5f8d3d95e6ede1ca8e5","unresolved":false,"context_lines":[{"line_number":506,"context_line":"                                         link_obj\u003dbroken_hardlink_obj,"},{"line_number":507,"context_line":"                                         tgt_cont\u003dself.env.link_cont,"},{"line_number":508,"context_line":"                                         tgt_obj\u003dsymlink_obj,"},{"line_number":509,"context_line":"                                         etag\u003dMD5_OF_EMPTY_STRING)"},{"line_number":510,"context_line":""},{"line_number":511,"context_line":"    def test_symlink_get_ranged(self):"},{"line_number":512,"context_line":"        link_obj \u003d uuid4().hex"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_03af48e3","line":509,"updated":"2019-07-31 20:47:15.000000000","message":"I think we want this to work, correct?  with the symlink_* bits in the container listing describing the symlink.","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"777c4674447646b9f178f02eed4570d24083b5ef","unresolved":false,"context_lines":[{"line_number":506,"context_line":"                                         link_obj\u003dbroken_hardlink_obj,"},{"line_number":507,"context_line":"                                         tgt_cont\u003dself.env.link_cont,"},{"line_number":508,"context_line":"                                         tgt_obj\u003dsymlink_obj,"},{"line_number":509,"context_line":"                                         etag\u003dMD5_OF_EMPTY_STRING)"},{"line_number":510,"context_line":""},{"line_number":511,"context_line":"    def test_symlink_get_ranged(self):"},{"line_number":512,"context_line":"        link_obj \u003d uuid4().hex"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_e9152d3e","line":509,"in_reply_to":"7faddb67_03af48e3","updated":"2019-08-01 22:22:59.000000000","message":"Yeah, pretty sure that sounds right.","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"021ccfdeec2f1879717ba5f8d3d95e6ede1ca8e5","unresolved":false,"context_lines":[{"line_number":1257,"context_line":"                         b\"does not match X-Symlink-Target-Etag header \""},{"line_number":1258,"context_line":"                         b\"\u0027not-the-real-etag\u0027\")"},{"line_number":1259,"context_line":""},{"line_number":1260,"context_line":"    def test_symlink_object_listing(self):"},{"line_number":1261,"context_line":"        link_obj \u003d uuid4().hex"},{"line_number":1262,"context_line":"        self._test_put_symlink(link_cont\u003dself.env.link_cont, link_obj\u003dlink_obj,"},{"line_number":1263,"context_line":"                               tgt_cont\u003dself.env.tgt_cont,"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_e3430c3e","line":1260,"updated":"2019-07-31 20:47:15.000000000","message":"so this was one of the existing tests that makes assertions about symlink listings...","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"f9f98e87fc5f15c57107ac0f2f9ffbd8f4ed7ddd","unresolved":false,"context_lines":[{"line_number":1462,"context_line":"            \u0027hash\u0027: u\u0027d41d8cd98f00b204e9800998ecf8427e\u0027,"},{"line_number":1463,"context_line":"            # XXX when versioned writes make a hardlink to a SLO manifest the"},{"line_number":1464,"context_line":"            # swift_bytes param makes it into the content-length"},{"line_number":1465,"context_line":"            \u0027bytes\u0027: 0,"},{"line_number":1466,"context_line":"            \u0027slo_etag\u0027: slo_info[\u0027etag\u0027],"},{"line_number":1467,"context_line":"            \u0027symlink_path\u0027: \u0027/v1/AUTH_test/%s/manifest-abcde\u0027 % ("},{"line_number":1468,"context_line":"                self.env.container2.name),"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_c6ecd3bc","line":1465,"updated":"2019-08-01 14:28:47.000000000","message":"This comment is wrong s/content-length/content-type/\n\nAlso, on IRC Tim pointed out that we can grab the SLO bytes of a manifest from X-Object-Sysmeta-Slo-Size ... so maybe we can make use of that somehow?","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"777c4674447646b9f178f02eed4570d24083b5ef","unresolved":false,"context_lines":[{"line_number":1462,"context_line":"            \u0027hash\u0027: u\u0027d41d8cd98f00b204e9800998ecf8427e\u0027,"},{"line_number":1463,"context_line":"            # XXX when versioned writes make a hardlink to a SLO manifest the"},{"line_number":1464,"context_line":"            # swift_bytes param makes it into the content-length"},{"line_number":1465,"context_line":"            \u0027bytes\u0027: 0,"},{"line_number":1466,"context_line":"            \u0027slo_etag\u0027: slo_info[\u0027etag\u0027],"},{"line_number":1467,"context_line":"            \u0027symlink_path\u0027: \u0027/v1/AUTH_test/%s/manifest-abcde\u0027 % ("},{"line_number":1468,"context_line":"                self.env.container2.name),"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_4f10f04e","line":1465,"in_reply_to":"7faddb67_c6ecd3bc","updated":"2019-08-01 22:22:59.000000000","message":"Yeah, this part feels suspect -- why is versioned_writes going to get to do a thing that clients can\u0027t?","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"021ccfdeec2f1879717ba5f8d3d95e6ede1ca8e5","unresolved":false,"context_lines":[{"line_number":1467,"context_line":"            \u0027symlink_path\u0027: \u0027/v1/AUTH_test/%s/manifest-abcde\u0027 % ("},{"line_number":1468,"context_line":"                self.env.container2.name),"},{"line_number":1469,"context_line":"            \u0027symlink_bytes\u0027: manifest_size,"},{"line_number":1470,"context_line":"            \u0027symlink_etag\u0027: manifest_etag,"},{"line_number":1471,"context_line":"        })"},{"line_number":1472,"context_line":""},{"line_number":1473,"context_line":"    def test_hardlink_target_slo_manifest_wrong_etag(self):"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_436c60cf","line":1470,"updated":"2019-07-31 20:47:15.000000000","message":"I think we want the symlink_* bits here to describe the manifest.","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"777c4674447646b9f178f02eed4570d24083b5ef","unresolved":false,"context_lines":[{"line_number":1467,"context_line":"            \u0027symlink_path\u0027: \u0027/v1/AUTH_test/%s/manifest-abcde\u0027 % ("},{"line_number":1468,"context_line":"                self.env.container2.name),"},{"line_number":1469,"context_line":"            \u0027symlink_bytes\u0027: manifest_size,"},{"line_number":1470,"context_line":"            \u0027symlink_etag\u0027: manifest_etag,"},{"line_number":1471,"context_line":"        })"},{"line_number":1472,"context_line":""},{"line_number":1473,"context_line":"    def test_hardlink_target_slo_manifest_wrong_etag(self):"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_af4de472","line":1470,"in_reply_to":"7faddb67_436c60cf","updated":"2019-08-01 22:22:59.000000000","message":"Yeah -- I suppose that makes some sense. I still kinda want the slo size though... I guess we could jam it into content-type like slo does?","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"021ccfdeec2f1879717ba5f8d3d95e6ede1ca8e5","unresolved":false,"context_lines":[{"line_number":1536,"context_line":"            # the only time bytes/etag aren\u0027t the target object are when they"},{"line_number":1537,"context_line":"            # validate through another hardlink"},{"line_number":1538,"context_line":"            \u0027symlink_bytes\u0027: 0,"},{"line_number":1539,"context_line":"            \u0027symlink_etag\u0027: MD5_OF_EMPTY_STRING,"},{"line_number":1540,"context_line":"        })"},{"line_number":1541,"context_line":""},{"line_number":1542,"context_line":"    def test_symlink_target_slo_nested_manifest(self):"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_2367e4eb","line":1539,"updated":"2019-07-31 20:47:15.000000000","message":"I don\u0027t think the symlink -\u003e slo part is significant here, I think hardlinks to symlinks should always look this way?","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"777c4674447646b9f178f02eed4570d24083b5ef","unresolved":false,"context_lines":[{"line_number":1536,"context_line":"            # the only time bytes/etag aren\u0027t the target object are when they"},{"line_number":1537,"context_line":"            # validate through another hardlink"},{"line_number":1538,"context_line":"            \u0027symlink_bytes\u0027: 0,"},{"line_number":1539,"context_line":"            \u0027symlink_etag\u0027: MD5_OF_EMPTY_STRING,"},{"line_number":1540,"context_line":"        })"},{"line_number":1541,"context_line":""},{"line_number":1542,"context_line":"    def test_symlink_target_slo_nested_manifest(self):"}],"source_content_type":"text/x-python","patch_set":18,"id":"7faddb67_cf04e017","line":1539,"in_reply_to":"7faddb67_2367e4eb","updated":"2019-08-01 22:22:59.000000000","message":"Makes sense -- I agree.","commit_id":"4bfd3dcee0b7b8f54c026dbfe668e6bd3c47fa70"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3fcae8aa1bbf9281d7a4ff06e7a8c49ef73d6220","unresolved":false,"context_lines":[{"line_number":1418,"context_line":"            \u0027content_type\u0027: \u0027application/octet-stream\u0027,"},{"line_number":1419,"context_line":"            \u0027hash\u0027: \u0027d41d8cd98f00b204e9800998ecf8427e\u0027,"},{"line_number":1420,"context_line":"            \u0027bytes\u0027: 0,"},{"line_number":1421,"context_line":"            \u0027symlink_path\u0027: \u0027/v1/AUTH_test/%s/manifest-abcde\u0027 % ("},{"line_number":1422,"context_line":"                self.env.container.name),"},{"line_number":1423,"context_line":"        })"},{"line_number":1424,"context_line":""}],"source_content_type":"text/x-python","patch_set":19,"id":"7faddb67_333952a3","line":1421,"range":{"start_line":1421,"start_character":33,"end_line":1421,"end_character":42},"updated":"2019-08-02 17:30:56.000000000","message":"lulz","commit_id":"a83a7692af11c49ecda4152e0bf857cc19b8832a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3fcae8aa1bbf9281d7a4ff06e7a8c49ef73d6220","unresolved":false,"context_lines":[{"line_number":1462,"context_line":"            \u0027hash\u0027: u\u0027d41d8cd98f00b204e9800998ecf8427e\u0027,"},{"line_number":1463,"context_line":"            \u0027bytes\u0027: 4 * 2 ** 20 + 1,"},{"line_number":1464,"context_line":"            \u0027slo_etag\u0027: slo_info[\u0027etag\u0027],"},{"line_number":1465,"context_line":"            \u0027symlink_path\u0027: \u0027/v1/AUTH_test/%s/manifest-abcde\u0027 % ("},{"line_number":1466,"context_line":"                self.env.container2.name),"},{"line_number":1467,"context_line":"            \u0027symlink_bytes\u0027: manifest_size,"},{"line_number":1468,"context_line":"            \u0027symlink_etag\u0027: manifest_etag,"}],"source_content_type":"text/x-python","patch_set":19,"id":"7faddb67_533c0e92","line":1465,"range":{"start_line":1465,"start_character":33,"end_line":1465,"end_character":42},"updated":"2019-08-02 17:30:56.000000000","message":"and here","commit_id":"a83a7692af11c49ecda4152e0bf857cc19b8832a"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"3fcae8aa1bbf9281d7a4ff06e7a8c49ef73d6220","unresolved":false,"context_lines":[{"line_number":1529,"context_line":"            \u0027content_type\u0027: \u0027application/octet-stream\u0027,"},{"line_number":1530,"context_line":"            \u0027hash\u0027: \u0027d41d8cd98f00b204e9800998ecf8427e\u0027,"},{"line_number":1531,"context_line":"            \u0027bytes\u0027: 0,"},{"line_number":1532,"context_line":"            \u0027symlink_path\u0027: u\u0027/v1/AUTH_test/%s/%s\u0027 % ("},{"line_number":1533,"context_line":"                self.file_symlink.container, self.file_symlink.name),"},{"line_number":1534,"context_line":"            # the only time bytes/etag aren\u0027t the target object are when they"},{"line_number":1535,"context_line":"            # validate through another hardlink"}],"source_content_type":"text/x-python","patch_set":19,"id":"7faddb67_b34c6242","line":1532,"range":{"start_line":1532,"start_character":34,"end_line":1532,"end_character":43},"updated":"2019-08-02 17:30:56.000000000","message":"...and here","commit_id":"a83a7692af11c49ecda4152e0bf857cc19b8832a"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":106,"context_line":"    @classmethod"},{"line_number":107,"context_line":"    def _create_tgt_object(cls, body\u003dTARGET_BODY):"},{"line_number":108,"context_line":"        resp \u003d retry(cls._make_request, method\u003d\u0027PUT\u0027,"},{"line_number":109,"context_line":"                     headers\u003d{\u0027Content-Type\u0027: \u0027application/target\u0027},"},{"line_number":110,"context_line":"                     container\u003dcls.tgt_cont, obj\u003dcls.tgt_obj,"},{"line_number":111,"context_line":"                     body\u003dbody)"},{"line_number":112,"context_line":"        if resp.status !\u003d 201:"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_25432c41","line":109,"updated":"2019-08-05 19:37:22.000000000","message":"so we\u0027re setting an explicit content-type by default on the target object","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"5e6b3fe5507118c0fe1a46f98926309812775112","unresolved":false,"context_lines":[{"line_number":262,"context_line":"        self.assertEqual(resp.getheader(\u0027content-length\u0027), str(0))"},{"line_number":263,"context_line":"        self.assertTrue(resp.getheader(\u0027x-symlink-target\u0027))"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"    def _assertSymlink(self, link_cont, link_obj,"},{"line_number":266,"context_line":"                       expected_content_location\u003dNone, use_account\u003d1):"},{"line_number":267,"context_line":"        expected_content_location \u003d \\"},{"line_number":268,"context_line":"            expected_content_location or self.env.target_content_location()"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_4748b35a","line":265,"updated":"2019-08-05 14:22:04.000000000","message":"would it be worth adding a `expected_content_type`","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":262,"context_line":"        self.assertEqual(resp.getheader(\u0027content-length\u0027), str(0))"},{"line_number":263,"context_line":"        self.assertTrue(resp.getheader(\u0027x-symlink-target\u0027))"},{"line_number":264,"context_line":""},{"line_number":265,"context_line":"    def _assertSymlink(self, link_cont, link_obj,"},{"line_number":266,"context_line":"                       expected_content_location\u003dNone, use_account\u003d1):"},{"line_number":267,"context_line":"        expected_content_location \u003d \\"},{"line_number":268,"context_line":"            expected_content_location or self.env.target_content_location()"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_857b0079","line":265,"in_reply_to":"7faddb67_4748b35a","updated":"2019-08-05 19:37:22.000000000","message":"would that be for the *symlink* (passed to _assertLinkObject) or the content-type of the *target* (passed to _test_get/head_as_target_object)\n\nThe content-type of the target isn\u0027t explicit when using a bare _make_request, and sometimes get\u0027s guessed a image/png, but I\u0027m not sure how deterministic our guess based on file extension is going to be\n\nWhen the symlink is a hardlink *it\u0027s* content-type matches the target - and this check is used in both cases.  For example, we use this assertion helper a dozen times - with the default symlink/target ctypes it fails 10 times, 7 of the failing tests have \"with_etag\" or \"hardlink\" in the name (with default target/target ctypes those tests pass, but a number of other symlink tests that call _assertLinkObject directly fail)\n\nDoes that help you evaluate if it would be \"worth\" adding this keyword?","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"}],"test/unit/common/middleware/test_symlink.py":[{"author":{"_account_id":9625,"name":"Thiago da Silva","email":"thiagodasilva@gmail.com","username":"thiago"},"change_message_id":"aa1fbe8bce690a4e81f3ec17089e93672374a5ee","unresolved":false,"context_lines":[{"line_number":216,"context_line":"        status, headers, body \u003d self.call_sym(req)"},{"line_number":217,"context_line":"        self.assertEqual(status, \u0027404 Not Found\u0027)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"    def test_symlink_put_with_prevalidated_etag(self):"},{"line_number":220,"context_line":"        self.app.register(\u0027PUT\u0027, \u0027/v1/a/c/symlink\u0027, swob.HTTPCreated, {})"},{"line_number":221,"context_line":"        req \u003d Request.blank(\u0027/v1/a/c/symlink\u0027, method\u003d\u0027PUT\u0027, headers\u003d{"},{"line_number":222,"context_line":"            \u0027X-Symlink-Target\u0027: \u0027c1/o\u0027,"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_3cb75089","line":219,"range":{"start_line":219,"start_character":8,"end_line":219,"end_character":47},"updated":"2019-07-26 17:35:20.000000000","message":"nice, this is the case where versioning would already have this data, so no need for symlink to make an additional HEAD request.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":221,"context_line":"        req \u003d Request.blank(\u0027/v1/a/c/symlink\u0027, method\u003d\u0027PUT\u0027, headers\u003d{"},{"line_number":222,"context_line":"            \u0027X-Symlink-Target\u0027: \u0027c1/o\u0027,"},{"line_number":223,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Etag\u0027: \u0027tgt-etag\u0027,"},{"line_number":224,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Bytes\u0027: \u002713\u0027,"},{"line_number":225,"context_line":"            \u0027Content-Type\u0027: \u0027application/foo\u0027,"},{"line_number":226,"context_line":"        }, body\u003d\u0027\u0027)"},{"line_number":227,"context_line":"        status, headers, body \u003d self.call_sym(req)"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_c8d432ec","line":224,"updated":"2019-07-26 21:37:38.000000000","message":"Oh, interesting... so that\u0027s going to be the \"blessed\" way to do it? At that point... why wouldn\u0027t VW plumb in\n\n \u0027X-Object-Sysmeta-Symlink-Target\u0027: \u0027c1/o\u0027,\n\nand skip the whole thing?","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":221,"context_line":"        req \u003d Request.blank(\u0027/v1/a/c/symlink\u0027, method\u003d\u0027PUT\u0027, headers\u003d{"},{"line_number":222,"context_line":"            \u0027X-Symlink-Target\u0027: \u0027c1/o\u0027,"},{"line_number":223,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Etag\u0027: \u0027tgt-etag\u0027,"},{"line_number":224,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Bytes\u0027: \u002713\u0027,"},{"line_number":225,"context_line":"            \u0027Content-Type\u0027: \u0027application/foo\u0027,"},{"line_number":226,"context_line":"        }, body\u003d\u0027\u0027)"},{"line_number":227,"context_line":"        status, headers, body \u003d self.call_sym(req)"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_9a016409","line":224,"in_reply_to":"7faddb67_c8d432ec","updated":"2019-07-31 16:40:25.000000000","message":"you mean use the translated sysmeta header instead of x-symlink-target?\n\nI\u0027m not sure that wouldn\u0027t work... I\u0027m no priest.","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d535861d74b4b9beeaa44f7af4c2c6d73bbfc547","unresolved":false,"context_lines":[{"line_number":248,"context_line":"            \u0027X-Symlink-Target\u0027: \u0027c1/o\u0027,"},{"line_number":249,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Etag\u0027: \u0027tgt-etag\u0027,"},{"line_number":250,"context_line":"        }, body\u003d\u0027\u0027)"},{"line_number":251,"context_line":"        with self.assertRaises(KeyError) as cm:"},{"line_number":252,"context_line":"            self.call_sym(req)"},{"line_number":253,"context_line":"        self.assertEqual(cm.exception.args[0], swob.header_to_environ_key("},{"line_number":254,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Bytes\u0027))"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_a8f21699","line":251,"updated":"2019-07-26 21:37:38.000000000","message":"Hmm... I take it *this* is part of why we\u0027re adding symlink_bytes when doing a hardlink to a symlink??","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"bf0245cca1d620fdb4f51502104984fd2f10bd8a","unresolved":false,"context_lines":[{"line_number":248,"context_line":"            \u0027X-Symlink-Target\u0027: \u0027c1/o\u0027,"},{"line_number":249,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Etag\u0027: \u0027tgt-etag\u0027,"},{"line_number":250,"context_line":"        }, body\u003d\u0027\u0027)"},{"line_number":251,"context_line":"        with self.assertRaises(KeyError) as cm:"},{"line_number":252,"context_line":"            self.call_sym(req)"},{"line_number":253,"context_line":"        self.assertEqual(cm.exception.args[0], swob.header_to_environ_key("},{"line_number":254,"context_line":"            \u0027X-Object-Sysmeta-Symlink-Target-Bytes\u0027))"}],"source_content_type":"text/x-python","patch_set":17,"id":"7faddb67_f553c914","line":251,"in_reply_to":"7faddb67_a8f21699","updated":"2019-07-31 16:40:25.000000000","message":"symlink_bytes in the ... container listing?  or like in sysmeta?\n\nYes, the code (and this supporting test) are trying to highlight/validate that when you provide a target-etag you get a target-bytes and it\u0027s not correct to have one w/o the other.\n\nWhile I think that the zero-byte etag is recognizable I don\u0027t think it\u0027s worth the trouble to special case a scenario where you would have symlink_etag w/o symlink_bytes","commit_id":"a0c5197a26008069e210e5a02e071986e3aa4676"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"52ae84d07fe742f4d2b7c1223ab809adfb4882eb","unresolved":false,"context_lines":[{"line_number":214,"context_line":"                                \u0027X-Symlink-Target-Etag\u0027: \u0027not-tgt-etag\u0027,"},{"line_number":215,"context_line":"                            }, body\u003d\u0027\u0027)"},{"line_number":216,"context_line":"        status, headers, body \u003d self.call_sym(req)"},{"line_number":217,"context_line":"        self.assertEqual(status, \u0027404 Not Found\u0027)"},{"line_number":218,"context_line":""},{"line_number":219,"context_line":"    def test_symlink_put_with_prevalidated_etag(self):"},{"line_number":220,"context_line":"        self.app.register(\u0027PUT\u0027, \u0027/v1/a/c/symlink\u0027, swob.HTTPCreated, {})"}],"source_content_type":"text/x-python","patch_set":20,"id":"7faddb67_a8fb8cbb","line":217,"updated":"2019-08-02 19:46:35.000000000","message":"hrm....\n\nAssertionError: \u0027409 Conflict\u0027 !\u003d \u0027404 Not Found\u0027","commit_id":"80f59e3d42c6844b6d5e193aa0fadb620c626d58"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":90,"context_line":"        self.assertNotIn(\u0027X-Object-Sysmeta-Symlink-Target-Account\u0027, hdrs)"},{"line_number":91,"context_line":"        val \u003d hdrs.get(\u0027X-Object-Sysmeta-Container-Update-Override-Etag\u0027)"},{"line_number":92,"context_line":"        self.assertEqual(val, \u0027%s; symlink_target\u003dc1/o\u0027 % MD5_OF_EMPTY_STRING)"},{"line_number":93,"context_line":"        self.assertEqual(\u0027application/symlink\u0027, hdrs.get(\u0027Content-Type\u0027))"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    def test_symlink_simple_put_with_content_type(self):"},{"line_number":96,"context_line":"        self.app.register(\u0027PUT\u0027, \u0027/v1/a/c/symlink\u0027, swob.HTTPCreated, {})"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_b8f0a8fe","line":93,"updated":"2019-08-05 19:37:22.000000000","message":"I want to call attention to this change in behavior","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":15343,"name":"Tim Burke","email":"tburke@nvidia.com","username":"tburke"},"change_message_id":"d26c73962383108fc1c7c1274aa2c9dd640f0061","unresolved":false,"context_lines":[{"line_number":920,"context_line":"        self.assertEqual(hdrs[\u0027X-Object-Sysmeta-Symlink-Target-Etag\u0027],"},{"line_number":921,"context_line":"                         \u0027manifest-etag\u0027)"},{"line_number":922,"context_line":"        self.assertEqual(hdrs[\u0027X-Object-Sysmeta-Symlink-Target-Bytes\u0027],"},{"line_number":923,"context_line":"                         \u00271048576\u0027)"},{"line_number":924,"context_line":""},{"line_number":925,"context_line":"    def test_hardlink_to_slo_manifest_slo_etag(self):"},{"line_number":926,"context_line":"        self.app.register(\u0027HEAD\u0027, \u0027/v1/a/c1/o\u0027, swob.HTTPOk, {"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_9e97ea45","line":923,"updated":"2019-08-02 22:54:41.000000000","message":"I feel like we oughta be looking at the update-override header, too...\n\nSpeaking of, we probably ought to add that (complete with ;slo_etag\u003d param) to the HEAD response.","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"},{"author":{"_account_id":1179,"name":"Clay Gerrard","email":"clay.gerrard@gmail.com","username":"clay-gerrard"},"change_message_id":"ed7abcefa7c729a9194653d1206c5dac892a96ab","unresolved":false,"context_lines":[{"line_number":920,"context_line":"        self.assertEqual(hdrs[\u0027X-Object-Sysmeta-Symlink-Target-Etag\u0027],"},{"line_number":921,"context_line":"                         \u0027manifest-etag\u0027)"},{"line_number":922,"context_line":"        self.assertEqual(hdrs[\u0027X-Object-Sysmeta-Symlink-Target-Bytes\u0027],"},{"line_number":923,"context_line":"                         \u00271048576\u0027)"},{"line_number":924,"context_line":""},{"line_number":925,"context_line":"    def test_hardlink_to_slo_manifest_slo_etag(self):"},{"line_number":926,"context_line":"        self.app.register(\u0027HEAD\u0027, \u0027/v1/a/c1/o\u0027, swob.HTTPOk, {"}],"source_content_type":"text/x-python","patch_set":22,"id":"7faddb67_c8002f04","line":923,"in_reply_to":"7faddb67_9e97ea45","updated":"2019-08-05 19:37:22.000000000","message":"yeah I think I misunderstood how that was working - thanks for calling it out.  #willfix","commit_id":"dfbc0e8f781f9fd7cb9cfb1669826bc63225e4e7"}]}
