Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(201)

Unified Diff: components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java

Issue 475533003: Upstream changes to enable chunked uploads. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 6 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « components/cronet/android/chromium_url_request.cc ('k') | components/cronet/android/url_request_adapter.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
diff --git a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
index 91268c3f072eca2d7e7b89799d18215a4d76dd3b..ae22787434fd208d2e991a069ec1d5bad61e1204 100644
--- a/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
+++ b/components/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java
@@ -22,6 +22,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import java.util.concurrent.Semaphore;
/**
* Network request using the native http stack implementation.
@@ -41,6 +42,7 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
private String mUploadContentType;
private String mMethod;
private byte[] mUploadData;
+ private Semaphore mAppendChunkSemaphore;
private ReadableByteChannel mUploadChannel;
private WritableByteChannel mOutputChannel;
private IOException mSinkException;
@@ -220,6 +222,7 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
mUploadContentType = contentType;
mUploadData = data;
mUploadChannel = null;
+ mAppendChunkSemaphore = null;
}
}
@@ -240,9 +243,28 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
mUploadChannel = channel;
mUploadContentLength = contentLength;
mUploadData = null;
+ mAppendChunkSemaphore = null;
}
}
+ /**
+ * Creates writable byte channel for chunked uploads as part of a POST or
+ * PUT request.
+ *
+ * @param contentType MIME type of the upload content.
+ */
+ public WritableByteChannel createChunkedUploadChannel(String contentType) {
+ synchronized (mLock) {
+ validateNotStarted();
+ mUploadContentType = contentType;
+ mUploadChannel = null;
+ mUploadContentLength = 0;
+ mUploadData = null;
+ mAppendChunkSemaphore = new Semaphore(0);
+ }
+ return new UploadChannel();
+ }
+
/**
* Sets HTTP method for upload request. Only PUT or POST are allowed.
*/
@@ -303,6 +325,9 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
} else if (mUploadChannel != null) {
nativeSetUploadChannel(mUrlRequestAdapter, mUploadContentType,
mUploadContentLength);
+ } else if (mUploadContentType != null) {
+ nativeEnableChunkedUpload(mUrlRequestAdapter,
+ mUploadContentType);
}
nativeStart(mUrlRequestAdapter);
@@ -378,6 +403,40 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
cancel();
}
+ /**
+ * Invokes {@link #nativeAppendChunk(long, ByteBuffer, int, boolean)} and
+ * waits for it to notify completion.
+ * @param chunk The data. It's position must be zero.
+ * @param isLastChunk Whether chunk is the last one.
+ */
+ void appendChunkBlocking(ByteBuffer chunk, boolean isLastChunk)
+ throws IOException {
+ if (chunk.position() != 0) {
+ throw new IllegalArgumentException("The position must be zero.");
+ }
+ synchronized (mLock) {
+ if (mUrlRequestAdapter == 0) {
+ throw new IOException("Native adapter is destroyed.");
+ }
+ nativeAppendChunkToUpload(mUrlRequestAdapter, chunk, chunk.limit(),
+ false);
+ // Wait for the data to be actually consumed.
+ try {
+ mAppendChunkSemaphore.acquire();
+ } catch (InterruptedException e) {
+ // We were interrupted before the data was uploaded. Recovering
+ // from this state is complicated so we cancel the upload
+ // operation and fail.
+ Thread.currentThread().interrupt();
+
+ // TODO(miloslav): Not sure why do we set mSinkException here.
+ mSinkException = new IOException("Upload interrupted", e);
+ cancel();
+ throw mSinkException;
+ }
+ }
+ }
+
/**
* A callback invoked when the response has been fully consumed.
*/
@@ -403,6 +462,68 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
}
}
+ class UploadChannel implements WritableByteChannel {
+ private static final int UPLOAD_BYTE_BUFFER_SIZE = 32768;
+
+ private boolean mOpen = true;
+ // Native wants a direct buffer.
+ private final ByteBuffer mBuffer =
+ ByteBuffer.allocateDirect(UPLOAD_BYTE_BUFFER_SIZE);
+
+ @Override
+ public synchronized boolean isOpen() {
+ return mOpen;
+ }
+
+ @Override
+ public synchronized void close() throws IOException {
+ Log.d(ChromiumUrlRequestContext.LOG_TAG,
+ "UploadChannel.close() url=" + getUrl());
+ if (!mOpen) {
+ return;
+ }
+
+ mOpen = false;
+ mBuffer.clear();
+
+ // NOOP If the native peer has been destroyed.
+ try {
+ Log.d(ChromiumUrlRequestContext.LOG_TAG,
+ "UploadChannel.close(): final chunk.");
+ appendChunkBlocking(mBuffer, true);
+ } catch (IOException e) {
+ Log.w(ChromiumUrlRequestContext.LOG_TAG,
+ "Ignoring exception during closing.", e);
+ }
+ Log.d(ChromiumUrlRequestContext.LOG_TAG,
+ "UploadChannel.close() done.");
+ }
+
+ @Override
+ public synchronized int write(ByteBuffer sourceBuffer)
+ throws IOException {
+ Log.d(ChromiumUrlRequestContext.LOG_TAG, "UploadChannel.write(" +
+ sourceBuffer.remaining() + " bytes) url=" + getUrl());
+ int written = 0;
+ while (sourceBuffer.hasRemaining()) {
+ mBuffer.clear();
+ int oldLimit = sourceBuffer.limit();
+ if (sourceBuffer.remaining() > mBuffer.remaining()) {
+ sourceBuffer.limit(sourceBuffer.position()
+ + mBuffer.remaining());
+ }
+ mBuffer.put(sourceBuffer);
+ mBuffer.flip();
+ written += mBuffer.limit();
+ appendChunkBlocking(mBuffer, false);
+ sourceBuffer.limit(oldLimit);
+ }
+ Log.d(ChromiumUrlRequestContext.LOG_TAG,
+ "UploadChannel.write() returning");
+ return written;
+ }
+ }
+
// Private methods called by native library.
/**
@@ -423,6 +544,14 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
}
/**
+ * A callback invoked when appending a chunk to the request has completed.
+ */
+ @CalledByNative
+ protected void onAppendChunkCompleted() {
+ mAppendChunkSemaphore.release();
+ }
+
+ /**
* A callback invoked when the first chunk of the response has arrived.
*/
@CalledByNative
@@ -605,6 +734,12 @@ public class ChromiumUrlRequest implements HttpUrlRequest {
private native void nativeSetUploadChannel(long urlRequestAdapter,
String contentType, long contentLength);
+ private native void nativeEnableChunkedUpload(long urlRequestAdapter,
+ String contentType);
+
+ private native void nativeAppendChunkToUpload(long urlRequestAdapter,
+ ByteBuffer chunk, int chunkSize, boolean isLastChunk);
+
private native void nativeStart(long urlRequestAdapter);
private native void nativeCancel(long urlRequestAdapter);
« no previous file with comments | « components/cronet/android/chromium_url_request.cc ('k') | components/cronet/android/url_request_adapter.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698