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); }
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; }
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 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); }
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 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 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; }
// 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()); }
// 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); }
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); } }
// 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; }
static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer data) { ResourceHandle* handle = static_cast<ResourceHandle*>(data); ResourceHandleInternal* d = handle->getInternal(); ResourceHandleClient* client = handle->client(); if (d->m_cancelled) { cleanupGioOperation(handle); return; } ResourceResponse response; char* uri = g_file_get_uri(d->m_gfile); response.setUrl(KURL(uri)); g_free(uri); GError *error = NULL; GFileInfo* info = g_file_query_info_finish(d->m_gfile, res, &error); if (error) { // FIXME: to be able to handle ftp URIs properly, we must // check if the error is G_IO_ERROR_NOT_MOUNTED, and if so, // call g_file_mount_enclosing_volume() to mount the ftp // server (and then keep track of the fact that we mounted it, // and set a timeout to unmount it later after it's been idle // for a while). cleanupGioOperation(handle); if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_NOT_FOUND) response.setHTTPStatusCode(SOUP_STATUS_NOT_FOUND); else if (error->domain == G_IO_ERROR && error->code == G_IO_ERROR_PERMISSION_DENIED) response.setHTTPStatusCode(SOUP_STATUS_FORBIDDEN); else response.setHTTPStatusCode(SOUP_STATUS_BAD_REQUEST); // ? g_error_free(error); // FIXME: do we need to fake up a response body containing the // error message? client->didReceiveResponse(handle, response); client->didFinishLoading(handle); return; } if (g_file_info_get_file_type(info) != G_FILE_TYPE_REGULAR) { // FIXME: what if the URI points to a directory? Should we // generate a listing? How? What do other backends do here? cleanupGioOperation(handle); response.setHTTPStatusCode(SOUP_STATUS_FORBIDDEN); // ? client->didReceiveResponse(handle, response); client->didFinishLoading(handle); return; } response.setMimeType(g_file_info_get_content_type(info)); response.setExpectedContentLength(g_file_info_get_size(info)); response.setHTTPStatusCode(SOUP_STATUS_OK); GTimeVal tv; g_file_info_get_modification_time(info, &tv); response.setLastModifiedDate(tv.tv_sec); client->didReceiveResponse(handle, response); g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable, openCallback, handle); }