This source file includes following definitions.
- JNINamespace
- addHeader
- setUploadData
- setUploadChannel
- getSink
- start
- uploadFromChannel
- cancel
- isCanceled
- isRecycled
- getException
- getHttpStatusCode
- getContentLength
- getContentType
- onAppendChunkCompleted
- onResponseStarted
- onRequestComplete
- onBytesRead
- SuppressWarnings
- finish
- validateNotRecycled
- validateNotStarted
- validatePostBodyNotSet
- getUrl
- nativeCreateRequestPeer
- nativeAddHeader
- nativeSetPostData
- nativeBeginChunkedUpload
- nativeAppendChunk
- nativeStart
- nativeCancel
- nativeDestroyRequestPeer
- nativeGetErrorCode
- nativeGetHttpStatusCode
- nativeGetErrorString
- nativeGetContentType
- nativeGetContentLength
package org.chromium.net;
import org.apache.http.conn.ConnectTimeoutException;
import org.chromium.base.CalledByNative;
import org.chromium.base.JNINamespace;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.UnknownHostException;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.Semaphore;
@JNINamespace("net")
public class UrlRequest {
private static final class ContextLock {
}
private static final int UPLOAD_BYTE_BUFFER_SIZE = 32768;
private final UrlRequestContext mRequestContext;
private final String mUrl;
private final int mPriority;
private final Map<String, String> mHeaders;
private final WritableByteChannel mSink;
private Map<String, String> mAdditionalHeaders;
private boolean mPostBodySet;
private ReadableByteChannel mPostBodyChannel;
private WritableByteChannel mOutputChannel;
private IOException mSinkException;
private volatile boolean mStarted;
private volatile boolean mCanceled;
private volatile boolean mRecycled;
private volatile boolean mFinished;
private String mContentType;
private long mContentLength;
private Semaphore mAppendChunkSemaphore;
private final ContextLock mLock;
private long mUrlRequestPeer;
public UrlRequest(UrlRequestContext requestContext, String url,
int priority, Map<String, String> headers,
WritableByteChannel sink) {
if (requestContext == null) {
throw new NullPointerException("Context is required");
}
if (url == null) {
throw new NullPointerException("URL is required");
}
mRequestContext = requestContext;
mUrl = url;
mPriority = priority;
mHeaders = headers;
mSink = sink;
mLock = new ContextLock();
mUrlRequestPeer = nativeCreateRequestPeer(
mRequestContext.getUrlRequestContextPeer(), mUrl, mPriority);
mPostBodySet = false;
}
public void addHeader(String header, String value) {
validateNotStarted();
if (mAdditionalHeaders == null) {
mAdditionalHeaders = new HashMap<String, String>();
}
mAdditionalHeaders.put(header, value);
}
public void setUploadData(String contentType, byte[] data) {
synchronized (mLock) {
validateNotStarted();
validatePostBodyNotSet();
nativeSetPostData(mUrlRequestPeer, contentType, data);
mPostBodySet = true;
}
}
public void setUploadChannel(String contentType,
ReadableByteChannel channel) {
synchronized (mLock) {
validateNotStarted();
validatePostBodyNotSet();
nativeBeginChunkedUpload(mUrlRequestPeer, contentType);
mPostBodyChannel = channel;
mPostBodySet = true;
}
mAppendChunkSemaphore = new Semaphore(0);
}
public WritableByteChannel getSink() {
return mSink;
}
public void start() {
synchronized (mLock) {
if (mCanceled) {
return;
}
validateNotStarted();
validateNotRecycled();
mStarted = true;
if (mHeaders != null && !mHeaders.isEmpty()) {
for (Entry<String, String> entry : mHeaders.entrySet()) {
nativeAddHeader(mUrlRequestPeer, entry.getKey(),
entry.getValue());
}
}
if (mAdditionalHeaders != null && !mAdditionalHeaders.isEmpty()) {
for (Entry<String, String> entry :
mAdditionalHeaders.entrySet()) {
nativeAddHeader(mUrlRequestPeer, entry.getKey(),
entry.getValue());
}
}
nativeStart(mUrlRequestPeer);
}
if (mPostBodyChannel != null) {
uploadFromChannel(mPostBodyChannel);
}
}
private void uploadFromChannel(ReadableByteChannel channel) {
ByteBuffer buffer = ByteBuffer.allocateDirect(UPLOAD_BYTE_BUFFER_SIZE);
ByteBuffer checkForEnd = ByteBuffer.allocate(1);
try {
boolean lastChunk;
do {
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;
}
mAppendChunkSemaphore.acquire();
} while (!lastChunk && !mFinished);
} catch (IOException e) {
mSinkException = e;
cancel();
} catch (InterruptedException e) {
mSinkException = new IOException(e);
cancel();
} finally {
try {
mPostBodyChannel.close();
} catch (IOException ignore) {
;
}
}
}
public void cancel() {
synchronized (mLock) {
if (mCanceled) {
return;
}
mCanceled = true;
if (!mRecycled) {
nativeCancel(mUrlRequestPeer);
}
}
}
public boolean isCanceled() {
synchronized (mLock) {
return mCanceled;
}
}
public boolean isRecycled() {
synchronized (mLock) {
return mRecycled;
}
}
public IOException getException() {
if (mSinkException != null) {
return mSinkException;
}
validateNotRecycled();
int errorCode = nativeGetErrorCode(mUrlRequestPeer);
switch (errorCode) {
case UrlRequestError.SUCCESS:
return null;
case UrlRequestError.UNKNOWN:
return new IOException(nativeGetErrorString(mUrlRequestPeer));
case UrlRequestError.MALFORMED_URL:
return new MalformedURLException("Malformed URL: " + mUrl);
case UrlRequestError.CONNECTION_TIMED_OUT:
return new ConnectTimeoutException("Connection timed out");
case UrlRequestError.UNKNOWN_HOST:
String host;
try {
host = new URL(mUrl).getHost();
} catch (MalformedURLException e) {
host = mUrl;
}
return new UnknownHostException("Unknown host: " + host);
default:
throw new IllegalStateException(
"Unrecognized error code: " + errorCode);
}
}
public int getHttpStatusCode() {
return nativeGetHttpStatusCode(mUrlRequestPeer);
}
public long getContentLength() {
return mContentLength;
}
public String getContentType() {
return mContentType;
}
@CalledByNative
protected void onAppendChunkCompleted() {
mAppendChunkSemaphore.release();
}
@CalledByNative
protected void onResponseStarted() {
mContentType = nativeGetContentType(mUrlRequestPeer);
mContentLength = nativeGetContentLength(mUrlRequestPeer);
}
protected void onRequestComplete() {
}
@CalledByNative
protected void onBytesRead(ByteBuffer byteBuffer) {
try {
while (byteBuffer.hasRemaining()) {
mSink.write(byteBuffer);
}
} catch (IOException e) {
mSinkException = e;
cancel();
}
}
@SuppressWarnings("unused")
@CalledByNative
private void finish() {
synchronized (mLock) {
mFinished = true;
if (mAppendChunkSemaphore != null) {
mAppendChunkSemaphore.release();
}
if (mRecycled) {
return;
}
try {
mSink.close();
} catch (IOException e) {
}
onRequestComplete();
nativeDestroyRequestPeer(mUrlRequestPeer);
mUrlRequestPeer = 0;
mRecycled = true;
}
}
private void validateNotRecycled() {
if (mRecycled) {
throw new IllegalStateException("Accessing recycled request");
}
}
private void validateNotStarted() {
if (mStarted) {
throw new IllegalStateException("Request already started");
}
}
private void validatePostBodyNotSet() {
if (mPostBodySet) {
throw new IllegalStateException("Post Body already set");
}
}
public String getUrl() {
return mUrl;
}
private native long nativeCreateRequestPeer(long urlRequestContextPeer,
String url, int priority);
private native void nativeAddHeader(long urlRequestPeer, String name,
String value);
private native void nativeSetPostData(long urlRequestPeer,
String contentType, byte[] content);
private native void nativeBeginChunkedUpload(long urlRequestPeer,
String contentType);
private native void nativeAppendChunk(long urlRequestPeer, ByteBuffer chunk,
int chunkSize, boolean isLastChunk);
private native void nativeStart(long urlRequestPeer);
private native void nativeCancel(long urlRequestPeer);
private native void nativeDestroyRequestPeer(long urlRequestPeer);
private native int nativeGetErrorCode(long urlRequestPeer);
private native int nativeGetHttpStatusCode(long urlRequestPeer);
private native String nativeGetErrorString(long urlRequestPeer);
private native String nativeGetContentType(long urlRequestPeer);
private native long nativeGetContentLength(long urlRequestPeer);
}