• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2004, 2006 Apple Computer, Inc.  All rights reserved.
3  * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "ResourceHandle.h"
29 
30 #include "DataURL.h"
31 #include "HTTPParsers.h"
32 #include "MIMETypeRegistry.h"
33 #include "MainThread.h"
34 #include "NotImplemented.h"
35 #include "ResourceError.h"
36 #include "ResourceHandleClient.h"
37 #include "ResourceHandleInternal.h"
38 #include "SharedBuffer.h"
39 #include "Timer.h"
40 #include "UnusedParam.h"
41 #include <wtf/text/CString.h>
42 #include <windows.h>
43 #include <wininet.h>
44 
45 namespace WebCore {
46 
createInternetHandle(const String & userAgent,bool asynchronous)47 static inline HINTERNET createInternetHandle(const String& userAgent, bool asynchronous)
48 {
49     String userAgentString = userAgent;
50     HINTERNET internetHandle = InternetOpenW(userAgentString.charactersWithNullTermination(), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, asynchronous ? INTERNET_FLAG_ASYNC : 0);
51 
52     if (asynchronous)
53         InternetSetStatusCallback(internetHandle, &ResourceHandle::internetStatusCallback);
54 
55     return internetHandle;
56 }
57 
asynchronousInternetHandle(const String & userAgent)58 static HINTERNET asynchronousInternetHandle(const String& userAgent)
59 {
60     static HINTERNET internetHandle = createInternetHandle(userAgent, true);
61     return internetHandle;
62 }
63 
queryHTTPHeader(HINTERNET requestHandle,DWORD infoLevel)64 static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel)
65 {
66     DWORD bufferSize = 0;
67     HttpQueryInfoW(requestHandle, infoLevel, 0, &bufferSize, 0);
68 
69     Vector<UChar> characters(bufferSize / sizeof(UChar));
70 
71     if (!HttpQueryInfoW(requestHandle, infoLevel, characters.data(), &bufferSize, 0))
72         return String();
73 
74     characters.removeLast(); // Remove NullTermination.
75     return String::adopt(characters);
76 }
77 
78 
79 class WebCoreSynchronousLoader : public ResourceHandleClient {
80     WTF_MAKE_NONCOPYABLE(WebCoreSynchronousLoader);
81 public:
82     WebCoreSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&, const String& userAgent);
83     ~WebCoreSynchronousLoader();
84 
internetHandle() const85     HINTERNET internetHandle() const { return m_internetHandle; }
86 
87     virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
88     virtual void didReceiveData(ResourceHandle*, const char*, int, int encodedDataLength);
89     virtual void didFinishLoading(ResourceHandle*, double /*finishTime*/);
90     virtual void didFail(ResourceHandle*, const ResourceError&);
91 
92 private:
93     ResourceError& m_error;
94     ResourceResponse& m_response;
95     Vector<char>& m_data;
96     HINTERNET m_internetHandle;
97 };
98 
WebCoreSynchronousLoader(ResourceError & error,ResourceResponse & response,Vector<char> & data,const String & userAgent)99 WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data, const String& userAgent)
100     : m_error(error)
101     , m_response(response)
102     , m_data(data)
103     , m_internetHandle(createInternetHandle(userAgent, false))
104 {
105 }
106 
~WebCoreSynchronousLoader()107 WebCoreSynchronousLoader::~WebCoreSynchronousLoader()
108 {
109     InternetCloseHandle(m_internetHandle);
110 }
111 
didReceiveResponse(ResourceHandle *,const ResourceResponse & response)112 void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
113 {
114     m_response = response;
115 }
116 
didReceiveData(ResourceHandle *,const char * data,int length,int)117 void WebCoreSynchronousLoader::didReceiveData(ResourceHandle*, const char* data, int length, int)
118 {
119     m_data.append(data, length);
120 }
121 
didFinishLoading(ResourceHandle *,double)122 void WebCoreSynchronousLoader::didFinishLoading(ResourceHandle*, double)
123 {
124 }
125 
didFail(ResourceHandle *,const ResourceError & error)126 void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& error)
127 {
128     m_error = error;
129 }
130 
131 
~ResourceHandleInternal()132 ResourceHandleInternal::~ResourceHandleInternal()
133 {
134 }
135 
~ResourceHandle()136 ResourceHandle::~ResourceHandle()
137 {
138 }
139 
callOnRedirect(void * context)140 static void callOnRedirect(void* context)
141 {
142     ResourceHandle* handle = static_cast<ResourceHandle*>(context);
143     handle->onRedirect();
144 }
145 
callOnRequestComplete(void * context)146 static void callOnRequestComplete(void* context)
147 {
148     ResourceHandle* handle = static_cast<ResourceHandle*>(context);
149     handle->onRequestComplete();
150 }
151 
internetStatusCallback(HINTERNET internetHandle,DWORD_PTR context,DWORD internetStatus,LPVOID statusInformation,DWORD statusInformationLength)152 void ResourceHandle::internetStatusCallback(HINTERNET internetHandle, DWORD_PTR context, DWORD internetStatus,
153                                                      LPVOID statusInformation, DWORD statusInformationLength)
154 {
155     ResourceHandle* handle = reinterpret_cast<ResourceHandle*>(context);
156 
157     switch (internetStatus) {
158     case INTERNET_STATUS_REDIRECT:
159         handle->d->m_redirectUrl = String(static_cast<UChar*>(statusInformation), statusInformationLength);
160         callOnMainThread(callOnRedirect, handle);
161         break;
162 
163     case INTERNET_STATUS_REQUEST_COMPLETE:
164         callOnMainThread(callOnRequestComplete, handle);
165         break;
166 
167     default:
168         break;
169     }
170 }
171 
onRedirect()172 void ResourceHandle::onRedirect()
173 {
174     ResourceRequest newRequest = firstRequest();
175     newRequest.setURL(KURL(ParsedURLString, d->m_redirectUrl));
176 
177     ResourceResponse response(firstRequest().url(), String(), 0, String(), String());
178 
179     if (ResourceHandleClient* resourceHandleClient = client())
180         resourceHandleClient->willSendRequest(this, newRequest, response);
181 }
182 
onRequestComplete()183 bool ResourceHandle::onRequestComplete()
184 {
185     if (!d->m_internetHandle) { // 0 if canceled.
186         deref(); // balances ref in start
187         return false;
188     }
189 
190     if (d->m_bytesRemainingToWrite) {
191         DWORD bytesWritten;
192         InternetWriteFile(d->m_requestHandle,
193                           d->m_formData.data() + (d->m_formData.size() - d->m_bytesRemainingToWrite),
194                           d->m_bytesRemainingToWrite,
195                           &bytesWritten);
196         d->m_bytesRemainingToWrite -= bytesWritten;
197         if (d->m_bytesRemainingToWrite)
198             return true;
199         d->m_formData.clear();
200     }
201 
202     if (!d->m_sentEndRequest) {
203         HttpEndRequestW(d->m_requestHandle, 0, 0, reinterpret_cast<DWORD_PTR>(this));
204         d->m_sentEndRequest = true;
205         return true;
206     }
207 
208     static const int bufferSize = 32768;
209     char buffer[bufferSize];
210     INTERNET_BUFFERSA buffers;
211     buffers.dwStructSize = sizeof(INTERNET_BUFFERSA);
212     buffers.lpvBuffer = buffer;
213     buffers.dwBufferLength = bufferSize;
214 
215     BOOL ok = FALSE;
216     while ((ok = InternetReadFileExA(d->m_requestHandle, &buffers, d->m_loadSynchronously ? 0 : IRF_NO_WAIT, reinterpret_cast<DWORD_PTR>(this))) && buffers.dwBufferLength) {
217         if (!d->m_hasReceivedResponse) {
218             d->m_hasReceivedResponse = true;
219 
220             ResourceResponse response;
221             response.setURL(firstRequest().url());
222 
223             String httpStatusText = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_TEXT);
224             if (!httpStatusText.isNull())
225                 response.setHTTPStatusText(httpStatusText);
226 
227             String httpStatusCode = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_CODE);
228             if (!httpStatusCode.isNull())
229                 response.setHTTPStatusCode(httpStatusCode.toInt());
230 
231             String httpContentLength = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_LENGTH);
232             if (!httpContentLength.isNull())
233                 response.setExpectedContentLength(httpContentLength.toInt());
234 
235             String httpContentType = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_TYPE);
236             if (!httpContentType.isNull()) {
237                 response.setMimeType(extractMIMETypeFromMediaType(httpContentType));
238                 response.setTextEncodingName(extractCharsetFromMediaType(httpContentType));
239             }
240 
241             if (ResourceHandleClient* resourceHandleClient = client())
242                 resourceHandleClient->didReceiveResponse(this, response);
243         }
244 
245         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793
246         // -1 means we do not provide any data about transfer size to inspector so it would use
247         // Content-Length headers or content size to show transfer size.
248         if (ResourceHandleClient* resourceHandleClient = client())
249             resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, -1);
250         buffers.dwBufferLength = bufferSize;
251     }
252 
253     if (!ok && GetLastError() == ERROR_IO_PENDING)
254         return true;
255 
256     if (ResourceHandleClient* resourceHandleClient = client())
257         resourceHandleClient->didFinishLoading(this, 0);
258 
259     InternetCloseHandle(d->m_requestHandle);
260     InternetCloseHandle(d->m_connectHandle);
261     deref(); // balances ref in start
262     return false;
263 }
264 
start(NetworkingContext * context)265 bool ResourceHandle::start(NetworkingContext* context)
266 {
267     if (firstRequest().url().isLocalFile() || firstRequest().url().protocolIsData()) {
268         ref(); // balanced by deref in fileLoadTimer
269         if (d->m_loadSynchronously)
270             fileLoadTimer(0);
271         else
272             d->m_fileLoadTimer.startOneShot(0.0);
273         return true;
274     }
275 
276     if (!d->m_internetHandle)
277         d->m_internetHandle = asynchronousInternetHandle(context->userAgent());
278 
279     if (!d->m_internetHandle)
280         return false;
281 
282     DWORD flags = INTERNET_FLAG_KEEP_CONNECTION
283         | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS
284         | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP
285         | INTERNET_FLAG_DONT_CACHE
286         | INTERNET_FLAG_RELOAD;
287 
288     d->m_connectHandle = InternetConnectW(d->m_internetHandle, firstRequest().url().host().charactersWithNullTermination(), firstRequest().url().port(),
289                                           0, 0, INTERNET_SERVICE_HTTP, flags, reinterpret_cast<DWORD_PTR>(this));
290 
291     if (!d->m_connectHandle)
292         return false;
293 
294     String urlStr = firstRequest().url().path();
295     String urlQuery = firstRequest().url().query();
296 
297     if (!urlQuery.isEmpty()) {
298         urlStr.append('?');
299         urlStr.append(urlQuery);
300     }
301 
302     String httpMethod = firstRequest().httpMethod();
303     String httpReferrer = firstRequest().httpReferrer();
304 
305     LPCWSTR httpAccept[] = { L"*/*", 0 };
306 
307     d->m_requestHandle = HttpOpenRequestW(d->m_connectHandle, httpMethod.charactersWithNullTermination(), urlStr.charactersWithNullTermination(),
308                                           0, httpReferrer.charactersWithNullTermination(), httpAccept, flags, reinterpret_cast<DWORD_PTR>(this));
309 
310     if (!d->m_requestHandle) {
311         InternetCloseHandle(d->m_connectHandle);
312         return false;
313     }
314 
315     if (firstRequest().httpBody()) {
316         firstRequest().httpBody()->flatten(d->m_formData);
317         d->m_bytesRemainingToWrite = d->m_formData.size();
318     }
319 
320     Vector<UChar> httpHeaders;
321     const HTTPHeaderMap& httpHeaderFields = firstRequest().httpHeaderFields();
322 
323     for (HTTPHeaderMap::const_iterator it = httpHeaderFields.begin(); it != httpHeaderFields.end(); ++it) {
324         if (equalIgnoringCase(it->first, "Accept") || equalIgnoringCase(it->first, "Referer") || equalIgnoringCase(it->first, "User-Agent"))
325             continue;
326 
327         if (!httpHeaders.isEmpty())
328             httpHeaders.append('\n');
329 
330         httpHeaders.append(it->first.characters(), it->first.length());
331         httpHeaders.append(':');
332         httpHeaders.append(it->second.characters(), it->second.length());
333     }
334 
335     INTERNET_BUFFERSW internetBuffers;
336     ZeroMemory(&internetBuffers, sizeof(internetBuffers));
337     internetBuffers.dwStructSize = sizeof(internetBuffers);
338     internetBuffers.lpcszHeader = httpHeaders.data();
339     internetBuffers.dwHeadersLength = httpHeaders.size();
340     internetBuffers.dwBufferTotal = d->m_bytesRemainingToWrite;
341 
342     HttpSendRequestExW(d->m_requestHandle, &internetBuffers, 0, 0, reinterpret_cast<DWORD_PTR>(this));
343 
344     ref(); // balanced by deref in onRequestComplete
345 
346     if (d->m_loadSynchronously)
347         while (onRequestComplete()) {
348             // Loop until finished.
349         }
350 
351     return true;
352 }
353 
fileLoadTimer(Timer<ResourceHandle> *)354 void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*)
355 {
356     RefPtr<ResourceHandle> protector(this);
357     deref(); // balances ref in start
358 
359     if (firstRequest().url().protocolIsData()) {
360         handleDataURL(this);
361         return;
362     }
363 
364     String fileName = firstRequest().url().fileSystemPath();
365     HANDLE fileHandle = CreateFileW(fileName.charactersWithNullTermination(), GENERIC_READ, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
366 
367     if (fileHandle == INVALID_HANDLE_VALUE) {
368         client()->didFail(this, ResourceError());
369         return;
370     }
371 
372     ResourceResponse response;
373 
374     int dotPos = fileName.reverseFind('.');
375     int slashPos = fileName.reverseFind('/');
376 
377     if (slashPos < dotPos && dotPos != -1) {
378         String ext = fileName.substring(dotPos + 1);
379         response.setMimeType(MIMETypeRegistry::getMIMETypeForExtension(ext));
380     }
381 
382     client()->didReceiveResponse(this, response);
383 
384     bool result = false;
385     DWORD bytesRead = 0;
386 
387     do {
388         const int bufferSize = 8192;
389         char buffer[bufferSize];
390         result = ReadFile(fileHandle, &buffer, bufferSize, &bytesRead, 0);
391         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793
392         // -1 means we do not provide any data about transfer size to inspector so it would use
393         // Content-Length headers or content size to show transfer size.
394         if (result && bytesRead)
395             client()->didReceiveData(this, buffer, bytesRead, -1);
396         // Check for end of file.
397     } while (result && bytesRead);
398 
399     CloseHandle(fileHandle);
400 
401     client()->didFinishLoading(this, 0);
402 }
403 
cancel()404 void ResourceHandle::cancel()
405 {
406     if (d->m_requestHandle) {
407         d->m_internetHandle = 0;
408         InternetCloseHandle(d->m_requestHandle);
409         InternetCloseHandle(d->m_connectHandle);
410     } else
411         d->m_fileLoadTimer.stop();
412 }
413 
loadResourceSynchronously(NetworkingContext * context,const ResourceRequest & request,StoredCredentials storedCredentials,ResourceError & error,ResourceResponse & response,Vector<char> & data)414 void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
415 {
416     UNUSED_PARAM(storedCredentials);
417 
418     WebCoreSynchronousLoader syncLoader(error, response, data, request.httpUserAgent());
419     ResourceHandle handle(request, &syncLoader, true, false);
420 
421     handle.setSynchronousInternetHandle(syncLoader.internetHandle());
422     handle.start(context);
423 }
424 
setSynchronousInternetHandle(HINTERNET internetHandle)425 void ResourceHandle::setSynchronousInternetHandle(HINTERNET internetHandle)
426 {
427     d->m_internetHandle = internetHandle;
428     d->m_loadSynchronously = true;
429 }
430 
willLoadFromCache(ResourceRequest &,Frame *)431 bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*)
432 {
433     notImplemented();
434     return false;
435 }
436 
prefetchDNS(const String &)437 void prefetchDNS(const String&)
438 {
439     notImplemented();
440 }
441 
bufferedData()442 PassRefPtr<SharedBuffer> ResourceHandle::bufferedData()
443 {
444     ASSERT_NOT_REACHED();
445     return 0;
446 }
447 
supportsBufferedData()448 bool ResourceHandle::supportsBufferedData()
449 {
450     return false;
451 }
452 
loadsBlocked()453 bool ResourceHandle::loadsBlocked()
454 {
455     return false;
456 }
457 
platformSetDefersLoading(bool)458 void ResourceHandle::platformSetDefersLoading(bool)
459 {
460     notImplemented();
461 }
462 
463 } // namespace WebCore
464