void ResourceResponse::updateFromSoupMessage(SoupMessage* soupMessage) { SoupURI* soupURI = soup_message_get_uri(soupMessage); GOwnPtr<gchar> uri(soup_uri_to_string(soupURI, FALSE)); m_url = KURL(KURL(), String::fromUTF8(uri.get())); m_httpStatusCode = soupMessage->status_code; SoupMessageHeadersIter headersIter; const char* headerName; const char* headerValue; soup_message_headers_iter_init(&headersIter, soupMessage->response_headers); while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) m_httpHeaderFields.set(String::fromUTF8(headerName), String::fromUTF8(headerValue)); m_soupFlags = soup_message_get_flags(soupMessage); String contentType = soup_message_headers_get_one(soupMessage->response_headers, "Content-Type"); setMimeType(extractMIMETypeFromMediaType(contentType)); setTextEncodingName(extractCharsetFromMediaType(contentType)); setExpectedContentLength(soup_message_headers_get_content_length(soupMessage->response_headers)); setHTTPStatusText(soupMessage->reason_phrase); setSuggestedFilename(filenameFromHTTPContentDisposition(httpHeaderField("Content-Disposition"))); }
void QNetworkReplyHandler::sendResponseIfNeeded() { m_shouldSendResponse = (m_loadMode != LoadNormal); if (m_shouldSendResponse) return; if (m_reply->error()) return; if (m_responseSent || !m_resourceHandle) return; m_responseSent = true; ResourceHandleClient* client = m_resourceHandle->client(); if (!client) return; WebCore::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); WebCore::String encoding = extractCharsetFromMediaType(contentType); WebCore::String mimeType = extractMIMETypeFromMediaType(contentType); if (mimeType.isEmpty()) { // let's try to guess from the extension QString extension = m_reply->url().path(); int index = extension.lastIndexOf(QLatin1Char('.')); if (index > 0) { extension = extension.mid(index + 1); mimeType = MIMETypeRegistry::getMIMETypeForExtension(extension); } } KURL url(m_reply->url()); ResourceResponse response(url, mimeType, m_reply->header(QNetworkRequest::ContentLengthHeader).toLongLong(), encoding, String()); if (url.isLocalFile()) { client->didReceiveResponse(m_resourceHandle, response); return; } // The status code is equal to 0 for protocols not in the HTTP family. int statusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (url.protocolInHTTPFamily()) { String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromAscii(m_reply->rawHeader("Content-Disposition"))); if (!suggestedFilename.isEmpty()) response.setSuggestedFilename(suggestedFilename); else response.setSuggestedFilename(url.lastPathComponent()); response.setHTTPStatusCode(statusCode); response.setHTTPStatusText(m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); // Add remaining headers. foreach (const QByteArray& headerName, m_reply->rawHeaderList()) { response.setHTTPHeaderField(QString::fromAscii(headerName), QString::fromAscii(m_reply->rawHeader(headerName))); } }
// set response headers from memory void CurlCacheEntry::setResponseFromCachedHeaders(ResourceResponse& response) { response.setHTTPStatusCode(304); response.setWasCached(true); // Integrate the headers in the response with the cached ones. HTTPHeaderMap::const_iterator it = m_cachedResponse.httpHeaderFields().begin(); HTTPHeaderMap::const_iterator end = m_cachedResponse.httpHeaderFields().end(); while (it != end) { if (response.httpHeaderField(it->key).isNull()) response.setHTTPHeaderField(it->key, it->value); ++it; } // Try to parse expected content length long long contentLength = -1; if (!response.httpHeaderField("Content-Length").isNull()) { bool success = false; long long parsedContentLength = response.httpHeaderField("Content-Length").toInt64(&success); if (success) contentLength = parsedContentLength; } response.setExpectedContentLength(contentLength); // -1 on parse error or null response.setMimeType(extractMIMETypeFromMediaType(response.httpHeaderField("Content-Type"))); response.setTextEncodingName(extractCharsetFromMediaType(response.httpHeaderField("Content-Type"))); response.setSuggestedFilename(filenameFromHTTPContentDisposition(response.httpHeaderField("Content-Disposition"))); }
void CurlDownload::didReceiveHeader(const String& header) { MutexLocker locker(m_mutex); if (header == "\r\n" || header == "\n") { long httpCode = 0; CURLcode err = curl_easy_getinfo(m_curlHandle, CURLINFO_RESPONSE_CODE, &httpCode); if (httpCode >= 200 && httpCode < 300) { const char* url = 0; err = curl_easy_getinfo(m_curlHandle, CURLINFO_EFFECTIVE_URL, &url); m_response.setURL(URL(ParsedURLString, url)); m_response.setMimeType(extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type"))); m_response.setTextEncodingName(extractCharsetFromMediaType(m_response.httpHeaderField("Content-Type"))); m_response.setSuggestedFilename(filenameFromHTTPContentDisposition(m_response.httpHeaderField("Content-Disposition"))); callOnMainThread(MainThreadTask(receivedResponseCallback, this)); } } else { int splitPos = header.find(":"); if (splitPos != -1) m_response.setHTTPHeaderField(header.left(splitPos), header.substring(splitPos+1).stripWhiteSpace()); } }
void QNetworkReplyHandler::sendResponseIfNeeded() { ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted()); if (m_replyWrapper->reply()->error() && m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).isNull()) return; ResourceHandleClient* client = m_resourceHandle->client(); if (!client) return; WTF::String mimeType = m_replyWrapper->mimeType(); if (mimeType.isEmpty()) { // let's try to guess from the extension mimeType = MIMETypeRegistry::getMIMETypeForPath(m_replyWrapper->reply()->url().path()); } KURL url(m_replyWrapper->reply()->url()); ResourceResponse response(url, mimeType.lower(), m_replyWrapper->reply()->header(QNetworkRequest::ContentLengthHeader).toLongLong(), m_replyWrapper->encoding(), String()); if (url.isLocalFile()) { client->didReceiveResponse(m_resourceHandle, response); return; } // The status code is equal to 0 for protocols not in the HTTP family. int statusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt(); if (url.protocolIsInHTTPFamily()) { String suggestedFilename = filenameFromHTTPContentDisposition(QString::fromLatin1(m_replyWrapper->reply()->rawHeader("Content-Disposition"))); if (!suggestedFilename.isEmpty()) response.setSuggestedFilename(suggestedFilename); else { Vector<String> extensions = MIMETypeRegistry::getExtensionsForMIMEType(mimeType); if (extensions.isEmpty()) response.setSuggestedFilename(url.lastPathComponent()); else { // If the suffix doesn't match the MIME type, correct the suffix. QString filename = url.lastPathComponent(); const String suffix = QMimeDatabase().suffixForFileName(filename); if (!extensions.contains(suffix)) { filename.chop(suffix.length()); filename += MIMETypeRegistry::getPreferredExtensionForMIMEType(mimeType); } response.setSuggestedFilename(filename); } } response.setHTTPStatusCode(statusCode); response.setHTTPStatusText(m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toByteArray().constData()); // Add remaining headers. foreach (const QNetworkReply::RawHeaderPair& pair, m_replyWrapper->reply()->rawHeaderPairs()) response.setHTTPHeaderField(QString::fromLatin1(pair.first), QString::fromLatin1(pair.second)); }
static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) { SoupMessageHeadersIter iter; const char* name = 0; const char* value = 0; soup_message_headers_iter_init(&iter, msg->response_headers); while (soup_message_headers_iter_next(&iter, &name, &value)) response->setHTTPHeaderField(name, value); GHashTable* contentTypeParameters = 0; String contentType = soup_message_headers_get_content_type(msg->response_headers, &contentTypeParameters); // When the server sends multiple Content-Type headers, soup will // give us their values concatenated with commas as a separator; // we need to handle this and use only one value. We use the first // value, and add all the parameters, afterwards, if any. Vector<String> contentTypes; contentType.split(',', true, contentTypes); contentType = contentTypes[0]; if (contentTypeParameters) { GString* parametersString = g_string_new(0); GHashTableIter hashTableIter; const char* hashKey; const char* hashValue; g_hash_table_iter_init(&hashTableIter, contentTypeParameters); while (g_hash_table_iter_next(&hashTableIter, reinterpret_cast<void**>(const_cast<char**>(&hashKey)), reinterpret_cast<void**>(const_cast<char**>(&hashValue)))) { // Work-around bug in soup which causes a crash; // See http://bugzilla.gnome.org/show_bug.cgi?id=577728 if (!hashValue) hashValue = ""; g_string_append(parametersString, "; "); soup_header_g_string_append_param(parametersString, hashKey, hashValue); } contentType += String(parametersString->str); g_string_free(parametersString, true); g_hash_table_destroy(contentTypeParameters); } response->setMimeType(extractMIMETypeFromMediaType(contentType)); char* uri = soup_uri_to_string(soup_message_get_uri(msg), false); response->setURL(KURL(KURL(), uri)); g_free(uri); response->setTextEncodingName(extractCharsetFromMediaType(contentType)); response->setExpectedContentLength(soup_message_headers_get_content_length(msg->response_headers)); response->setHTTPStatusCode(msg->status_code); response->setHTTPStatusText(msg->reason_phrase); response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition"))); }
/* * This is being called for each HTTP header in the response. This includes '\r\n' * for the last line of the header. * * We will add each HTTP Header to the ResourceResponse and on the termination * of the header (\r\n) we will parse Content-Type and Content-Disposition and * update the ResourceResponse and then send it away. * */ static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data) { ResourceHandle* job = static_cast<ResourceHandle*>(data); ResourceHandleInternal* d = job->getInternal(); unsigned int totalSize = size * nmemb; ResourceHandleClient* client = d->client(); if (!client) { return totalSize; } String header(static_cast<const char*>(ptr), totalSize); /* * a) We can finish and send the ResourceResponse * b) We will add the current header to the HTTPHeaderMap of the ResourceResponse */ if (header == String("\r\n")) { CURL* h = d->m_handle; CURLcode err; double contentLength = 0; err = curl_easy_getinfo(h, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength); d->m_response.setExpectedContentLength(static_cast<long long int>(contentLength)); const char* hdr; err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr); d->m_response.setUrl(KURL(hdr)); long httpCode = 0; err = curl_easy_getinfo(h, CURLINFO_RESPONSE_CODE, &httpCode); d->m_response.setHTTPStatusCode(httpCode); d->m_response.setMimeType(extractMIMETypeFromMediaType(d->m_response.httpHeaderField("Content-Type"))); d->m_response.setTextEncodingName(extractCharsetFromMediaType(d->m_response.httpHeaderField("Content-Type"))); d->m_response.setSuggestedFilename(filenameFromHTTPContentDisposition(d->m_response.httpHeaderField("Content-Disposition"))); client->didReceiveResponse(job, d->m_response); } else { int splitPos = header.find(":"); if (splitPos != -1) d->m_response.setHTTPHeaderField(header.left(splitPos), header.substring(splitPos+1).stripWhiteSpace()); } return totalSize; }
static void fillResponseFromMessage(SoupMessage* msg, ResourceResponse* response) { SoupMessageHeadersIter iter; const char* name = NULL; const char* value = NULL; soup_message_headers_iter_init(&iter, msg->response_headers); while (soup_message_headers_iter_next(&iter, &name, &value)) response->setHTTPHeaderField(name, value); String contentType = soup_message_headers_get(msg->response_headers, "Content-Type"); char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE); response->setUrl(KURL(uri)); g_free(uri); response->setMimeType(extractMIMETypeFromMediaType(contentType)); response->setTextEncodingName(extractCharsetFromMediaType(contentType)); response->setExpectedContentLength(soup_message_headers_get_content_length(msg->response_headers)); response->setHTTPStatusCode(msg->status_code); response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition"))); }
void MultipartHandle::didReceiveResponse() { ResourceHandleInternal* d = m_resourceHandle->getInternal(); if (d->client()) { OwnPtr<ResourceResponse> response = ResourceResponseBase::adopt(d->m_response.copyData()); HTTPHeaderMap::const_iterator end = m_headers.end(); for (HTTPHeaderMap::const_iterator it = m_headers.begin(); it != end; ++it) response->setHTTPHeaderField(it->key, it->value); String contentType = m_headers.get("Content-Type"); String mimeType = extractMIMETypeFromMediaType(contentType); response->setMimeType(mimeType.lower()); response->setTextEncodingName(extractCharsetFromMediaType(contentType)); response->setSuggestedFilename(filenameFromHTTPContentDisposition(response->httpHeaderField("Content-Disposition"))); d->client()->didReceiveResponse(m_resourceHandle, *response); response->setResponseFired(true); } }
void ResourceResponse::updateFromSoupMessageHeaders(const SoupMessageHeaders* messageHeaders) { SoupMessageHeaders* headers = const_cast<SoupMessageHeaders*>(messageHeaders); SoupMessageHeadersIter headersIter; const char* headerName; const char* headerValue; // updateFromSoupMessage could be called several times for the same ResourceResponse object, // thus, we need to clear old header values and update m_httpHeaderFields from soupMessage headers. m_httpHeaderFields.clear(); soup_message_headers_iter_init(&headersIter, headers); while (soup_message_headers_iter_next(&headersIter, &headerName, &headerValue)) { String headerNameString = String::fromUTF8WithLatin1Fallback(headerName, strlen(headerName)); HTTPHeaderMap::const_iterator it = m_httpHeaderFields.find(headerNameString); if (it == m_httpHeaderFields.end() || (it != m_httpHeaderFields.end() && it->value.isEmpty())) m_httpHeaderFields.set(headerNameString, String::fromUTF8WithLatin1Fallback(headerValue, strlen(headerValue))); else { StringBuilder builder; builder.append(it->value); builder.appendLiteral(", "); builder.append(String::fromUTF8WithLatin1Fallback(headerValue, strlen(headerValue))); m_httpHeaderFields.set(headerNameString, builder.toString()); } } String contentType; const char* officialType = soup_message_headers_get_one(headers, "Content-Type"); if (!m_sniffedContentType.isEmpty() && m_sniffedContentType != officialType) contentType = m_sniffedContentType; else contentType = officialType; setMimeType(extractMIMETypeFromMediaType(contentType)); setTextEncodingName(extractCharsetFromMediaType(contentType)); setExpectedContentLength(soup_message_headers_get_content_length(headers)); setSuggestedFilename(filenameFromHTTPContentDisposition(httpHeaderField("Content-Disposition")));}
/* * This is being called for each HTTP header in the response. This includes '\r\n' * for the last line of the header. * * We will add each HTTP Header to the ResourceResponse and on the termination * of the header (\r\n) we will parse Content-Type and Content-Disposition and * update the ResourceResponse and then send it away. * */ static size_t headerCallback(char* ptr, size_t size, size_t nmemb, void* data) { ResourceHandle* job = static_cast<ResourceHandle*>(data); ResourceHandleInternal* d = job->getInternal(); if (d->m_cancelled) return 0; size_t totalSize = size * nmemb; ResourceHandleClient* client = d->client(); String header(static_cast<const char*>(ptr), totalSize); /* * a) We can finish and send the ResourceResponse * b) We will add the current header to the HTTPHeaderMap of the ResourceResponse * * The HTTP standard requires to use \r\n but for compatibility it recommends to * accept also \n. */ if (header == String("\r\n") || header == String("\n")) { CURL* h = d->m_handle; CURLcode err; double contentLength = 0; err = curl_easy_getinfo(h, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &contentLength); d->m_response.setExpectedContentLength(static_cast<long long int>(contentLength)); const char* hdr; err = curl_easy_getinfo(h, CURLINFO_EFFECTIVE_URL, &hdr); d->m_response.setUrl(KURL(hdr)); long httpCode = 0; err = curl_easy_getinfo(h, CURLINFO_RESPONSE_CODE, &httpCode); d->m_response.setHTTPStatusCode(httpCode); d->m_response.setMimeType(extractMIMETypeFromMediaType(d->m_response.httpHeaderField("Content-Type"))); d->m_response.setTextEncodingName(extractCharsetFromMediaType(d->m_response.httpHeaderField("Content-Type"))); d->m_response.setSuggestedFilename(filenameFromHTTPContentDisposition(d->m_response.httpHeaderField("Content-Disposition"))); // HTTP redirection if (httpCode >= 300 && httpCode < 400) { String location = d->m_response.httpHeaderField("location"); if (!location.isEmpty()) { KURL newURL = KURL(job->request().url(), location); ResourceRequest redirectedRequest = job->request(); redirectedRequest.setURL(newURL); if (client) client->willSendRequest(job, redirectedRequest, d->m_response); d->m_request.setURL(newURL); return totalSize; } } if (client) client->didReceiveResponse(job, d->m_response); d->m_response.setResponseFired(true); } else { int splitPos = header.find(":"); if (splitPos != -1) d->m_response.setHTTPHeaderField(header.left(splitPos), header.substring(splitPos+1).stripWhiteSpace()); } return totalSize; }
void NetworkJob::sendResponseIfNeeded() { if (m_responseSent) return; m_responseSent = true; if (isError(m_extendedStatusCode) && !m_dataReceived) return; String urlFilename = m_response.url().lastPathComponent(); // Get the MIME type that was set by the content sniffer // if there's no custom sniffer header, try to set it from the Content-Type header // if this fails, guess it from extension. String mimeType; if (m_isFTP && m_isFTPDir) mimeType = "application/x-ftp-directory"; else mimeType = m_response.httpHeaderField(BlackBerry::Platform::NetworkRequest::HEADER_RIM_SNIFFED_MIME_TYPE); if (mimeType.isNull()) mimeType = extractMIMETypeFromMediaType(m_contentType); if (mimeType.isNull()) mimeType = MIMETypeRegistry::getMIMETypeForPath(urlFilename); m_response.setMimeType(mimeType); // Set encoding from Content-Type header. m_response.setTextEncodingName(extractCharsetFromMediaType(m_contentType)); // Set content length from header. String contentLength = m_response.httpHeaderField("Content-Length"); if (!contentLength.isNull()) m_response.setExpectedContentLength(contentLength.toInt64()); // Set suggested filename for downloads from the Content-Disposition header; if this fails, // fill it in from the url and sniffed mime type;Skip this for data and about URLs, // because they have no Content-Disposition header and the format is wrong to be a filename. if (!m_isData && !m_isAbout) { String suggestedFilename = filenameFromHTTPContentDisposition(m_contentDisposition); if (suggestedFilename.isEmpty()) { // Check and see if an extension already exists. String mimeExtension = MIMETypeRegistry::getPreferredExtensionForMIMEType(mimeType); if (urlFilename.isEmpty()) { if (mimeExtension.isEmpty()) // No extension found for the mimeType. suggestedFilename = String("Untitled"); else suggestedFilename = String("Untitled") + "." + mimeExtension; } else { if (urlFilename.reverseFind('.') == notFound && !mimeExtension.isEmpty()) suggestedFilename = urlFilename + '.' + mimeExtension; else suggestedFilename = urlFilename; } } m_response.setSuggestedFilename(suggestedFilename); } // Make sure local files aren't cached, since this just duplicates them. if (m_isFile || m_isData || m_isAbout) m_response.setHTTPHeaderField("Cache-Control", "no-cache"); if (isClientAvailable()) { RecursionGuard guard(m_callingClient); m_handle->client()->didReceiveResponse(m_handle.get(), m_response); } }