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)));
        }
    }
示例#3
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")));
}
示例#4
0
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")));
}
示例#6
0
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());
    }
}
示例#7
0
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 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);
}
示例#9
0
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());
    }
}
示例#10
0
文件: DataURL.cpp 项目: 13W/phantomjs
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")));
}
/*
 * 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;
}
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));
    }
}
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")));
}
示例#15
0
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);
    }
}
示例#16
0
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);
    }
}
示例#17
0
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")));}
// 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;
}
示例#19
0
/*
 * 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;
}
示例#20
0
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);
    }
}
示例#21
0
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;
}