Changeset 32761 in webkit


Ignore:
Timestamp:
May 1, 2008 9:50:00 AM (16 years ago)
Author:
alp@webkit.org
Message:

2008-05-01 Dan Winship <danw@gnome.org>

Reviewed by Alp Toker.

http://bugs.webkit.org/show_bug.cgi?id=18490
Add mostly-working file: support and mostly-broken ftp: support to
the soup backend.

  • platform/network/soup/ResourceHandleSoup.cpp (start): after doing basic checks, delegate to one of three submethods (startData): handles data: URLs (startHttp): handles http: and https: URLs, via libsoup (startGio, etc): handles file: and ftp: URLs, via gio. Lots of FIXMEs detailing the parts that don't fully work yet.
  • platform/network/ResourceHandle.h:
  • platform/network/ResourceHandleInternal.h: add new member variables for gio-based loading
Location:
trunk/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r32759 r32761  
     12008-05-01  Dan Winship  <danw@gnome.org>
     2
     3        Reviewed by Alp Toker.
     4
     5        http://bugs.webkit.org/show_bug.cgi?id=18490
     6        Add mostly-working file: support and mostly-broken ftp: support to
     7        the soup backend.
     8
     9        * platform/network/soup/ResourceHandleSoup.cpp (start): after
     10        doing basic checks, delegate to one of three submethods
     11        (startData): handles data: URLs
     12        (startHttp): handles http: and https: URLs, via libsoup
     13        (startGio, etc): handles file: and ftp: URLs, via gio. Lots of
     14        FIXMEs detailing the parts that don't fully work yet.
     15
     16        * platform/network/ResourceHandle.h:
     17        * platform/network/ResourceHandleInternal.h: add new member
     18        variables for gio-based loading
     19
    1202008-05-01  Alp Toker  <alp@nuanti.com>
    221
  • trunk/WebCore/platform/network/ResourceHandle.h

    r32442 r32761  
    173173
    174174private:
    175     void scheduleFailure(FailureType);
     175#if USE(SOUP)
     176    bool startData(String urlString);
     177    bool startHttp(String urlString);
     178    bool startGio(String urlString);
     179#endif
     180
     181void scheduleFailure(FailureType);
    176182
    177183    bool start(Frame*);
  • trunk/WebCore/platform/network/ResourceHandleInternal.h

    r31682 r32761  
    111111            , m_msg(0)
    112112            , m_cancelled(false)
     113            , m_gfile(0)
     114            , m_input_stream(0)
     115            , m_cancellable(0)
     116            , m_buffer(0)
     117            , m_bufsize(0)
     118            , m_total(0)
    113119#endif
    114120#if PLATFORM(QT)
     
    177183        ResourceResponse m_response;
    178184        bool m_cancelled;
     185        GFile* m_gfile;
     186        GInputStream* m_input_stream;
     187        GCancellable* m_cancellable;
     188        char* m_buffer;
     189        gsize m_bufsize, m_total;
    179190#endif
    180191#if PLATFORM(QT)
  • trunk/WebCore/platform/network/soup/ResourceHandleSoup.cpp

    r31878 r32761  
    2323#include "ResourceHandle.h"
    2424
    25 #include "Base64.h"
     25#include "CookieJar.h"
    2626#include "DocLoader.h"
    2727#include "Frame.h"
     
    3333#include "ResourceHandleInternal.h"
    3434#include "ResourceResponse.h"
    35 #include "CookieJar.h"
    36 
     35
     36#include <gio/gio.h>
    3737#include <libsoup/soup.h>
    3838#include <libsoup/soup-message.h>
     
    4545{
    4646    ERROR_TRANSPORT,
    47     ERROR_UNKNOWN_PROTOCOL
     47    ERROR_UNKNOWN_PROTOCOL,
     48    ERROR_BAD_NON_HTTP_METHOD
    4849};
    4950
     
    246247}
    247248
    248 bool ResourceHandle::start(Frame* frame)
    249 {
    250     ASSERT(!d->m_msg);
    251 
    252     // If we are no longer attached to a Page, this must be an attempted load from an
    253     // onUnload handler, so let's just block it.
    254     if (!frame->page())
    255         return false;
    256 
    257     KURL url = request().url();
    258     String protocol = url.protocol();
    259 
    260     if (equalIgnoringCase(protocol, "data")) {
    261         // If parseDataUrl is called syncronously the job is not yet effectively started
     249bool ResourceHandle::startData(String urlString)
     250{
     251        // If parseDataUrl is called synchronously the job is not yet effectively started
    262252        // and webkit won't never know that the data has been parsed even didFinishLoading is called.
    263253        g_idle_add(parseDataUrl, this);
    264254        return true;
    265     }
    266 
    267     String urlString = url.string();
    268 
    269     if (!equalIgnoringCase(protocol, "http") && !equalIgnoringCase(protocol, "https")) {
    270         // If we don't call didFail the job is not complete for webkit even false is returned.
    271         if (d->client()) {
    272             ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, urlString, protocol);
    273             d->client()->didFail(this, error);
    274         }
    275         return false;
    276     }
    277 
    278     if (url.isLocalFile()) {
    279         String query = url.query();
    280         // Remove any query part sent to a local file.
    281         if (!query.isEmpty())
    282             urlString = urlString.left(urlString.find(query));
    283         // Determine the MIME type based on the path.
    284         d->m_response.setMimeType(MIMETypeRegistry::getMIMETypeForPath(String(urlString)));
    285     }
    286 
     255}
     256
     257bool ResourceHandle::startHttp(String urlString)
     258{
    287259    if (!session) {
    288260        session = soup_session_async_new();
     
    335307}
    336308
     309bool ResourceHandle::start(Frame* frame)
     310{
     311    ASSERT(!d->m_msg);
     312
     313    // If we are no longer attached to a Page, this must be an attempted load from an
     314    // onUnload handler, so let's just block it.
     315    if (!frame->page())
     316        return false;
     317
     318    KURL url = request().url();
     319    String urlString = url.string();
     320    String protocol = url.protocol();
     321
     322    if (equalIgnoringCase(protocol, "data"))
     323        return startData(urlString);
     324    else if (equalIgnoringCase(protocol, "http") || equalIgnoringCase(protocol, "https"))
     325        return startHttp(urlString);
     326    else if (equalIgnoringCase(protocol, "file") || equalIgnoringCase(protocol, "ftp") || equalIgnoringCase(protocol, "ftps"))
     327        // FIXME: should we be doing any other protocols here?
     328        return startGio(urlString);
     329    else {
     330        // If we don't call didFail the job is not complete for webkit even false is returned.
     331        if (d->client()) {
     332            ResourceError error("webkit-network-error", ERROR_UNKNOWN_PROTOCOL, urlString, protocol);
     333            d->client()->didFail(this, error);
     334        }
     335        return false;
     336    }
     337}
     338
    337339void ResourceHandle::cancel()
    338340{
     
    342344        // For re-entrancy troubles we call didFinishLoading when the message hasn't been handled yet.
    343345        d->client()->didFinishLoading(this);
     346    } else if (d->m_cancellable) {
     347        g_cancellable_cancel(d->m_cancellable);
     348        d->client()->didFinishLoading(this);
    344349    }
    345350}
     
    380385}
    381386
    382 }
     387// GIO-based loader
     388
     389static void cleanupGioOperation(ResourceHandle* handle)
     390{
     391    ResourceHandleInternal* d = handle->getInternal();
     392
     393    if (d->m_gfile) {
     394        g_object_unref(d->m_gfile);
     395        d->m_gfile = NULL;
     396    }
     397    if (d->m_cancellable) {
     398        g_object_unref(d->m_cancellable);
     399        d->m_cancellable = NULL;
     400    }
     401    if (d->m_input_stream) {
     402        g_object_unref(d->m_input_stream);
     403        d->m_cancellable = NULL;
     404    }
     405    if (d->m_buffer) {
     406        g_free(d->m_buffer);
     407        d->m_buffer = NULL;
     408    }
     409}
     410
     411static void closeCallback(GObject* source, GAsyncResult* res, gpointer data)
     412{
     413    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
     414    ResourceHandleInternal* d = handle->getInternal();
     415
     416    g_input_stream_close_finish(d->m_input_stream, res, NULL);
     417    cleanupGioOperation(handle);
     418}
     419
     420static void readCallback(GObject* source, GAsyncResult* res, gpointer data)
     421{
     422    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
     423    ResourceHandleInternal* d = handle->getInternal();
     424    ResourceHandleClient* client = handle->client();
     425
     426    if (d->m_cancelled || !client) {
     427        cleanupGioOperation(handle);
     428        return;
     429    }
     430
     431    gssize nread;
     432    GError *error = 0;
     433
     434    nread = g_input_stream_read_finish(d->m_input_stream, res, &error);
     435    if (error) {
     436        cleanupGioOperation(handle);
     437        // FIXME: error
     438        client->didFinishLoading(handle);
     439        return;
     440    } else if (!nread) {
     441        client->didFinishLoading(handle);
     442        g_input_stream_close_async(d->m_input_stream, G_PRIORITY_DEFAULT,
     443                                   NULL, closeCallback, handle);
     444        return;
     445    }
     446
     447    d->m_total += nread;
     448    client->didReceiveData(handle, d->m_buffer, nread, d->m_total);
     449
     450    g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize,
     451                              G_PRIORITY_DEFAULT, d->m_cancellable,
     452                              readCallback, handle);
     453}
     454
     455static void openCallback(GObject* source, GAsyncResult* res, gpointer data)
     456{
     457    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
     458    ResourceHandleInternal* d = handle->getInternal();
     459    ResourceHandleClient* client = handle->client();
     460
     461    if (d->m_cancelled || !client) {
     462        cleanupGioOperation(handle);
     463        return;
     464    }
     465
     466    GFileInputStream* in;
     467    GError *error = NULL;
     468    in = g_file_read_finish(G_FILE(source), res, &error);
     469    if (error) {
     470        cleanupGioOperation(handle);
     471        // FIXME: error
     472        client->didFinishLoading(handle);
     473        return;
     474    }
     475
     476    d->m_input_stream = G_INPUT_STREAM(in);
     477    d->m_bufsize = 8192;
     478    d->m_buffer = static_cast<char*>(g_malloc(d->m_bufsize));
     479    d->m_total = 0;
     480    g_input_stream_read_async(d->m_input_stream, d->m_buffer, d->m_bufsize,
     481                              G_PRIORITY_DEFAULT, d->m_cancellable,
     482                              readCallback, handle);
     483}
     484
     485static void queryInfoCallback(GObject* source, GAsyncResult* res, gpointer data)
     486{
     487    ResourceHandle* handle = static_cast<ResourceHandle*>(data);
     488    ResourceHandleInternal* d = handle->getInternal();
     489    ResourceHandleClient* client = handle->client();
     490
     491    if (d->m_cancelled) {
     492        cleanupGioOperation(handle);
     493        return;
     494    }
     495
     496    ResourceResponse response;
     497
     498    char* uri = g_file_get_uri(d->m_gfile);
     499    response.setUrl(KURL(uri));
     500    g_free(uri);
     501
     502    GError *error = NULL;
     503    GFileInfo* info = g_file_query_info_finish(d->m_gfile, res, &error);
     504
     505    if (error) {
     506        // FIXME: to be able to handle ftp URIs properly, we must
     507        // check if the error is G_IO_ERROR_NOT_MOUNTED, and if so,
     508        // call g_file_mount_enclosing_volume() to mount the ftp
     509        // server (and then keep track of the fact that we mounted it,
     510        // and set a timeout to unmount it later after it's been idle
     511        // for a while).
     512
     513        cleanupGioOperation(handle);
     514
     515        if (error->domain == G_IO_ERROR &&
     516            error->code == G_IO_ERROR_NOT_FOUND)
     517            response.setHTTPStatusCode(SOUP_STATUS_NOT_FOUND);
     518        else if (error->domain == G_IO_ERROR &&
     519                 error->code == G_IO_ERROR_PERMISSION_DENIED)
     520            response.setHTTPStatusCode(SOUP_STATUS_FORBIDDEN);
     521        else
     522            response.setHTTPStatusCode(SOUP_STATUS_BAD_REQUEST); // ?
     523        g_error_free(error);
     524
     525        // FIXME: do we need to fake up a response body containing the
     526        // error message?
     527
     528        client->didReceiveResponse(handle, response);
     529        client->didFinishLoading(handle);
     530        return;
     531    }
     532
     533    if (g_file_info_get_file_type(info) != G_FILE_TYPE_REGULAR) {
     534        // FIXME: what if the URI points to a directory? Should we
     535        // generate a listing? How? What do other backends do here?
     536
     537        cleanupGioOperation(handle);
     538        response.setHTTPStatusCode(SOUP_STATUS_FORBIDDEN); // ?
     539        client->didReceiveResponse(handle, response);
     540        client->didFinishLoading(handle);
     541        return;
     542    }
     543
     544    response.setMimeType(g_file_info_get_content_type(info));
     545    response.setExpectedContentLength(g_file_info_get_size(info));
     546    response.setHTTPStatusCode(SOUP_STATUS_OK);
     547
     548    GTimeVal tv;
     549    g_file_info_get_modification_time(info, &tv);
     550    response.setLastModifiedDate(tv.tv_sec);
     551
     552    client->didReceiveResponse(handle, response);
     553
     554    g_file_read_async(d->m_gfile, G_PRIORITY_DEFAULT, d->m_cancellable,
     555                      openCallback, handle);
     556}
     557
     558bool ResourceHandle::startGio(String urlString)
     559{
     560    if (request().httpMethod() != "GET") {
     561        ResourceError error("webkit-network-error", ERROR_BAD_NON_HTTP_METHOD, urlString, request().httpMethod());
     562        d->client()->didFail(this, error);
     563        return false;
     564    }
     565
     566    d->m_gfile = g_file_new_for_uri(urlString.utf8().data());
     567    d->m_cancellable = g_cancellable_new();
     568    g_file_query_info_async(d->m_gfile,
     569                            G_FILE_ATTRIBUTE_STANDARD_TYPE ","
     570                            G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE ","
     571                            G_FILE_ATTRIBUTE_STANDARD_SIZE,
     572                            G_FILE_QUERY_INFO_NONE,
     573                            G_PRIORITY_DEFAULT, d->m_cancellable,
     574                            queryInfoCallback, this);
     575    return true;
     576}
     577
     578}
     579
Note: See TracChangeset for help on using the changeset viewer.