)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"16bcbc971a9cdcd4e16ab5392908464dacd33179","unresolved":false,"context_lines":[{"line_number":9,"context_line":"a GET request with if-(un)modified-since header with the value from last-modified"},{"line_number":10,"context_line":"should be compared the file\u0027s integer value of x-timestamp to work correctly."},{"line_number":11,"context_line":""},{"line_number":12,"context_line":"update unitest for last-modified header"},{"line_number":13,"context_line":"pep8 fix"},{"line_number":14,"context_line":"recover test_GET_if_unmodified_snice() in test/unit/obj/test_server.py"},{"line_number":15,"context_line":""}],"source_content_type":"text/x-gerrit-commit-message","patch_set":11,"id":"AAAATn%2F%2BsnA%3D","line":12,"updated":"2013-11-22 03:20:48.000000000","message":"I don\u0027t believe these three lines add any additional information for the commit, as pep8 working is a requirement, so it is assumed, and unit tests are required to cover the code changes being made.","commit_id":"2c01ef88c0429f5e6189880d482444bd1f43d0b6"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"16bcbc971a9cdcd4e16ab5392908464dacd33179","unresolved":false,"context_lines":[{"line_number":13,"context_line":"pep8 fix"},{"line_number":14,"context_line":"recover test_GET_if_unmodified_snice() in test/unit/obj/test_server.py"},{"line_number":15,"context_line":""},{"line_number":16,"context_line":"reverify bug 1241479"},{"line_number":17,"context_line":"recheck bug 1251784"},{"line_number":18,"context_line":""},{"line_number":19,"context_line":"Closes-Bug: #1248818"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":11,"id":"AAAATn%2F%2BsnQ%3D","line":16,"updated":"2013-11-22 03:20:48.000000000","message":"Please remove these two lines, as they are commands used in review comments in gerrit only to retrigger gate and check jobs for a commit.","commit_id":"2c01ef88c0429f5e6189880d482444bd1f43d0b6"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"1ac6fbefbce7189f50968a471bb69995ae546cff","unresolved":false,"context_lines":[{"line_number":7,"context_line":"change the last-modified header value with valid one"},{"line_number":8,"context_line":""},{"line_number":9,"context_line":"the Last-Modified header in Response had a invalid value."},{"line_number":10,"context_line":"; an integer part of object\u0027s timestamp"},{"line_number":11,"context_line":"This leads that the the if-[un]modified-since header with the"},{"line_number":12,"context_line":"value from last-modified is always earlier than timestamp"},{"line_number":13,"context_line":"and results the content is always newer than value of these"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":16,"id":"AAAATn%2F85fQ%3D","line":10,"updated":"2013-12-19 01:49:45.000000000","message":"Not sure if this sentence is supposed to read that way with a semi-colon...","commit_id":"8dd6fc040c722001a2fa9b76311a177ea01bf8da"}],"swift/obj/server.py":[{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"5a82ae2f5963be475006f7000903d390789455b3","unresolved":false,"context_lines":[{"line_number":469,"context_line":"                        resp.etag \u003d metadata[\u0027ETag\u0027]"},{"line_number":470,"context_line":"                        return resp"},{"line_number":471,"context_line":"                file_x_ts \u003d metadata[\u0027X-Timestamp\u0027]"},{"line_number":472,"context_line":"                file_x_ts_flt \u003d int(float(file_x_ts))"},{"line_number":473,"context_line":"                try:"},{"line_number":474,"context_line":"                    if_unmodified_since \u003d request.if_unmodified_since"},{"line_number":475,"context_line":"                except (OverflowError, ValueError):"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FRmo%3D","line":472,"updated":"2013-11-11 21:44:00.000000000","message":"It would seem this is not really the correct thing to do here.\n\nTimestamps on objects (as well as on container and accounts) are stored as 16.5 ascii floating point strings.  The proxy server is (usually) responsible for providing the consistent timestamp values when objects are created (or modified), and they include sub-second values (seconds . microseconds).\n\nThe swob.Request objects have two properties which internally are python datatime representations, \"if_modified_since\" and \"if_unmodified_since\", and swob.Response has the \"last_modified\" property. The ascii values of those corresponding headers is defined by the HTTP protocol to be an Http-date string (see http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html, 3.3.1 Full Date). Note that it does not include a sub-second value for the time.\n\nAs a result, the \"last-modified\" header of an HTTP response from Swift will always include a timestamp that has had its sub-second value truncated. And so a last-modified header value will only be equivalent to an object\u0027s actual timestamp if that timestamp had a 0 (zero) for its microsecond component.\n\nIf you change the test to use int() on the initial timestamp value generated (made comments there as well), then with the change below at line 486 the code works as advertised.\n\nIt appears to be a limitation of the protocol that the last-modified header from a PUT response cannot be used as input to an if-modified-since or if-unmodified-since header while expecting to get the correct behavior in all cases (1/100,000 chance of it working as expected, the one case where an object\u0027s timestamp has no microsecond component).\n\nBy using int() here, then two PUTs to the same file within one second will not result in the client of the first PUT being able to see the change from the second PUT.","commit_id":"5a3ca173df7461737bff0a63d25f2e7a13ece9ef"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"5a82ae2f5963be475006f7000903d390789455b3","unresolved":false,"context_lines":[{"line_number":483,"context_line":"                except (OverflowError, ValueError):"},{"line_number":484,"context_line":"                    # catches timestamps before the epoch"},{"line_number":485,"context_line":"                    return HTTPPreconditionFailed(request\u003drequest)"},{"line_number":486,"context_line":"                if if_modified_since and file_x_ts_utc \u003c\u003d if_modified_since:"},{"line_number":487,"context_line":"                    return HTTPNotModified(request\u003drequest)"},{"line_number":488,"context_line":"                keep_cache \u003d (self.keep_cache_private or"},{"line_number":489,"context_line":"                              (\u0027X-Auth-Token\u0027 not in request.headers and"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FRmk%3D","line":486,"updated":"2013-11-11 21:44:00.000000000","message":"This is a good change, as truly identical timestamps should not result in returning the full body of the file.","commit_id":"5a3ca173df7461737bff0a63d25f2e7a13ece9ef"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"0b09ce9e5f0538c88b894319954e2fe7ba90457d","unresolved":false,"context_lines":[{"line_number":476,"context_line":"                except (OverflowError, ValueError):"},{"line_number":477,"context_line":"                    # catches timestamps before the epoch"},{"line_number":478,"context_line":"                    return HTTPPreconditionFailed(request\u003drequest)"},{"line_number":479,"context_line":"                file_x_ts_utc \u003d datetime.fromtimestamp(file_x_ts_flt, UTC)"},{"line_number":480,"context_line":"                if if_unmodified_since and file_x_ts_utc \u003e if_unmodified_since:"},{"line_number":481,"context_line":"                    return HTTPPreconditionFailed(request\u003drequest)"},{"line_number":482,"context_line":"                try:"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F%2B1Ac%3D","line":479,"updated":"2013-11-19 16:41:52.000000000","message":"I think this has to be math.ceil(file_x_ts_flt) as well, since the \"if_unmodified_since\" value will come from the client, which could take it from a previous last_modified value, which has had math.ceil() applied to it, such that it will always be greater than or equal to the X-Timestamp value.","commit_id":"21739d63aa299824ae65d9ccdf52bf3ef079ee3c"},{"author":{"_account_id":8231,"name":"Kiyoung Jung","email":"kiyoung.jung@kt.com","username":"jackieyoung"},"change_message_id":"b6b32fa12d86f80f6abef084d3f655c962eaa48c","unresolved":false,"context_lines":[{"line_number":476,"context_line":"                except (OverflowError, ValueError):"},{"line_number":477,"context_line":"                    # catches timestamps before the epoch"},{"line_number":478,"context_line":"                    return HTTPPreconditionFailed(request\u003drequest)"},{"line_number":479,"context_line":"                file_x_ts_utc \u003d datetime.fromtimestamp(file_x_ts_flt, UTC)"},{"line_number":480,"context_line":"                if if_unmodified_since and file_x_ts_utc \u003e if_unmodified_since:"},{"line_number":481,"context_line":"                    return HTTPPreconditionFailed(request\u003drequest)"},{"line_number":482,"context_line":"                try:"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F%2BzL8%3D","line":479,"in_reply_to":"AAAATn%2F%2B1Ac%3D","updated":"2013-11-20 01:30:09.000000000","message":"Yes, you right. So the comparing logic is correct not to return 412 in that case.","commit_id":"21739d63aa299824ae65d9ccdf52bf3ef079ee3c"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"c3b494fefadab1701c0b617ec887b5b5420d2c50","unresolved":false,"context_lines":[{"line_number":484,"context_line":"                except (OverflowError, ValueError):"},{"line_number":485,"context_line":"                    # catches timestamps before the epoch"},{"line_number":486,"context_line":"                    return HTTPPreconditionFailed(request\u003drequest)"},{"line_number":487,"context_line":"                if if_modified_since and file_x_ts_utc \u003c\u003d if_modified_since:"},{"line_number":488,"context_line":"                    return HTTPNotModified(request\u003drequest)"},{"line_number":489,"context_line":"                keep_cache \u003d (self.keep_cache_private or"},{"line_number":490,"context_line":"                              (\u0027X-Auth-Token\u0027 not in request.headers and"}],"source_content_type":"text/x-python","patch_set":14,"id":"AAAATn%2F9zUk%3D","line":487,"updated":"2013-12-05 19:02:29.000000000","message":"Can you add a unit test that also fails if this change is not present? When I undid this change no unit or functional tests failed for me.","commit_id":"b9c39048b060b83e3a6400c8377618614aa572ad"}],"swift/proxy/controllers/obj.py":[{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"c3b494fefadab1701c0b617ec887b5b5420d2c50","unresolved":false,"context_lines":[{"line_number":1170,"context_line":"                resp.headers[\u0027X-Copied-From-Last-Modified\u0027] \u003d \\"},{"line_number":1171,"context_line":"                    source_resp.headers[\u0027last-modified\u0027]"},{"line_number":1172,"context_line":"            copy_headers_into(req, resp)"},{"line_number":1173,"context_line":"        resp.last_modified \u003d math.ceil(float(req.headers[\u0027X-Timestamp\u0027]))"},{"line_number":1174,"context_line":"        return resp"},{"line_number":1175,"context_line":""},{"line_number":1176,"context_line":"    @public"}],"source_content_type":"text/x-python","patch_set":14,"id":"AAAATn%2F9zSY%3D","line":1173,"updated":"2013-12-05 19:02:29.000000000","message":"Can you add a unit test that fails without this change in place?\n\nIt is nice that the functional tests catch this, but it is a bit more convenient for developers to catch things in the unit tests first.","commit_id":"b9c39048b060b83e3a6400c8377618614aa572ad"}],"test/functional/tests.py":[{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"5a82ae2f5963be475006f7000903d390789455b3","unresolved":false,"context_lines":[{"line_number":1636,"context_line":""},{"line_number":1637,"context_line":"        last_modified \u003d info[\u0027last_modified\u0027]"},{"line_number":1638,"context_line":""},{"line_number":1639,"context_line":"        hdrs \u003d {\u0027If-Modified-Since\u0027: last_modified}"},{"line_number":1640,"context_line":""},{"line_number":1641,"context_line":"        self.assertRaises(ResponseError, file.read, hdrs\u003dhdrs)"},{"line_number":1642,"context_line":"        self.assert_status(304)"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FRlw%3D","line":1639,"updated":"2013-11-11 21:44:00.000000000","message":"Again, last_modified is not the exact timestamp of the file, so we cannot expect this to work currently (not sure what we can reasonably do to make it work).\n\nAdding one to the last_modified timestamp might be a sufficient work-around.","commit_id":"5a3ca173df7461737bff0a63d25f2e7a13ece9ef"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"7a7f629d101f3176043de38824b4905dcf99d08d","unresolved":false,"context_lines":[{"line_number":1620,"context_line":"            self.assertRaises(ResponseError, file_item.read, hdrs\u003dhdrs)"},{"line_number":1621,"context_line":"            self.assert_status(412)"},{"line_number":1622,"context_line":""},{"line_number":1623,"context_line":"    def testLastModified(self):"},{"line_number":1624,"context_line":"        file_name \u003d Utils.create_name()"},{"line_number":1625,"context_line":"        content_type \u003d Utils.create_name()"},{"line_number":1626,"context_line":""}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAATn%2F93K4%3D","line":1623,"updated":"2013-12-05 05:37:49.000000000","message":"Does this test verify both HEAD and GET method behaviors?","commit_id":"5800a214d5b1aed4bcdc1d7814c00dcaa15d8d48"}],"test/unit/obj/test_server.py":[{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"5a82ae2f5963be475006f7000903d390789455b3","unresolved":false,"context_lines":[{"line_number":940,"context_line":"        self.assertEquals(resp.status_int, 304)"},{"line_number":941,"context_line":"        self.assertEquals(resp.etag, etag)"},{"line_number":942,"context_line":""},{"line_number":943,"context_line":"    def test_GET_if_modified_since(self):"},{"line_number":944,"context_line":"        timestamp \u003d normalize_timestamp(time())"},{"line_number":945,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027PUT\u0027},"},{"line_number":946,"context_line":"                            headers\u003d{"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FRl8%3D","line":943,"updated":"2013-11-11 21:44:00.000000000","message":"Using int(time()) here will result in the test being able to specify an if-modifed-since header that matches the object\u0027s on-disk timestamp exactly.","commit_id":"5a3ca173df7461737bff0a63d25f2e7a13ece9ef"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"5a82ae2f5963be475006f7000903d390789455b3","unresolved":false,"context_lines":[{"line_number":984,"context_line":"        self.assertEquals(resp.status_int, 304)"},{"line_number":985,"context_line":""},{"line_number":986,"context_line":"    def test_GET_if_unmodified_since(self):"},{"line_number":987,"context_line":"        timestamp \u003d normalize_timestamp(time())"},{"line_number":988,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027PUT\u0027},"},{"line_number":989,"context_line":"                            headers\u003d{"},{"line_number":990,"context_line":"                                \u0027X-Timestamp\u0027: timestamp,"}],"source_content_type":"text/x-python","patch_set":3,"id":"AAAATn%2F%2FRmU%3D","line":987,"updated":"2013-11-11 21:44:00.000000000","message":"Using int(time()) here will result in the test being able to specify an if-unmodifed-since header that matches the object\u0027s on-disk timestamp exactly.","commit_id":"5a3ca173df7461737bff0a63d25f2e7a13ece9ef"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"0b09ce9e5f0538c88b894319954e2fe7ba90457d","unresolved":false,"context_lines":[{"line_number":976,"context_line":"        resp \u003d req.get_response(self.object_controller)"},{"line_number":977,"context_line":"        self.assertEquals(resp.status_int, 304)"},{"line_number":978,"context_line":""},{"line_number":979,"context_line":"    def test_GET_if_unmodified_since(self):"},{"line_number":980,"context_line":"        timestamp \u003d normalize_timestamp(time())"},{"line_number":981,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027PUT\u0027},"},{"line_number":982,"context_line":"                            headers\u003d{"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F%2B1AE%3D","side":"PARENT","line":979,"updated":"2013-11-19 16:41:52.000000000","message":"Why was this test removed?","commit_id":"deaddf003bef0fcb2f14ec90b0ea774aad3f1458"},{"author":{"_account_id":8231,"name":"Kiyoung Jung","email":"kiyoung.jung@kt.com","username":"jackieyoung"},"change_message_id":"b6b32fa12d86f80f6abef084d3f655c962eaa48c","unresolved":false,"context_lines":[{"line_number":976,"context_line":"        resp \u003d req.get_response(self.object_controller)"},{"line_number":977,"context_line":"        self.assertEquals(resp.status_int, 304)"},{"line_number":978,"context_line":""},{"line_number":979,"context_line":"    def test_GET_if_unmodified_since(self):"},{"line_number":980,"context_line":"        timestamp \u003d normalize_timestamp(time())"},{"line_number":981,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027PUT\u0027},"},{"line_number":982,"context_line":"                            headers\u003d{"}],"source_content_type":"text/x-python","patch_set":7,"id":"AAAATn%2F%2BzLw%3D","side":"PARENT","line":979,"in_reply_to":"AAAATn%2F%2B1AE%3D","updated":"2013-11-20 01:30:09.000000000","message":"That was my mistake. Thank you for the comment. I\u0027ll restore them.","commit_id":"deaddf003bef0fcb2f14ec90b0ea774aad3f1458"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"7a7f629d101f3176043de38824b4905dcf99d08d","unresolved":false,"context_lines":[{"line_number":984,"context_line":"                     gmtime(math.ceil(float(timestamp))))"},{"line_number":985,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":986,"context_line":"                            headers\u003d{\u0027If-Unmodified-Since\u0027: since})"},{"line_number":987,"context_line":"        resp \u003d self.object_controller.GET(req)"},{"line_number":988,"context_line":"        self.assertEquals(resp.status_int, 200)"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":"    def test_GET_if_unmodified_since(self):"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAATn%2F93Ko%3D","line":987,"updated":"2013-12-05 05:37:49.000000000","message":"Can you repeat this for a HEAD method?","commit_id":"5800a214d5b1aed4bcdc1d7814c00dcaa15d8d48"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"7a7f629d101f3176043de38824b4905dcf99d08d","unresolved":false,"context_lines":[{"line_number":985,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":986,"context_line":"                            headers\u003d{\u0027If-Unmodified-Since\u0027: since})"},{"line_number":987,"context_line":"        resp \u003d self.object_controller.GET(req)"},{"line_number":988,"context_line":"        self.assertEquals(resp.status_int, 200)"},{"line_number":989,"context_line":""},{"line_number":990,"context_line":"    def test_GET_if_unmodified_since(self):"},{"line_number":991,"context_line":"        timestamp \u003d normalize_timestamp(time())"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAATn%2F93KM%3D","line":988,"updated":"2013-12-05 05:37:49.000000000","message":"When I undo your changes, this part of the test does not fail, can you find out why?","commit_id":"5800a214d5b1aed4bcdc1d7814c00dcaa15d8d48"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"7a7f629d101f3176043de38824b4905dcf99d08d","unresolved":false,"context_lines":[{"line_number":1028,"context_line":"                     gmtime(math.ceil(float(timestamp))))"},{"line_number":1029,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":1030,"context_line":"                            headers\u003d{\u0027If-Unmodified-Since\u0027: since})"},{"line_number":1031,"context_line":"        resp \u003d self.object_controller.GET(req)"},{"line_number":1032,"context_line":"        self.assertEquals(resp.status_int, 200)"},{"line_number":1033,"context_line":""},{"line_number":1034,"context_line":"    def test_GET_quarantine(self):"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAATn%2F93Ks%3D","line":1031,"updated":"2013-12-05 05:37:49.000000000","message":"Can you repeat this for a HEAD method?","commit_id":"5800a214d5b1aed4bcdc1d7814c00dcaa15d8d48"},{"author":{"_account_id":6198,"name":"Peter Portante","email":"peter.a.portante@gmail.com","username":"peter-a-portante"},"change_message_id":"7a7f629d101f3176043de38824b4905dcf99d08d","unresolved":false,"context_lines":[{"line_number":1029,"context_line":"        req \u003d Request.blank(\u0027/sda1/p/a/c/o\u0027, environ\u003d{\u0027REQUEST_METHOD\u0027: \u0027GET\u0027},"},{"line_number":1030,"context_line":"                            headers\u003d{\u0027If-Unmodified-Since\u0027: since})"},{"line_number":1031,"context_line":"        resp \u003d self.object_controller.GET(req)"},{"line_number":1032,"context_line":"        self.assertEquals(resp.status_int, 200)"},{"line_number":1033,"context_line":""},{"line_number":1034,"context_line":"    def test_GET_quarantine(self):"},{"line_number":1035,"context_line":"        # Test swift.obj.server.ObjectController.GET"}],"source_content_type":"text/x-python","patch_set":13,"id":"AAAATn%2F93KE%3D","line":1032,"updated":"2013-12-05 05:37:49.000000000","message":"Same as above, this test does not fail when I revert to the original code.","commit_id":"5800a214d5b1aed4bcdc1d7814c00dcaa15d8d48"}]}
