📄 resourcehandlemanager.cpp
字号:
}void ResourceHandleManager::setupPUT(ResourceHandle*, struct curl_slist**){ notImplemented();}/* Calculate the length of the POST. Force chunked data transfer if size of files can't be obtained. */void ResourceHandleManager::setupPOST(ResourceHandle* job, struct curl_slist** headers){ ResourceHandleInternal* d = job->getInternal(); curl_easy_setopt(d->m_handle, CURLOPT_POST, TRUE); curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDSIZE, 0); if (!job->request().httpBody()) return; Vector<FormDataElement> elements = job->request().httpBody()->elements(); size_t numElements = elements.size(); if (!numElements) return; // Do not stream for simple POST data if (numElements == 1) { job->request().httpBody()->flatten(d->m_postBytes); if (d->m_postBytes.size() != 0) { curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDSIZE, d->m_postBytes.size()); curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDS, d->m_postBytes.data()); } return; } // Obtain the total size of the POST // The size of a curl_off_t could be different in WebKit and in cURL depending on // compilation flags of both. For CURLOPT_POSTFIELDSIZE_LARGE we have to pass the // right size or random data will be used as the size. static int expectedSizeOfCurlOffT = 0; if (!expectedSizeOfCurlOffT) { curl_version_info_data *infoData = curl_version_info(CURLVERSION_NOW); if (infoData->features & CURL_VERSION_LARGEFILE) expectedSizeOfCurlOffT = sizeof(long long); else expectedSizeOfCurlOffT = sizeof(int); }#if COMPILER(MSVC) // work around compiler error in Visual Studio 2005. It can't properly // handle math with 64-bit constant declarations.#pragma warning(disable: 4307)#endif static const long long maxCurlOffT = (1LL << (expectedSizeOfCurlOffT * 8 - 1)) - 1; curl_off_t size = 0; bool chunkedTransfer = false; for (size_t i = 0; i < numElements; i++) { FormDataElement element = elements[i]; if (element.m_type == FormDataElement::encodedFile) { long long fileSizeResult; if (getFileSize(element.m_filename, fileSizeResult)) { if (fileSizeResult > maxCurlOffT) { // File size is too big for specifying it to cURL chunkedTransfer = true; break; } size += fileSizeResult; } else { chunkedTransfer = true; break; } } else size += elements[i].m_data.size(); } // cURL guesses that we want chunked encoding as long as we specify the header if (chunkedTransfer) *headers = curl_slist_append(*headers, "Transfer-Encoding: chunked"); else { if (sizeof(long long) == expectedSizeOfCurlOffT) curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDSIZE_LARGE, (long long)size); else curl_easy_setopt(d->m_handle, CURLOPT_POSTFIELDSIZE_LARGE, (int)size); } curl_easy_setopt(d->m_handle, CURLOPT_READFUNCTION, readCallback); curl_easy_setopt(d->m_handle, CURLOPT_READDATA, job);}void ResourceHandleManager::add(ResourceHandle* job){ // we can be called from within curl, so to avoid re-entrancy issues // schedule this job to be added the next time we enter curl download loop job->ref(); m_resourceHandleList.append(job); if (!m_downloadTimer.isActive()) m_downloadTimer.startOneShot(pollTimeSeconds);}bool ResourceHandleManager::removeScheduledJob(ResourceHandle* job){ int size = m_resourceHandleList.size(); for (int i = 0; i < size; i++) { if (job == m_resourceHandleList[i]) { m_resourceHandleList.remove(i); job->deref(); return true; } } return false;}bool ResourceHandleManager::startScheduledJobs(){ // TODO: Create a separate stack of jobs for each domain. bool started = false; while (!m_resourceHandleList.isEmpty() && m_runningJobs < maxRunningJobs) { ResourceHandle* job = m_resourceHandleList[0]; m_resourceHandleList.remove(0); startJob(job); started = true; } return started;}static void parseDataUrl(ResourceHandle* handle){ ResourceHandleClient* client = handle->client(); ASSERT(client); if (!client) return; String url = handle->request().url().string(); ASSERT(url.startsWith("data:", false)); int index = url.find(','); if (index == -1) { client->cannotShowURL(handle); return; } String mediaType = url.substring(5, index - 5); String data = url.substring(index + 1); bool base64 = mediaType.endsWith(";base64", false); if (base64) mediaType = mediaType.left(mediaType.length() - 7); if (mediaType.isEmpty()) mediaType = "text/plain;charset=US-ASCII"; String mimeType = extractMIMETypeFromMediaType(mediaType); String charset = extractCharsetFromMediaType(mediaType); ResourceResponse response; response.setMimeType(mimeType); if (base64) { data = decodeURLEscapeSequences(data); response.setTextEncodingName(charset); client->didReceiveResponse(handle, response); // Use the GLib Base64 if available, since WebCore's decoder isn't // general-purpose and fails on Acid3 test 97 (whitespace).#ifdef USE_GLIB_BASE64 size_t outLength = 0; char* outData = 0; outData = reinterpret_cast<char*>(g_base64_decode(data.utf8().data(), &outLength)); if (outData && outLength > 0) client->didReceiveData(handle, outData, outLength, 0); g_free(outData);#else Vector<char> out; if (base64Decode(data.latin1().data(), data.latin1().length(), out) && out.size() > 0) client->didReceiveData(handle, out.data(), out.size(), 0);#endif } else { // We have to convert to UTF-16 early due to limitations in KURL data = decodeURLEscapeSequences(data, TextEncoding(charset)); response.setTextEncodingName("UTF-16"); client->didReceiveResponse(handle, response); if (data.length() > 0) client->didReceiveData(handle, reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0); } client->didFinishLoading(handle);}void ResourceHandleManager::dispatchSynchronousJob(ResourceHandle* job){ KURL kurl = job->request().url(); if (kurl.protocolIs("data")) { parseDataUrl(job); return; } ResourceHandleInternal* handle = job->getInternal();#if LIBCURL_VERSION_NUM > 0x071200 // If defersLoading is true and we call curl_easy_perform // on a paused handle, libcURL would do the transfert anyway // and we would assert so force defersLoading to be false. handle->m_defersLoading = false;#endif initializeHandle(job); // curl_easy_perform blocks until the transfert is finished. CURLcode ret = curl_easy_perform(handle->m_handle); if (ret != 0) { ResourceError error(String(handle->m_url), ret, String(handle->m_url), String(curl_easy_strerror(ret))); handle->client()->didFail(job, error); } curl_easy_cleanup(handle->m_handle);}void ResourceHandleManager::startJob(ResourceHandle* job){ KURL kurl = job->request().url(); if (kurl.protocolIs("data")) { parseDataUrl(job); return; } initializeHandle(job); m_runningJobs++; CURLMcode ret = curl_multi_add_handle(m_curlMultiHandle, job->getInternal()->m_handle); // don't call perform, because events must be async // timeout will occur and do curl_multi_perform if (ret && ret != CURLM_CALL_MULTI_PERFORM) {#ifndef NDEBUG fprintf(stderr, "Error %d starting job %s\n", ret, encodeWithURLEscapeSequences(job->request().url().string()).latin1().data());#endif job->cancel(); return; }}void ResourceHandleManager::initializeHandle(ResourceHandle* job){ KURL kurl = job->request().url(); // Remove any fragment part, otherwise curl will send it as part of the request. kurl.removeRef(); ResourceHandleInternal* d = job->getInternal(); String url = kurl.string(); if (kurl.isLocalFile()) { String query = kurl.query(); // Remove any query part sent to a local file. if (!query.isEmpty()) url = url.left(url.find(query)); // Determine the MIME type based on the path. d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(url)); } d->m_handle = curl_easy_init();#if LIBCURL_VERSION_NUM > 0x071200 if (d->m_defersLoading) { CURLcode error = curl_easy_pause(d->m_handle, CURLPAUSE_ALL); // If we did not pause the handle, we would ASSERT in the // header callback. So just assert here. ASSERT(error == CURLE_OK); }#endif#ifndef NDEBUG if (getenv("DEBUG_CURL")) curl_easy_setopt(d->m_handle, CURLOPT_VERBOSE, 1);#endif curl_easy_setopt(d->m_handle, CURLOPT_PRIVATE, job); curl_easy_setopt(d->m_handle, CURLOPT_ERRORBUFFER, m_curlErrorBuffer); curl_easy_setopt(d->m_handle, CURLOPT_WRITEFUNCTION, writeCallback); curl_easy_setopt(d->m_handle, CURLOPT_WRITEDATA, job); curl_easy_setopt(d->m_handle, CURLOPT_HEADERFUNCTION, headerCallback); curl_easy_setopt(d->m_handle, CURLOPT_WRITEHEADER, job); curl_easy_setopt(d->m_handle, CURLOPT_AUTOREFERER, 1); curl_easy_setopt(d->m_handle, CURLOPT_FOLLOWLOCATION, 1); curl_easy_setopt(d->m_handle, CURLOPT_MAXREDIRS, 10); curl_easy_setopt(d->m_handle, CURLOPT_HTTPAUTH, CURLAUTH_ANY); curl_easy_setopt(d->m_handle, CURLOPT_SHARE, m_curlShareHandle); curl_easy_setopt(d->m_handle, CURLOPT_DNS_CACHE_TIMEOUT, 60 * 5); // 5 minutes // FIXME: Enable SSL verification when we have a way of shipping certs // and/or reporting SSL errors to the user. if (ignoreSSLErrors) curl_easy_setopt(d->m_handle, CURLOPT_SSL_VERIFYPEER, false); // enable gzip and deflate through Accept-Encoding: curl_easy_setopt(d->m_handle, CURLOPT_ENCODING, ""); // url must remain valid through the request ASSERT(!d->m_url); // url is in ASCII so latin1() will only convert it to char* without character translation. d->m_url = strdup(url.latin1().data()); curl_easy_setopt(d->m_handle, CURLOPT_URL, d->m_url); if (m_cookieJarFileName) { curl_easy_setopt(d->m_handle, CURLOPT_COOKIEFILE, m_cookieJarFileName); curl_easy_setopt(d->m_handle, CURLOPT_COOKIEJAR, m_cookieJarFileName); } struct curl_slist* headers = 0; if (job->request().httpHeaderFields().size() > 0) { HTTPHeaderMap customHeaders = job->request().httpHeaderFields(); HTTPHeaderMap::const_iterator end = customHeaders.end(); for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it) { String key = it->first; String value = it->second; String headerString(key); headerString.append(": "); headerString.append(value); CString headerLatin1 = headerString.latin1(); headers = curl_slist_append(headers, headerLatin1.data()); } } if ("GET" == job->request().httpMethod()) curl_easy_setopt(d->m_handle, CURLOPT_HTTPGET, TRUE); else if ("POST" == job->request().httpMethod()) setupPOST(job, &headers); else if ("PUT" == job->request().httpMethod()) setupPUT(job, &headers); else if ("HEAD" == job->request().httpMethod()) curl_easy_setopt(d->m_handle, CURLOPT_NOBODY, TRUE); if (headers) { curl_easy_setopt(d->m_handle, CURLOPT_HTTPHEADER, headers); d->m_customHeaders = headers; }}void ResourceHandleManager::cancel(ResourceHandle* job){ if (removeScheduledJob(job)) return; ResourceHandleInternal* d = job->getInternal(); d->m_cancelled = true; if (!m_downloadTimer.isActive()) m_downloadTimer.startOneShot(pollTimeSeconds);}} // namespace WebCore
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -