Merge "Object server PUTs should respect client_timeout"
This commit is contained in:
commit
b9434b5c3e
@ -35,7 +35,7 @@ from swift.common.constraints import check_object_creation, \
|
|||||||
check_float, check_utf8
|
check_float, check_utf8
|
||||||
from swift.common.exceptions import ConnectionTimeout, DiskFileQuarantined, \
|
from swift.common.exceptions import ConnectionTimeout, DiskFileQuarantined, \
|
||||||
DiskFileNotExist, DiskFileCollision, DiskFileNoSpace, DiskFileDeleted, \
|
DiskFileNotExist, DiskFileCollision, DiskFileNoSpace, DiskFileDeleted, \
|
||||||
DiskFileDeviceUnavailable, DiskFileExpired
|
DiskFileDeviceUnavailable, DiskFileExpired, ChunkReadTimeout
|
||||||
from swift.obj import ssync_receiver
|
from swift.obj import ssync_receiver
|
||||||
from swift.common.http import is_success
|
from swift.common.http import is_success
|
||||||
from swift.common.request_helpers import split_and_validate_path, is_user_meta
|
from swift.common.request_helpers import split_and_validate_path, is_user_meta
|
||||||
@ -398,15 +398,23 @@ class ObjectController(object):
|
|||||||
try:
|
try:
|
||||||
with disk_file.create(size=fsize) as writer:
|
with disk_file.create(size=fsize) as writer:
|
||||||
upload_size = 0
|
upload_size = 0
|
||||||
reader = request.environ['wsgi.input'].read
|
|
||||||
for chunk in iter(lambda: reader(self.network_chunk_size), ''):
|
def timeout_reader():
|
||||||
start_time = time.time()
|
with ChunkReadTimeout(self.client_timeout):
|
||||||
if start_time > upload_expiration:
|
return request.environ['wsgi.input'].read(
|
||||||
self.logger.increment('PUT.timeouts')
|
self.network_chunk_size)
|
||||||
return HTTPRequestTimeout(request=request)
|
|
||||||
etag.update(chunk)
|
try:
|
||||||
upload_size = writer.write(chunk)
|
for chunk in iter(lambda: timeout_reader(), ''):
|
||||||
elapsed_time += time.time() - start_time
|
start_time = time.time()
|
||||||
|
if start_time > upload_expiration:
|
||||||
|
self.logger.increment('PUT.timeouts')
|
||||||
|
return HTTPRequestTimeout(request=request)
|
||||||
|
etag.update(chunk)
|
||||||
|
upload_size = writer.write(chunk)
|
||||||
|
elapsed_time += time.time() - start_time
|
||||||
|
except ChunkReadTimeout:
|
||||||
|
return HTTPRequestTimeout(request=request)
|
||||||
if upload_size:
|
if upload_size:
|
||||||
self.logger.transfer_rate(
|
self.logger.transfer_rate(
|
||||||
'PUT.' + device + '.timing', elapsed_time,
|
'PUT.' + device + '.timing', elapsed_time,
|
||||||
|
@ -639,6 +639,28 @@ class TestObjectController(unittest.TestCase):
|
|||||||
'X-Object-Meta-1': 'One',
|
'X-Object-Meta-1': 'One',
|
||||||
'X-Object-Meta-Two': 'Two'})
|
'X-Object-Meta-Two': 'Two'})
|
||||||
|
|
||||||
|
def test_PUT_client_timeout(self):
|
||||||
|
class FakeTimeout(BaseException):
|
||||||
|
def __enter__(self):
|
||||||
|
raise self
|
||||||
|
|
||||||
|
def __exit__(self, typ, value, tb):
|
||||||
|
pass
|
||||||
|
# This is just so the test fails when run on older object server code
|
||||||
|
# instead of exploding.
|
||||||
|
if not hasattr(object_server, 'ChunkReadTimeout'):
|
||||||
|
object_server.ChunkReadTimeout = None
|
||||||
|
with mock.patch.object(object_server, 'ChunkReadTimeout', FakeTimeout):
|
||||||
|
timestamp = normalize_timestamp(time())
|
||||||
|
req = Request.blank(
|
||||||
|
'/sda1/p/a/c/o', environ={'REQUEST_METHOD': 'PUT'},
|
||||||
|
headers={'X-Timestamp': timestamp,
|
||||||
|
'Content-Type': 'text/plain',
|
||||||
|
'Content-Length': '6'})
|
||||||
|
req.environ['wsgi.input'] = StringIO('VERIFY')
|
||||||
|
resp = req.get_response(self.object_controller)
|
||||||
|
self.assertEquals(resp.status_int, 408)
|
||||||
|
|
||||||
def test_PUT_container_connection(self):
|
def test_PUT_container_connection(self):
|
||||||
|
|
||||||
def mock_http_connect(response, with_exc=False):
|
def mock_http_connect(response, with_exc=False):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user