def test_check_delete_headers_removes_delete_after(self): ts = utils.Timestamp.now() headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(ts) + 40), 'X-Timestamp': ts.internal} req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertNotIn('X-Delete-After', req.headers) self.assertEqual(req.headers['X-Delete-At'], str(int(ts) + 42))
def test_check_delete_headers_sets_delete_at(self): ts = utils.Timestamp.now() expected = str(int(ts) + 1000) # check delete-at is passed through headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-At': expected, 'X-Timestamp': ts.internal } req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) self.assertEqual(req.headers['X-Delete-At'], expected) # check delete-after is converted to delete-at headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Timestamp': ts.internal } req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) expected = str(int(ts) + 42) self.assertEqual(req.headers['X-Delete-At'], expected) # check delete-after takes precedence over delete-at headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(ts) + 40), 'X-Timestamp': ts.internal } req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) self.assertEqual(req.headers['X-Delete-At'], expected) headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(ts) + 44), 'X-Timestamp': ts.internal } req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) self.assertEqual(req.headers['X-Delete-At'], expected)
def test_check_delete_headers_sets_delete_at(self): t = time.time() + 1000 # check delete-at is passed through headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-At': str(int(t)) } req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) self.assertEqual(req.headers['X-Delete-At'], str(int(t))) # check delete-after is converted to delete-at headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42' } req = Request.blank('/', headers=headers) with mock.patch('time.time', lambda: t): constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) expected = str(int(t) + 42) self.assertEqual(req.headers['X-Delete-At'], expected) # check delete-after takes precedence over delete-at headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(t) + 40) } req = Request.blank('/', headers=headers) with mock.patch('time.time', lambda: t): constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) self.assertEqual(req.headers['X-Delete-At'], expected) headers = { 'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(t) + 44) } req = Request.blank('/', headers=headers) with mock.patch('time.time', lambda: t): constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) self.assertEqual(req.headers['X-Delete-At'], expected)
def test_check_delete_headers_sets_delete_at(self): ts = utils.Timestamp.now() expected = str(int(ts) + 1000) # check delete-at is passed through headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-At': expected, 'X-Timestamp': ts.internal} req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) self.assertEqual(req.headers['X-Delete-At'], expected) # check delete-after is converted to delete-at headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Timestamp': ts.internal} req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) expected = str(int(ts) + 42) self.assertEqual(req.headers['X-Delete-At'], expected) # check delete-after takes precedence over delete-at headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(ts) + 40), 'X-Timestamp': ts.internal} req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) self.assertEqual(req.headers['X-Delete-At'], expected) headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(ts) + 44), 'X-Timestamp': ts.internal} req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertIn('X-Delete-At', req.headers) self.assertEqual(req.headers['X-Delete-At'], expected)
def test_check_delete_headers_sets_delete_at(self): t = time.time() + 1000 # check delete-at is passed through headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-At': str(int(t))} req = Request.blank('/', headers=headers) constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) self.assertEqual(req.headers['X-Delete-At'], str(int(t))) # check delete-after is converted to delete-at headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42'} req = Request.blank('/', headers=headers) with mock.patch('time.time', lambda: t): constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) expected = str(int(t) + 42) self.assertEqual(req.headers['X-Delete-At'], expected) # check delete-after takes precedence over delete-at headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(t) + 40)} req = Request.blank('/', headers=headers) with mock.patch('time.time', lambda: t): constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) self.assertEqual(req.headers['X-Delete-At'], expected) headers = {'Content-Length': '0', 'Content-Type': 'text/plain', 'X-Delete-After': '42', 'X-Delete-At': str(int(t) + 44)} req = Request.blank('/', headers=headers) with mock.patch('time.time', lambda: t): constraints.check_delete_headers(req) self.assertTrue('X-Delete-At' in req.headers) self.assertEqual(req.headers['X-Delete-At'], expected)
def test_check_delete_headers_sets_delete_at(self): t = time.time() + 1000 # check delete-at is passed through headers = {"Content-Length": "0", "Content-Type": "text/plain", "X-Delete-At": str(int(t))} req = Request.blank("/", headers=headers) constraints.check_delete_headers(req) self.assertTrue("X-Delete-At" in req.headers) self.assertEqual(req.headers["X-Delete-At"], str(int(t))) # check delete-after is converted to delete-at headers = {"Content-Length": "0", "Content-Type": "text/plain", "X-Delete-After": "42"} req = Request.blank("/", headers=headers) with mock.patch("time.time", lambda: t): constraints.check_delete_headers(req) self.assertTrue("X-Delete-At" in req.headers) expected = str(int(t) + 42) self.assertEqual(req.headers["X-Delete-At"], expected) # check delete-after takes precedence over delete-at headers = { "Content-Length": "0", "Content-Type": "text/plain", "X-Delete-After": "42", "X-Delete-At": str(int(t) + 40), } req = Request.blank("/", headers=headers) with mock.patch("time.time", lambda: t): constraints.check_delete_headers(req) self.assertTrue("X-Delete-At" in req.headers) self.assertEqual(req.headers["X-Delete-At"], expected) headers = { "Content-Length": "0", "Content-Type": "text/plain", "X-Delete-After": "42", "X-Delete-At": str(int(t) + 44), } req = Request.blank("/", headers=headers) with mock.patch("time.time", lambda: t): constraints.check_delete_headers(req) self.assertTrue("X-Delete-At" in req.headers) self.assertEqual(req.headers["X-Delete-At"], expected)
def _config_obj_expiration(self, req): delete_at_container = None delete_at_part = None delete_at_nodes = None req = constraints.check_delete_headers(req) if 'x-delete-at' in req.headers: x_delete_at = int(normalize_delete_at_timestamp( int(req.headers['x-delete-at']))) req.environ.setdefault('swift.log_info', []).append( 'x-delete-at:%s' % x_delete_at) delete_at_container = get_expirer_container( x_delete_at, self.app.expiring_objects_container_divisor, self.account_name, self.container_name, self.object_name) delete_at_part, delete_at_nodes = \ self.app.container_ring.get_nodes( self.app.expiring_objects_account, delete_at_container) return req, delete_at_container, delete_at_part, delete_at_nodes
def _config_obj_expiration(self, req): delete_at_container = None delete_at_part = None delete_at_nodes = None req = constraints.check_delete_headers(req) if 'x-delete-at' in req.headers: x_delete_at = int( normalize_delete_at_timestamp(int(req.headers['x-delete-at']))) req.environ.setdefault('swift.log_info', []).append('x-delete-at:%s' % x_delete_at) delete_at_container = get_expirer_container( x_delete_at, self.app.expiring_objects_container_divisor, self.account_name, self.container_name, self.object_name) delete_at_part, delete_at_nodes = \ self.app.container_ring.get_nodes( self.app.expiring_objects_account, delete_at_container) return req, delete_at_container, delete_at_part, delete_at_nodes
def test_check_delete_headers(self): # x-delete-at value should be relative to the request timestamp rather # than time.time() so separate the two to ensure the checks are robust ts = utils.Timestamp(time.time() + 100) # X-Delete-After headers = {'X-Delete-After': '600', 'X-Timestamp': ts.internal} req = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertIsInstance(req, Request) self.assertIn('x-delete-at', req.headers) self.assertNotIn('x-delete-after', req.headers) expected_delete_at = str(int(ts) + 600) self.assertEqual(req.headers.get('X-Delete-At'), expected_delete_at) headers = {'X-Delete-After': 'abc', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-After', cm.exception.body) headers = {'X-Delete-After': '60.1', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-After', cm.exception.body) headers = {'X-Delete-After': '-1', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-After in past', cm.exception.body) headers = {'X-Delete-After': '0', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-After in past', cm.exception.body) # x-delete-after = 0 disallowed when it results in x-delete-at equal to # the timestamp headers = { 'X-Delete-After': '0', 'X-Timestamp': utils.Timestamp(int(ts)).internal } with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-After in past', cm.exception.body) # X-Delete-At delete_at = str(int(ts) + 100) headers = {'X-Delete-At': delete_at, 'X-Timestamp': ts.internal} req = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertIsInstance(req, Request) self.assertIn('x-delete-at', req.headers) self.assertEqual(req.headers.get('X-Delete-At'), delete_at) headers = {'X-Delete-At': 'abc', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-At', cm.exception.body) delete_at = str(int(ts) + 100) + '.1' headers = {'X-Delete-At': delete_at, 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-At', cm.exception.body) delete_at = str(int(ts) - 1) headers = {'X-Delete-At': delete_at, 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-At in past', cm.exception.body) # x-delete-at disallowed when exactly equal to timestamp delete_at = str(int(ts)) headers = { 'X-Delete-At': delete_at, 'X-Timestamp': utils.Timestamp(int(ts)).internal } with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-At in past', cm.exception.body)
def test_check_delete_headers(self): # X-Delete-After headers = {'X-Delete-After': '60'} resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertTrue(isinstance(resp, Request)) self.assertTrue('x-delete-at' in resp.headers) headers = {'X-Delete-After': 'abc'} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('Non-integer X-Delete-After' in e.body) else: self.fail("Should have failed with HTTPBadRequest") headers = {'X-Delete-After': '60.1'} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('Non-integer X-Delete-After' in e.body) else: self.fail("Should have failed with HTTPBadRequest") headers = {'X-Delete-After': '-1'} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('X-Delete-After in past' in e.body) else: self.fail("Should have failed with HTTPBadRequest") # X-Delete-At t = str(int(time.time() + 100)) headers = {'X-Delete-At': t} resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertTrue(isinstance(resp, Request)) self.assertTrue('x-delete-at' in resp.headers) self.assertEquals(resp.headers.get('X-Delete-At'), t) headers = {'X-Delete-At': 'abc'} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('Non-integer X-Delete-At' in e.body) else: self.fail("Should have failed with HTTPBadRequest") t = str(int(time.time() + 100)) + '.1' headers = {'X-Delete-At': t} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('Non-integer X-Delete-At' in e.body) else: self.fail("Should have failed with HTTPBadRequest") t = str(int(time.time())) headers = {'X-Delete-At': t} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('X-Delete-At in past' in e.body) else: self.fail("Should have failed with HTTPBadRequest") t = str(int(time.time() - 1)) headers = {'X-Delete-At': t} try: resp = constraints.check_delete_headers( Request.blank('/', headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue('X-Delete-At in past' in e.body) else: self.fail("Should have failed with HTTPBadRequest")
def test_check_delete_headers(self): # x-delete-at value should be relative to the request timestamp rather # than time.time() so separate the two to ensure the checks are robust ts = time.time() + 100 # X-Delete-After headers = {'X-Delete-After': '600', 'X-Timestamp': str(ts)} req = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertIsInstance(req, Request) self.assertIn('x-delete-at', req.headers) self.assertNotIn('x-delete-after', req.headers) expected_delete_at = str(int(ts) + 600) self.assertEqual(req.headers.get('X-Delete-At'), expected_delete_at) headers = {'X-Delete-After': 'abc', 'X-Timestamp': str(time.time())} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('Non-integer X-Delete-After', cm.exception.body) headers = {'X-Delete-After': '60.1', 'X-Timestamp': str(time.time())} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('Non-integer X-Delete-After', cm.exception.body) headers = {'X-Delete-After': '-1', 'X-Timestamp': str(time.time())} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('X-Delete-After in past', cm.exception.body) headers = {'X-Delete-After': '0', 'X-Timestamp': str(time.time())} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('X-Delete-After in past', cm.exception.body) # X-Delete-At delete_at = str(int(ts + 100)) headers = {'X-Delete-At': delete_at, 'X-Timestamp': str(ts)} req = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertIsInstance(req, Request) self.assertIn('x-delete-at', req.headers) self.assertEqual(req.headers.get('X-Delete-At'), delete_at) headers = {'X-Delete-At': 'abc', 'X-Timestamp': str(ts)} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('Non-integer X-Delete-At', cm.exception.body) delete_at = str(int(ts + 100)) + '.1' headers = {'X-Delete-At': delete_at, 'X-Timestamp': str(ts)} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('Non-integer X-Delete-At', cm.exception.body) delete_at = str(int(ts - 1)) headers = {'X-Delete-At': delete_at, 'X-Timestamp': str(ts)} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn('X-Delete-At in past', cm.exception.body)
def test_check_delete_headers(self): # X-Delete-After headers = {"X-Delete-After": "60"} resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) self.assertTrue(isinstance(resp, Request)) self.assertTrue("x-delete-at" in resp.headers) headers = {"X-Delete-After": "abc"} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("Non-integer X-Delete-After" in e.body) else: self.fail("Should have failed with HTTPBadRequest") headers = {"X-Delete-After": "60.1"} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("Non-integer X-Delete-After" in e.body) else: self.fail("Should have failed with HTTPBadRequest") headers = {"X-Delete-After": "-1"} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("X-Delete-After in past" in e.body) else: self.fail("Should have failed with HTTPBadRequest") # X-Delete-At t = str(int(time.time() + 100)) headers = {"X-Delete-At": t} resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) self.assertTrue(isinstance(resp, Request)) self.assertTrue("x-delete-at" in resp.headers) self.assertEquals(resp.headers.get("X-Delete-At"), t) headers = {"X-Delete-At": "abc"} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("Non-integer X-Delete-At" in e.body) else: self.fail("Should have failed with HTTPBadRequest") t = str(int(time.time() + 100)) + ".1" headers = {"X-Delete-At": t} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("Non-integer X-Delete-At" in e.body) else: self.fail("Should have failed with HTTPBadRequest") t = str(int(time.time())) headers = {"X-Delete-At": t} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("X-Delete-At in past" in e.body) else: self.fail("Should have failed with HTTPBadRequest") t = str(int(time.time() - 1)) headers = {"X-Delete-At": t} try: resp = constraints.check_delete_headers(Request.blank("/", headers=headers)) except HTTPException as e: self.assertEquals(e.status_int, HTTP_BAD_REQUEST) self.assertTrue("X-Delete-At in past" in e.body) else: self.fail("Should have failed with HTTPBadRequest")
def test_check_delete_headers(self): # x-delete-at value should be relative to the request timestamp rather # than time.time() so separate the two to ensure the checks are robust ts = utils.Timestamp(time.time() + 100) # X-Delete-After headers = {'X-Delete-After': '600', 'X-Timestamp': ts.internal} req = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertIsInstance(req, Request) self.assertIn('x-delete-at', req.headers) self.assertNotIn('x-delete-after', req.headers) expected_delete_at = str(int(ts) + 600) self.assertEqual(req.headers.get('X-Delete-At'), expected_delete_at) headers = {'X-Delete-After': 'abc', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-After', cm.exception.body) headers = {'X-Delete-After': '60.1', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-After', cm.exception.body) headers = {'X-Delete-After': '-1', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-After in past', cm.exception.body) headers = {'X-Delete-After': '0', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-After in past', cm.exception.body) # x-delete-after = 0 disallowed when it results in x-delete-at equal to # the timestamp headers = {'X-Delete-After': '0', 'X-Timestamp': utils.Timestamp(int(ts)).internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-After in past', cm.exception.body) # X-Delete-At delete_at = str(int(ts) + 100) headers = {'X-Delete-At': delete_at, 'X-Timestamp': ts.internal} req = constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertIsInstance(req, Request) self.assertIn('x-delete-at', req.headers) self.assertEqual(req.headers.get('X-Delete-At'), delete_at) headers = {'X-Delete-At': 'abc', 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-At', cm.exception.body) delete_at = str(int(ts) + 100) + '.1' headers = {'X-Delete-At': delete_at, 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'Non-integer X-Delete-At', cm.exception.body) delete_at = str(int(ts) - 1) headers = {'X-Delete-At': delete_at, 'X-Timestamp': ts.internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-At in past', cm.exception.body) # x-delete-at disallowed when exactly equal to timestamp delete_at = str(int(ts)) headers = {'X-Delete-At': delete_at, 'X-Timestamp': utils.Timestamp(int(ts)).internal} with self.assertRaises(HTTPException) as cm: constraints.check_delete_headers( Request.blank('/', headers=headers)) self.assertEqual(cm.exception.status_int, HTTP_BAD_REQUEST) self.assertIn(b'X-Delete-At in past', cm.exception.body)