1.
PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start(
ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync)
{
// Called on main thread
FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(client);
#if USE(CHROME_NETWORK_STACK)
WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view());
bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent());
return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext());
#else
return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync);
#endif
}
2.
PassRefPtr<WebCore::ResourceLoaderAndroid>
WebFrame::startLoadingResource(WebCore::ResourceHandle* loader,
const WebCore::ResourceRequest& request,
bool mainResource,
bool synchronous)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
#endif
LOGV("::WebCore:: startLoadingResource(%p, %s)",
loader, request.url().string().latin1().data());
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
return 0;
WTF::String method = request.httpMethod();
WebCore::HTTPHeaderMap headers = request.httpHeaderFields();
WTF::String urlStr = request.url().string();
int colon = urlStr.find(':');
bool allLower = true;
for (int index = 0; index < colon; index++) {
UChar ch = urlStr[index];
if (!WTF::isASCIIAlpha(ch))
break;
allLower &= WTF::isASCIILower(ch);
if (index == colon - 1 && !allLower) {
urlStr = urlStr.substring(0, colon).lower()
+ urlStr.substring(colon);
}
}
LOGV("%s lower=%s", __FUNCTION__, urlStr.latin1().data());
jstring jUrlStr = wtfStringToJstring(env, urlStr);
jstring jMethodStr = NULL;
if (!method.isEmpty())
jMethodStr = wtfStringToJstring(env, method);
WebCore::FormData* formdata = request.httpBody();
jbyteArray jPostDataStr = getPostData(request);
jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers);
// Convert the WebCore Cache Policy to a WebView Cache Policy.
int cacheMode = 0; // WebSettings.LOAD_NORMAL
switch (request.cachePolicy()) {
case WebCore::ReloadIgnoringCacheData:
cacheMode = 2; // WebSettings.LOAD_NO_CACHE
break;
case WebCore::ReturnCacheDataDontLoad:
cacheMode = 3; // WebSettings.LOAD_CACHE_ONLY
break;
case WebCore::ReturnCacheDataElseLoad:
cacheMode = 1; // WebSettings.LOAD_CACHE_ELSE_NETWORK
break;
case WebCore::UseProtocolCachePolicy:
default:
break;
}
LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii().data(), cacheMode);
ResourceHandleInternal* loaderInternal = loader->getInternal();
jstring jUsernameString = loaderInternal->m_user.isEmpty() ?
NULL : wtfStringToJstring(env, loaderInternal->m_user);
jstring jPasswordString = loaderInternal->m_pass.isEmpty() ?
NULL : wtfStringToJstring(env, loaderInternal->m_pass);
bool isUserGesture = UserGestureIndicator::processingUserGesture();
jobject jLoadListener =
env->CallObjectMethod(javaFrame.get(), mJavaFrame->mStartLoadingResource,
(int)loader, jUrlStr, jMethodStr, jHeaderMap,
jPostDataStr, formdata ? formdata->identifier(): 0,
cacheMode, mainResource, isUserGesture,
synchronous, jUsernameString, jPasswordString);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(jMethodStr);
env->DeleteLocalRef(jPostDataStr);
env->DeleteLocalRef(jHeaderMap);
env->DeleteLocalRef(jUsernameString);
env->DeleteLocalRef(jPasswordString);
if (checkException(env))
return 0;
PassRefPtr<WebCore::ResourceLoaderAndroid> h;
if (jLoadListener)
h = WebCoreResourceLoader::create(env, jLoadListener);
env->DeleteLocalRef(jLoadListener);
return h;
}
3.
/**
* Start loading a resource.
* @param loaderHandle The native ResourceLoader that is the target of the
* data.
* @param url The url to load.
* @param method The http method.
* @param headers The http headers.
* @param postData If the method is "POST" postData is sent as the request
* body. Is null when empty.
* @param postDataIdentifier If the post data contained form this is the form identifier, otherwise it is 0.
* @param cacheMode The cache mode to use when loading this resource. See WebSettings.setCacheMode
* @param mainResource True if the this resource is the main request, not a supporting resource
* @param userGesture
* @param synchronous True if the load is synchronous.
* @return A newly created LoadListener object.
*/
private LoadListener startLoadingResource(int loaderHandle,
String url,
String method,
HashMap headers,
byte[] postData,
long postDataIdentifier,
int cacheMode,
boolean mainResource,
boolean userGesture,
boolean synchronous,
String username,
String password) {
PerfChecker checker = new PerfChecker();
if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
cacheMode = mSettings.getCacheMode();
}
if (method.equals("POST")) {
// Don't use the cache on POSTs when issuing a normal POST
// request.
if (cacheMode == WebSettings.LOAD_NORMAL) {
cacheMode = WebSettings.LOAD_NO_CACHE;
}
String[] ret = getUsernamePassword();
if (ret != null) {
String domUsername = ret[0];
String domPassword = ret[1];
maybeSavePassword(postData, domUsername, domPassword);
}
}
// is this resource the main-frame top-level page?
boolean isMainFramePage = mIsMainFrame;
if (DebugFlags.BROWSER_FRAME) {
Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
+ method + ", postData=" + postData + ", isMainFramePage="
+ isMainFramePage + ", mainResource=" + mainResource
+ ", userGesture=" + userGesture);
}
// Create a LoadListener
LoadListener loadListener = LoadListener.getLoadListener(mContext,
this, url, loaderHandle, synchronous, isMainFramePage,
mainResource, userGesture, postDataIdentifier, username, password);
if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
// send an error message, so that loadListener can be deleted
// after this is returned. This is important as LoadListener's
// nativeError will remove the request from its DocLoader's request
// list. But the set up is not done until this method is returned.
loadListener.error(
android.net.http.EventHandler.ERROR, mContext.getString(
com.android.internal.R.string.httpErrorTooManyRequests));
return loadListener;
}
// Note that we are intentionally skipping
// inputStreamForAndroidResource. This is so that FrameLoader will use
// the various StreamLoader classes to handle assets.
FrameLoader loader = new FrameLoader(loadListener, mSettings, method,
mCallbackProxy.shouldInterceptRequest(url));
loader.setHeaders(headers);
loader.setPostData(postData);
// Set the load mode to the mode used for the current page.
// If WebKit wants validation, go to network directly.
loader.setCacheMode(headers.containsKey("If-Modified-Since")
|| headers.containsKey("If-None-Match") ?
WebSettings.LOAD_NO_CACHE : cacheMode);
// Set referrer to current URL?
if (!loader.executeLoad()) {
checker.responseAlert("startLoadingResource fail");
}
checker.responseAlert("startLoadingResource succeed");
return !synchronous ? loadListener : null;
}
4.
/**
* Issues the load request.
*
* Return value does not indicate if the load was successful or not. It
* simply indicates that the load request is reasonable.
*
* @return true if the load is reasonable.
*/
public boolean executeLoad() {
String url = mListener.url();
// Process intercepted requests first as they could be any url.
if (mInterceptResponse != null) {
if (mListener.isSynchronous()) {
mInterceptResponse.loader(mListener).load();
} else {
WebViewWorker.getHandler().obtainMessage(
WebViewWorker.MSG_ADD_STREAMLOADER,
mInterceptResponse.loader(mListener)).sendToTarget();
}
return true;
} else if (URLUtil.isNetworkUrl(url)){
if (mSettings.getBlockNetworkLoads()) {
mListener.error(EventHandler.ERROR_BAD_URL,
mListener.getContext().getString(
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
// Make sure the host part of the url is correctly
// encoded before sending the request
if (!URLUtil.verifyURLEncoding(mListener.host())) {
mListener.error(EventHandler.ERROR_BAD_URL,
mListener.getContext().getString(
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
mNetwork = Network.getInstance(mListener.getContext());
if (mListener.isSynchronous()) {
return handleHTTPLoad();
}
WebViewWorker.getHandler().obtainMessage(
WebViewWorker.MSG_ADD_HTTPLOADER, this).sendToTarget();
return true;
} else if (handleLocalFile(url, mListener, mSettings)) {
return true;
}
if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
+ mListener.url());
}
mListener.error(EventHandler.ERROR_UNSUPPORTED_SCHEME,
mListener.getContext().getText(
com.android.internal.R.string.httpErrorUnsupportedScheme).toString());
return false;
}
5.
boolean handleHTTPLoad() {
if (mHeaders == null) {
mHeaders = new HashMap<String, String>();
}
populateStaticHeaders();
populateHeaders();
// response was handled by Cache, don't issue HTTP request
if (handleCache()) {
// push the request data down to the LoadListener
// as response from the cache could be a redirect
// and we may need to initiate a network request if the cache
// can't satisfy redirect URL
mListener.setRequestData(mMethod, mHeaders, mPostData);
return true;
}
if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
+ mListener.url());
}
boolean ret = false;
int error = EventHandler.ERROR_UNSUPPORTED_SCHEME;
try {
ret = mNetwork.requestURL(mMethod, mHeaders,
mPostData, mListener);
} catch (android.net.ParseException ex) {
error = EventHandler.ERROR_BAD_URL;
} catch (java.lang.RuntimeException ex) {
/* probably an empty header set by javascript. We want
the same result as bad URL */
error = EventHandler.ERROR_BAD_URL;
}
if (!ret) {
mListener.error(error, ErrorStrings.getString(error, mListener.getContext()));
return false;
}
return true;
}
6.
/**
* Request a url from either the network or the file system.
* @param url The url to load.
* @param method The http method.
* @param headers The http headers.
* @param postData The body of the request.
* @param loader A LoadListener for receiving the results of the request.
* @return True if the request was successfully queued.
*/
public boolean requestURL(String method,
Map<String, String> headers,
byte [] postData,
LoadListener loader) {
String url = loader.url();
// Not a valid url, return false because we won't service the request!
if (!URLUtil.isValidUrl(url)) {
return false;
}
// asset, res, file system or data stream are handled in the other code
// path. This only handles network request.
if (URLUtil.isAssetUrl(url) || URLUtil.isResourceUrl(url)
|| URLUtil.isFileUrl(url) || URLUtil.isDataUrl(url)) {
return false;
}
// If this is a prefetch, abort it if we're roaming.
if (mRoaming && headers.containsKey("X-Moz") && "prefetch".equals(headers.get("X-Moz"))) {
return false;
}
/* FIXME: this is lame. Pass an InputStream in, rather than
making this lame one here */
InputStream bodyProvider = null;
int bodyLength = 0;
if (postData != null) {
bodyLength = postData.length;
bodyProvider = new ByteArrayInputStream(postData);
}
RequestQueue q = mRequestQueue;
RequestHandle handle = null;
if (loader.isSynchronous()) {
handle = q.queueSynchronousRequest(url, loader.getWebAddress(),
method, headers, loader, bodyProvider, bodyLength);
loader.attachRequestHandle(handle);
handle.processRequest();
loader.loadSynchronousMessages();
} else {
handle = q.queueRequest(url, loader.getWebAddress(), method,
headers, loader, bodyProvider, bodyLength);
// FIXME: Although this is probably a rare condition, normal network
// requests are processed in a separate thread. This means that it
// is possible to process part of the request before setting the
// request handle on the loader. We should probably refactor this to
// ensure the handle is attached before processing begins.
loader.attachRequestHandle(handle);
}
return true;
}
PassRefPtr<ResourceLoaderAndroid> ResourceLoaderAndroid::start(
ResourceHandle* handle, const ResourceRequest& request, FrameLoaderClient* client, bool isMainResource, bool isSync)
{
// Called on main thread
FrameLoaderClientAndroid* clientAndroid = static_cast<FrameLoaderClientAndroid*>(client);
#if USE(CHROME_NETWORK_STACK)
WebViewCore* webViewCore = WebViewCore::getWebViewCore(clientAndroid->getFrame()->view());
bool isMainFrame = !(clientAndroid->getFrame()->tree() && clientAndroid->getFrame()->tree()->parent());
return WebUrlLoader::start(client, handle, request, isMainResource, isMainFrame, isSync, webViewCore->webRequestContext());
#else
return clientAndroid->webFrame()->startLoadingResource(handle, request, isMainResource, isSync);
#endif
}
2.
PassRefPtr<WebCore::ResourceLoaderAndroid>
WebFrame::startLoadingResource(WebCore::ResourceHandle* loader,
const WebCore::ResourceRequest& request,
bool mainResource,
bool synchronous)
{
#ifdef ANDROID_INSTRUMENT
TimeCounterAuto counter(TimeCounter::JavaCallbackTimeCounter);
#endif
LOGV("::WebCore:: startLoadingResource(%p, %s)",
loader, request.url().string().latin1().data());
JNIEnv* env = getJNIEnv();
AutoJObject javaFrame = mJavaFrame->frame(env);
if (!javaFrame.get())
return 0;
WTF::String method = request.httpMethod();
WebCore::HTTPHeaderMap headers = request.httpHeaderFields();
WTF::String urlStr = request.url().string();
int colon = urlStr.find(':');
bool allLower = true;
for (int index = 0; index < colon; index++) {
UChar ch = urlStr[index];
if (!WTF::isASCIIAlpha(ch))
break;
allLower &= WTF::isASCIILower(ch);
if (index == colon - 1 && !allLower) {
urlStr = urlStr.substring(0, colon).lower()
+ urlStr.substring(colon);
}
}
LOGV("%s lower=%s", __FUNCTION__, urlStr.latin1().data());
jstring jUrlStr = wtfStringToJstring(env, urlStr);
jstring jMethodStr = NULL;
if (!method.isEmpty())
jMethodStr = wtfStringToJstring(env, method);
WebCore::FormData* formdata = request.httpBody();
jbyteArray jPostDataStr = getPostData(request);
jobject jHeaderMap = createJavaMapFromHTTPHeaders(env, headers);
// Convert the WebCore Cache Policy to a WebView Cache Policy.
int cacheMode = 0; // WebSettings.LOAD_NORMAL
switch (request.cachePolicy()) {
case WebCore::ReloadIgnoringCacheData:
cacheMode = 2; // WebSettings.LOAD_NO_CACHE
break;
case WebCore::ReturnCacheDataDontLoad:
cacheMode = 3; // WebSettings.LOAD_CACHE_ONLY
break;
case WebCore::ReturnCacheDataElseLoad:
cacheMode = 1; // WebSettings.LOAD_CACHE_ELSE_NETWORK
break;
case WebCore::UseProtocolCachePolicy:
default:
break;
}
LOGV("::WebCore:: startLoadingResource %s with cacheMode %d", urlStr.ascii().data(), cacheMode);
ResourceHandleInternal* loaderInternal = loader->getInternal();
jstring jUsernameString = loaderInternal->m_user.isEmpty() ?
NULL : wtfStringToJstring(env, loaderInternal->m_user);
jstring jPasswordString = loaderInternal->m_pass.isEmpty() ?
NULL : wtfStringToJstring(env, loaderInternal->m_pass);
bool isUserGesture = UserGestureIndicator::processingUserGesture();
jobject jLoadListener =
env->CallObjectMethod(javaFrame.get(), mJavaFrame->mStartLoadingResource,
(int)loader, jUrlStr, jMethodStr, jHeaderMap,
jPostDataStr, formdata ? formdata->identifier(): 0,
cacheMode, mainResource, isUserGesture,
synchronous, jUsernameString, jPasswordString);
env->DeleteLocalRef(jUrlStr);
env->DeleteLocalRef(jMethodStr);
env->DeleteLocalRef(jPostDataStr);
env->DeleteLocalRef(jHeaderMap);
env->DeleteLocalRef(jUsernameString);
env->DeleteLocalRef(jPasswordString);
if (checkException(env))
return 0;
PassRefPtr<WebCore::ResourceLoaderAndroid> h;
if (jLoadListener)
h = WebCoreResourceLoader::create(env, jLoadListener);
env->DeleteLocalRef(jLoadListener);
return h;
}
3.
/**
* Start loading a resource.
* @param loaderHandle The native ResourceLoader that is the target of the
* data.
* @param url The url to load.
* @param method The http method.
* @param headers The http headers.
* @param postData If the method is "POST" postData is sent as the request
* body. Is null when empty.
* @param postDataIdentifier If the post data contained form this is the form identifier, otherwise it is 0.
* @param cacheMode The cache mode to use when loading this resource. See WebSettings.setCacheMode
* @param mainResource True if the this resource is the main request, not a supporting resource
* @param userGesture
* @param synchronous True if the load is synchronous.
* @return A newly created LoadListener object.
*/
private LoadListener startLoadingResource(int loaderHandle,
String url,
String method,
HashMap headers,
byte[] postData,
long postDataIdentifier,
int cacheMode,
boolean mainResource,
boolean userGesture,
boolean synchronous,
String username,
String password) {
PerfChecker checker = new PerfChecker();
if (mSettings.getCacheMode() != WebSettings.LOAD_DEFAULT) {
cacheMode = mSettings.getCacheMode();
}
if (method.equals("POST")) {
// Don't use the cache on POSTs when issuing a normal POST
// request.
if (cacheMode == WebSettings.LOAD_NORMAL) {
cacheMode = WebSettings.LOAD_NO_CACHE;
}
String[] ret = getUsernamePassword();
if (ret != null) {
String domUsername = ret[0];
String domPassword = ret[1];
maybeSavePassword(postData, domUsername, domPassword);
}
}
// is this resource the main-frame top-level page?
boolean isMainFramePage = mIsMainFrame;
if (DebugFlags.BROWSER_FRAME) {
Log.v(LOGTAG, "startLoadingResource: url=" + url + ", method="
+ method + ", postData=" + postData + ", isMainFramePage="
+ isMainFramePage + ", mainResource=" + mainResource
+ ", userGesture=" + userGesture);
}
// Create a LoadListener
LoadListener loadListener = LoadListener.getLoadListener(mContext,
this, url, loaderHandle, synchronous, isMainFramePage,
mainResource, userGesture, postDataIdentifier, username, password);
if (LoadListener.getNativeLoaderCount() > MAX_OUTSTANDING_REQUESTS) {
// send an error message, so that loadListener can be deleted
// after this is returned. This is important as LoadListener's
// nativeError will remove the request from its DocLoader's request
// list. But the set up is not done until this method is returned.
loadListener.error(
android.net.http.EventHandler.ERROR, mContext.getString(
com.android.internal.R.string.httpErrorTooManyRequests));
return loadListener;
}
// Note that we are intentionally skipping
// inputStreamForAndroidResource. This is so that FrameLoader will use
// the various StreamLoader classes to handle assets.
FrameLoader loader = new FrameLoader(loadListener, mSettings, method,
mCallbackProxy.shouldInterceptRequest(url));
loader.setHeaders(headers);
loader.setPostData(postData);
// Set the load mode to the mode used for the current page.
// If WebKit wants validation, go to network directly.
loader.setCacheMode(headers.containsKey("If-Modified-Since")
|| headers.containsKey("If-None-Match") ?
WebSettings.LOAD_NO_CACHE : cacheMode);
// Set referrer to current URL?
if (!loader.executeLoad()) {
checker.responseAlert("startLoadingResource fail");
}
checker.responseAlert("startLoadingResource succeed");
return !synchronous ? loadListener : null;
}
4.
/**
* Issues the load request.
*
* Return value does not indicate if the load was successful or not. It
* simply indicates that the load request is reasonable.
*
* @return true if the load is reasonable.
*/
public boolean executeLoad() {
String url = mListener.url();
// Process intercepted requests first as they could be any url.
if (mInterceptResponse != null) {
if (mListener.isSynchronous()) {
mInterceptResponse.loader(mListener).load();
} else {
WebViewWorker.getHandler().obtainMessage(
WebViewWorker.MSG_ADD_STREAMLOADER,
mInterceptResponse.loader(mListener)).sendToTarget();
}
return true;
} else if (URLUtil.isNetworkUrl(url)){
if (mSettings.getBlockNetworkLoads()) {
mListener.error(EventHandler.ERROR_BAD_URL,
mListener.getContext().getString(
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
// Make sure the host part of the url is correctly
// encoded before sending the request
if (!URLUtil.verifyURLEncoding(mListener.host())) {
mListener.error(EventHandler.ERROR_BAD_URL,
mListener.getContext().getString(
com.android.internal.R.string.httpErrorBadUrl));
return false;
}
mNetwork = Network.getInstance(mListener.getContext());
if (mListener.isSynchronous()) {
return handleHTTPLoad();
}
WebViewWorker.getHandler().obtainMessage(
WebViewWorker.MSG_ADD_HTTPLOADER, this).sendToTarget();
return true;
} else if (handleLocalFile(url, mListener, mSettings)) {
return true;
}
if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader.executeLoad: url protocol not supported:"
+ mListener.url());
}
mListener.error(EventHandler.ERROR_UNSUPPORTED_SCHEME,
mListener.getContext().getText(
com.android.internal.R.string.httpErrorUnsupportedScheme).toString());
return false;
}
5.
boolean handleHTTPLoad() {
if (mHeaders == null) {
mHeaders = new HashMap<String, String>();
}
populateStaticHeaders();
populateHeaders();
// response was handled by Cache, don't issue HTTP request
if (handleCache()) {
// push the request data down to the LoadListener
// as response from the cache could be a redirect
// and we may need to initiate a network request if the cache
// can't satisfy redirect URL
mListener.setRequestData(mMethod, mHeaders, mPostData);
return true;
}
if (DebugFlags.FRAME_LOADER) {
Log.v(LOGTAG, "FrameLoader: http " + mMethod + " load for: "
+ mListener.url());
}
boolean ret = false;
int error = EventHandler.ERROR_UNSUPPORTED_SCHEME;
try {
ret = mNetwork.requestURL(mMethod, mHeaders,
mPostData, mListener);
} catch (android.net.ParseException ex) {
error = EventHandler.ERROR_BAD_URL;
} catch (java.lang.RuntimeException ex) {
/* probably an empty header set by javascript. We want
the same result as bad URL */
error = EventHandler.ERROR_BAD_URL;
}
if (!ret) {
mListener.error(error, ErrorStrings.getString(error, mListener.getContext()));
return false;
}
return true;
}
6.
/**
* Request a url from either the network or the file system.
* @param url The url to load.
* @param method The http method.
* @param headers The http headers.
* @param postData The body of the request.
* @param loader A LoadListener for receiving the results of the request.
* @return True if the request was successfully queued.
*/
public boolean requestURL(String method,
Map<String, String> headers,
byte [] postData,
LoadListener loader) {
String url = loader.url();
// Not a valid url, return false because we won't service the request!
if (!URLUtil.isValidUrl(url)) {
return false;
}
// asset, res, file system or data stream are handled in the other code
// path. This only handles network request.
if (URLUtil.isAssetUrl(url) || URLUtil.isResourceUrl(url)
|| URLUtil.isFileUrl(url) || URLUtil.isDataUrl(url)) {
return false;
}
// If this is a prefetch, abort it if we're roaming.
if (mRoaming && headers.containsKey("X-Moz") && "prefetch".equals(headers.get("X-Moz"))) {
return false;
}
/* FIXME: this is lame. Pass an InputStream in, rather than
making this lame one here */
InputStream bodyProvider = null;
int bodyLength = 0;
if (postData != null) {
bodyLength = postData.length;
bodyProvider = new ByteArrayInputStream(postData);
}
RequestQueue q = mRequestQueue;
RequestHandle handle = null;
if (loader.isSynchronous()) {
handle = q.queueSynchronousRequest(url, loader.getWebAddress(),
method, headers, loader, bodyProvider, bodyLength);
loader.attachRequestHandle(handle);
handle.processRequest();
loader.loadSynchronousMessages();
} else {
handle = q.queueRequest(url, loader.getWebAddress(), method,
headers, loader, bodyProvider, bodyLength);
// FIXME: Although this is probably a rare condition, normal network
// requests are processed in a separate thread. This means that it
// is possible to process part of the request before setting the
// request handle on the loader. We should probably refactor this to
// ensure the handle is attached before processing begins.
loader.attachRequestHandle(handle);
}
return true;
}