static void readCallback(GObject* source, GAsyncResult* res, gpointer data)
{
    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
    ResourceHandleInternal* d = handle->getInternal();
    ResourceHandleClient* client = handle->client();

    if (d->m_cancelled || !client) {
        cleanupGioOperation(handle);
        return;
    }

    gssize nread;
    GError *error = 0;

    nread = g_input_stream_read_finish(d->m_input_stream, res, &error);
    if (error) {
        cleanupGioOperation(handle);
        // FIXME: error
        client->didFinishLoading(handle);
        return;
    } else if (!nread) {
        client->didFinishLoading(handle);
        g_input_stream_close_async(d->m_input_stream, G_PRIORITY_DEFAULT,
                                   NULL, closeCallback, handle);
        return;
    }

    d->m_total += nread;
    client->didReceiveData(handle, d->m_buffer, nread, d->m_total);

    g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize,
                              G_PRIORITY_DEFAULT, d->m_cancellable,
                              readCallback, handle);
}
static void openCallback(GObject* source, GAsyncResult* res, gpointer data)
{
    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
    ResourceHandleInternal* d = handle->getInternal();
    ResourceHandleClient* client = handle->client();

    if (d->m_cancelled || !client) {
        cleanupGioOperation(handle);
        return;
    }

    GFileInputStream* in;
    GError *error = NULL;
    in = g_file_read_finish(G_FILE(source), res, &error);
    if (error) {
        cleanupGioOperation(handle);
        // FIXME: error
        client->didFinishLoading(handle);
        return;
    }

    d->m_input_stream = G_INPUT_STREAM(in);
    d->m_bufsize = 8192;
    d->m_buffer = static_cast<char*>(g_malloc(d->m_bufsize));
    d->m_total = 0;
    g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize,
                              G_PRIORITY_DEFAULT, d->m_cancellable,
                              readCallback, handle);
}
// This callback will not be called if the content sniffer is disabled in startHttp.
static void contentSniffedCallback(SoupMessage* msg, const char* sniffedType, GHashTable *params, gpointer data)
{
    if (sniffedType) {
        const char* officialType = soup_message_headers_get_one(msg->response_headers, "Content-Type");

        if (!officialType || strcmp(officialType, sniffedType))
            soup_message_headers_set_content_type(msg->response_headers, sniffedType, params);
    }

    if (statusWillBeHandledBySoup(msg->status_code))
        return;

    RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
    if (!handle)
        return;
    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    fillResponseFromMessage(msg, &d->m_response);
    client->didReceiveResponse(handle.get(), d->m_response);
}
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;
}
static void contentSniffedCallback(SoupMessage* msg, const char* sniffedType, GHashTable *params, gpointer data)
{
    if (sniffedType) {
        const char* officialType = soup_message_headers_get_one(msg->response_headers, "Content-Type");

        if (!officialType || strcmp(officialType, sniffedType))
            soup_message_headers_set_content_type(msg->response_headers, sniffedType, params);
    }

    // The 304 status code (SOUP_STATUS_NOT_MODIFIED) needs to be fed
    // into WebCore, as opposed to other kinds of redirections, which
    // are handled by soup directly, so we special-case it here and in
    // gotChunk.
    if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)
        || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED))
        || (msg->status_code == SOUP_STATUS_UNAUTHORIZED))
        return;

    RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
    if (!handle)
        return;
    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    fillResponseFromMessage(msg, &d->m_response);
    client->didReceiveResponse(handle.get(), d->m_response);
}
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 QNetworkReplyHandler::finish()
{
    ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());

    ResourceHandleClient* client = m_resourceHandle->client();
    if (!client) {
        m_replyWrapper = 0;
        return;
    }

    if (m_replyWrapper->wasRedirected()) {
        m_replyWrapper = 0;
        m_queue.push(&QNetworkReplyHandler::start);
        return;
    }

    if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_replyWrapper->responseContainsData()))
        client->didFinishLoading(m_resourceHandle, 0);
    else {
        QUrl url = m_replyWrapper->reply()->url();
        int httpStatusCode = m_replyWrapper->reply()->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

        if (httpStatusCode) {
            ResourceError error("HTTP", httpStatusCode, url.toString(), m_replyWrapper->reply()->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
            client->didFail(m_resourceHandle, error);
        } else {
            ResourceError error("QtNetwork", m_replyWrapper->reply()->error(), url.toString(), m_replyWrapper->reply()->errorString());
            client->didFail(m_resourceHandle, error);
        }
    }

    m_replyWrapper = 0;
}
static void gotHeadersCallback(SoupMessage* msg, gpointer data)
{
    // For 401, we will accumulate the resource body, and only use it
    // in case authentication with the soup feature doesn't happen
    if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
        soup_message_body_set_accumulate(msg->response_body, TRUE);
        return;
    }

    // For all the other responses, we handle each chunk ourselves,
    // and we don't need msg->response_body to contain all of the data
    // we got, when we finish downloading.
    soup_message_body_set_accumulate(msg->response_body, FALSE);

    RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);

    // The content-sniffed callback will handle the response if WebCore
    // require us to sniff.
    if(!handle || statusWillBeHandledBySoup(msg->status_code) || handle->shouldContentSniff())
        return;

    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    fillResponseFromMessage(msg, &d->m_response);
    client->didReceiveResponse(handle.get(), d->m_response);
}
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));
    }
