From 151ebde5d1135ca7b50ffd97df14cda5d3282477 Mon Sep 17 00:00:00 2001 From: Marc Blank Date: Thu, 29 Oct 2009 11:09:58 -0700 Subject: [PATCH] Allow sync data via the chunked transfer encoding DO NOT MERGE * Fixes #2216885 * The bug is that the sync adapters weren't set up to handle chunked encoding, primarily because 1) I hadn't seen any servers use it, and 2) when we changed from HttpUrlConnection to HttpClient, support for chunked wasn't added (HttpUrlConnection didn't support it) * The fix for xml data is trivial, since the Content-Length returned in the chunked case (-1) was being disallowed, but works perfectly well with HttpClient. * The fix for attachments is less trivial, but still straightforward. * With this change, we are no longer dependent on receiving content-length, which is highly desirable Change-Id: I8d46790e41eaeee2887c8a207006c5d6786498ed --- src/com/android/exchange/EasSyncService.java | 47 +++++++++++++++----- 1 file changed, 36 insertions(+), 11 deletions(-) diff --git a/src/com/android/exchange/EasSyncService.java b/src/com/android/exchange/EasSyncService.java index 54e426429..390602468 100644 --- a/src/com/android/exchange/EasSyncService.java +++ b/src/com/android/exchange/EasSyncService.java @@ -314,19 +314,44 @@ public class EasSyncService extends AbstractSyncService { destDir.mkdirs(); } FileOutputStream os = new FileOutputStream(f); - if (len > 0) { + // len > 0 means that Content-Length was set in the headers + // len < 0 means "chunked" transfer-encoding + if (len != 0) { try { mPendingPartRequest = req; byte[] bytes = new byte[CHUNK_SIZE]; int length = len; - while (len > 0) { - int n = (len > CHUNK_SIZE ? CHUNK_SIZE : len); - int read = is.read(bytes, 0, n); + // Loop terminates 1) when EOF is reached or 2) if an IOException occurs + // One of these is guaranteed to occur + int totalRead = 0; + userLog("Attachment content-length: ", len); + while (true) { + int read = is.read(bytes, 0, CHUNK_SIZE); + + // read < 0 means that EOF was reached + if (read < 0) { + userLog("Attachment load reached EOF, totalRead: ", totalRead); + break; + } + + // Keep track of how much we've read for progress callback + totalRead += read; + + // Write these bytes out os.write(bytes, 0, read); - len -= read; - int pct = ((length - len) * 100 / length); - doProgressCallback(msg.mId, att.mId, pct); - } + + // We can't report percentages if this is chunked; by definition, the + // length of incoming data is unknown + if (length > 0) { + // Belt and suspenders check to prevent runaway reading + if (totalRead > length) { + errorLog("totalRead is greater than attachment length?"); + break; + } + int pct = (totalRead * 100 / length); + doProgressCallback(msg.mId, att.mId, pct); + } + } } finally { mPendingPartRequest = null; } @@ -562,7 +587,7 @@ public class EasSyncService extends AbstractSyncService { if (code == HttpStatus.SC_OK) { HttpEntity entity = resp.getEntity(); int len = (int)entity.getContentLength(); - if (len > 0) { + if (len != 0) { InputStream is = entity.getContent(); // Returns true if we need to sync again if (new FolderSyncParser(is, new AccountSyncAdapter(mMailbox, this)) @@ -747,7 +772,7 @@ public class EasSyncService extends AbstractSyncService { HttpEntity e = res.getEntity(); int len = (int)e.getContentLength(); InputStream is = res.getEntity().getContent(); - if (len > 0) { + if (len != 0) { int pingResult = parsePingResult(is, mContentResolver, pingErrorMap); // If our ping completed (status = 1), and we weren't forced and we're // not at the maximum, try increasing timeout by two minutes @@ -1019,7 +1044,7 @@ public class EasSyncService extends AbstractSyncService { HttpResponse resp = sendHttpClientPost("Sync", s.toByteArray()); int code = resp.getStatusLine().getStatusCode(); if (code == HttpStatus.SC_OK) { - InputStream is = resp.getEntity().getContent(); + InputStream is = resp.getEntity().getContent(); if (is != null) { moreAvailable = target.parse(is); target.cleanup();