ChromiumUrlRequest.java revision 5c02ac1a9c1b504631c0a3d2b6e737b5d738bae1
1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5package org.chromium.net; 6 7import java.io.IOException; 8import java.nio.ByteBuffer; 9import java.nio.channels.WritableByteChannel; 10import java.util.Map; 11 12/** 13 * Network request using the native http stack implementation. 14 */ 15class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest { 16 17 private final HttpUrlRequestListener mListener; 18 19 private boolean mBufferFullResponse; 20 21 private long mOffset; 22 23 private long mContentLength; 24 25 private long mContentLengthLimit; 26 27 private boolean mCancelIfContentLengthOverLimit; 28 29 private boolean mContentLengthOverLimit; 30 31 private boolean mSkippingToOffset; 32 33 private long mSize; 34 35 public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext, 36 String url, int priority, Map<String, String> headers, 37 HttpUrlRequestListener listener) { 38 this(requestContext, url, priority, headers, 39 new ChunkedWritableByteChannel(), listener); 40 mBufferFullResponse = true; 41 } 42 43 public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext, 44 String url, int priority, Map<String, String> headers, 45 WritableByteChannel sink, HttpUrlRequestListener listener) { 46 super(requestContext, url, convertRequestPriority(priority), headers, 47 sink); 48 mListener = listener; 49 } 50 51 private static int convertRequestPriority(int priority) { 52 switch (priority) { 53 case HttpUrlRequest.REQUEST_PRIORITY_IDLE: 54 return UrlRequestPriority.IDLE; 55 case HttpUrlRequest.REQUEST_PRIORITY_LOWEST: 56 return UrlRequestPriority.LOWEST; 57 case HttpUrlRequest.REQUEST_PRIORITY_LOW: 58 return UrlRequestPriority.LOW; 59 case HttpUrlRequest.REQUEST_PRIORITY_MEDIUM: 60 return UrlRequestPriority.MEDIUM; 61 case HttpUrlRequest.REQUEST_PRIORITY_HIGHEST: 62 return UrlRequestPriority.HIGHEST; 63 default: 64 return UrlRequestPriority.MEDIUM; 65 } 66 } 67 68 @Override 69 public void setOffset(long offset) { 70 mOffset = offset; 71 if (offset != 0) { 72 addHeader("Range", "bytes=" + offset + "-"); 73 } 74 } 75 76 @Override 77 public long getContentLength() { 78 return mContentLength; 79 } 80 81 @Override 82 public void setContentLengthLimit(long limit, boolean cancelEarly) { 83 mContentLengthLimit = limit; 84 mCancelIfContentLengthOverLimit = cancelEarly; 85 } 86 87 @Override 88 protected void onResponseStarted() { 89 super.onResponseStarted(); 90 91 mContentLength = super.getContentLength(); 92 if (mContentLengthLimit > 0 && mContentLength > mContentLengthLimit 93 && mCancelIfContentLengthOverLimit) { 94 onContentLengthOverLimit(); 95 return; 96 } 97 98 if (mBufferFullResponse && mContentLength != -1 99 && !mContentLengthOverLimit) { 100 ((ChunkedWritableByteChannel)getSink()).setCapacity( 101 (int)mContentLength); 102 } 103 104 if (mOffset != 0) { 105 // The server may ignore the request for a byte range. 106 if (super.getHttpStatusCode() == 200) { 107 if (mContentLength != -1) { 108 mContentLength -= mOffset; 109 } 110 mSkippingToOffset = true; 111 } else { 112 mSize = mOffset; 113 } 114 } 115 mListener.onResponseStarted(this); 116 } 117 118 @Override 119 protected void onBytesRead(ByteBuffer buffer) { 120 if (mContentLengthOverLimit) { 121 return; 122 } 123 124 int size = buffer.remaining(); 125 mSize += size; 126 if (mSkippingToOffset) { 127 if (mSize <= mOffset) { 128 return; 129 } else { 130 mSkippingToOffset = false; 131 buffer.position((int)(mOffset - (mSize - size))); 132 } 133 } 134 135 if (mContentLengthLimit != 0 && mSize > mContentLengthLimit) { 136 buffer.limit(size - (int)(mSize - mContentLengthLimit)); 137 super.onBytesRead(buffer); 138 onContentLengthOverLimit(); 139 return; 140 } 141 142 super.onBytesRead(buffer); 143 } 144 145 private void onContentLengthOverLimit() { 146 mContentLengthOverLimit = true; 147 cancel(); 148 } 149 150 @Override 151 protected void onRequestComplete() { 152 mListener.onRequestComplete(this); 153 } 154 155 @Override 156 public int getHttpStatusCode() { 157 int httpStatusCode = super.getHttpStatusCode(); 158 159 // TODO(mef): Investigate the following: 160 // If we have been able to successfully resume a previously interrupted 161 // download, 162 // the status code will be 206, not 200. Since the rest of the 163 // application is 164 // expecting 200 to indicate success, we need to fake it. 165 if (httpStatusCode == 206) { 166 httpStatusCode = 200; 167 } 168 return httpStatusCode; 169 } 170 171 @Override 172 public IOException getException() { 173 IOException ex = super.getException(); 174 if (ex == null && mContentLengthOverLimit) { 175 ex = new ResponseTooLargeException(); 176 } 177 return ex; 178 } 179 180 @Override 181 public ByteBuffer getByteBuffer() { 182 return ((ChunkedWritableByteChannel)getSink()).getByteBuffer(); 183 } 184 185 @Override 186 public byte[] getResponseAsBytes() { 187 return ((ChunkedWritableByteChannel)getSink()).getBytes(); 188 } 189} 190