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

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

Issue 367763004: WIP: Some cronet modifications for the AndroidGSA (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Second attempt on UploadChannel Created 6 years, 5 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
Index: components/cronet/android/java/src/org/chromium/net/UrlRequest.java
diff --git a/components/cronet/android/java/src/org/chromium/net/UrlRequest.java b/components/cronet/android/java/src/org/chromium/net/UrlRequest.java
index da00fdd9a61fb912d17a3ca4e849019bc9aab927..0b8e45a9caa0d07b2c8571fb614c26aa6f91ea03 100644
--- a/components/cronet/android/java/src/org/chromium/net/UrlRequest.java
+++ b/components/cronet/android/java/src/org/chromium/net/UrlRequest.java
@@ -4,6 +4,8 @@
package org.chromium.net;
+import android.util.Log;
+
import org.apache.http.conn.ConnectTimeoutException;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
@@ -15,7 +17,9 @@ import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
+import java.util.ArrayList;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Semaphore;
@@ -25,6 +29,9 @@ import java.util.concurrent.Semaphore;
*/
@JNINamespace("cronet")
public class UrlRequest {
+ private static final String TAG = "UrlRequest";
+ private static final boolean DBG = false;
+
private static final class ContextLock {
}
@@ -123,14 +130,19 @@ public class UrlRequest {
*/
public void setUploadChannel(String contentType,
ReadableByteChannel channel) {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ public WritableByteChannel enableUpload(String contentType) {
synchronized (mLock) {
validateNotStarted();
validatePostBodyNotSet();
nativeBeginChunkedUpload(mUrlRequestPeer, contentType);
- mPostBodyChannel = channel;
+ //mPostBodyChannel = new UploadChannel();
mPostBodySet = true;
}
mAppendChunkSemaphore = new Semaphore(0);
+ return new UploadChannel();
}
public WritableByteChannel getSink() {
@@ -167,9 +179,6 @@ public class UrlRequest {
nativeStart(mUrlRequestPeer);
}
- if (mPostBodyChannel != null) {
- uploadFromChannel(mPostBodyChannel);
- }
} finally {
if (mPostBodyChannel != null) {
try {
@@ -181,56 +190,6 @@ public class UrlRequest {
}
}
- /**
- * Uploads data from a {@code ReadableByteChannel} using chunked transfer
- * encoding. The native call to append a chunk is asynchronous so a
- * semaphore is used to delay writing into the buffer again until chromium
- * is finished with it.
- *
- * @param channel the channel to read data from.
- */
- private void uploadFromChannel(ReadableByteChannel channel) {
- ByteBuffer buffer = ByteBuffer.allocateDirect(UPLOAD_BYTE_BUFFER_SIZE);
-
- // The chromium API requires us to specify in advance if a chunk is the
- // last one. This extra ByteBuffer is needed to peek ahead and check for
- // the end of the channel.
- ByteBuffer checkForEnd = ByteBuffer.allocate(1);
-
- try {
- boolean lastChunk;
- do {
- // First dump in the one byte we read to check for the end of
- // the channel. (The first time through the loop the checkForEnd
- // buffer will be empty).
- checkForEnd.flip();
- buffer.clear();
- buffer.put(checkForEnd);
- checkForEnd.clear();
-
- channel.read(buffer);
- lastChunk = channel.read(checkForEnd) <= 0;
- buffer.flip();
- nativeAppendChunk(mUrlRequestPeer, buffer, buffer.limit(),
- lastChunk);
-
- if (lastChunk) {
- break;
- }
-
- // Acquire permit before writing to the buffer again to ensure
- // chromium is done with it.
- mAppendChunkSemaphore.acquire();
- } while (!lastChunk && !mFinished);
- } catch (IOException e) {
- mSinkException = e;
- cancel();
- } catch (InterruptedException e) {
- mSinkException = new IOException(e);
- cancel();
- }
- }
-
public void cancel() {
synchronized (mLock) {
if (mCanceled) {
@@ -313,6 +272,23 @@ public class UrlRequest {
return nativeGetHeader(mUrlRequestPeer, name);
}
+ // All response headers.
+ public Map<String, List<String>> getAllHeaders() {
+ validateHeadersAvailable();
+ String[] headers = nativeGetAllHeaders(mUrlRequestPeer);
+ Map<String, List<String>> result = new HashMap<String, List<String>>();
+ for (int i = 0; i < headers.length / 2; ++i) {
+ String key = headers[2 * i];
+ String value = headers[2 * i + 1];
+ if (!result.containsKey(key)) {
+ result.put(key, new ArrayList<String>());
+ }
+ result.get(key).add(value);
+ }
+ return result;
+ }
+
+
/**
* A callback invoked when appending a chunk to the request has completed.
*/
@@ -408,6 +384,39 @@ public class UrlRequest {
}
}
+ /**
+ * 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 (mUrlRequestPeer == 0) {
+ throw new IOException("Native peer destroyed.");
+ }
+ nativeAppendChunk(mUrlRequestPeer, 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;
+ }
+ }
+ }
+
public String getUrl() {
return mUrl;
}
@@ -444,4 +453,65 @@ public class UrlRequest {
private native long nativeGetContentLength(long urlRequestPeer);
private native String nativeGetHeader(long urlRequestPeer, String name);
+
+ private native String[] nativeGetAllHeaders(long urlRequestPeer);
+
+
+ class UploadChannel implements WritableByteChannel {
+
+ 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 {
+ if (DBG) Log.d(TAG, "UploadChannel.close() url=" + getUrl());
+ if (!mOpen) {
+ return;
+ }
+
+ mOpen = false;
+ mBuffer.clear();
+
+ // NOOP If the native peer has been destroyed.
+ try {
+ if (DBG) Log.d(TAG, "UploadChannel.close(): final chunk.");
+ appendChunkBlocking(mBuffer, true);
+ } catch (IOException e) {
+ Log.w(TAG, "Ignoring exception during closing.", e);
+ }
+
+ if (DBG) Log.d(TAG, "UploadChannel.close() done.");
+ }
+
+ @Override
+ public synchronized int write(ByteBuffer sourceBuffer)
+ throws IOException {
+ if (DBG) Log.d(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);
+ }
+ if (DBG) Log.d(TAG, "UploadChannel.write() returning");
+ return written;
+ }
+
+ }
}

Powered by Google App Engine
This is Rietveld 408576698