Merge "change the last-modified header value with valid one"

This commit is contained in:
Jenkins 2013-12-20 00:57:36 +00:00 committed by Gerrit Code Review
commit 7f456ef35f
6 changed files with 140 additions and 7 deletions
swift
obj
proxy/controllers
test

@ -21,6 +21,7 @@ import multiprocessing
import time import time
import traceback import traceback
import socket import socket
import math
from datetime import datetime from datetime import datetime
from swift import gettext_ as _ from swift import gettext_ as _
from hashlib import md5 from hashlib import md5
@ -492,7 +493,7 @@ class ObjectController(object):
except (OverflowError, ValueError): except (OverflowError, ValueError):
# catches timestamps before the epoch # catches timestamps before the epoch
return HTTPPreconditionFailed(request=request) return HTTPPreconditionFailed(request=request)
if if_modified_since and file_x_ts_utc < if_modified_since: if if_modified_since and file_x_ts_utc <= if_modified_since:
return HTTPNotModified(request=request) return HTTPNotModified(request=request)
keep_cache = (self.keep_cache_private or keep_cache = (self.keep_cache_private or
('X-Auth-Token' not in request.headers and ('X-Auth-Token' not in request.headers and
@ -507,7 +508,7 @@ class ObjectController(object):
key.lower() in self.allowed_headers: key.lower() in self.allowed_headers:
response.headers[key] = value response.headers[key] = value
response.etag = metadata['ETag'] response.etag = metadata['ETag']
response.last_modified = file_x_ts_flt response.last_modified = math.ceil(file_x_ts_flt)
response.content_length = obj_size response.content_length = obj_size
try: try:
response.content_encoding = metadata[ response.content_encoding = metadata[
@ -549,7 +550,7 @@ class ObjectController(object):
response.headers[key] = value response.headers[key] = value
response.etag = metadata['ETag'] response.etag = metadata['ETag']
ts = metadata['X-Timestamp'] ts = metadata['X-Timestamp']
response.last_modified = float(ts) response.last_modified = math.ceil(float(ts))
# Needed for container sync feature # Needed for container sync feature
response.headers['X-Timestamp'] = ts response.headers['X-Timestamp'] = ts
response.content_length = int(metadata['Content-Length']) response.content_length = int(metadata['Content-Length'])

@ -28,6 +28,7 @@ import itertools
import mimetypes import mimetypes
import re import re
import time import time
import math
from datetime import datetime from datetime import datetime
from swift import gettext_ as _ from swift import gettext_ as _
from urllib import unquote, quote from urllib import unquote, quote
@ -1164,7 +1165,7 @@ class ObjectController(Controller):
resp.headers['X-Copied-From-Last-Modified'] = \ resp.headers['X-Copied-From-Last-Modified'] = \
source_resp.headers['last-modified'] source_resp.headers['last-modified']
copy_headers_into(req, resp) copy_headers_into(req, resp)
resp.last_modified = float(req.headers['X-Timestamp']) resp.last_modified = math.ceil(float(req.headers['X-Timestamp']))
return resp return resp
@public @public

@ -723,7 +723,8 @@ class File(Base):
else: else:
raise RuntimeError raise RuntimeError
def write(self, data='', hdrs={}, parms={}, callback=None, cfg={}): def write(self, data='', hdrs={}, parms={}, callback=None, cfg={},
return_resp=False):
block_size = 2 ** 20 block_size = 2 ** 20
if isinstance(data, file): if isinstance(data, file):
@ -767,6 +768,9 @@ class File(Base):
pass pass
self.md5 = self.compute_md5sum(data) self.md5 = self.compute_md5sum(data)
if return_resp:
return self.conn.response
return True return True
def write_random(self, size=None, hdrs={}, parms={}, cfg={}): def write_random(self, size=None, hdrs={}, parms={}, cfg={}):
@ -776,3 +780,12 @@ class File(Base):
self.conn.make_path(self.path)) self.conn.make_path(self.path))
self.md5 = self.compute_md5sum(StringIO.StringIO(data)) self.md5 = self.compute_md5sum(StringIO.StringIO(data))
return data return data
def write_random_return_resp(self, size=None, hdrs={}, parms={}, cfg={}):
data = self.random_data(size)
resp = self.write(data, hdrs=hdrs, parms=parms, cfg=cfg,
return_resp=True)
if not resp:
raise ResponseError(self.conn.response)
self.md5 = self.compute_md5sum(StringIO.StringIO(data))
return resp

@ -1732,6 +1732,28 @@ class TestFileComparison(Base):
self.assertRaises(ResponseError, file_item.read, hdrs=hdrs) self.assertRaises(ResponseError, file_item.read, hdrs=hdrs)
self.assert_status(412) self.assert_status(412)
def testLastModified(self):
file_name = Utils.create_name()
content_type = Utils.create_name()
file = self.env.container.file(file_name)
file.content_type = content_type
resp = file.write_random_return_resp(self.env.file_size)
put_last_modified = resp.getheader('last-modified')
file = self.env.container.file(file_name)
info = file.info()
self.assert_('last_modified' in info)
last_modified = info['last_modified']
self.assertEqual(put_last_modified, info['last_modified'])
hdrs = {'If-Modified-Since': last_modified}
self.assertRaises(ResponseError, file.read, hdrs=hdrs)
self.assert_status(304)
hdrs = {'If-Unmodified-Since': last_modified}
self.assert_(file.read(hdrs=hdrs))
class TestFileComparisonUTF8(Base2, TestFileComparison): class TestFileComparisonUTF8(Base2, TestFileComparison):
set_up = False set_up = False

@ -21,6 +21,7 @@ import operator
import os import os
import mock import mock
import unittest import unittest
import math
from shutil import rmtree from shutil import rmtree
from StringIO import StringIO from StringIO import StringIO
from time import gmtime, strftime, time from time import gmtime, strftime, time
@ -739,7 +740,8 @@ class TestObjectController(unittest.TestCase):
self.assertEquals(resp.headers['content-type'], 'application/x-test') self.assertEquals(resp.headers['content-type'], 'application/x-test')
self.assertEquals( self.assertEquals(
resp.headers['last-modified'], resp.headers['last-modified'],
strftime('%a, %d %b %Y %H:%M:%S GMT', gmtime(float(timestamp)))) strftime('%a, %d %b %Y %H:%M:%S GMT',
gmtime(math.ceil(float(timestamp)))))
self.assertEquals(resp.headers['etag'], self.assertEquals(resp.headers['etag'],
'"0b4c12d7e0a73840c1c4f148fda3b037"') '"0b4c12d7e0a73840c1c4f148fda3b037"')
self.assertEquals(resp.headers['x-object-meta-1'], 'One') self.assertEquals(resp.headers['x-object-meta-1'], 'One')
@ -841,7 +843,8 @@ class TestObjectController(unittest.TestCase):
self.assertEquals(resp.headers['content-type'], 'application/x-test') self.assertEquals(resp.headers['content-type'], 'application/x-test')
self.assertEquals( self.assertEquals(
resp.headers['last-modified'], resp.headers['last-modified'],
strftime('%a, %d %b %Y %H:%M:%S GMT', gmtime(float(timestamp)))) strftime('%a, %d %b %Y %H:%M:%S GMT',
gmtime(math.ceil(float(timestamp)))))
self.assertEquals(resp.headers['etag'], self.assertEquals(resp.headers['etag'],
'"0b4c12d7e0a73840c1c4f148fda3b037"') '"0b4c12d7e0a73840c1c4f148fda3b037"')
self.assertEquals(resp.headers['x-object-meta-1'], 'One') self.assertEquals(resp.headers['x-object-meta-1'], 'One')
@ -1043,6 +1046,37 @@ class TestObjectController(unittest.TestCase):
resp = req.get_response(self.object_controller) resp = req.get_response(self.object_controller)
self.assertEquals(resp.status_int, 304) self.assertEquals(resp.status_int, 304)
req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'HEAD'})
resp = req.get_response(self.object_controller)
since = resp.headers['Last-Modified']
self.assertEquals(since, strftime('%a, %d %b %Y %H:%M:%S GMT',
gmtime(math.ceil(float(timestamp)))))
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'},
headers={'If-Modified-Since': since})
resp = self.object_controller.GET(req)
self.assertEquals(resp.status_int, 304)
timestamp = normalize_timestamp(int(time()))
req = Request.blank('/sda1/p/a/c/o2',
environ={'REQUEST_METHOD': 'PUT'},
headers={
'X-Timestamp': timestamp,
'Content-Type': 'application/octet-stream',
'Content-Length': '4'})
req.body = 'test'
resp = req.get_response(self.object_controller)
self.assertEquals(resp.status_int, 201)
since = strftime('%a, %d %b %Y %H:%M:%S GMT',
gmtime(float(timestamp)))
req = Request.blank('/sda1/p/a/c/o2',
environ={'REQUEST_METHOD': 'GET'},
headers={'If-Modified-Since': since})
resp = req.get_response(self.object_controller)
self.assertEquals(resp.status_int, 304)
def test_GET_if_unmodified_since(self): def test_GET_if_unmodified_since(self):
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'}, req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
@ -1079,6 +1113,18 @@ class TestObjectController(unittest.TestCase):
resp = req.get_response(self.object_controller) resp = req.get_response(self.object_controller)
self.assertEquals(resp.status_int, 200) self.assertEquals(resp.status_int, 200)
req = Request.blank('/sda1/p/a/c/o',
environ={'REQUEST_METHOD': 'HEAD'})
resp = req.get_response(self.object_controller)
since = resp.headers['Last-Modified']
self.assertEquals(since, strftime('%a, %d %b %Y %H:%M:%S GMT',
gmtime(math.ceil(float(timestamp)))))
req = Request.blank('/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'GET'},
headers={'If-Unmodified-Since': since})
resp = self.object_controller.GET(req)
self.assertEquals(resp.status_int, 200)
def test_GET_quarantine(self): def test_GET_quarantine(self):
# Test swift.obj.server.ObjectController.GET # Test swift.obj.server.ObjectController.GET
timestamp = normalize_timestamp(time()) timestamp = normalize_timestamp(time())

@ -1036,6 +1036,56 @@ class TestObjectController(unittest.TestCase):
finally: finally:
swift.proxy.controllers.obj.MAX_FILE_SIZE = MAX_FILE_SIZE swift.proxy.controllers.obj.MAX_FILE_SIZE = MAX_FILE_SIZE
def test_PUT_last_modified(self):
prolis = _test_sockets[0]
sock = connect_tcp(('localhost', prolis.getsockname()[1]))
fd = sock.makefile()
fd.write('PUT /v1/a/c/o.last_modified HTTP/1.1\r\n'
'Host: localhost\r\nConnection: close\r\n'
'X-Storage-Token: t\r\nContent-Length: 0\r\n\r\n')
fd.flush()
headers = readuntil2crlfs(fd)
exp = 'HTTP/1.1 201'
lm_hdr = 'Last-Modified: '
self.assertEqual(headers[:len(exp)], exp)
last_modified_put = [line for line in headers.split('\r\n')
if lm_hdr in line][0][len(lm_hdr):]
sock = connect_tcp(('localhost', prolis.getsockname()[1]))
fd = sock.makefile()
fd.write('HEAD /v1/a/c/o.last_modified HTTP/1.1\r\n'
'Host: localhost\r\nConnection: close\r\n'
'X-Storage-Token: t\r\n\r\n')
fd.flush()
headers = readuntil2crlfs(fd)
exp = 'HTTP/1.1 200'
self.assertEqual(headers[:len(exp)], exp)
last_modified_head = [line for line in headers.split('\r\n')
if lm_hdr in line][0][len(lm_hdr):]
self.assertEqual(last_modified_put, last_modified_head)
sock = connect_tcp(('localhost', prolis.getsockname()[1]))
fd = sock.makefile()
fd.write('GET /v1/a/c/o.last_modified HTTP/1.1\r\n'
'Host: localhost\r\nConnection: close\r\n'
'If-Modified-Since: %s\r\n'
'X-Storage-Token: t\r\n\r\n' % last_modified_put)
fd.flush()
headers = readuntil2crlfs(fd)
exp = 'HTTP/1.1 304'
self.assertEqual(headers[:len(exp)], exp)
sock = connect_tcp(('localhost', prolis.getsockname()[1]))
fd = sock.makefile()
fd.write('GET /v1/a/c/o.last_modified HTTP/1.1\r\n'
'Host: localhost\r\nConnection: close\r\n'
'If-Unmodified-Since: %s\r\n'
'X-Storage-Token: t\r\n\r\n' % last_modified_put)
fd.flush()
headers = readuntil2crlfs(fd)
exp = 'HTTP/1.1 200'
self.assertEqual(headers[:len(exp)], exp)
def test_expirer_DELETE_on_versioned_object(self): def test_expirer_DELETE_on_versioned_object(self):
test_errors = [] test_errors = []