2 * Copyright 2010, The Android Open Source Project
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #define LOG_TAG "WebUrlLoaderClient"
29 #include "WebUrlLoaderClient.h"
31 #include "ChromiumIncludes.h"
33 #include "ResourceHandle.h"
34 #include "ResourceHandleClient.h"
35 #include "ResourceResponse.h"
36 #include "WebCoreFrameBridge.h"
37 #include "WebRequest.h"
38 #include "WebResourceRequest.h"
40 #include <wtf/text/CString.h>
44 base::Thread* WebUrlLoaderClient::ioThread()
46 static base::Thread* networkThread = 0;
47 static Lock networkThreadLock;
49 // Multiple threads appear to access the ioThread so we must ensure the
50 // critical section ordering.
51 AutoLock lock(networkThreadLock);
54 networkThread = new base::Thread("network");
59 if (networkThread->IsRunning())
62 base::Thread::Options options;
63 options.message_loop_type = MessageLoop::TYPE_IO;
64 if (!networkThread->StartWithOptions(options)) {
72 Lock* WebUrlLoaderClient::syncLock() {
73 static Lock s_syncLock;
77 ConditionVariable* WebUrlLoaderClient::syncCondition() {
78 static ConditionVariable s_syncCondition(syncLock());
79 return &s_syncCondition;
82 WebUrlLoaderClient::~WebUrlLoaderClient()
86 bool WebUrlLoaderClient::isActive() const
90 if (!m_resourceHandle->client())
96 WebUrlLoaderClient::WebUrlLoaderClient(WebFrame* webFrame, WebCore::ResourceHandle* resourceHandle, const WebCore::ResourceRequest& resourceRequest)
97 : m_webFrame(webFrame)
98 , m_resourceHandle(resourceHandle)
103 WebResourceRequest webResourceRequest(resourceRequest);
104 UrlInterceptResponse* intercept = webFrame->shouldInterceptRequest(resourceRequest.url().string());
106 m_request = new WebRequest(this, webResourceRequest, intercept);
110 m_request = new WebRequest(this, webResourceRequest);
112 // Set uploads before start is called on the request
113 if (resourceRequest.httpBody() && !(webResourceRequest.method() == "GET" || webResourceRequest.method() == "HEAD")) {
114 Vector<FormDataElement>::iterator iter;
115 Vector<FormDataElement> elements = resourceRequest.httpBody()->elements();
116 for (iter = elements.begin(); iter != elements.end(); iter++) {
117 FormDataElement element = *iter;
119 switch (element.m_type) {
120 case FormDataElement::data:
121 if (!element.m_data.isEmpty()) {
122 // WebKit sometimes gives up empty data to append. These aren't
123 // necessary so we just optimize those out here.
124 base::Thread* thread = ioThread();
126 Vector<char>* data = new Vector<char>(element.m_data);
127 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendBytesToUpload, data));
131 case FormDataElement::encodedFile:
133 // Chromium check if it is a directory by checking
134 // element.m_fileLength, that doesn't work in Android
135 std::string filename = element.m_filename.utf8().data();
136 if (filename.size()) {
137 // Change from a url string to a filename
138 if (filename.find("file://") == 0) // Found at pos 0
139 filename.erase(0, 7);
140 base::Thread* thread = ioThread();
142 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::appendFileToUpload, filename));
147 case FormDataElement::encodedBlob:
148 LOG_ASSERT(false, "Unexpected use of FormDataElement::encodedBlob");
150 #endif // ENABLE(BLOB)
152 LOG_ASSERT(false, "Unexpected default case in WebUrlLoaderClient.cpp");
159 bool WebUrlLoaderClient::start(bool sync, WebRequestContext* context)
161 base::Thread* thread = ioThread();
168 AutoLock autoLock(*syncLock());
169 m_request->setRequestContext(context);
170 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start));
172 // Run callbacks until the queue is exhausted and m_finished is true.
174 while (!m_queue.empty()) {
175 OwnPtr<Task> task(m_queue.front());
179 if (m_queue.empty() && !m_finished) {
180 syncCondition()->Wait();
184 // This may be the last reference to us, so we may be deleted now.
185 // Don't access any more member variables after releasing this reference.
186 m_resourceHandle = 0;
188 // Asynchronous start.
189 // Important to set this before the thread starts so it has a reference and can't be deleted
190 // before the task starts running on the IO thread.
191 m_request->setRequestContext(context);
192 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::start));
197 void WebUrlLoaderClient::downloadFile()
200 std::string contentDisposition;
201 m_response->getHeader("content-disposition", &contentDisposition);
202 m_webFrame->downloadStart(m_request->getUrl(), m_request->getUserAgent(), contentDisposition, m_response->getMimeType(), m_response->getExpectedSize());
204 LOGE("Unexpected call to downloadFile() before didReceiveResponse(). URL: %s", m_request->getUrl().c_str());
205 // TODO: Turn off asserts crashing before release
206 // http://b/issue?id=2951985
211 void WebUrlLoaderClient::cancel()
215 base::Thread* thread = ioThread();
217 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancel));
220 void WebUrlLoaderClient::setAuth(const std::string& username, const std::string& password)
222 base::Thread* thread = ioThread();
226 string16 username16 = ASCIIToUTF16(username);
227 string16 password16 = ASCIIToUTF16(password);
228 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::setAuth, username16, password16));
231 void WebUrlLoaderClient::cancelAuth()
233 base::Thread* thread = ioThread();
237 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelAuth));
240 void WebUrlLoaderClient::proceedSslCertError()
242 base::Thread* thread = ioThread();
246 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::proceedSslCertError));
249 void WebUrlLoaderClient::cancelSslCertError(int cert_error)
251 base::Thread* thread = ioThread();
255 thread->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::cancelSslCertError, cert_error));
259 void WebUrlLoaderClient::finish()
263 // This is the last reference to us, so we will be deleted now.
264 // We only release the reference here if start() was called asynchronously!
265 m_resourceHandle = 0;
271 // Trampoline to wrap a Chromium Task* in a WebKit-style static function + void*.
272 static void RunTask(void* v) {
273 OwnPtr<Task> task(static_cast<Task*>(v));
278 // This is called from the IO thread, and dispatches the callback to the main thread.
279 void WebUrlLoaderClient::maybeCallOnMainThread(Task* task)
282 AutoLock autoLock(*syncLock());
283 if (m_queue.empty()) {
284 syncCondition()->Broadcast();
286 m_queue.push_back(task);
288 // Let WebKit handle it.
289 callOnMainThread(RunTask, task);
294 void WebUrlLoaderClient::didReceiveResponse(PassOwnPtr<WebResponse> webResponse)
299 m_response = webResponse;
300 m_resourceHandle->client()->didReceiveResponse(m_resourceHandle.get(), m_response->createResourceResponse());
303 void WebUrlLoaderClient::didReceiveData(scoped_refptr<net::IOBuffer> buf, int size)
305 if (!isActive() || !size)
308 // didReceiveData will take a copy of the data
309 if (m_resourceHandle && m_resourceHandle->client())
310 m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), buf->data(), size, size);
314 void WebUrlLoaderClient::didReceiveDataUrl(PassOwnPtr<std::string> str)
316 if (!isActive() || !str->size())
319 // didReceiveData will take a copy of the data
320 m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), str->data(), str->size(), str->size());
323 // For special android files
324 void WebUrlLoaderClient::didReceiveAndroidFileData(PassOwnPtr<std::vector<char> > vector)
326 if (!isActive() || !vector->size())
329 // didReceiveData will take a copy of the data
330 m_resourceHandle->client()->didReceiveData(m_resourceHandle.get(), vector->begin(), vector->size(), vector->size());
333 void WebUrlLoaderClient::didFail(PassOwnPtr<WebResponse> webResponse)
336 m_resourceHandle->client()->didFail(m_resourceHandle.get(), webResponse->createResourceError());
338 // Always finish a request, if not it will leak
342 void WebUrlLoaderClient::willSendRequest(PassOwnPtr<WebResponse> webResponse)
347 KURL url = webResponse->createKurl();
348 OwnPtr<WebCore::ResourceRequest> resourceRequest(new WebCore::ResourceRequest(url));
349 m_resourceHandle->client()->willSendRequest(m_resourceHandle.get(), *resourceRequest, webResponse->createResourceResponse());
351 // WebKit may have killed the request.
355 // Like Chrome, we only follow the redirect if WebKit left the URL unmodified.
356 if (url == resourceRequest->url()) {
357 ioThread()->message_loop()->PostTask(FROM_HERE, NewRunnableMethod(m_request.get(), &WebRequest::followDeferredRedirect));
363 void WebUrlLoaderClient::didFinishLoading()
366 m_resourceHandle->client()->didFinishLoading(m_resourceHandle.get(), 0);
368 // Always finish a request, if not it will leak
372 void WebUrlLoaderClient::authRequired(scoped_refptr<net::AuthChallengeInfo> authChallengeInfo, bool firstTime)
378 std::string host = base::SysWideToUTF8(authChallengeInfo->host_and_port);
379 std::string realm = base::SysWideToUTF8(authChallengeInfo->realm);
381 m_webFrame->didReceiveAuthenticationChallenge(this, host, realm, firstTime);
384 void WebUrlLoaderClient::reportSslCertError(int cert_error, net::X509Certificate* cert)
386 if (!isActive()) return;
387 std::vector<std::string> chain_bytes;
388 cert->GetChainDEREncodedBytes(&chain_bytes);
389 m_webFrame->reportSslCertError(this, cert_error, chain_bytes[0]);
392 } // namespace android