import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
+import java.net.ProtocolException;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.WritableByteChannel;
+import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ExecutorService;
private int mContentLength;
+ private int mUploadContentLength;
+
private long mContentLengthLimit;
private boolean mCancelIfContentLengthOverLimit;
private int mHttpStatusCode;
+ private String mHttpStatusText;
+
private boolean mStarted;
private boolean mCanceled;
+ private String mMethod;
+
private InputStream mResponseStream;
private final Object mLock;
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r,
- "HttpUrlConnection #" +
- mCount.getAndIncrement());
+ "HttpUrlConnection #"
+ + mCount.getAndIncrement());
// Note that this thread is not doing actual networking.
// It's only a controller.
thread.setPriority(Thread.NORM_PRIORITY);
@Override
public void setUploadChannel(String contentType,
- ReadableByteChannel channel) {
+ ReadableByteChannel channel, long contentLength) {
validateNotStarted();
+ if (contentLength > Integer.MAX_VALUE) {
+ throw new IllegalArgumentException(
+ "Upload contentLength is too big.");
+ }
+ mUploadContentLength = (int) contentLength;
mPostContentType = contentType;
mPostDataChannel = channel;
mPostData = null;
}
+
+ @Override
+ public void setHttpMethod(String method) {
+ validateNotStarted();
+ mMethod = method;
+ }
+
+ @Override
+ public void disableRedirects() {
+ validateNotStarted();
+ mConnection.setFollowRedirects(false);
+ }
+
@Override
public void start() {
+ getExecutor().execute(new Runnable() {
+ @Override
+ public void run() {
+ startOnExecutorThread();
+ }
+ });
+ }
+
+ private void startOnExecutorThread() {
boolean readingResponse = false;
try {
synchronized (mLock) {
}
URL url = new URL(mUrl);
- mConnection = (HttpURLConnection)url.openConnection();
+ mConnection = (HttpURLConnection) url.openConnection();
+ // If configured, use the provided http verb.
+ if (mMethod != null) {
+ try {
+ mConnection.setRequestMethod(mMethod);
+ } catch (ProtocolException e) {
+ // Since request hasn't started earlier, it
+ // must be an illegal HTTP verb.
+ throw new IllegalArgumentException(e);
+ }
+ }
mConnection.setConnectTimeout(CONNECT_TIMEOUT);
mConnection.setReadTimeout(READ_TIMEOUT);
mConnection.setInstanceFollowRedirects(true);
}
mHttpStatusCode = mConnection.getResponseCode();
+ mHttpStatusText = mConnection.getResponseMessage();
mContentType = mConnection.getContentType();
mContentLength = mConnection.getContentLength();
if (mContentLengthLimit > 0 && mContentLength > mContentLengthLimit
return;
}
+ mListener.onResponseStarted(this);
+
mResponseStream = isError(mHttpStatusCode) ? mConnection
.getErrorStream()
: stream;
} catch (IOException e) {
mException = e;
} finally {
+ if (mPostDataChannel != null) {
+ try {
+ mPostDataChannel.close();
+ } catch (IOException e) {
+ // Ignore
+ }
+ }
+
// Don't call onRequestComplete yet if we are reading the response
// on a separate thread
if (!readingResponse) {
uploadStream = mConnection.getOutputStream();
uploadStream.write(mPostData);
} else {
- mConnection.setChunkedStreamingMode(MAX_CHUNK_SIZE);
+ mConnection.setFixedLengthStreamingMode(mUploadContentLength);
uploadStream = mConnection.getOutputStream();
byte[] bytes = new byte[MAX_CHUNK_SIZE];
ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);
continue;
} else {
mSkippingToOffset = false;
- start = (int)(mOffset - (mSize - size));
+ start = (int) (mOffset - (mSize - size));
count -= start;
}
}
if (mContentLengthLimit != 0 && mSize > mContentLengthLimit) {
- count -= (int)(mSize - mContentLengthLimit);
+ count -= (int) (mSize - mContentLengthLimit);
if (count > 0) {
mSink.write(ByteBuffer.wrap(buffer, start, count));
}
}
@Override
+ public String getNegotiatedProtocol() {
+ return "";
+ }
+
+ @Override
public int getHttpStatusCode() {
int httpStatusCode = mHttpStatusCode;
}
@Override
+ public String getHttpStatusText() {
+ return mHttpStatusText;
+ }
+
+ @Override
public IOException getException() {
if (mException == null && mContentLengthOverLimit) {
mException = new ResponseTooLargeException();
*/
@Override
public ByteBuffer getByteBuffer() {
- return ((ChunkedWritableByteChannel)mSink).getByteBuffer();
+ return ((ChunkedWritableByteChannel) mSink).getByteBuffer();
}
@Override
public byte[] getResponseAsBytes() {
- return ((ChunkedWritableByteChannel)mSink).getBytes();
+ return ((ChunkedWritableByteChannel) mSink).getBytes();
}
@Override
return mContentType;
}
+ @Override
+ public String getHeader(String name) {
+ if (mConnection == null) {
+ throw new IllegalStateException("Response headers not available");
+ }
+ Map<String, List<String>> headerFields = mConnection.getHeaderFields();
+ if (headerFields != null) {
+ List<String> headerValues = headerFields.get(name);
+ if (headerValues != null) {
+ return TextUtils.join(", ", headerValues);
+ }
+ }
+ return null;
+ }
+
+ @Override
+ public Map<String, List<String>> getAllHeaders() {
+ if (mConnection == null) {
+ throw new IllegalStateException("Response headers not available");
+ }
+ return mConnection.getHeaderFields();
+ }
+
private void validateNotStarted() {
if (mStarted) {
throw new IllegalStateException("Request already started");