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