⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 resourcehandlesoup.cpp

📁 linux下开源浏览器WebKit的源码,市面上的很多商用浏览器都是移植自WebKit
💻 CPP
📖 第 1 页 / 共 2 页
字号:
    g_object_set_data(G_OBJECT(msg), "resourceHandle", reinterpret_cast<void*>(this));    HTTPHeaderMap customHeaders = d->m_request.httpHeaderFields();    if (!customHeaders.isEmpty()) {        HTTPHeaderMap::const_iterator end = customHeaders.end();        for (HTTPHeaderMap::const_iterator it = customHeaders.begin(); it != end; ++it)            soup_message_headers_append(msg->request_headers, it->first.string().utf8().data(), it->second.utf8().data());    }    FormData* httpBody = d->m_request.httpBody();    if (httpBody && !httpBody->isEmpty()) {        size_t numElements = httpBody->elements().size();        // handle the most common case (i.e. no file upload)        if (numElements < 2) {            Vector<char> body;            httpBody->flatten(body);            soup_message_set_request(msg, d->m_request.httpContentType().utf8().data(),                                     SOUP_MEMORY_COPY, body.data(), body.size());        } else {            /*             * we have more than one element to upload, and some may             * be (big) files, which we will want to mmap instead of             * copying into memory; TODO: support upload of non-local             * (think sftp://) files by using GIO?             */            soup_message_body_set_accumulate(msg->request_body, FALSE);            for (size_t i = 0; i < numElements; i++) {                const FormDataElement& element = httpBody->elements()[i];                if (element.m_type == FormDataElement::data)                    soup_message_body_append(msg->request_body, SOUP_MEMORY_TEMPORARY, element.m_data.data(), element.m_data.size());                else {                    /*                     * mapping for uploaded files code inspired by technique used in                     * libsoup's simple-httpd test                     */                    /* FIXME: Since Linux 2.6.23 we should also use O_CLOEXEC */                    int fd = open(element.m_filename.utf8().data(), O_RDONLY);                    if (fd == -1) {                        ResourceError error("webkit-network-error", ERROR_UNABLE_TO_OPEN_FILE, urlString, strerror(errno));                        d->client()->didFail(this, error);                        g_object_unref(msg);                        return false;                    }                    struct stat statBuf;                    fstat(fd, &statBuf);                    FileMapping* fileMapping = g_slice_new(FileMapping);                    fileMapping->ptr = mmap(0, statBuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0);                    if (fileMapping->ptr == MAP_FAILED) {                        ResourceError error("webkit-network-error", ERROR_UNABLE_TO_OPEN_FILE, urlString, strerror(errno));                        d->client()->didFail(this, error);                        freeFileMapping(fileMapping);                        g_object_unref(msg);                        close(fd);                        return false;                    }                    fileMapping->length = statBuf.st_size;                    close(fd);                    SoupBuffer* soupBuffer = soup_buffer_new_with_owner(fileMapping->ptr, fileMapping->length, fileMapping, freeFileMapping);                    soup_message_body_append_buffer(msg->request_body, soupBuffer);                    soup_buffer_free(soupBuffer);                }            }        }    }    d->m_msg = static_cast<SoupMessage*>(g_object_ref(msg));    // balanced by a deref() in finishedCallback, which should always run    ref();    // 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);    soup_session_queue_message(session, d->m_msg, finishedCallback, this);    return true;}static gboolean reportUnknownProtocolError(gpointer callback_data){    ResourceHandle* handle = static_cast<ResourceHandle*>(callback_data);    ResourceHandleInternal* d = handle->getInternal();    ResourceHandleClient* client = handle->client();    if (d->m_cancelled || !client) {        handle->deref();        return false;    }    KURL url = handle->request().url();    ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, url.string(), url.protocol());    client->didFail(handle, error);    handle->deref();    return false;}bool ResourceHandle::start(Frame* frame){    ASSERT(!d->m_msg);    // The frame could be null if the ResourceHandle is not associated to any    // Frame, e.g. if we are downloading a file.    // If the frame is not null but the page is null this must be an attempted    // load from an onUnload handler, so let's just block it.    if (frame && !frame->page())        return false;    KURL url = request().url();    String urlString = url.string();    String protocol = url.protocol();    // Used to set the authentication dialog toplevel; may be NULL    d->m_frame = frame;    if (equalIgnoringCase(protocol, "data"))        return startData(urlString);    if ((equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https")) && SOUP_URI_VALID_FOR_HTTP(soup_uri_new(urlString.utf8().data())))        return startHttp(urlString);    if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps"))        // FIXME: should we be doing any other protocols here?        return startGio(url);    // Error must not be reported immediately, but through an idle function.    // Despite error, we should return true so a proper handle is created,    // to which this failure can be reported.    ref();    d->m_idleHandler = g_idle_add(reportUnknownProtocolError, this);    return true;}void ResourceHandle::cancel(){    d->m_cancelled = true;    if (d->m_msg)        soup_session_cancel_message(defaultSession(), d->m_msg, SOUP_STATUS_CANCELLED);    else if (d->m_cancellable)        g_cancellable_cancel(d->m_cancellable);}PassRefPtr<SharedBuffer> ResourceHandle::bufferedData(){    ASSERT_NOT_REACHED();    return 0;}bool ResourceHandle::supportsBufferedData(){    return false;}void ResourceHandle::setDefersLoading(bool defers){    d->m_defersLoading = defers;    notImplemented();}bool ResourceHandle::loadsBlocked(){    return false;}bool ResourceHandle::willLoadFromCache(ResourceRequest&){    // Not having this function means that we'll ask the user about re-posting a form    // even when we go back to a page that's still in the cache.    notImplemented();    return false;}void ResourceHandle::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data, Frame* frame){    WebCoreSynchronousLoader syncLoader(error, response, data);    ResourceHandle handle(request, &syncLoader, true, false, true);    handle.start(frame);    syncLoader.run();}// GIO-based loaderstatic inline ResourceError networkErrorForFile(GFile* file, GError* error){    // FIXME: Map gio errors to a more detailed error code when we have it in WebKit.    gchar* uri = g_file_get_uri(file);    ResourceError resourceError("webkit-network-error", ERROR_TRANSPORT, uri, error ? String::fromUTF8(error->message) : String());    g_free(uri);    return resourceError;}static void cleanupGioOperation(ResourceHandleInternal* d){    if (d->m_gfile) {        g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", 0);        g_object_unref(d->m_gfile);        d->m_gfile = 0;    }    if (d->m_cancellable) {        g_object_unref(d->m_cancellable);        d->m_cancellable = 0;    }    if (d->m_inputStream) {        g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", 0);        g_object_unref(d->m_inputStream);        d->m_inputStream = 0;    }    if (d->m_buffer) {        g_free(d->m_buffer);        d->m_buffer = 0;    }}static void closeCallback(GObject* source, GAsyncResult* res, gpointer){    ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));    if (!handle)        return;    ResourceHandleInternal* d = handle->getInternal();    ResourceHandleClient* client = handle->client();    g_input_stream_close_finish(d->m_inputStream, res, 0);    cleanupGioOperation(d);    client->didFinishLoading(handle);}static void readCallback(GObject* source, GAsyncResult* res, gpointer){    // didReceiveData may cancel the load, which may release the last reference.    RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));    if (!handle)        return;    ResourceHandleInternal* d = handle->getInternal();    ResourceHandleClient* client = handle->client();    if (d->m_cancelled || !client) {        cleanupGioOperation(d);        return;    }    GError *error = 0;    gssize bytesRead = g_input_stream_read_finish(d->m_inputStream, res, &error);    if (error) {        ResourceError resourceError = networkErrorForFile(d->m_gfile, error);        g_error_free(error);        cleanupGioOperation(d);        client->didFail(handle.get(), resourceError);        return;    }    if (!bytesRead) {        g_input_stream_close_async(d->m_inputStream, G_PRIORITY_DEFAULT,                                   0, closeCallback, 0);        return;    }    d->m_total += bytesRead;    client->didReceiveData(handle.get(), d->m_buffer, bytesRead, d->m_total);    if (d->m_cancelled) {        cleanupGioOperation(d);        return;    }    g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize,                              G_PRIORITY_DEFAULT, d->m_cancellable,                              readCallback, 0);}static void openCallback(GObject* source, GAsyncResult* res, gpointer){    ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));    if (!handle)        return;    ResourceHandleInternal* d = handle->getInternal();    ResourceHandleClient* client = handle->client();    if (d->m_cancelled || !client) {        cleanupGioOperation(d);        return;    }    GError *error = 0;    GFileInputStream* in = g_file_read_finish(G_FILE(source), res, &error);    if (error) {        ResourceError resourceError = networkErrorForFile(d->m_gfile, error);        g_error_free(error);        cleanupGioOperation(d);        client->didFail(handle, resourceError);        return;    }    d->m_inputStream = G_INPUT_STREAM(in);    d->m_bufferSize = 8192;    d->m_buffer = static_cast<char*>(g_malloc(d->m_bufferSize));    d->m_total = 0;    g_object_set_data(G_OBJECT(d->m_inputStream), "webkit-resource", handle);    g_input_stream_read_async(d->m_inputStream, d->m_buffer, d->m_bufferSize,                              G_PRIORITY_DEFAULT, d->m_cancellable,                              readCallback, 0);}static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer){    ResourceHandle* handle = static_cast<ResourceHandle*>(g_object_get_data(source, "webkit-resource"));    if (!handle)        return;    ResourceHandleInternal* d = handle->getInternal();    ResourceHandleClient* client = handle->client();    if (d->m_cancelled) {        cleanupGioOperation(d);        return;    }    ResourceResponse response;    char* uri = g_file_get_uri(d->m_gfile);    response.setUrl(KURL(uri));    g_free(uri);    GError *error = 0;    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).        ResourceError resourceError = networkErrorForFile(d->m_gfile, error);        g_error_free(error);        cleanupGioOperation(d);        client->didFail(handle, resourceError);        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?        ResourceError resourceError = networkErrorForFile(d->m_gfile, 0);        cleanupGioOperation(d);        client->didFail(handle, resourceError);        return;    }    response.setMimeType(g_file_info_get_content_type(info));    response.setExpectedContentLength(g_file_info_get_size(info));    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, 0);}bool ResourceHandle::startGio(KURL url){    if (request().httpMethod() != "GET" && request().httpMethod() != "POST") {        ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, url.string(), request().httpMethod());        d->client()->didFail(this, error);        return false;    }    // GIO doesn't know how to handle refs and queries, so remove them    // TODO: use KURL.fileSystemPath after KURLGtk and FileSystemGtk are    // using GIO internally, and providing URIs instead of file paths    url.removeRef();    url.setQuery(String());    url.setPort(0);    // we avoid the escaping for local files, because    // g_filename_from_uri (used internally by GFile) has problems    // decoding strings with arbitrary percent signs    if (url.isLocalFile())        d->m_gfile = g_file_new_for_path(url.prettyURL().utf8().data() + sizeof("file://") - 1);    else        d->m_gfile = g_file_new_for_uri(url.string().utf8().data());    g_object_set_data(G_OBJECT(d->m_gfile), "webkit-resource", this);    d->m_cancellable = g_cancellable_new();    g_file_query_info_async(d->m_gfile,                            G_FILE_ATTRIBUTE_STANDARD_TYPE ","                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","                            G_FILE_ATTRIBUTE_STANDARD_SIZE,                            G_FILE_QUERY_INFO_NONE,                            G_PRIORITY_DEFAULT, d->m_cancellable,                            queryInfoCallback, 0);    return true;}SoupSession* ResourceHandle::defaultSession(){    static SoupSession* session = createSoupSession();;    return session;}}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -