FileDocCategorySizeDatePackage
RequestHandle.javaAPI DocAndroid 1.5 API13177Wed May 06 22:41:56 BST 2009android.net.http

RequestHandle

public class RequestHandle extends Object
RequestHandle: handles a request session that may include multiple redirects, HTTP authentication requests, etc. {@hide}

Fields Summary
private String
mUrl
private android.net.WebAddress
mUri
private String
mMethod
private Map
mHeaders
private RequestQueue
mRequestQueue
private Request
mRequest
private InputStream
mBodyProvider
private int
mBodyLength
private int
mRedirectCount
private static final String
AUTHORIZATION_HEADER
private static final String
PROXY_AUTHORIZATION_HEADER
public static final int
MAX_REDIRECT_COUNT
Constructors Summary
public RequestHandle(RequestQueue requestQueue, String url, android.net.WebAddress uri, String method, Map headers, InputStream bodyProvider, int bodyLength, Request request)
Creates a new request session.


              
          
                
                  

        if (headers == null) {
            headers = new HashMap<String, String>();
        }
        mHeaders = headers;
        mBodyProvider = bodyProvider;
        mBodyLength = bodyLength;
        mMethod = method == null? "GET" : method;

        mUrl = url;
        mUri = uri;

        mRequestQueue = requestQueue;

        mRequest = request;
    
Methods Summary
private java.lang.StringH(java.lang.String param)

return
MD5 hash of param.

        if (param != null) {
            Md5MessageDigest md5 = new Md5MessageDigest();

            byte[] d = md5.digest(param.getBytes());
            if (d != null) {
                return bufferToHex(d);
            }
        }

        return null;
    
private java.lang.StringKD(java.lang.String secret, java.lang.String data)

return
MD5 hash of concat(secret, ":", data).

        return H(secret + ":" + data);
    
public static java.lang.StringauthorizationHeader(boolean isProxy)

return
The right authorization header (dependeing on whether it is a proxy or not).

        if (!isProxy) {
            return AUTHORIZATION_HEADER;
        } else {
            return PROXY_AUTHORIZATION_HEADER;
        }
    
private java.lang.StringbufferToHex(byte[] buffer)

