FileDocCategorySizeDatePackage
Request.javaAPI DocAndroid 5.1 API18351Thu Mar 12 22:22:10 GMT 2015android.net.http

Request

public class Request extends Object
Represents an HTTP request for a given host. {@hide}

Fields Summary
EventHandler
mEventHandler
The eventhandler to call as the request progresses
private Connection
mConnection
BasicHttpRequest
mHttpRequest
The Apache http request
String
mPath
The path component of this request
HttpHost
mHost
Host serving this request
HttpHost
mProxyHost
Set if I'm using a proxy server
volatile boolean
mCancelled
True if request has been cancelled
int
mFailCount
private int
mReceivedBytes
private InputStream
mBodyProvider
private int
mBodyLength
private static final String
HOST_HEADER
private static final String
ACCEPT_ENCODING_HEADER
private static final String
CONTENT_LENGTH_HEADER
private final Object
mClientResource
private boolean
mLoadingPaused
True if loading should be paused
private static RequestContent
requestContentProcessor
Processor used to set content-length and transfer-encoding headers.
Constructors Summary
Request(String method, HttpHost host, HttpHost proxyHost, String path, InputStream bodyProvider, int bodyLength, EventHandler eventHandler, Map headers)
Instantiates a new Request.

param
method GET/POST/PUT
param
host The server that will handle this request
param
path path part of URI
param
bodyProvider InputStream providing HTTP body, null if none
param
bodyLength length of body, must be 0 if bodyProvider is null
param
eventHandler request will make progress callbacks on this interface
param
headers reqeust headers


                                                                  
           
               
             
               
        mEventHandler = eventHandler;
        mHost = host;
        mProxyHost = proxyHost;
        mPath = path;
        mBodyProvider = bodyProvider;
        mBodyLength = bodyLength;

        if (bodyProvider == null && !"POST".equalsIgnoreCase(method)) {
            mHttpRequest = new BasicHttpRequest(method, getUri());
        } else {
            mHttpRequest = new BasicHttpEntityEnclosingRequest(
                    method, getUri());
            // it is ok to have null entity for BasicHttpEntityEnclosingRequest.
            // By using BasicHttpEntityEnclosingRequest, it will set up the
            // correct content-length, content-type and content-encoding.
            if (bodyProvider != null) {
                setBodyProvider(bodyProvider, bodyLength);
            }
        }
        addHeader(HOST_HEADER, getHostPort());

        /* FIXME: if webcore will make the root document a
           high-priority request, we can ask for gzip encoding only on
           high priority reqs (saving the trouble for images, etc) */
        addHeader(ACCEPT_ENCODING_HEADER, "gzip");
        addHeaders(headers);
    
Methods Summary
voidaddHeader(java.lang.String name, java.lang.String value)
Add header represented by given pair to request. Header will be formatted in request as "name: value\r\n".

param
name of header
param
value of header

        if (name == null) {
            String damage = "Null http header name";
            HttpLog.e(damage);
            throw new NullPointerException(damage);
        }
        if (value == null || value.length() == 0) {
            String damage = "Null or empty value for header \"" + name + "\"";
            HttpLog.e(damage);
            throw new RuntimeException(damage);
        }
        mHttpRequest.addHeader(name, value);
    
voidaddHeaders(java.util.Map headers)
Add all headers in given map to this request. This is a helper method: it calls addHeader for each pair in the map.

        if (headers == null) {
            return;
        }

        Entry<String, String> entry;
        Iterator<Entry<String, String>> i = headers.entrySet().iterator();
        while (i.hasNext()) {
            entry = i.next();
            addHeader(entry.getKey(), entry.getValue());
        }
    
private static booleancanResponseHaveBody(org.apache.http.HttpRequest request, int status)
Decide whether a response comes with an entity. The implementation in this class is based on RFC 2616. Unknown methods and response codes are supposed to indicate responses with an entity.
Derived executors can override this method to handle methods and response codes not specified in RFC 2616.

param
request the request, to obtain the executed method
param
response the response, to obtain the status code


        if ("HEAD".equalsIgnoreCase(request.getRequestLine().getMethod())) {
            return false;
        }
        return status >= HttpStatus.SC_OK
            && status != HttpStatus.SC_NO_CONTENT
            && status != HttpStatus.SC_NOT_MODIFIED;
    
