• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2010, The Android Open Source Project
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *  * Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  *  * Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25 
26 #include "config.h"
27 #include "WebRequest.h"
28 
29 #include "JNIUtility.h"
30 #include "MainThread.h"
31 #include "UrlInterceptResponse.h"
32 #include "WebCoreFrameBridge.h"
33 #include "WebCoreJni.h"
34 #include "WebRequestContext.h"
35 #include "WebResourceRequest.h"
36 #include "WebUrlLoaderClient.h"
37 #include "jni.h"
38 
39 #include <cutils/log.h>
40 #include <openssl/x509.h>
41 #include <string>
42 #include <androidfw/AssetManager.h>
43 
44 extern android::AssetManager* globalAssetManager();
45 
46 // TODO:
47 // - Finish the file upload. Testcase is mobile buzz
48 // - Add network throttle needed by Android plugins
49 
50 // TODO: Turn off asserts crashing before release
51 // http://b/issue?id=2951985
52 #undef ASSERT
53 #define ASSERT(assertion, ...) do \
54     if (!(assertion)) { \
55         android_printLog(ANDROID_LOG_ERROR, __FILE__, __VA_ARGS__); \
56     } \
57 while (0)
58 
59 namespace android {
60 
61 namespace {
62 const int kInitialReadBufSize = 32768;
63 const char* kXRequestedWithHeader = "X-Requested-With";
64 
65 struct RequestPackageName {
66     std::string value;
67     RequestPackageName();
68 };
69 
RequestPackageName()70 RequestPackageName::RequestPackageName() {
71     JNIEnv* env = JSC::Bindings::getJNIEnv();
72     jclass bridgeClass = env->FindClass("android/webkit/JniUtil");
73     jmethodID method = env->GetStaticMethodID(bridgeClass, "getPackageName", "()Ljava/lang/String;");
74     value = jstringToStdString(env, static_cast<jstring>(env->CallStaticObjectMethod(bridgeClass, method)));
75     env->DeleteLocalRef(bridgeClass);
76 }
77 
78 base::LazyInstance<RequestPackageName> s_packageName(base::LINKER_INITIALIZED);
79 
80 }
81 
WebRequest(WebUrlLoaderClient * loader,const WebResourceRequest & webResourceRequest)82 WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest)
83     : m_urlLoader(loader)
84     , m_url(webResourceRequest.url())
85     , m_userAgent(webResourceRequest.userAgent())
86     , m_referer(webResourceRequest.referrer())
87     , m_loadState(Created)
88     , m_authRequestCount(0)
89     , m_cacheMode(0)
90     , m_runnableFactory(this)
91     , m_wantToPause(false)
92     , m_isPaused(false)
93     , m_isSync(false)
94 {
95     GURL gurl(m_url);
96 
97     m_request = new net::URLRequest(gurl, this);
98 
99     m_request->SetExtraRequestHeaders(webResourceRequest.requestHeaders());
100     m_request->SetExtraRequestHeaderByName(kXRequestedWithHeader, s_packageName.Get().value, false);
101     m_request->set_referrer(webResourceRequest.referrer());
102     m_request->set_method(webResourceRequest.method());
103     m_request->set_load_flags(webResourceRequest.loadFlags());
104 }
105 
106 // This is a special URL for Android. Query the Java InputStream
107 // for data and send to WebCore
WebRequest(WebUrlLoaderClient * loader,const WebResourceRequest & webResourceRequest,UrlInterceptResponse * intercept)108 WebRequest::WebRequest(WebUrlLoaderClient* loader, const WebResourceRequest& webResourceRequest, UrlInterceptResponse* intercept)
109     : m_urlLoader(loader)
110     , m_interceptResponse(intercept)
111     , m_url(webResourceRequest.url())
112     , m_userAgent(webResourceRequest.userAgent())
113     , m_referer(webResourceRequest.referrer())
114     , m_loadState(Created)
115     , m_authRequestCount(0)
116     , m_cacheMode(0)
117     , m_runnableFactory(this)
118     , m_wantToPause(false)
119     , m_isPaused(false)
120     , m_isSync(false)
121 {
122 }
123 
~WebRequest()124 WebRequest::~WebRequest()
125 {
126     ASSERT(m_loadState == Finished, "dtor called on a WebRequest in a different state than finished (%d)", m_loadState);
127 
128     m_loadState = Deleted;
129 }
130 
getUrl() const131 const std::string& WebRequest::getUrl() const
132 {
133     return m_url;
134 }
135 
getUserAgent() const136 const std::string& WebRequest::getUserAgent() const
137 {
138     return m_userAgent;
139 }
140 
getReferer() const141 const std::string& WebRequest::getReferer() const
142 {
143     return m_referer;
144 }
145 
146 #ifdef LOG_REQUESTS
147 namespace {
148 int remaining = 0;
149 }
150 #endif
151 
finish(bool success)152 void WebRequest::finish(bool success)
153 {
154     m_runnableFactory.RevokeAll();
155     ASSERT(m_loadState < Finished, "(%p) called finish on an already finished WebRequest (%d) (%s)", this, m_loadState, m_url.c_str());
156     if (m_loadState >= Finished)
157         return;
158 #ifdef LOG_REQUESTS
159     time_t finish;
160     time(&finish);
161     finish = finish - m_startTime;
162     struct tm * timeinfo;
163     char buffer[80];
164     timeinfo = localtime(&finish);
165     strftime(buffer, 80, "Time: %M:%S",timeinfo);
166     android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) finish (%d) (%s) (%d) (%s)", this, --remaining, buffer, success, m_url.c_str());
167 #endif
168 
169     // Make sure WebUrlLoaderClient doesn't delete us in the middle of this method.
170     scoped_refptr<WebRequest> guard(this);
171 
172     m_loadState = Finished;
173     if (success) {
174         m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
175                 m_urlLoader.get(), &WebUrlLoaderClient::didFinishLoading));
176     } else {
177         if (m_interceptResponse == NULL) {
178             OwnPtr<WebResponse> webResponse(new WebResponse(m_request.get()));
179             m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
180                     m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release()));
181         } else {
182             OwnPtr<WebResponse> webResponse(new WebResponse(m_url, m_interceptResponse->mimeType(), 0,
183                     m_interceptResponse->encoding(), m_interceptResponse->status()));
184             m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
185                     m_urlLoader.get(), &WebUrlLoaderClient::didFail, webResponse.release()));
186         }
187     }
188     m_networkBuffer = 0;
189     m_request = 0;
190     m_urlLoader = 0;
191 }
192 
appendFileToUpload(const std::string & filename)193 void WebRequest::appendFileToUpload(const std::string& filename)
194 {
195     // AppendFileToUpload is only valid before calling start
196     ASSERT(m_loadState == Created, "appendFileToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str());
197     FilePath filePath(filename);
198     m_request->AppendFileToUpload(filePath);
199 }
200 
appendBytesToUpload(WTF::Vector<char> * data)201 void WebRequest::appendBytesToUpload(WTF::Vector<char>* data)
202 {
203     // AppendBytesToUpload is only valid before calling start
204     ASSERT(m_loadState == Created, "appendBytesToUpload called on a WebRequest not in CREATED state: (%s)", m_url.c_str());
205     m_request->AppendBytesToUpload(data->data(), data->size());
206     delete data;
207 }
208 
setRequestContext(WebRequestContext * context)209 void WebRequest::setRequestContext(WebRequestContext* context)
210 {
211     m_cacheMode = context->getCacheMode();
212     if (m_request)
213         m_request->set_context(context);
214 }
215 
updateLoadFlags(int & loadFlags)216 void WebRequest::updateLoadFlags(int& loadFlags)
217 {
218     if (m_cacheMode == 1) { // LOAD_CACHE_ELSE_NETWORK
219         loadFlags |= net::LOAD_PREFERRING_CACHE;
220         loadFlags &= ~net::LOAD_VALIDATE_CACHE;
221     }
222     if (m_cacheMode == 2) // LOAD_NO_CACHE
223         loadFlags |= net::LOAD_BYPASS_CACHE;
224     if (m_cacheMode == 3) // LOAD_CACHE_ONLY
225         loadFlags |= net::LOAD_ONLY_FROM_CACHE;
226 
227     if (m_isSync)
228         loadFlags |= net::LOAD_IGNORE_LIMITS;
229 }
230 
start()231 void WebRequest::start()
232 {
233     ASSERT(m_loadState == Created, "Start called on a WebRequest not in CREATED state: (%s)", m_url.c_str());
234 #ifdef LOG_REQUESTS
235     android_printLog(ANDROID_LOG_DEBUG, "KM", "(%p) start (%d) (%s)", this, ++remaining, m_url.c_str());
236     time(&m_startTime);
237 #endif
238 
239     m_loadState = Started;
240 
241     if (m_interceptResponse != NULL)
242         return handleInterceptedURL();
243 
244     // Handle data urls before we send it off to the http stack
245     if (m_request->url().SchemeIs("data"))
246         return handleDataURL(m_request->url());
247 
248     if (m_request->url().SchemeIs("browser"))
249         return handleBrowserURL(m_request->url());
250 
251     // Update load flags with settings from WebSettings
252     int loadFlags = m_request->load_flags();
253     updateLoadFlags(loadFlags);
254     m_request->set_load_flags(loadFlags);
255 
256     m_request->Start();
257 }
258 
cancel()259 void WebRequest::cancel()
260 {
261     ASSERT(m_loadState >= Started, "Cancel called on a not started WebRequest: (%s)", m_url.c_str());
262     ASSERT(m_loadState != Cancelled, "Cancel called on an already cancelled WebRequest: (%s)", m_url.c_str());
263 
264     // There is a possible race condition between the IO thread finishing the request and
265     // the WebCore thread cancelling it. If the request has already finished, do
266     // nothing to avoid sending duplicate finish messages to WebCore.
267     if (m_loadState > Cancelled) {
268         return;
269     }
270     ASSERT(m_request, "Request set to 0 before it is finished");
271 
272     m_loadState = Cancelled;
273 
274     m_request->Cancel();
275     finish(true);
276 }
277 
pauseLoad(bool pause)278 void WebRequest::pauseLoad(bool pause)
279 {
280     ASSERT(m_loadState >= GotData, "PauseLoad in state other than RESPONSE and GOTDATA");
281     if (pause) {
282         if (!m_isPaused)
283             m_wantToPause = true;
284     } else {
285         m_wantToPause = false;
286         if (m_isPaused) {
287             m_isPaused = false;
288             MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading));
289         }
290     }
291 }
292 
handleInterceptedURL()293 void WebRequest::handleInterceptedURL()
294 {
295     m_loadState = Response;
296 
297     const std::string& mime = m_interceptResponse->mimeType();
298     // Get the MIME type from the URL. "text/html" is a last resort, hopefully overridden.
299     std::string mimeType("text/html");
300     if (mime == "") {
301         // Get the MIME type from the file extension, if any.
302         FilePath path(m_url);
303         net::GetMimeTypeFromFile(path, &mimeType);
304     } else {
305         // Set from the intercept response.
306         mimeType = mime;
307     }
308 
309 
310     OwnPtr<WebResponse> webResponse(new WebResponse(m_url, mimeType, 0, m_interceptResponse->encoding(), m_interceptResponse->status()));
311     m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
312             m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release()));
313 
314     do {
315         // data is deleted in WebUrlLoaderClient::didReceiveAndroidFileData
316         // data is sent to the webcore thread
317         OwnPtr<std::vector<char> > data(new std::vector<char>);
318         data->reserve(kInitialReadBufSize);
319 
320         // Read returns false on error and size of 0 on eof.
321         if (!m_interceptResponse->readStream(data.get()) || data->size() == 0)
322             break;
323 
324         m_loadState = GotData;
325         m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
326                 m_urlLoader.get(), &WebUrlLoaderClient::didReceiveAndroidFileData, data.release()));
327     } while (true);
328 
329     finish(m_interceptResponse->status() == 200);
330 }
331 
handleDataURL(GURL url)332 void WebRequest::handleDataURL(GURL url)
333 {
334     OwnPtr<std::string> data(new std::string);
335     std::string mimeType;
336     std::string charset;
337 
338     if (net::DataURL::Parse(url, &mimeType, &charset, data.get())) {
339         // PopulateURLResponse from chrome implementation
340         // weburlloader_impl.cc
341         m_loadState = Response;
342         OwnPtr<WebResponse> webResponse(new WebResponse(url.spec(), mimeType, data->size(), charset, 200));
343         m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
344                 m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release()));
345 
346         if (!data->empty()) {
347             m_loadState = GotData;
348             m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
349                     m_urlLoader.get(), &WebUrlLoaderClient::didReceiveDataUrl, data.release()));
350         }
351     } else {
352         // handle the failed case
353     }
354 
355     finish(true);
356 }
357 
handleBrowserURL(GURL url)358 void WebRequest::handleBrowserURL(GURL url)
359 {
360     std::string data("data:text/html;charset=utf-8,");
361     if (url.spec() == "browser:incognito") {
362         AssetManager* assetManager = globalAssetManager();
363         Asset* asset = assetManager->open("webkit/incognito_mode_start_page.html", Asset::ACCESS_BUFFER);
364         if (asset) {
365             data.append((const char*)asset->getBuffer(false), asset->getLength());
366             delete asset;
367         }
368     }
369     GURL dataURL(data.c_str());
370     handleDataURL(dataURL);
371 }
372 
373 // Called upon a server-initiated redirect.  The delegate may call the
374 // request's Cancel method to prevent the redirect from being followed.
375 // Since there may be multiple chained redirects, there may also be more
376 // than one redirect call.
377 //
378 // When this function is called, the request will still contain the
379 // original URL, the destination of the redirect is provided in 'new_url'.
380 // If the delegate does not cancel the request and |*defer_redirect| is
381 // false, then the redirect will be followed, and the request's URL will be
382 // changed to the new URL.  Otherwise if the delegate does not cancel the
383 // request and |*defer_redirect| is true, then the redirect will be
384 // followed once FollowDeferredRedirect is called on the URLRequest.
385 //
386 // The caller must set |*defer_redirect| to false, so that delegates do not
387 // need to set it if they are happy with the default behavior of not
388 // deferring redirect.
OnReceivedRedirect(net::URLRequest * newRequest,const GURL & newUrl,bool * deferRedirect)389 void WebRequest::OnReceivedRedirect(net::URLRequest* newRequest, const GURL& newUrl, bool* deferRedirect)
390 {
391     ASSERT(m_loadState < Response, "Redirect after receiving response");
392     ASSERT(newRequest && newRequest->status().is_success(), "Invalid redirect");
393 
394     OwnPtr<WebResponse> webResponse(new WebResponse(newRequest));
395     webResponse->setUrl(newUrl.spec());
396     m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
397             m_urlLoader.get(), &WebUrlLoaderClient::willSendRequest, webResponse.release()));
398 
399     // Defer the redirect until followDeferredRedirect() is called.
400     *deferRedirect = true;
401 }
402 
403 // Called when we receive an authentication failure.  The delegate should
404 // call request->SetAuth() with the user's credentials once it obtains them,
405 // or request->CancelAuth() to cancel the login and display the error page.
406 // When it does so, the request will be reissued, restarting the sequence
407 // of On* callbacks.
OnAuthRequired(net::URLRequest * request,net::AuthChallengeInfo * authInfo)408 void WebRequest::OnAuthRequired(net::URLRequest* request, net::AuthChallengeInfo* authInfo)
409 {
410     ASSERT(m_loadState == Started, "OnAuthRequired called on a WebRequest not in STARTED state (state=%d)", m_loadState);
411 
412     scoped_refptr<net::AuthChallengeInfo> authInfoPtr(authInfo);
413     bool firstTime = (m_authRequestCount == 0);
414     ++m_authRequestCount;
415 
416     bool suppressDialog = (request->load_flags() & net::LOAD_DO_NOT_PROMPT_FOR_LOGIN);
417 
418     m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
419             m_urlLoader.get(), &WebUrlLoaderClient::authRequired, authInfoPtr, firstTime, suppressDialog));
420 }
421 
422 // Called when we received an SSL certificate error. The delegate will provide
423 // the user the options to proceed, cancel, or view certificates.
OnSSLCertificateError(net::URLRequest * request,int cert_error,net::X509Certificate * cert)424 void WebRequest::OnSSLCertificateError(net::URLRequest* request, int cert_error, net::X509Certificate* cert)
425 {
426     scoped_refptr<net::X509Certificate> scoped_cert = cert;
427     m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
428             m_urlLoader.get(), &WebUrlLoaderClient::reportSslCertError, cert_error, scoped_cert));
429 }
430 
OnCertificateRequested(net::URLRequest * request,net::SSLCertRequestInfo * cert_request_info)431 void WebRequest::OnCertificateRequested(net::URLRequest* request, net::SSLCertRequestInfo* cert_request_info)
432 {
433     scoped_refptr<net::SSLCertRequestInfo> scoped_cert_request_info = cert_request_info;
434     m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
435             m_urlLoader.get(), &WebUrlLoaderClient::requestClientCert, scoped_cert_request_info));
436 }
437 
438 
439 // After calling Start(), the delegate will receive an OnResponseStarted
440 // callback when the request has completed.  If an error occurred, the
441 // request->status() will be set.  On success, all redirects have been
442 // followed and the final response is beginning to arrive.  At this point,
443 // meta data about the response is available, including for example HTTP
444 // response headers if this is a request for a HTTP resource.
OnResponseStarted(net::URLRequest * request)445 void WebRequest::OnResponseStarted(net::URLRequest* request)
446 {
447     ASSERT(m_loadState == Started, "Got response after receiving response");
448 
449     m_loadState = Response;
450     if (request && request->status().is_success()) {
451         OwnPtr<WebResponse> webResponse(new WebResponse(request));
452         m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
453                 m_urlLoader.get(), &WebUrlLoaderClient::didReceiveResponse, webResponse.release()));
454 
455         // Start reading the response
456         startReading();
457     } else {
458         finish(false);
459     }
460 }
461 
setAuth(const string16 & username,const string16 & password)462 void WebRequest::setAuth(const string16& username, const string16& password)
463 {
464     ASSERT(m_loadState == Started, "setAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState);
465 
466     m_request->SetAuth(username, password);
467 }
468 
cancelAuth()469 void WebRequest::cancelAuth()
470 {
471     ASSERT(m_loadState == Started, "cancelAuth called on a WebRequest not in STARTED state (state=%d)", m_loadState);
472 
473     m_request->CancelAuth();
474 }
475 
followDeferredRedirect()476 void WebRequest::followDeferredRedirect()
477 {
478     ASSERT(m_loadState < Response, "Redirect after receiving response");
479 
480     m_request->FollowDeferredRedirect();
481 }
482 
proceedSslCertError()483 void WebRequest::proceedSslCertError()
484 {
485     m_request->ContinueDespiteLastError();
486 }
487 
cancelSslCertError(int cert_error)488 void WebRequest::cancelSslCertError(int cert_error)
489 {
490     m_request->SimulateError(cert_error);
491 }
492 
sslClientCert(EVP_PKEY * pkey,scoped_refptr<net::X509Certificate> chain)493 void WebRequest::sslClientCert(EVP_PKEY* pkey, scoped_refptr<net::X509Certificate> chain)
494 {
495     base::ScopedOpenSSL<EVP_PKEY, EVP_PKEY_free> privateKey(pkey);
496     if (privateKey.get() == NULL || chain.get() == NULL) {
497         m_request->ContinueWithCertificate(NULL);
498         return;
499     }
500     GURL gurl(m_url);
501     net::OpenSSLPrivateKeyStore::GetInstance()->StorePrivateKey(gurl, privateKey.release());
502     m_request->ContinueWithCertificate(chain.release());
503 }
504 
startReading()505 void WebRequest::startReading()
506 {
507     ASSERT(m_networkBuffer == 0, "startReading called with a nonzero buffer");
508     ASSERT(m_isPaused == 0, "startReading called in paused state");
509     ASSERT(m_loadState == Response || m_loadState == GotData, "StartReading in state other than RESPONSE and GOTDATA");
510     if (m_loadState > GotData) // We have been cancelled between reads
511         return;
512 
513     if (m_wantToPause) {
514         m_isPaused = true;
515         return;
516     }
517 
518     int bytesRead = 0;
519 
520     if (!read(&bytesRead)) {
521         if (m_request && m_request->status().is_io_pending())
522             return; // Wait for OnReadCompleted()
523         return finish(false);
524     }
525 
526     // bytesRead == 0 indicates finished
527     if (!bytesRead)
528         return finish(true);
529 
530     m_loadState = GotData;
531     // Read ok, forward buffer to webcore
532     m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead));
533     m_networkBuffer = 0;
534     MessageLoop::current()->PostTask(FROM_HERE, m_runnableFactory.NewRunnableMethod(&WebRequest::startReading));
535 }
536 
read(int * bytesRead)537 bool WebRequest::read(int* bytesRead)
538 {
539     ASSERT(m_loadState == Response || m_loadState == GotData, "read in state other than RESPONSE and GOTDATA");
540     ASSERT(m_networkBuffer == 0, "Read called with a nonzero buffer");
541 
542     // TODO: when asserts work, check that the buffer is 0 here
543     m_networkBuffer = new net::IOBuffer(kInitialReadBufSize);
544     return m_request->Read(m_networkBuffer, kInitialReadBufSize, bytesRead);
545 }
546 
547 // This is called when there is data available
548 
549 // Called when the a Read of the response body is completed after an
550 // IO_PENDING status from a Read() call.
551 // The data read is filled into the buffer which the caller passed
552 // to Read() previously.
553 //
554 // If an error occurred, request->status() will contain the error,
555 // and bytes read will be -1.
OnReadCompleted(net::URLRequest * request,int bytesRead)556 void WebRequest::OnReadCompleted(net::URLRequest* request, int bytesRead)
557 {
558     ASSERT(m_loadState == Response || m_loadState == GotData, "OnReadCompleted in state other than RESPONSE and GOTDATA");
559 
560     if (request->status().is_success()) {
561         m_loadState = GotData;
562         m_urlLoader->maybeCallOnMainThread(NewRunnableMethod(
563                 m_urlLoader.get(), &WebUrlLoaderClient::didReceiveData, m_networkBuffer, bytesRead));
564         m_networkBuffer = 0;
565 
566         // Get the rest of the data
567         startReading();
568     } else {
569         finish(false);
570     }
571 }
572 
573 } // namespace android
574