Browse code

* S3/S3.py: send_file() now computes MD5 sum of the file being uploaded, compares with ETag returned by Amazon and retries upload if they don't match.

git-svn-id: https://s3tools.svn.sourceforge.net/svnroot/s3tools/s3cmd/trunk@174 830e0280-6d2a-0410-9c65-932aecc39d9d

Michal Ludvig authored on 2008/04/28 23:32:22
Showing 2 changed files
... ...
@@ -1,3 +1,9 @@
1
+2008-04-28  Michal Ludvig  <michal@logix.cz>
2
+
3
+	* S3/S3.py: send_file() now computes MD5 sum of the file
4
+	  being uploaded, compares with ETag returned by Amazon
5
+	  and retries upload if they don't match.
6
+
1 7
 2008-03-05  Michal Ludvig  <michal@logix.cz>
2 8
 
3 9
 	* s3cmd, S3/S3.py, S3/Utils.py: Throttle upload speed and retry 
... ...
@@ -372,10 +372,12 @@ class S3(object):
372 372
 		conn.endheaders()
373 373
 		file.seek(0)
374 374
 		timestamp_start = time.time()
375
+		md5_hash = md5.new()
375 376
 		size_left = size_total = headers.get("content-length")
376 377
 		while (size_left > 0):
377 378
 			debug("SendFile: Reading up to %d bytes from '%s'" % (self.config.send_chunk, file.name))
378 379
 			data = file.read(self.config.send_chunk)
380
+			md5_hash.update(data)
379 381
 			debug("SendFile: Sending %d bytes to the server" % len(data))
380 382
 			try:
381 383
 				conn.send(data)
... ...
@@ -399,6 +401,7 @@ class S3(object):
399 399
 				(size_total - size_left) * 100 / size_total,
400 400
 				size_total))
401 401
 		timestamp_end = time.time()
402
+		md5_computed = md5_hash.hexdigest()
402 403
 		response = {}
403 404
 		http_response = conn.getresponse()
404 405
 		response["status"] = http_response.status
... ...
@@ -418,6 +421,16 @@ class S3(object):
418 418
 			info("Redirected to: %s" % (redir_hostname))
419 419
 			return self.send_file(request, file)
420 420
 
421
+		debug("MD5 sums: computed=%s, received=%s" % (md5_computed, response["headers"]["etag"]))
422
+		if response["headers"]["etag"].strip('"\'') != md5_hash.hexdigest():
423
+			warning("MD5 Sums don't match!")
424
+			if retries:
425
+				info("Retrying upload.")
426
+				return self.send_file(request, file, throttle, retries - 1)
427
+			else:
428
+				debug("Too many failures. Giving up on '%s'" % (file.name))
429
+				raise S3UploadError
430
+
421 431
 		if response["status"] < 200 or response["status"] > 299:
422 432
 			raise S3Error(response)
423 433
 		return response