diff options
Diffstat (limited to 'WebCore/platform/network/win/ResourceHandleWin.cpp')
-rw-r--r-- | WebCore/platform/network/win/ResourceHandleWin.cpp | 507 |
1 files changed, 185 insertions, 322 deletions
diff --git a/WebCore/platform/network/win/ResourceHandleWin.cpp b/WebCore/platform/network/win/ResourceHandleWin.cpp index 832a8e2..5de2e1b 100644 --- a/WebCore/platform/network/win/ResourceHandleWin.cpp +++ b/WebCore/platform/network/win/ResourceHandleWin.cpp @@ -27,43 +27,38 @@ #include "config.h" #include "ResourceHandle.h" -#include "CachedResourceLoader.h" -#include "Document.h" -#include "Frame.h" -#include "FrameLoader.h" -#include "Page.h" +#include "HTTPParsers.h" +#include "MIMETypeRegistry.h" +#include "MainThread.h" +#include "NotImplemented.h" #include "ResourceError.h" #include "ResourceHandleClient.h" #include "ResourceHandleInternal.h" -#include "ResourceHandleWin.h" +#include "SharedBuffer.h" #include "Timer.h" -#include "WebCoreInstanceHandle.h" - +#include "UnusedParam.h" #include <wtf/text/CString.h> #include <windows.h> #include <wininet.h> namespace WebCore { -static unsigned transferJobId = 0; -static HashMap<int, ResourceHandle*>* jobIdMap = 0; +static inline HINTERNET createInternetHandle(const String& userAgent, bool asynchronous) +{ + String userAgentString = userAgent; + HINTERNET internetHandle = InternetOpenW(userAgentString.charactersWithNullTermination(), INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, asynchronous ? INTERNET_FLAG_ASYNC : 0); -static HWND transferJobWindowHandle = 0; -const LPCWSTR kResourceHandleWindowClassName = L"ResourceHandleWindowClass"; + if (asynchronous) + InternetSetStatusCallback(internetHandle, &ResourceHandle::internetStatusCallback); -// Message types for internal use (keep in sync with kMessageHandlers) -enum { - handleCreatedMessage = WM_USER, - requestRedirectedMessage, - requestCompleteMessage -}; + return internetHandle; +} -typedef void (ResourceHandle:: *ResourceHandleEventHandler)(LPARAM); -static const ResourceHandleEventHandler messageHandlers[] = { - &ResourceHandle::onHandleCreated, - &ResourceHandle::onRequestRedirected, - &ResourceHandle::onRequestComplete -}; +static HINTERNET asynchronousInternetHandle(const String& userAgent) +{ + static HINTERNET internetHandle = createInternetHandle(userAgent, true); + return internetHandle; +} static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel) { @@ -79,69 +74,13 @@ static String queryHTTPHeader(HINTERNET requestHandle, DWORD infoLevel) return String::adopt(characters); } -static int addToOutstandingJobs(ResourceHandle* job) -{ - if (!jobIdMap) - jobIdMap = new HashMap<int, ResourceHandle*>; - transferJobId++; - jobIdMap->set(transferJobId, job); - return transferJobId; -} - -static void removeFromOutstandingJobs(int jobId) -{ - if (!jobIdMap) - return; - jobIdMap->remove(jobId); -} - -static ResourceHandle* lookupResourceHandle(int jobId) -{ - if (!jobIdMap) - return 0; - return jobIdMap->get(jobId); -} - -static LRESULT CALLBACK ResourceHandleWndProc(HWND hWnd, UINT message, - WPARAM wParam, LPARAM lParam) -{ - if (message >= handleCreatedMessage) { - UINT index = message - handleCreatedMessage; - if (index < _countof(messageHandlers)) { - unsigned jobId = (unsigned) wParam; - ResourceHandle* job = lookupResourceHandle(jobId); - if (job) { - ASSERT(job->d->m_jobId == jobId); - ASSERT(job->d->m_threadId == GetCurrentThreadId()); - (job->*(messageHandlers[index]))(lParam); - } - return 0; - } - } - return DefWindowProc(hWnd, message, wParam, lParam); -} - -static void initializeOffScreenResourceHandleWindow() -{ - if (transferJobWindowHandle) - return; - - WNDCLASSEX wcex; - memset(&wcex, 0, sizeof(WNDCLASSEX)); - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.lpfnWndProc = ResourceHandleWndProc; - wcex.hInstance = WebCore::instanceHandle(); - wcex.lpszClassName = kResourceHandleWindowClassName; - RegisterClassEx(&wcex); - - transferJobWindowHandle = CreateWindow(kResourceHandleWindowClassName, 0, 0, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, - HWND_MESSAGE, 0, WebCore::instanceHandle(), 0); -} - class WebCoreSynchronousLoader : public ResourceHandleClient, public Noncopyable { public: WebCoreSynchronousLoader(ResourceError&, ResourceResponse&, Vector<char>&, const String& userAgent); + ~WebCoreSynchronousLoader(); + + HINTERNET internetHandle() const { return m_internetHandle; } virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&); virtual void didReceiveData(ResourceHandle*, const char*, int, int lengthReceived); @@ -152,13 +91,20 @@ private: ResourceError& m_error; ResourceResponse& m_response; Vector<char>& m_data; + HINTERNET m_internetHandle; }; WebCoreSynchronousLoader::WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, Vector<char>& data, const String& userAgent) : m_error(error) , m_response(response) , m_data(data) + , m_internetHandle(createInternetHandle(userAgent, false)) +{ +} + +WebCoreSynchronousLoader::~WebCoreSynchronousLoader() { + InternetCloseHandle(m_internetHandle); } void WebCoreSynchronousLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response) @@ -183,107 +129,79 @@ void WebCoreSynchronousLoader::didFail(ResourceHandle*, const ResourceError& err ResourceHandleInternal::~ResourceHandleInternal() { - if (m_fileHandle != INVALID_HANDLE_VALUE) - CloseHandle(m_fileHandle); } ResourceHandle::~ResourceHandle() { - if (d->m_jobId) - removeFromOutstandingJobs(d->m_jobId); } -void ResourceHandle::onHandleCreated(LPARAM lParam) +static void callOnRedirect(void* context) { - if (!d->m_resourceHandle) { - d->m_resourceHandle = HINTERNET(lParam); - if (d->status != 0) { - // We were canceled before Windows actually created a handle for us, close and delete now. - InternetCloseHandle(d->m_resourceHandle); - delete this; - return; - } + ResourceHandle* handle = static_cast<ResourceHandle*>(context); + handle->onRedirect(); +} - if (request().httpMethod() == "POST") { - // FIXME: Too late to set referrer properly. - String urlStr = request().url().path(); - int fragmentIndex = urlStr.find('#'); - if (fragmentIndex != -1) - urlStr = urlStr.left(fragmentIndex); - static LPCSTR accept[2]={"*/*", NULL}; - HINTERNET urlHandle = HttpOpenRequestA(d->m_resourceHandle, - "POST", urlStr.latin1().data(), 0, 0, accept, - INTERNET_FLAG_KEEP_CONNECTION | - INTERNET_FLAG_FORMS_SUBMIT | - INTERNET_FLAG_RELOAD | - INTERNET_FLAG_NO_CACHE_WRITE | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP, - (DWORD_PTR)d->m_jobId); - if (urlHandle == INVALID_HANDLE_VALUE) { - InternetCloseHandle(d->m_resourceHandle); - delete this; - } - } - } else if (!d->m_secondaryHandle) { - assert(request().httpMethod() == "POST"); - d->m_secondaryHandle = HINTERNET(lParam); - - // Need to actually send the request now. - String headers = "Content-Type: application/x-www-form-urlencoded\n"; - headers += "Referer: "; - headers += d->m_postReferrer; - headers += "\n"; - const CString& headersLatin1 = headers.latin1(); - String formData = request().httpBody()->flattenToString(); - INTERNET_BUFFERSA buffers; - memset(&buffers, 0, sizeof(buffers)); - buffers.dwStructSize = sizeof(INTERNET_BUFFERSA); - buffers.lpcszHeader = headersLatin1.data(); - buffers.dwHeadersLength = headers.length(); - buffers.dwBufferTotal = formData.length(); - - d->m_bytesRemainingToWrite = formData.length(); - d->m_formDataString = (char*)malloc(formData.length()); - d->m_formDataLength = formData.length(); - strncpy(d->m_formDataString, formData.latin1().data(), formData.length()); - d->m_writing = true; - HttpSendRequestExA(d->m_secondaryHandle, &buffers, 0, 0, (DWORD_PTR)d->m_jobId); - // FIXME: add proper error handling +static void callOnRequestComplete(void* context) +{ + ResourceHandle* handle = static_cast<ResourceHandle*>(context); + handle->onRequestComplete(); +} + +void ResourceHandle::internetStatusCallback(HINTERNET internetHandle, DWORD_PTR context, DWORD internetStatus, + LPVOID statusInformation, DWORD statusInformationLength) +{ + ResourceHandle* handle = reinterpret_cast<ResourceHandle*>(context); + + switch (internetStatus) { + case INTERNET_STATUS_REDIRECT: + handle->d->m_redirectUrl = String(static_cast<UChar*>(statusInformation), statusInformationLength); + callOnMainThread(callOnRedirect, handle); + break; + + case INTERNET_STATUS_REQUEST_COMPLETE: + callOnMainThread(callOnRequestComplete, handle); + break; + + default: + break; } } -void ResourceHandle::onRequestRedirected(LPARAM lParam) +void ResourceHandle::onRedirect() { - // If already canceled, then ignore this event. - if (d->status != 0) - return; + ResourceRequest newRequest = firstRequest(); + newRequest.setURL(KURL(ParsedURLString, d->m_redirectUrl)); + + ResourceResponse response(firstRequest().url(), String(), 0, String(), String()); - ResourceRequest request((StringImpl*) lParam); - ResourceResponse redirectResponse; - client()->willSendRequest(this, request, redirectResponse); + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->willSendRequest(this, newRequest, response); } -void ResourceHandle::onRequestComplete(LPARAM lParam) +bool ResourceHandle::onRequestComplete() { - if (d->m_writing) { + if (!d->m_internetHandle) { // 0 if canceled. + deref(); // balances ref in start + return false; + } + + if (d->m_bytesRemainingToWrite) { DWORD bytesWritten; - InternetWriteFile(d->m_secondaryHandle, - d->m_formDataString + (d->m_formDataLength - d->m_bytesRemainingToWrite), + InternetWriteFile(d->m_requestHandle, + d->m_formData.data() + (d->m_formData.size() - d->m_bytesRemainingToWrite), d->m_bytesRemainingToWrite, &bytesWritten); d->m_bytesRemainingToWrite -= bytesWritten; - if (!d->m_bytesRemainingToWrite) { - // End the request. - d->m_writing = false; - HttpEndRequest(d->m_secondaryHandle, 0, 0, (DWORD_PTR)d->m_jobId); - free(d->m_formDataString); - d->m_formDataString = 0; - } - return; + if (d->m_bytesRemainingToWrite) + return true; + d->m_formData.clear(); } - HINTERNET handle = (request().httpMethod() == "POST") ? d->m_secondaryHandle : d->m_resourceHandle; + if (!d->m_sentEndRequest) { + HttpEndRequestW(d->m_requestHandle, 0, 0, reinterpret_cast<DWORD_PTR>(this)); + d->m_sentEndRequest = true; + return true; + } static const int bufferSize = 32768; char buffer[bufferSize]; @@ -293,9 +211,10 @@ void ResourceHandle::onRequestComplete(LPARAM lParam) buffers.dwBufferLength = bufferSize; BOOL ok = FALSE; - while ((ok = InternetReadFileExA(handle, &buffers, IRF_NO_WAIT, (DWORD_PTR)this)) && buffers.dwBufferLength) { - if (!hasReceivedResponse()) { - setHasReceivedResponse(); + while ((ok = InternetReadFileExA(d->m_requestHandle, &buffers, d->m_loadSynchronously ? 0 : IRF_NO_WAIT, reinterpret_cast<DWORD_PTR>(this))) && buffers.dwBufferLength) { + if (!d->m_hasReceivedResponse) { + d->m_hasReceivedResponse = true; + ResourceResponse response; response.setURL(firstRequest().url()); @@ -317,160 +236,112 @@ void ResourceHandle::onRequestComplete(LPARAM lParam) response.setTextEncodingName(extractCharsetFromMediaType(httpContentType)); } - client()->didReceiveResponse(this, response); + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->didReceiveResponse(this, response); } - client()->didReceiveData(this, buffer, buffers.dwBufferLength, 0); + + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, 0); buffers.dwBufferLength = bufferSize; } - PlatformDataStruct platformData; - platformData.errorString = 0; - platformData.error = 0; - platformData.loaded = ok; - - if (!ok) { - int error = GetLastError(); - if (error == ERROR_IO_PENDING) - return; - DWORD errorStringChars = 0; - if (!InternetGetLastResponseInfo(&platformData.error, 0, &errorStringChars)) { - if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) { - platformData.errorString = new TCHAR[errorStringChars]; - InternetGetLastResponseInfo(&platformData.error, platformData.errorString, &errorStringChars); - } - } -#ifdef RESOURCE_LOADER_DEBUG - char buf[64]; - _snprintf(buf, sizeof(buf), "Load error: %i\n", error); - OutputDebugStringA(buf); -#endif - } - - if (d->m_secondaryHandle) - InternetCloseHandle(d->m_secondaryHandle); - InternetCloseHandle(d->m_resourceHandle); + if (!ok && GetLastError() == ERROR_IO_PENDING) + return true; - client()->didFinishLoading(this, 0); - delete this; + if (ResourceHandleClient* resourceHandleClient = client()) + resourceHandleClient->didFinishLoading(this, 0); + + InternetCloseHandle(d->m_requestHandle); + InternetCloseHandle(d->m_connectHandle); + deref(); // balances ref in start + return false; } -static void __stdcall transferJobStatusCallback(HINTERNET internetHandle, - DWORD_PTR jobId, - DWORD internetStatus, - LPVOID statusInformation, - DWORD statusInformationLength) +bool ResourceHandle::start(NetworkingContext* context) { -#ifdef RESOURCE_LOADER_DEBUG - char buf[64]; - _snprintf(buf, sizeof(buf), "status-callback: status=%u, job=%p\n", - internetStatus, jobId); - OutputDebugStringA(buf); -#endif + if (request().url().isLocalFile()) { + ref(); // balanced by deref in fileLoadTimer + if (d->m_loadSynchronously) + fileLoadTimer(0); + else + d->m_fileLoadTimer.startOneShot(0.0); + return true; + } - UINT msg; - LPARAM lParam; + if (!d->m_internetHandle) + d->m_internetHandle = asynchronousInternetHandle(context->userAgent()); - switch (internetStatus) { - case INTERNET_STATUS_HANDLE_CREATED: - // tell the main thread about the newly created handle - msg = handleCreatedMessage; - lParam = (LPARAM) LPINTERNET_ASYNC_RESULT(statusInformation)->dwResult; - break; - case INTERNET_STATUS_REQUEST_COMPLETE: -#ifdef RESOURCE_LOADER_DEBUG - _snprintf(buf, sizeof(buf), "request-complete: result=%p, error=%u\n", - LPINTERNET_ASYNC_RESULT(statusInformation)->dwResult, - LPINTERNET_ASYNC_RESULT(statusInformation)->dwError); - OutputDebugStringA(buf); -#endif - // tell the main thread that the request is done - msg = requestCompleteMessage; - lParam = 0; - break; - case INTERNET_STATUS_REDIRECT: - // tell the main thread to observe this redirect (FIXME: we probably - // need to block the redirect at this point so the application can - // decide whether or not to follow the redirect) - msg = requestRedirectedMessage; - lParam = (LPARAM) StringImpl::create((const UChar*) statusInformation, - statusInformationLength).releaseRef(); - break; - case INTERNET_STATUS_USER_INPUT_REQUIRED: - // FIXME: prompt the user if necessary - ResumeSuspendedDownload(internetHandle, 0); - case INTERNET_STATUS_STATE_CHANGE: - // may need to call ResumeSuspendedDownload here as well - default: - return; + if (!d->m_internetHandle) + return false; + + DWORD flags = INTERNET_FLAG_KEEP_CONNECTION + | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS + | INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; + + d->m_connectHandle = InternetConnectW(d->m_internetHandle, firstRequest().url().host().charactersWithNullTermination(), firstRequest().url().port(), + 0, 0, INTERNET_SERVICE_HTTP, flags, reinterpret_cast<DWORD_PTR>(this)); + + if (!d->m_connectHandle) + return false; + + String urlStr = firstRequest().url().path(); + String urlQuery = firstRequest().url().query(); + + if (!urlQuery.isEmpty()) { + urlStr.append('?'); + urlStr.append(urlQuery); } - PostMessage(transferJobWindowHandle, msg, (WPARAM) jobId, lParam); -} + String httpMethod = firstRequest().httpMethod(); + String httpReferrer = firstRequest().httpReferrer(); -bool ResourceHandle::start(NetworkingContext* context) -{ - ref(); - if (request().url().isLocalFile()) { - d->m_fileLoadTimer.startOneShot(0.0); - return true; - } else { - static HINTERNET internetHandle = 0; - if (!internetHandle) { - String userAgentStr = context->userAgent() + String("", 1); - LPCWSTR userAgent = reinterpret_cast<const WCHAR*>(userAgentStr.characters()); - // leak the Internet for now - internetHandle = InternetOpen(userAgent, INTERNET_OPEN_TYPE_PRECONFIG, 0, 0, INTERNET_FLAG_ASYNC); - } - if (!internetHandle) { - delete this; - return false; - } - static INTERNET_STATUS_CALLBACK callbackHandle = - InternetSetStatusCallback(internetHandle, transferJobStatusCallback); - - initializeOffScreenResourceHandleWindow(); - d->m_jobId = addToOutstandingJobs(this); - - DWORD flags = - INTERNET_FLAG_KEEP_CONNECTION | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTPS | - INTERNET_FLAG_IGNORE_REDIRECT_TO_HTTP; - - // For form posting, we can't use InternetOpenURL. We have to use - // InternetConnect followed by HttpSendRequest. - HINTERNET urlHandle; - String referrer = context->referrer(); - if (request().httpMethod() == "POST") { - d->m_postReferrer = referrer; - String host = request().url().host(); - urlHandle = InternetConnectA(internetHandle, host.latin1().data(), - request().url().port(), - NULL, // no username - NULL, // no password - INTERNET_SERVICE_HTTP, - flags, (DWORD_PTR)d->m_jobId); - } else { - String urlStr = request().url().string(); - int fragmentIndex = urlStr.find('#'); - if (fragmentIndex != -1) - urlStr = urlStr.left(fragmentIndex); - String headers; - if (!referrer.isEmpty()) - headers += String("Referer: ") + referrer + "\r\n"; - - urlHandle = InternetOpenUrlA(internetHandle, urlStr.latin1().data(), - headers.latin1().data(), headers.length(), - flags, (DWORD_PTR)d->m_jobId); - } + LPCWSTR httpAccept[] = { L"*/*", 0 }; - if (urlHandle == INVALID_HANDLE_VALUE) { - delete this; - return false; - } - d->m_threadId = GetCurrentThreadId(); + d->m_requestHandle = HttpOpenRequestW(d->m_connectHandle, httpMethod.charactersWithNullTermination(), urlStr.charactersWithNullTermination(), + 0, httpReferrer.charactersWithNullTermination(), httpAccept, flags, reinterpret_cast<DWORD_PTR>(this)); - return true; + if (!d->m_requestHandle) { + InternetCloseHandle(d->m_connectHandle); + return false; + } + + if (firstRequest().httpBody()) { + firstRequest().httpBody()->flatten(d->m_formData); + d->m_bytesRemainingToWrite = d->m_formData.size(); + } + + Vector<UChar> httpHeaders; + const HTTPHeaderMap& httpHeaderFields = firstRequest().httpHeaderFields(); + + for (HTTPHeaderMap::const_iterator it = httpHeaderFields.begin(); it != httpHeaderFields.end(); ++it) { + if (equalIgnoringCase(it->first, "Accept") || equalIgnoringCase(it->first, "Referer") || equalIgnoringCase(it->first, "User-Agent")) + continue; + + if (!httpHeaders.isEmpty()) + httpHeaders.append('\n'); + + httpHeaders.append(it->first.characters(), it->first.length()); + httpHeaders.append(':'); + httpHeaders.append(it->second.characters(), it->second.length()); } + + INTERNET_BUFFERSW internetBuffers; + ZeroMemory(&internetBuffers, sizeof(internetBuffers)); + internetBuffers.dwStructSize = sizeof(internetBuffers); + internetBuffers.lpcszHeader = httpHeaders.data(); + internetBuffers.dwHeadersLength = httpHeaders.size(); + internetBuffers.dwBufferTotal = d->m_bytesRemainingToWrite; + + HttpSendRequestExW(d->m_requestHandle, &internetBuffers, 0, 0, reinterpret_cast<DWORD_PTR>(this)); + + ref(); // balanced by deref in onRequestComplete + + if (d->m_loadSynchronously) + while (onRequestComplete()) { + // Loop until finished. + } + + return true; } void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) @@ -517,37 +388,29 @@ void ResourceHandle::fileLoadTimer(Timer<ResourceHandle>*) void ResourceHandle::cancel() { - if (d->m_resourceHandle) - InternetCloseHandle(d->m_resourceHandle); - else + if (d->m_requestHandle) { + d->m_internetHandle = 0; + InternetCloseHandle(d->m_requestHandle); + InternetCloseHandle(d->m_connectHandle); + } else d->m_fileLoadTimer.stop(); - - client()->didFinishLoading(this, 0); - - if (!d->m_resourceHandle) - // Async load canceled before we have a handle -- mark ourselves as in error, to be deleted later. - // FIXME: need real cancel error - client()->didFail(this, ResourceError()); } -void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame) +void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data) { UNUSED_PARAM(storedCredentials); WebCoreSynchronousLoader syncLoader(error, response, data, request.httpUserAgent()); ResourceHandle handle(request, &syncLoader, true, false); - handle.start(frame); -} - -void ResourceHandle::setHasReceivedResponse(bool b) -{ - d->m_hasReceivedResponse = b; + handle.setSynchronousInternetHandle(syncLoader.internetHandle()); + handle.start(context); } -bool ResourceHandle::hasReceivedResponse() const +void ResourceHandle::setSynchronousInternetHandle(HINTERNET internetHandle) { - return d->m_hasReceivedResponse; + d->m_internetHandle = internetHandle; + d->m_loadSynchronously = true; } bool ResourceHandle::willLoadFromCache(ResourceRequest&, Frame*) |