static gboolean parseDataUrl(gpointer callback_data) { ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data); String data = handle->request().url().string(); ASSERT(data.startsWith("data:", false)); String header; bool base64 = false; int index = data.find(','); if (index != -1) { header = data.substring(5, index - 5).lower(); data = data.substring(index + 1); if (header.endsWith(";base64")) { base64 = true; header = header.left(header.length() - 7); } } else data = String(); data = decodeURLEscapeSequences(data); size_t outLength = 0; char* outData = 0; if (base64 && !data.isEmpty()) { // Use the GLib Base64 if available, since WebCore's decoder isn't // general-purpose and fails on Acid3 test 97 (whitespace). outData = reinterpret_cast<char*>(g_base64_decode(data.utf8().data(), &outLength)); } if (header.isEmpty()) header = "text/plain;charset=US-ASCII"; ResourceHandleClient* client = handle->getInternal()->client(); ResourceResponse response; response.setMimeType(extractMIMETypeFromMediaType(header)); response.setTextEncodingName(extractCharsetFromMediaType(header)); if (outData) response.setExpectedContentLength(outLength); else response.setExpectedContentLength(data.length()); response.setHTTPStatusCode(200); client->didReceiveResponse(handle, response); if (outData) client->didReceiveData(handle, outData, outLength, 0); else client->didReceiveData(handle, data.latin1().data(), data.length(), 0); g_free(outData); client->didFinishLoading(handle); return FALSE; }
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))); } }
void MyResourceLoader::loadData(const String& data) { LOGD("Loading data (%s) ...", data.latin1().data()); ResourceHandleClient* client = m_handle->client(); int index = data.find(','); if (index == -1) { client->cannotShowURL(m_handle); return; } String mediaType = data.substring(0, index); String base64 = data.substring(index + 1); bool decode = mediaType.endsWith(";base64", false); if (decode) mediaType = mediaType.left(mediaType.length() - 7); // 7 for base64; if (mediaType.isEmpty()) mediaType = "text/plain;charset=US-ASCII"; String mimeType = extractMIMETypeFromMediaType(mediaType); String charset = extractCharsetFromMediaType(mediaType); ResourceResponse response; response.setMimeType(mimeType); if (decode) { base64 = decodeURLEscapeSequences(base64); response.setTextEncodingName(charset); client->didReceiveResponse(m_handle, response); // FIXME: This is annoying. WebCore's Base64 decoder chokes on spaces. // That is correct with strict decoding but html authors (particularly // the acid3 authors) put spaces in the data which should be ignored. // Remove them here before sending to the decoder. Vector<char> in; CString str = base64.latin1(); const char* chars = str.data(); unsigned i = 0; while (i < str.length()) { char c = chars[i]; // Don't send spaces or control characters. if (c != ' ' && c != '\n' && c != '\t' && c != '\b' && c != '\f' && c != '\r') in.append(chars[i]); i++; } Vector<char> out; if (base64Decode(in, out) && out.size() > 0) client->didReceiveData(m_handle, out.data(), out.size(), 0); } else { base64 = decodeURLEscapeSequences(base64, TextEncoding(charset)); response.setTextEncodingName("UTF-16"); client->didReceiveResponse(m_handle, response); if (base64.length() > 0) client->didReceiveData(m_handle, (const char*)base64.characters(), base64.length() * sizeof(UChar), 0); } client->didFinishLoading(m_handle, 0); }
// 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) { LockHolder 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) { URL url = getCurlEffectiveURL(m_curlHandle); callOnMainThread([this, url = url.isolatedCopy(), protectedThis = makeRef(*this)] { m_response.setURL(url); m_response.setMimeType(extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType))); m_response.setTextEncodingName(extractCharsetFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType))); didReceiveResponse(); }); } } else { callOnMainThread([this, header = header.isolatedCopy(), protectedThis = makeRef(*this)] { int splitPos = header.find(":"); if (splitPos != -1) m_response.setHTTPHeaderField(header.left(splitPos), header.substring(splitPos + 1).stripWhiteSpace()); }); } }
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 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(HTTPHeaderName::ContentType))); m_response.setTextEncodingName(extractCharsetFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType))); callOnMainThread([this] { didReceiveResponse(); }); } } else { int splitPos = header.find(":"); if (splitPos != -1) m_response.setHTTPHeaderField(header.left(splitPos), header.substring(splitPos+1).stripWhiteSpace()); } }
void QNetworkReplyWrapper::receiveMetaData() { // This slot is only used to receive the first signal from the QNetworkReply object. stopForwarding(); WTF::String contentType = m_reply->header(QNetworkRequest::ContentTypeHeader).toString(); m_encoding = extractCharsetFromMediaType(contentType); m_advertisedMIMEType = extractMIMETypeFromMediaType(contentType); m_redirectionTargetUrl = m_reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl(); if (m_redirectionTargetUrl.isValid()) { QueueLocker lock(m_queue); m_queue->push(&QNetworkReplyHandler::sendResponseIfNeeded); m_queue->push(&QNetworkReplyHandler::finish); return; } if (!m_sniffMIMETypes) { emitMetaDataChanged(); return; } bool isSupportedImageType = MIMETypeRegistry::isSupportedImageMIMEType(m_advertisedMIMEType); Q_ASSERT(!m_sniffer); m_sniffer = adoptPtr(new QtMIMETypeSniffer(m_reply, m_advertisedMIMEType, isSupportedImageType)); if (m_sniffer->isFinished()) { receiveSniffedMIMEType(); return; } connect(m_sniffer.get(), SIGNAL(finished()), this, SLOT(receiveSniffedMIMEType())); }
void NetworkResourcesData::responseReceived(const String& requestId, const String& frameId, const ResourceResponse& response) { ResourceData* resourceData = resourceDataForRequestId(requestId); if (!resourceData) return; resourceData->setFrameId(frameId); resourceData->setUrl(response.url()); resourceData->setMimeType(response.mimeType()); resourceData->setTextEncodingName(response.textEncodingName()); resourceData->setDecoder(InspectorPageAgent::createResourceTextDecoder(response.mimeType(), response.textEncodingName())); resourceData->setHTTPStatusCode(response.httpStatusCode()); String filePath = response.downloadedFilePath(); if (!filePath.isEmpty()) { OwnPtr<BlobData> blobData = BlobData::create(); blobData->appendFile(filePath); AtomicString mimeType; if (response.isHTTP()) mimeType = extractMIMETypeFromMediaType(response.httpHeaderField("Content-Type")); if (mimeType.isEmpty()) mimeType = response.mimeType(); if (mimeType.isEmpty()) mimeType = AtomicString("text/plain", AtomicString::ConstructFromLiteral); blobData->setContentType(mimeType); resourceData->setDownloadedFileBlob(BlobDataHandle::create(blobData.release(), -1)); } }
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)); long long contentLength = -1; if (!m_response->httpHeaderField("Content-Length").isNull()) { bool success = false; long long parsedContentLength = m_response->httpHeaderField("Content-Length").toInt64(&success); if (success) contentLength = parsedContentLength; } m_response->setExpectedContentLength(contentLength); // -1 on parse error or null 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 handleDataURL(ResourceHandle* handle) { ASSERT(handle->firstRequest().url().protocolIs("data")); String url = handle->firstRequest().url().string(); int index = url.find(','); if (index == -1) { handle->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"; String mimeType = extractMIMETypeFromMediaType(mediaType); String charset = extractCharsetFromMediaType(mediaType); if (charset.isEmpty()) charset = "US-ASCII"; ResourceResponse response; response.setMimeType(mimeType); response.setTextEncodingName(charset); response.setURL(handle->firstRequest().url()); if (base64) { data = decodeURLEscapeSequences(data); handle->client()->didReceiveResponse(handle, response); Vector<char> out; if (base64Decode(data, out, IgnoreWhitespace) && out.size() > 0) { response.setExpectedContentLength(out.size()); handle->client()->didReceiveData(handle, out.data(), out.size(), 0); } } else { TextEncoding encoding(charset); data = decodeURLEscapeSequences(data, encoding); handle->client()->didReceiveResponse(handle, response); CString encodedData = encoding.encode(data.characters(), data.length(), URLEncodedEntitiesForUnencodables); response.setExpectedContentLength(encodedData.length()); if (encodedData.length()) handle->client()->didReceiveData(handle, encodedData.data(), encodedData.length(), 0); } handle->client()->didFinishLoading(handle, 0); }
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"))); }
bool isOnAccessControlSimpleRequestHeaderWhitelist(const String& name, const String& value) { if (equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-language")) return true; // Preflight is required for MIME types that can not be sent via form submission. if (equalIgnoringCase(name, "content-type")) { String mimeType = extractMIMETypeFromMediaType(value); return equalIgnoringCase(mimeType, "application/x-www-form-urlencoded") || equalIgnoringCase(mimeType, "multipart/form-data") || equalIgnoringCase(mimeType, "text/plain"); } return false; }
/* * 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 bool isSimpleHeader(const String& name, const String& value) { HTTPHeaderName headerName; if (!findHTTPHeaderName(name, headerName)) return false; switch (headerName) { case HTTPHeaderName::Accept: case HTTPHeaderName::AcceptLanguage: case HTTPHeaderName::ContentLanguage: return true; case HTTPHeaderName::ContentType: { String mimeType = extractMIMETypeFromMediaType(value); return equalLettersIgnoringASCIICase(mimeType, "application/x-www-form-urlencoded") || equalLettersIgnoringASCIICase(mimeType, "multipart/form-data") || equalLettersIgnoringASCIICase(mimeType, "text/plain"); } default: return false; } }
bool CachedCSSStyleSheet::canUseSheet(bool enforceMIMEType) const { if (errorOccurred()) return false; if (!enforceMIMEType) return true; // This check exactly matches Firefox. Note that we grab the Content-Type // header directly because we want to see what the value is BEFORE content // sniffing. Firefox does this by setting a "type hint" on the channel. // This implementation should be observationally equivalent. // // This code defaults to allowing the stylesheet for non-HTTP protocols so // folks can use standards mode for local HTML documents. String mimeType = extractMIMETypeFromMediaType(response().httpHeaderField("Content-Type")); return mimeType.isEmpty() || equalIgnoringCase(mimeType, "text/css") || equalIgnoringCase(mimeType, "application/x-unknown-content-type"); }
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()) { auto response = d->m_response; 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(HTTPHeaderName::ContentType); String mimeType = extractMIMETypeFromMediaType(contentType); response.setMimeType(mimeType.convertToASCIILowercase()); response.setTextEncodingName(extractCharsetFromMediaType(contentType)); d->client()->didReceiveResponse(m_resourceHandle, WTFMove(response)); } }
bool isOnAccessControlSimpleRequestHeaderWhitelist(HTTPHeaderName name, const String& value) { switch (name) { case HTTPHeaderName::Accept: case HTTPHeaderName::AcceptLanguage: case HTTPHeaderName::ContentLanguage: case HTTPHeaderName::Origin: case HTTPHeaderName::Referer: return true; case HTTPHeaderName::ContentType: { // Preflight is required for MIME types that can not be sent via form submission. String mimeType = extractMIMETypeFromMediaType(value); return equalIgnoringCase(mimeType, "application/x-www-form-urlencoded") || equalIgnoringCase(mimeType, "multipart/form-data") || equalIgnoringCase(mimeType, "text/plain"); } default: return false; } }
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); } }
bool FetchUtils::isSimpleHeader(const AtomicString& name, const AtomicString& value) { // http://fetch.spec.whatwg.org/#simple-header // "A simple header is a header whose name is either one of `Accept`, // `Accept-Language`, and `Content-Language`, or whose name is // `Content-Type` and value, once parsed, is one of // `application/x-www-form-urlencoded`, `multipart/form-data`, and // `text/plain`." if (equalIgnoringCase(name, "accept") || equalIgnoringCase(name, "accept-language") || equalIgnoringCase(name, "content-language")) return true; if (equalIgnoringCase(name, "content-type")) { AtomicString mimeType = extractMIMETypeFromMediaType(value); return equalIgnoringCase(mimeType, "application/x-www-form-urlencoded") || equalIgnoringCase(mimeType, "multipart/form-data") || equalIgnoringCase(mimeType, "text/plain"); } return false; }
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")));}
void NetworkJob::handleNotifyMultipartHeaderReceived(const String& key, const String& value) { if (!m_multipartResponse) { // Create a new response based on the original set of headers + the // replacement headers. We only replace the same few headers that gecko // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. m_multipartResponse = adoptPtr(new ResourceResponse); m_multipartResponse->setURL(m_response.url()); // The list of BlackBerry::Platform::replaceHeaders that we do not copy from the original // response when generating a response. const WebCore::HTTPHeaderMap& map = m_response.httpHeaderFields(); for (WebCore::HTTPHeaderMap::const_iterator it = map.begin(); it != map.end(); ++it) { bool needsCopyfromOriginalResponse = true; int replaceHeadersIndex = 0; while (BlackBerry::Platform::MultipartStream::replaceHeaders[replaceHeadersIndex]) { if (it->first.lower() == BlackBerry::Platform::MultipartStream::replaceHeaders[replaceHeadersIndex]) { needsCopyfromOriginalResponse = false; break; } replaceHeadersIndex++; } if (needsCopyfromOriginalResponse) m_multipartResponse->setHTTPHeaderField(it->first, it->second); } m_multipartResponse->setIsMultipartPayload(true); } else { if (key.lower() == "content-type") { String contentType = value.lower(); m_multipartResponse->setMimeType(extractMIMETypeFromMediaType(contentType)); m_multipartResponse->setTextEncodingName(extractCharsetFromMediaType(contentType)); } m_multipartResponse->setHTTPHeaderField(key, value); } }
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); } }
String CachedScript::mimeType() const { return extractMIMETypeFromMediaType(m_response.httpHeaderField(HTTPHeaderName::ContentType)).lower(); }
/* * 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; }
String ScriptResource::mimeType() const { return extractMIMETypeFromMediaType(m_response.httpHeaderField("Content-Type")).lower(); }
// parseDataUrl() is taken from the CURL http backend. static gboolean parseDataUrl(gpointer callback_data) { ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data); ResourceHandleClient* client = handle->client(); ResourceHandleInternal* d = handle->getInternal(); if (d->m_cancelled) return false; d->m_idleHandler = 0; ASSERT(client); if (!client) return false; String url = handle->request().url().string(); ASSERT(url.startsWith("data:", false)); int index = url.find(','); if (index == -1) { client->cannotShowURL(handle); return false; } String mediaType = url.substring(5, index - 5); String data = url.substring(index + 1); bool isBase64 = mediaType.endsWith(";base64", false); if (isBase64) 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 (isBase64) { data = decodeURLEscapeSequences(data); response.setTextEncodingName(charset); client->didReceiveResponse(handle, response); if (d->m_cancelled) return false; // Use the GLib Base64, since WebCore's decoder isn't // general-purpose and fails on Acid3 test 97 (whitespace). 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 { // 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 (d->m_cancelled) return false; if (data.length() > 0) client->didReceiveData(handle, reinterpret_cast<const char*>(data.characters()), data.length() * sizeof(UChar), 0); if (d->m_cancelled) return false; } client->didFinishLoading(handle); return false; }
TEST(HTTPParsersTest, ExtractMIMETypeFromMediaType) { const AtomicString textHtml("text/html"); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text/html; charset=iso-8859-1"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text/html ; charset=iso-8859-1"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text/html,text/plain"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text/html , text/plain"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text/html\t,\ttext/plain"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString(" text/html "))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("\ttext/html \t"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("\r\ntext/html\r\n"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text/html,text/plain;charset=iso-8859-1"))); EXPECT_EQ(emptyString(), extractMIMETypeFromMediaType(AtomicString(", text/html"))); EXPECT_EQ(emptyString(), extractMIMETypeFromMediaType(AtomicString("; text/html"))); // Preserves case. EXPECT_EQ("tExt/hTMl", extractMIMETypeFromMediaType(AtomicString("tExt/hTMl"))); // If no normalization is required, the same AtomicString should be returned. const AtomicString& passthrough = extractMIMETypeFromMediaType(textHtml); EXPECT_EQ(textHtml.impl(), passthrough.impl()); // These tests cover current behavior, but are not necessarily // expected/wanted behavior. (See FIXME in implementation.) EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text / html"))); // U+2003, EM SPACE (UTF-8: E2 80 83) EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString::fromUTF8("text\xE2\x80\x83/ html"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text\r\n/\nhtml"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("text\n/\nhtml"))); EXPECT_EQ(textHtml, extractMIMETypeFromMediaType(AtomicString("t e x t / h t m l"))); }
bool ResourceHandle::onRequestComplete() { if (!d->m_internetHandle) { // 0 if canceled. deref(); // balances ref in start return false; } if (d->m_bytesRemainingToWrite) { DWORD bytesWritten; 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) return true; d->m_formData.clear(); } 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]; INTERNET_BUFFERSA buffers; buffers.dwStructSize = sizeof(INTERNET_BUFFERSA); buffers.lpvBuffer = buffer; buffers.dwBufferLength = bufferSize; BOOL ok = FALSE; 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()); String httpStatusText = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_TEXT); if (!httpStatusText.isNull()) response.setHTTPStatusText(httpStatusText); String httpStatusCode = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_STATUS_CODE); if (!httpStatusCode.isNull()) response.setHTTPStatusCode(httpStatusCode.toInt()); String httpContentLength = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_LENGTH); if (!httpContentLength.isNull()) response.setExpectedContentLength(httpContentLength.toInt()); String httpContentType = queryHTTPHeader(d->m_requestHandle, HTTP_QUERY_CONTENT_TYPE); if (!httpContentType.isNull()) { response.setMimeType(extractMIMETypeFromMediaType(httpContentType)); response.setTextEncodingName(extractCharsetFromMediaType(httpContentType)); } if (ResourceHandleClient* resourceHandleClient = client()) resourceHandleClient->didReceiveResponse(this, response); } // FIXME: https://bugs.webkit.org/show_bug.cgi?id=19793 // -1 means we do not provide any data about transfer size to inspector so it would use // Content-Length headers or content size to show transfer size. if (ResourceHandleClient* resourceHandleClient = client()) resourceHandleClient->didReceiveData(this, buffer, buffers.dwBufferLength, -1); buffers.dwBufferLength = bufferSize; } if (!ok && GetLastError() == ERROR_IO_PENDING) return true; if (ResourceHandleClient* resourceHandleClient = client()) resourceHandleClient->didFinishLoading(this, 0); InternetCloseHandle(d->m_requestHandle); InternetCloseHandle(d->m_connectHandle); deref(); // balances ref in start return false; }