bool ResourceHandle::canAuthenticateAgainstProtectionSpace(const ProtectionSpace& protectionSpace)
{
    ResourceHandleClient* client = this->client();
    if (d->m_usesAsyncCallbacks) {
        if (client)
            client->canAuthenticateAgainstProtectionSpaceAsync(this, protectionSpace);
        else
            continueCanAuthenticateAgainstProtectionSpace(false);
        return false; // Ignored by caller.
    }

    return client && client->canAuthenticateAgainstProtectionSpace(this, protectionSpace);
}
/*
 * 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 ResourceHandleInternal::didFinishLoading(WebURLLoader*, double finishTime)
{
    ASSERT(m_client);
    if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
        CRASH();
    m_state = ConnectionStateFinishedLoading;
    m_client->didFinishLoading(m_owner, finishTime);
}
void ResourceHandleInternal::didReceiveCachedMetadata(WebURLLoader*, const char* data, int dataLength)
{
    ASSERT(m_client);
    if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
        CRASH();

    m_client->didReceiveCachedMetadata(m_owner, data, dataLength);
}
void ResourceHandleInternal::willSendRequest(
    WebURLLoader*, WebURLRequest& request, const WebURLResponse& response)
{
    ASSERT(m_client);
    ASSERT(!request.isNull());
    ASSERT(!response.isNull());
    m_client->willSendRequest(m_owner, request.toMutableResourceRequest(), response.toResourceResponse());
}
static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
{
    if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code))
        return;

    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
    if (!handle)
        return;
    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    client->didReceiveData(handle, chunk->data, chunk->length, false);
}
static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
{
    if (statusWillBeHandledBySoup(msg->status_code))
        return;

    RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
    if (!handle)
        return;
    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    client->didReceiveData(handle.get(), chunk->data, chunk->length, false);
}
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);
}
static void gotHeadersCallback(SoupMessage* msg, gpointer data)
{
    if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code))
        return;

    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
    if (!handle)
        return;
    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    fillResponseFromMessage(msg, &d->m_response);
    client->didReceiveResponse(handle, d->m_response);
    soup_message_set_flags(msg, SOUP_MESSAGE_OVERWRITE_CHUNKS);
}
static void gotChunkCallback(SoupMessage* msg, SoupBuffer* chunk, gpointer data)
{
    if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)
        || (SOUP_STATUS_IS_REDIRECTION(msg->status_code) && (msg->status_code != SOUP_STATUS_NOT_MODIFIED))
        || (msg->status_code == SOUP_STATUS_UNAUTHORIZED))
        return;

    RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
    if (!handle)
        return;
    ResourceHandleInternal* d = handle->getInternal();
    if (d->m_cancelled)
        return;
    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    client->didReceiveData(handle.get(), chunk->data, chunk->length, false);
}
// Called at the end of the message, with all the necessary about the last informations.
// Doesn't get called for redirects.
static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer data)
{
    RefPtr<ResourceHandle> handle = adoptRef(static_cast<ResourceHandle*>(data));
    // TODO: maybe we should run this code even if there's no client?
    if (!handle)
        return;

    ResourceHandleInternal* d = handle->getInternal();

    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    if (d->m_cancelled)
        return;

    if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
        char* uri = soup_uri_to_string(soup_message_get_uri(msg), false);
        ResourceError error(g_quark_to_string(SOUP_HTTP_ERROR),
                            msg->status_code,
                            uri,
                            String::fromUTF8(msg->reason_phrase));
        g_free(uri);
        client->didFail(handle.get(), error);
        return;
    }

    if (msg->status_code == SOUP_STATUS_UNAUTHORIZED) {
        fillResponseFromMessage(msg, &d->m_response);
        client->didReceiveResponse(handle.get(), d->m_response);

        // WebCore might have cancelled the job in the while
        if (d->m_cancelled)
            return;

        if (msg->response_body->data)
            client->didReceiveData(handle.get(), msg->response_body->data, msg->response_body->length, true);
    }

    client->didFinishLoading(handle.get());
}
void QNetworkReplyHandler::finish()
{
    m_shouldFinish = (m_loadMode != LoadNormal);
    if (m_shouldFinish)
        return;

    sendResponseIfNeeded();

    if (!m_resourceHandle)
        return;
    ResourceHandleClient* client = m_resourceHandle->client();
    if (!client) {
        m_reply->deleteLater();
        m_reply = 0;
        return;
    }

    QNetworkReply* oldReply = m_reply;

    if (m_redirected) {
        resetState();
        start();
    } else if (!m_reply->error() || ignoreHttpError(m_reply, m_responseDataSent)) {
        client->didFinishLoading(m_resourceHandle);
    } else {
        QUrl url = m_reply->url();
        int httpStatusCode = m_reply->attribute(QNetworkRequest::HttpStatusCodeAttribute).toInt();

        if (httpStatusCode) {
            ResourceError error("HTTP", httpStatusCode, url.toString(), m_reply->attribute(QNetworkRequest::HttpReasonPhraseAttribute).toString());
            client->didFail(m_resourceHandle, error);
        } else {
            ResourceError error("QtNetwork", m_reply->error(), url.toString(), m_reply->errorString());
            client->didFail(m_resourceHandle, error);
        }
    }

    oldReply->deleteLater();
    if (oldReply == m_reply)
        m_reply = 0;
}
void ResourceHandleInternal::didReceiveResponse(WebURLLoader*, const WebURLResponse& response)
{
    ASSERT(m_client);
    ASSERT(!response.isNull());
    bool isMultipart = response.isMultipartPayload();
    bool isValidStateTransition = (m_state == ConnectionStateStarted || m_state == ConnectionStateReceivedResponse);
    // In the case of multipart loads, calls to didReceiveData & didReceiveResponse can be interleaved.
    if (!isMultipart && !isValidStateTransition)
        CRASH();
    m_state = ConnectionStateReceivedResponse;
    m_client->didReceiveResponse(m_owner, response.toResourceResponse());
}
void ResourceHandleInternal::didReceiveData(
    WebURLLoader*, const char* data, int dataLength)
{
    ASSERT(m_client);
    if (m_state != ConnectionStateReceivedResponse && m_state != ConnectionStateReceivingData)
        CRASH();
    m_state = ConnectionStateReceivingData;

    // FIXME(yurys): it looks like lengthReceived is always the same as
    // dataLength and that the latter parameter can be eliminated.
    // See WebKit bug: https://bugs.webkit.org/show_bug.cgi?id=31019
    m_client->didReceiveData(m_owner, data, dataLength, dataLength);
}
// Called at the end of the message, with all the necessary about the last informations.
// Doesn't get called for redirects.
static void finishedCallback(SoupSession *session, SoupMessage* msg, gpointer data)
{
    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
    // TODO: maybe we should run this code even if there's no client?
    if (!handle)
        return;

    ResourceHandleInternal* d = handle->getInternal();
    // The message has been handled.
    d->m_msg = NULL;

    ResourceHandleClient* client = handle->client();
    if (!client)
        return;

    if (d->m_cancelled)
        return;

    if (SOUP_STATUS_IS_TRANSPORT_ERROR(msg->status_code)) {
        char* uri = soup_uri_to_string(soup_message_get_uri(msg), FALSE);
        ResourceError error("webkit-network-error", ERROR_TRANSPORT, uri, String::fromUTF8(msg->reason_phrase));
        g_free(uri);
        client->didFail(handle, error);
        return;
    } else if (!SOUP_STATUS_IS_SUCCESSFUL(msg->status_code)) {
        fillResponseFromMessage(msg, &d->m_response);
        client->didReceiveResponse(handle, d->m_response);

        // WebCore might have cancelled the job in the while
        if (d->m_cancelled)
            return;

        if (msg->response_body->data)
            client->didReceiveData(handle, msg->response_body->data, msg->response_body->length, true);
    }

    client->didFinishLoading(handle);
}
Exemple #25
0
void QNetworkReplyHandler::finish()
{
    ASSERT(m_replyWrapper && m_replyWrapper->reply() && !wasAborted());

    ResourceHandleClient* client = m_resourceHandle->client();
    if (!client) {
        m_replyWrapper = nullptr;
        return;
    }

    if (m_replyWrapper->wasRedirected()) {
        m_replyWrapper = nullptr;
        m_queue.push(&QNetworkReplyHandler::start);
        return;
    }

    if (!m_replyWrapper->reply()->error() || shouldIgnoreHttpError(m_replyWrapper->reply(), m_replyWrapper->responseContainsData()))
        client->didFinishLoading(m_resourceHandle, 0);
    else
        client->didFail(m_resourceHandle, errorForReply(m_replyWrapper->reply()));

    m_replyWrapper = nullptr;
}
void MyResourceLoader::loadFile(const String& file)
{
    LOGD("Loading file (%s) ...", file.latin1().data());
    FILE* f = fopen(file.latin1().data(), "r");
    ResourceHandleClient* client = m_handle->client();
    if (!f) {
        client->didFail(m_handle,
                ResourceError("", -14, file, "Could not open file"));
    } else {
        ResourceResponse response;
        response.setTextEncodingName("utf-8");
        response.setMimeType(mimeTypeForExtension(file));
        client->didReceiveResponse(m_handle, response);
        char buf[512];
        while (true) {
            int res = fread(buf, 1, sizeof(buf), f);
            if (res <= 0)
                break;
            client->didReceiveData(m_handle, buf, res, 0);
        }
        fclose(f);
        client->didFinishLoading(m_handle, 0);
    }
}
void QNetworkReplyHandler::timeout()
{
    if (!m_replyWrapper || wasAborted())
        return;

    // The request is already finished, but is probably just waiting in the queue to get processed.
    // In this case we ignore the timeout and proceed as normal.
    if (m_replyWrapper->isFinished())
        return;

    ResourceHandleClient* client = m_resourceHandle->client();
    if (!client) {
        m_replyWrapper.clear();
        return;
    }

    ASSERT(m_replyWrapper->reply());

    ResourceError timeoutError("QtNetwork", QNetworkReply::TimeoutError, m_replyWrapper->reply()->url().toString(), "Request timed out");
    timeoutError.setIsTimeout(true);
    client->didFail(m_resourceHandle, timeoutError);

    m_replyWrapper.clear();
}
/*
 * 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 ResourceHandleInternal::didSendData(
    WebURLLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
{
    ASSERT(m_client);
    m_client->didSendData(m_owner, bytesSent, totalBytesToBeSent);
}
void ResourceHandleInternal::didFail(WebURLLoader*, const WebURLError& error)
{
    ASSERT(m_client);
    m_state = ConnectionStateFailed;
    m_client->didFail(m_owner, error);
}