FileDocCategorySizeDatePackage
Request.javaAPI DocAndroid 1.5 API15594Wed May 06 22:41:56 BST 2009android.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
boolean
mHighPriority
True if request is .html, .js, .css
volatile boolean
mCancelled
True if request has been cancelled
int
mFailCount
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 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, boolean highPriority)
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
param
highPriority true for .html, css, .cs


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

        if (bodyProvider == null) {
            mHttpRequest = new BasicHttpRequest(method, getUri());
        } else {
            mHttpRequest = new BasicHttpEntityEnclosingRequest(
                    method, getUri());
            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
            && status != HttpStatus.SC_RESET_CONTENT;
    
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());
        }
        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;
        boolean reuse = 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);

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

            // process gzip content encoding
            Header contentEncoding = entity.getContentEncoding();
            InputStream nis = null;
            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 */
                byte[] buf = mConnection.getBuf();
                int len = 0;
                int count = 0;
                int lowWater = buf.length / 2;
                while (len != -1) {
                    len = nis.read(buf, count, buf.length - count);
                    if (len != -1) {
                        count += 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 (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) {
                    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);
        }
    
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;
    
public java.lang.StringtoString()
for debugging

        return (mHighPriority ? "P*" : "") + 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) {
            }
        }