root/net/cronet/android/java/src/org/chromium/net/ChromiumUrlRequest.java

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. convertRequestPriority
  2. setOffset
  3. getContentLength
  4. setContentLengthLimit
  5. onResponseStarted
  6. onBytesRead
  7. onContentLengthOverLimit
  8. onRequestComplete
  9. getHttpStatusCode
  10. getException
  11. getByteBuffer
  12. getResponseAsBytes

// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.net;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.WritableByteChannel;
import java.util.Map;

/**
 * Network request using the native http stack implementation.
 */
class ChromiumUrlRequest extends UrlRequest implements HttpUrlRequest {

    private final HttpUrlRequestListener mListener;

    private boolean mBufferFullResponse;

    private long mOffset;

    private long mContentLength;

    private long mContentLengthLimit;

    private boolean mCancelIfContentLengthOverLimit;

    private boolean mContentLengthOverLimit;

    private boolean mSkippingToOffset;

    private long mSize;

    public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext,
            String url, int priority, Map<String, String> headers,
            HttpUrlRequestListener listener) {
        this(requestContext, url, priority, headers,
                new ChunkedWritableByteChannel(), listener);
        mBufferFullResponse = true;
    }

    public ChromiumUrlRequest(ChromiumUrlRequestContext requestContext,
            String url, int priority, Map<String, String> headers,
            WritableByteChannel sink, HttpUrlRequestListener listener) {
        super(requestContext, url, convertRequestPriority(priority), headers,
                sink);
        mListener = listener;
    }

    private static int convertRequestPriority(int priority) {
        switch (priority) {
            case HttpUrlRequest.REQUEST_PRIORITY_IDLE:
                return UrlRequestPriority.IDLE;
            case HttpUrlRequest.REQUEST_PRIORITY_LOWEST:
                return UrlRequestPriority.LOWEST;
            case HttpUrlRequest.REQUEST_PRIORITY_LOW:
                return UrlRequestPriority.LOW;
            case HttpUrlRequest.REQUEST_PRIORITY_MEDIUM:
                return UrlRequestPriority.MEDIUM;
            case HttpUrlRequest.REQUEST_PRIORITY_HIGHEST:
                return UrlRequestPriority.HIGHEST;
            default:
                return UrlRequestPriority.MEDIUM;
        }
    }

    @Override
    public void setOffset(long offset) {
        mOffset = offset;
        if (offset != 0) {
            addHeader("Range", "bytes=" + offset + "-");
        }
    }

    @Override
    public long getContentLength() {
        return mContentLength;
    }

    @Override
    public void setContentLengthLimit(long limit, boolean cancelEarly) {
        mContentLengthLimit = limit;
        mCancelIfContentLengthOverLimit = cancelEarly;
    }

    @Override
    protected void onResponseStarted() {
        super.onResponseStarted();

        mContentLength = super.getContentLength();
        if (mContentLengthLimit > 0 && mContentLength > mContentLengthLimit
                && mCancelIfContentLengthOverLimit) {
            onContentLengthOverLimit();
            return;
        }

        if (mBufferFullResponse && mContentLength != -1
                && !mContentLengthOverLimit) {
            ((ChunkedWritableByteChannel)getSink()).setCapacity(
                    (int)mContentLength);
        }

        if (mOffset != 0) {
            // The server may ignore the request for a byte range.
            if (super.getHttpStatusCode() == 200) {
                if (mContentLength != -1) {
                    mContentLength -= mOffset;
                }
                mSkippingToOffset = true;
            } else {
                mSize = mOffset;
            }
        }
    }

    @Override
    protected void onBytesRead(ByteBuffer buffer) {
        if (mContentLengthOverLimit) {
            return;
        }

        int size = buffer.remaining();
        mSize += size;
        if (mSkippingToOffset) {
            if (mSize <= mOffset) {
                return;
            } else {
                mSkippingToOffset = false;
                buffer.position((int)(mOffset - (mSize - size)));
            }
        }

        if (mContentLengthLimit != 0 && mSize > mContentLengthLimit) {
            buffer.limit(size - (int)(mSize - mContentLengthLimit));
            super.onBytesRead(buffer);
            onContentLengthOverLimit();
            return;
        }

        super.onBytesRead(buffer);
    }

    private void onContentLengthOverLimit() {
        mContentLengthOverLimit = true;
        cancel();
    }

    @Override
    protected void onRequestComplete() {
        mListener.onRequestComplete(this);
    }

    @Override
    public int getHttpStatusCode() {
        int httpStatusCode = super.getHttpStatusCode();

        // TODO(mef): Investigate the following:
        // If we have been able to successfully resume a previously interrupted
        // download,
        // the status code will be 206, not 200. Since the rest of the
        // application is
        // expecting 200 to indicate success, we need to fake it.
        if (httpStatusCode == 206) {
            httpStatusCode = 200;
        }
        return httpStatusCode;
    }

    @Override
    public IOException getException() {
        IOException ex = super.getException();
        if (ex == null && mContentLengthOverLimit) {
            ex = new ResponseTooLargeException();
        }
        return ex;
    }

    @Override
    public ByteBuffer getByteBuffer() {
        return ((ChunkedWritableByteChannel)getSink()).getByteBuffer();
    }

    @Override
    public byte[] getResponseAsBytes() {
        return ((ChunkedWritableByteChannel)getSink()).getBytes();
    }
}

/* [<][>][^][v][top][bottom][index][help] */