synchronized voidcancel()
Data will not be sent to or received from server after cancel() call. Does not close connection--use close() below for that. Called by RequestHandle from non-network thread

        if (HttpLog.LOGV) {
            HttpLog.v("Request.cancel(): " + getUri());
        }

        // Ensure that the network thread is not blocked by a hanging request from WebCore to
        // pause the load.
        mLoadingPaused = false;
        notify();

        mCancelled = true;
        if (mConnection != null) {
            mConnection.cancel();
        }
    
voidcomplete()

        synchronized (mClientResource) {
            mClientResource.notifyAll();
        }
    
voiderror(int errorId, int resourceId)
Helper: calls error() on eventhandler with appropriate message This should not be called before the mConnection is set.

        mEventHandler.error(
                errorId,
                mConnection.mContext.getText(
                        resourceId).toString());
    
EventHandlergetEventHandler()

        return mEventHandler;
    
java.lang.StringgetHostPort()

        String myScheme = mHost.getSchemeName();
        int myPort = mHost.getPort();

        // Only send port when we must... many servers can't deal with it
        if (myPort != 80 && myScheme.equals("http") ||
            myPort != 443 && myScheme.equals("https")) {
            return mHost.toHostString();
        } else {
            return mHost.getHostName();
        }
    
java.lang.StringgetUri()

        if (mProxyHost == null ||
            mHost.getSchemeName().equals("https")) {
            return mPath;
        }
        return mHost.getSchemeName() + "://" + getHostPort() + mPath;
    
public voidhandleSslErrorResponse(boolean proceed)
Handles SSL error(s) on the way down from the user (the user has already provided their feedback).

        HttpsConnection connection = (HttpsConnection)(mConnection);
        if (connection != null) {
            connection.restartConnection(proceed);
        }
    
voidreadResponse(AndroidHttpClientConnection httpClientConnection)
Receive a single http response.

param
httpClientConnection the request to receive the response for.


        if (mCancelled) return; // don't send cancelled requests

        StatusLine statusLine = null;
        boolean hasBody = false;
        httpClientConnection.flush();
        int statusCode = 0;

        Headers header = new Headers();
        do {
            statusLine = httpClientConnection.parseResponseHeader(header);
            statusCode = statusLine.getStatusCode();
        } while (statusCode < HttpStatus.SC_OK);
        if (HttpLog.LOGV) HttpLog.v(
                "Request.readResponseStatus() " +
                statusLine.toString().length() + " " + statusLine);

        ProtocolVersion v = statusLine.getProtocolVersion();
        mEventHandler.status(v.getMajor(), v.getMinor(),
                statusCode, statusLine.getReasonPhrase());
        mEventHandler.headers(header);
        HttpEntity entity = null;
        hasBody = canResponseHaveBody(mHttpRequest, statusCode);

        if (hasBody)
            entity = httpClientConnection.receiveResponseEntity(header);

        // restrict the range request to the servers claiming that they are
        // accepting ranges in bytes
        boolean supportPartialContent = "bytes".equalsIgnoreCase(header
                .getAcceptRanges());

        if (entity != null) {
            InputStream is = entity.getContent();

            // process gzip content encoding
            Header contentEncoding = entity.getContentEncoding();
            InputStream nis = null;
            byte[] buf = null;
            int count = 0;
            try {
                if (contentEncoding != null &&
                    contentEncoding.getValue().equals("gzip")) {
                    nis = new GZIPInputStream(is);
                } else {
                    nis = is;
                }

                /* accumulate enough data to make it worth pushing it
                 * up the stack */
                buf = mConnection.getBuf();
                int len = 0;
                int lowWater = buf.length / 2;
                while (len != -1) {
                    synchronized(this) {
                        while (mLoadingPaused) {
                            // Put this (network loading) thread to sleep if WebCore
                            // has asked us to. This can happen with plugins for
                            // example, if we are streaming data but the plugin has
                            // filled its internal buffers.
                            try {
                                wait();
                            } catch (InterruptedException e) {
                                HttpLog.e("Interrupted exception whilst "
                                    + "network thread paused at WebCore's request."
                                    + " " + e.getMessage());
                            }
                        }
                    }

                    len = nis.read(buf, count, buf.length - count);

                    if (len != -1) {
                        count += len;
                        if (supportPartialContent) mReceivedBytes += len;
                    }
                    if (len == -1 || count >= lowWater) {
                        if (HttpLog.LOGV) HttpLog.v("Request.readResponse() " + count);
                        mEventHandler.data(buf, count);
                        count = 0;
                    }
                }
            } catch (EOFException e) {
                /* InflaterInputStream throws an EOFException when the
                   server truncates gzipped content.  Handle this case
                   as we do truncated non-gzipped content: no error */
                if (count > 0) {
                    // if there is uncommited content, we should commit them
                    mEventHandler.data(buf, count);
                }
                if (HttpLog.LOGV) HttpLog.v( "readResponse() handling " + e);
            } catch(IOException e) {
                // don't throw if we have a non-OK status code
                if (statusCode == HttpStatus.SC_OK
                        || statusCode == HttpStatus.SC_PARTIAL_CONTENT) {
                    if (supportPartialContent && count > 0) {
                        // if there is uncommited content, we should commit them
                        // as we will continue the request
                        mEventHandler.data(buf, count);
                    }
                    throw e;
                }
            } finally {
                if (nis != null) {
                    nis.close();
                }
            }
        }
        mConnection.setCanPersist(entity, statusLine.getProtocolVersion(),
                header.getConnectionType());
        mEventHandler.endData();
        complete();

        if (HttpLog.LOGV) HttpLog.v("Request.readResponse(): done " +
                                    mHost.getSchemeName() + "://" + getHostPort() + mPath);
    
