ChromiumUrlRequest.java revision c5cede9ae108bb15f6b7a8aea21c7e1fefa2834c
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 } 116 117 @Override 118 protected void onBytesRead(ByteBuffer buffer) { 119 if (mContentLengthOverLimit) { 120 return; 121 } 122 123 int size = buffer.remaining(); 124 mSize += size; 125 if (mSkippingToOffset) { 126 if (mSize <= mOffset) { 127 return; 128 } else { 129 mSkippingToOffset = false; 130 buffer.position((int)(mOffset - (mSize - size))); 131 } 132 } 133 134 if (mContentLengthLimit != 0 && mSize > mContentLengthLimit) { 135 buffer.limit(size - (int)(mSize - mContentLengthLimit)); 136 super.onBytesRead(buffer); 137 onContentLengthOverLimit(); 138 return; 139 } 140 141 super.onBytesRead(buffer); 142 } 143 144 private void onContentLengthOverLimit() { 145 mContentLengthOverLimit = true; 146 cancel(); 147 } 148 149 @Override 150 protected void onRequestComplete() { 151 mListener.onRequestComplete(this); 152 } 153 154 @Override 155 public int getHttpStatusCode() { 156 int httpStatusCode = super.getHttpStatusCode(); 157 158 // TODO(mef): Investigate the following: 159 // If we have been able to successfully resume a previously interrupted 160 // download, 161 // the status code will be 206, not 200. Since the rest of the 162 // application is 163 // expecting 200 to indicate success, we need to fake it. 164 if (httpStatusCode == 206) { 165 httpStatusCode = 200; 166 } 167 return httpStatusCode; 168 } 169 170 @Override 171 public IOException getException() { 172 IOException ex = super.getException(); 173 if (ex == null && mContentLengthOverLimit) { 174 ex = new ResponseTooLargeException(); 175 } 176 return ex; 177 } 178 179 @Override 180 public ByteBuffer getByteBuffer() { 181 return ((ChunkedWritableByteChannel)getSink()).getByteBuffer(); 182 } 183 184 @Override 185 public byte[] getResponseAsBytes() { 186 return ((ChunkedWritableByteChannel)getSink()).getBytes(); 187 } 188} 189