return
HEX buffer representation.

        final char hexChars[] =
            { '0",'1",'2",'3",'4",'5",'6",'7",'8",'9",'a",'b",'c",'d",'e",'f" };

        if (buffer != null) {
            int length = buffer.length;
            if (length > 0) {
                StringBuilder hex = new StringBuilder(2 * length);

                for (int i = 0; i < length; ++i) {
                    byte l = (byte) (buffer[i] & 0x0F);
                    byte h = (byte)((buffer[i] & 0xF0) >> 4);

                    hex.append(hexChars[h]);
                    hex.append(hexChars[l]);
                }

                return hex.toString();
            } else {
                return "";
            }
        }

        return null;
    
public voidcancel()
Cancels this request

        if (mRequest != null) {
            mRequest.cancel();
        }
    
public static java.lang.StringcomputeBasicAuthResponse(java.lang.String username, java.lang.String password)

return
Basic-scheme authentication response: BASE64(username:password).

        Assert.assertNotNull(username);
        Assert.assertNotNull(password);

        // encode username:password to base64
        return new String(Base64.encodeBase64((username + ':" + password).getBytes()));
    
private java.lang.StringcomputeCnonce()
Computes a random cnonce value based on the current time.

        Random rand = new Random();
        int nextInt = rand.nextInt();
        nextInt = (nextInt == Integer.MIN_VALUE) ?
                Integer.MAX_VALUE : Math.abs(nextInt);
        return Integer.toString(nextInt, 16);
    
private java.lang.StringcomputeDigest(java.lang.String A1, java.lang.String A2, java.lang.String nonce, java.lang.String QOP, java.lang.String nc, java.lang.String cnonce)

return
Double-quoted MD5 digest.

        if (HttpLog.LOGV) {
            HttpLog.v("computeDigest(): QOP: " + QOP);
        }

        if (QOP == null) {
            return KD(H(A1), nonce + ":" + H(A2));
        } else {
            if (QOP.equalsIgnoreCase("auth")) {
                return KD(H(A1), nonce + ":" + nc + ":" + cnonce + ":" + QOP + ":" + H(A2));
            }
        }

        return null;
    
private java.lang.StringcomputeDigestAuthResponse(java.lang.String username, java.lang.String password, java.lang.String realm, java.lang.String nonce, java.lang.String QOP, java.lang.String algorithm, java.lang.String opaque)

return
Digest-scheme authentication response.


        Assert.assertNotNull(username);
        Assert.assertNotNull(password);
        Assert.assertNotNull(realm);

        String A1 = username + ":" + realm + ":" + password;
        String A2 = mMethod  + ":" + mUrl;

        // because we do not preemptively send authorization headers, nc is always 1
        String nc = "000001";
        String cnonce = computeCnonce();
        String digest = computeDigest(A1, A2, nonce, QOP, nc, cnonce);

        String response = "";
        response += "username=" + doubleQuote(username) + ", ";
        response += "realm="    + doubleQuote(realm)    + ", ";
        response += "nonce="    + doubleQuote(nonce)    + ", ";
        response += "uri="      + doubleQuote(mUrl)     + ", ";
        response += "response=" + doubleQuote(digest) ;

        if (opaque     != null) {
            response += ", opaque=" + doubleQuote(opaque);
        }

         if (algorithm != null) {
            response += ", algorithm=" +  algorithm;
        }

        if (QOP        != null) {
            response += ", qop=" + QOP + ", nc=" + nc + ", cnonce=" + doubleQuote(cnonce);
        }

        return response;
    
private voidcreateAndQueueNewRequest()
Creates and queues new request.

        mRequest = mRequestQueue.queueRequest(
                mUrl, mUri, mMethod, mHeaders, mRequest.mEventHandler,
                mBodyProvider,
                mBodyLength, mRequest.mHighPriority).mRequest;
    
private java.lang.StringdoubleQuote(java.lang.String param)
"Double-quotes" the argument.

        if (param != null) {
            return "\"" + param + "\"";
        }

        return null;
    
public java.lang.StringgetMethod()

return
HTTP request method (GET, PUT, etc).

        return mMethod;
    
public intgetRedirectCount()

        return mRedirectCount;
    
public voidhandleSslErrorResponse(boolean proceed)
Handles SSL error(s) on the way down from the user (the user has already provided their feedback).

        if (mRequest != null) {
            mRequest.handleSslErrorResponse(proceed);
        }
    
public booleanisRedirectMax()

return
true if we've hit the max redirect count

        return mRedirectCount >= MAX_REDIRECT_COUNT;
    
public voidsetRedirectCount(int count)

        mRedirectCount = count;
    
private voidsetupAuthResponse()

        try {
            if (mBodyProvider != null) mBodyProvider.reset();
        } catch (java.io.IOException ex) {
            if (HttpLog.LOGV) {
                HttpLog.v("setupAuthResponse() failed to reset body provider");
            }
        }
        createAndQueueNewRequest();
    
public voidsetupBasicAuthResponse(boolean isProxy, java.lang.String username, java.lang.String password)
Create and queue an HTTP authentication-response (basic) request.

        String response = computeBasicAuthResponse(username, password);
        if (HttpLog.LOGV) {
            HttpLog.v("setupBasicAuthResponse(): response: " + response);
        }
        mHeaders.put(authorizationHeader(isProxy), "Basic " + response);
        setupAuthResponse();
    
public voidsetupDigestAuthResponse(boolean isProxy, java.lang.String username, java.lang.String password, java.lang.String realm, java.lang.String nonce, java.lang.String QOP, java.lang.String algorithm, java.lang.String opaque)
Create and queue an HTTP authentication-response (digest) request.


        String response = computeDigestAuthResponse(
                username, password, realm, nonce, QOP, algorithm, opaque);
        if (HttpLog.LOGV) {
            HttpLog.v("setupDigestAuthResponse(): response: " + response);
        }
        mHeaders.put(authorizationHeader(isProxy), "Digest " + response);
        setupAuthResponse();
    
public booleansetupRedirect(java.lang.String redirectTo, int statusCode, java.util.Map cacheHeaders)
Create and queue a redirect request.

param
redirectTo URL to redirect to
param
statusCode HTTP status code returned from original request
param
cacheHeaders Cache header for redirect URL
return
true if setup succeeds, false otherwise (redirect loop count exceeded, body provider unable to rewind on 307 redirect)

        if (HttpLog.LOGV) {
            HttpLog.v("RequestHandle.setupRedirect(): redirectCount " +
                  mRedirectCount);
        }

        // be careful and remove authentication headers, if any
        mHeaders.remove(AUTHORIZATION_HEADER);
        mHeaders.remove(PROXY_AUTHORIZATION_HEADER);

        if (++mRedirectCount == MAX_REDIRECT_COUNT) {
            // Way too many redirects -- fail out
            if (HttpLog.LOGV) HttpLog.v(
                    "RequestHandle.setupRedirect(): too many redirects " +
                    mRequest);
            mRequest.error(EventHandler.ERROR_REDIRECT_LOOP,
                           com.android.internal.R.string.httpErrorRedirectLoop);
            return false;
        }

        if (mUrl.startsWith("https:") && redirectTo.startsWith("http:")) {
            // implement http://www.w3.org/Protocols/rfc2616/rfc2616-sec15.html#sec15.1.3
            if (HttpLog.LOGV) {
                HttpLog.v("blowing away the referer on an https -> http redirect");
            }
            mHeaders.remove("Referer");
        }

        mUrl = redirectTo;
        try {
            mUri = new WebAddress(mUrl);
        } catch (ParseException e) {
            e.printStackTrace();
        }

        // update the "cookie" header based on the redirected url
        mHeaders.remove("cookie");
        String cookie = CookieManager.getInstance().getCookie(mUri);
        if (cookie != null && cookie.length() > 0) {
            mHeaders.put("cookie", cookie);
        }

        if ((statusCode == 302 || statusCode == 303) && mMethod.equals("POST")) {
            if (HttpLog.LOGV) {
                HttpLog.v("replacing POST with GET on redirect to " + redirectTo);
            }
            mMethod = "GET";
        }
        /* Only repost content on a 307.  If 307, reset the body
           provider so we can replay the body */
        if (statusCode == 307) {
            try {
                if (mBodyProvider != null) mBodyProvider.reset();
            } catch (java.io.IOException ex) {
                if (HttpLog.LOGV) {
                    HttpLog.v("setupAuthResponse() failed to reset body provider");
                }
                return false;
            }

        } else {
            mHeaders.remove("Content-Type");
            mBodyProvider = null;
        }

        // Update the cache headers for this URL
        mHeaders.putAll(cacheHeaders);

        createAndQueueNewRequest();
        return true;
    
public voidwaitUntilComplete()

        mRequest.waitUntilComplete();