voidreset()
If this request has been sent once and failed, it must be reset before it can be sent again.

        /* clear content-length header */
        mHttpRequest.removeHeaders(CONTENT_LENGTH_HEADER);

        if (mBodyProvider != null) {
            try {
                mBodyProvider.reset();
            } catch (IOException ex) {
                if (HttpLog.LOGV) HttpLog.v(
                        "failed to reset body provider " +
                        getUri());
            }
            setBodyProvider(mBodyProvider, mBodyLength);
        }

        if (mReceivedBytes > 0) {
            // reset the fail count as we continue the request
            mFailCount = 0;
            // set the "Range" header to indicate that the retry will continue
            // instead of restarting the request
            HttpLog.v("*** Request.reset() to range:" + mReceivedBytes);
            mHttpRequest.setHeader("Range", "bytes=" + mReceivedBytes + "-");
        }
    
voidsendRequest(AndroidHttpClientConnection httpClientConnection)
Send the request line and headers


        if (mCancelled) return; // don't send cancelled requests

        if (HttpLog.LOGV) {
            HttpLog.v("Request.sendRequest() " + mHost.getSchemeName() + "://" + getHostPort());
            // HttpLog.v(mHttpRequest.getRequestLine().toString());
            if (false) {
                Iterator i = mHttpRequest.headerIterator();
                while (i.hasNext()) {
                    Header header = (Header)i.next();
                    HttpLog.v(header.getName() + ": " + header.getValue());
                }
            }
        }

        requestContentProcessor.process(mHttpRequest,
                                        mConnection.getHttpContext());
        httpClientConnection.sendRequestHeader(mHttpRequest);
        if (mHttpRequest instanceof HttpEntityEnclosingRequest) {
            httpClientConnection.sendRequestEntity(
                    (HttpEntityEnclosingRequest) mHttpRequest);
        }

        if (HttpLog.LOGV) {
            HttpLog.v("Request.requestSent() " + mHost.getSchemeName() + "://" + getHostPort() + mPath);
        }
    
private voidsetBodyProvider(java.io.InputStream bodyProvider, int bodyLength)
Supply an InputStream that provides the body of a request. It's not great that the caller must also provide the length of the data returned by that InputStream, but the client needs to know up front, and I'm not sure how to get this out of the InputStream itself without a costly readthrough. I'm not sure skip() would do what we want. If you know a better way, please let me know.

        if (!bodyProvider.markSupported()) {
            throw new IllegalArgumentException(
                    "bodyProvider must support mark()");
        }
        // Mark beginning of stream
        bodyProvider.mark(Integer.MAX_VALUE);

        ((BasicHttpEntityEnclosingRequest)mHttpRequest).setEntity(
                new InputStreamEntity(bodyProvider, bodyLength));
    
voidsetConnection(Connection connection)

param
connection Request served by this connection

        mConnection = connection;
    
synchronized voidsetLoadingPaused(boolean pause)

param
pause True if the load should be paused.

        mLoadingPaused = pause;

        // Wake up the paused thread if we're unpausing the load.
        if (!mLoadingPaused) {
            notify();
        }
    
public java.lang.StringtoString()
for debugging

        return mPath;
    
voidwaitUntilComplete()
Pause thread request completes. Used for synchronous requests, and testing

        synchronized (mClientResource) {
            try {
                if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete()");
                mClientResource.wait();
                if (HttpLog.LOGV) HttpLog.v("Request.waitUntilComplete() done waiting");
            } catch (InterruptedException e) {
            }
        }