Changeset 210374 in webkit


Ignore:
Timestamp:
Jan 5, 2017 1:27:50 PM (7 years ago)
Author:
commit-queue@webkit.org
Message:

[SOUP] Network process crash in WebKit::CustomProtocolManagerImpl::didFailWithError
https://bugs.webkit.org/show_bug.cgi?id=165082

Patch by Carlos Garcia Campos <cgarcia@igalia.com> on 2017-01-05
Reviewed by Alex Christensen.

Source/WebCore:

Simplified WebKitSoupRequestGenericClient.

  • platform/network/soup/WebKitSoupRequestGeneric.cpp:

(webkitSoupRequestGenericSendAsync):
(webkitSoupRequestGenericSendFinish):
(webkitSoupRequestGenericGetRequest):

  • platform/network/soup/WebKitSoupRequestGeneric.h:
  • platform/network/soup/WebKitSoupRequestGenericClient.h:

Source/WebKit2:

CustomProtocolManager uses a Workqueue to receive the IPC messages since r149194. Then we added the Soup
implementation adopting that approach, but without making our implementation thread safe. The crash happens
because the CustomProtocolManager implementation is used by two threads at the same time, the main thread
because of a ping load (probably caused by an image load in the unload handler, I haven't been able to
reproduce the crash) and the work queue thread. The reasons to make CustomProtocolManager use a WorkQueue
are no longer valid because CustomProtocolManager is now only used in the network process and sync loads don't
use any nested run loop, they are just an IPC sync message. So this patch makes CustomProtocolManager a normal
message receiver again to ensure messages are handled in the main thread. It also adds the common implementation
to a new CustomProtocolManager.cpp file shared by Cocoa and Soup based ports.

  • CMakeLists.txt: Add CustomProtocolManager.cpp.
  • NetworkProcess/CustomProtocols/Cocoa/CustomProtocolManagerCocoa.mm:

(-[WKCustomProtocol initWithRequest:cachedResponse:client:]): Use new CustomProtocolManager API.
(-[WKCustomProtocol startLoading]): Ditto.
(-[WKCustomProtocol stopLoading]): Ditto.
(WebKit::CustomProtocolManager::registerProtocolClass): Register the NSURLProtocol class when not using the
network session.
(WebKit::CustomProtocolManager::didFailWithError): removeCustomProtocol now receives an ID.
(WebKit::CustomProtocolManager::didFinishLoading): Ditto.

  • NetworkProcess/CustomProtocols/CustomProtocolManager.cpp: Added.

(WebKit::generateCustomProtocolID): Moved from CustomProtocolManagerCocoa.mm and CustomProtocolManagerSoup.cpp.
(WebKit::CustomProtocolManager::supplementName): Ditto.
(WebKit::CustomProtocolManager::CustomProtocolManager): Also removes the work queue initialization.
(WebKit::CustomProtocolManager::initialize): Copied and modernized the loop.
(WebKit::CustomProtocolManager::addCustomProtocol): Copied from CustomProtocolManagerCocoa.mm.
(WebKit::CustomProtocolManager::removeCustomProtocol): Ditto.
(WebKit::CustomProtocolManager::startLoading): Send the StartLoading message to the proxy.
(WebKit::CustomProtocolManager::stopLoading): Send the StopLoading message to the proxy.

  • NetworkProcess/CustomProtocols/CustomProtocolManager.h:
  • NetworkProcess/CustomProtocols/soup/CustomProtocolManagerImpl.cpp: Removed.
  • NetworkProcess/CustomProtocols/soup/CustomProtocolManagerImpl.h: Removed.
  • NetworkProcess/CustomProtocols/soup/CustomProtocolManagerSoup.cpp: Moved the implementation from

CustomProtocolManagerImpl and updated to the new CustomProtocolManager API.
(WebKit::CustomProtocolManager::WebSoupRequestAsyncData::WebSoupRequestAsyncData):
(WebKit::CustomProtocolManager::WebSoupRequestAsyncData::~WebSoupRequestAsyncData):
(WebKit::CustomProtocolManager::registerProtocolClass):
(WebKit::CustomProtocolManager::registerScheme):
(WebKit::CustomProtocolManager::supportsScheme):
(WebKit::CustomProtocolManager::didFailWithError):
(WebKit::CustomProtocolManager::didLoadData):
(WebKit::CustomProtocolManager::didReceiveResponse):
(WebKit::CustomProtocolManager::didFinishLoading):
(WebKit::CustomProtocolManager::wasRedirectedToRequest):

  • NetworkProcess/cocoa/NetworkSessionCocoa.mm:

(WebKit::globalCustomProtocolManager):
(WebKit::NetworkSessionCocoa::defaultSession):
CustomProtocolManager is no longer refcounted, so just pass a pointer.
A static pointer has the same lifetime as the NetworkProcess object in the NetworkProcess,
and in the WebProcess it will remain nullptr, just like it used to.

  • PlatformEfl.cmake:
  • PlatformGTK.cmake:
  • WebKit2.xcodeproj/project.pbxproj:
Location:
trunk/Source
Files:
1 added
2 deleted
13 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r210372 r210374  
     12017-01-05  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [SOUP] Network process crash in WebKit::CustomProtocolManagerImpl::didFailWithError
     4        https://bugs.webkit.org/show_bug.cgi?id=165082
     5
     6        Reviewed by Alex Christensen.
     7
     8        Simplified WebKitSoupRequestGenericClient.
     9
     10        * platform/network/soup/WebKitSoupRequestGeneric.cpp:
     11        (webkitSoupRequestGenericSendAsync):
     12        (webkitSoupRequestGenericSendFinish):
     13        (webkitSoupRequestGenericGetRequest):
     14        * platform/network/soup/WebKitSoupRequestGeneric.h:
     15        * platform/network/soup/WebKitSoupRequestGenericClient.h:
     16
    1172017-01-05  Chris Dumez  <cdumez@apple.com>
    218
  • trunk/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.cpp

    r185774 r210374  
    5151    WebKitSoupRequestGenericClient* client = WEBKIT_SOUP_REQUEST_GENERIC_GET_CLASS(request)->client;
    5252    ASSERT(client);
    53     client->start(g_task_new(request, cancellable, callback, userData));
     53    client->startRequest(adoptGRef(g_task_new(request, cancellable, callback, userData)));
    5454}
    5555
     
    5757{
    5858    g_return_val_if_fail(g_task_is_valid(result, request), nullptr);
    59     WebKitSoupRequestGenericClient* client = WEBKIT_SOUP_REQUEST_GENERIC_GET_CLASS(request)->client;
    60     ASSERT(client);
    61     return client->finish(G_TASK(result), error);
     59    auto* inputStream = g_task_propagate_pointer(G_TASK(result), error);
     60    return inputStream ? G_INPUT_STREAM(inputStream) : nullptr;
    6261}
    6362
     
    101100}
    102101
    103 const ResourceRequest* webkitSoupRequestGenericGetRequest(WebKitSoupRequestGeneric* request)
     102const ResourceRequest& webkitSoupRequestGenericGetRequest(WebKitSoupRequestGeneric* request)
    104103{
    105     return &request->priv->resourceRequest;
     104    return request->priv->resourceRequest;
    106105}
  • trunk/Source/WebCore/platform/network/soup/WebKitSoupRequestGeneric.h

    r185774 r210374  
    5959void webkitSoupRequestGenericSetContentType(WebKitSoupRequestGeneric*, const char* mimeType);
    6060void webkitSoupRequestGenericSetRequest(WebKitSoupRequestGeneric*, const WebCore::ResourceRequest&);
    61 const WebCore::ResourceRequest* webkitSoupRequestGenericGetRequest(WebKitSoupRequestGeneric*);
     61const WebCore::ResourceRequest& webkitSoupRequestGenericGetRequest(WebKitSoupRequestGeneric*);
    6262
    6363G_END_DECLS
  • trunk/Source/WebCore/platform/network/soup/WebKitSoupRequestGenericClient.h

    r185551 r210374  
    1818 */
    1919
    20 #ifndef WebKitSoupRequestGenericClient_h
    21 #define WebKitSoupRequestGenericClient_h
     20#pragma once
    2221
    23 typedef struct _GError GError;
    24 typedef struct _GInputStream GInputStream;
     22#include <wtf/glib/GRefPtr.h>
     23
    2524typedef struct _GTask GTask;
    2625
     
    2928class WebKitSoupRequestGenericClient {
    3029public:
    31     virtual void start(GTask*) = 0;
    32     virtual GInputStream* finish(GTask*, GError**) = 0;
     30    virtual void startRequest(GRefPtr<GTask>&&) = 0;
    3331};
    3432
    3533} // namespace WebCore
    3634
    37 #endif // WebKitSoupRequestGenericClient_h
  • trunk/Source/WebKit2/CMakeLists.txt

    r209665 r210374  
    9494
    9595set(NetworkProcess_COMMON_SOURCES
     96    NetworkProcess/CustomProtocols/CustomProtocolManager.cpp
     97
    9698    NetworkProcess/NetworkConnectionToWebProcess.cpp
    9799    NetworkProcess/NetworkDataTask.cpp
  • trunk/Source/WebKit2/ChangeLog

    r210364 r210374  
     12017-01-05  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [SOUP] Network process crash in WebKit::CustomProtocolManagerImpl::didFailWithError
     4        https://bugs.webkit.org/show_bug.cgi?id=165082
     5
     6        Reviewed by Alex Christensen.
     7
     8        CustomProtocolManager uses a Workqueue to receive the IPC messages since r149194. Then we added the Soup
     9        implementation adopting that approach, but without making our implementation thread safe. The crash happens
     10        because the CustomProtocolManager implementation is used by two threads at the same time, the main thread
     11        because of a ping load (probably caused by an image load in the unload handler, I haven't been able to
     12        reproduce the crash) and the work queue thread. The reasons to make CustomProtocolManager use a WorkQueue
     13        are no longer valid because CustomProtocolManager is now only used in the network process and sync loads don't
     14        use any nested run loop, they are just an IPC sync message. So this patch makes CustomProtocolManager a normal
     15        message receiver again to ensure messages are handled in the main thread. It also adds the common implementation
     16        to a new CustomProtocolManager.cpp file shared by Cocoa and Soup based ports.
     17
     18        * CMakeLists.txt: Add CustomProtocolManager.cpp.
     19        * NetworkProcess/CustomProtocols/Cocoa/CustomProtocolManagerCocoa.mm:
     20        (-[WKCustomProtocol initWithRequest:cachedResponse:client:]): Use new CustomProtocolManager API.
     21        (-[WKCustomProtocol startLoading]): Ditto.
     22        (-[WKCustomProtocol stopLoading]): Ditto.
     23        (WebKit::CustomProtocolManager::registerProtocolClass): Register the NSURLProtocol class when not using the
     24        network session.
     25        (WebKit::CustomProtocolManager::didFailWithError): removeCustomProtocol now receives an ID.
     26        (WebKit::CustomProtocolManager::didFinishLoading): Ditto.
     27        * NetworkProcess/CustomProtocols/CustomProtocolManager.cpp: Added.
     28        (WebKit::generateCustomProtocolID): Moved from CustomProtocolManagerCocoa.mm and CustomProtocolManagerSoup.cpp.
     29        (WebKit::CustomProtocolManager::supplementName): Ditto.
     30        (WebKit::CustomProtocolManager::CustomProtocolManager): Also removes the work queue initialization.
     31        (WebKit::CustomProtocolManager::initialize): Copied and modernized the loop.
     32        (WebKit::CustomProtocolManager::addCustomProtocol): Copied from CustomProtocolManagerCocoa.mm.
     33        (WebKit::CustomProtocolManager::removeCustomProtocol): Ditto.
     34        (WebKit::CustomProtocolManager::startLoading): Send the StartLoading message to the proxy.
     35        (WebKit::CustomProtocolManager::stopLoading): Send the StopLoading message to the proxy.
     36        * NetworkProcess/CustomProtocols/CustomProtocolManager.h:
     37        * NetworkProcess/CustomProtocols/soup/CustomProtocolManagerImpl.cpp: Removed.
     38        * NetworkProcess/CustomProtocols/soup/CustomProtocolManagerImpl.h: Removed.
     39        * NetworkProcess/CustomProtocols/soup/CustomProtocolManagerSoup.cpp: Moved the implementation from
     40        CustomProtocolManagerImpl and updated to the new CustomProtocolManager API.
     41        (WebKit::CustomProtocolManager::WebSoupRequestAsyncData::WebSoupRequestAsyncData):
     42        (WebKit::CustomProtocolManager::WebSoupRequestAsyncData::~WebSoupRequestAsyncData):
     43        (WebKit::CustomProtocolManager::registerProtocolClass):
     44        (WebKit::CustomProtocolManager::registerScheme):
     45        (WebKit::CustomProtocolManager::supportsScheme):
     46        (WebKit::CustomProtocolManager::didFailWithError):
     47        (WebKit::CustomProtocolManager::didLoadData):
     48        (WebKit::CustomProtocolManager::didReceiveResponse):
     49        (WebKit::CustomProtocolManager::didFinishLoading):
     50        (WebKit::CustomProtocolManager::wasRedirectedToRequest):
     51        * NetworkProcess/cocoa/NetworkSessionCocoa.mm:
     52        (WebKit::globalCustomProtocolManager):
     53        (WebKit::NetworkSessionCocoa::defaultSession):
     54        CustomProtocolManager is no longer refcounted, so just pass a pointer.
     55        A static pointer has the same lifetime as the NetworkProcess object in the NetworkProcess,
     56        and in the WebProcess it will remain nullptr, just like it used to.
     57        * PlatformEfl.cmake:
     58        * PlatformGTK.cmake:
     59        * WebKit2.xcodeproj/project.pbxproj:
     60
    1612017-01-05  Antti Koivisto  <antti@apple.com>
    262
  • trunk/Source/WebKit2/NetworkProcess/CustomProtocols/Cocoa/CustomProtocolManagerCocoa.mm

    r203174 r210374  
    2727#import "CustomProtocolManager.h"
    2828
    29 #import "ChildProcess.h"
    3029#import "CustomProtocolManagerMessages.h"
    31 #import "CustomProtocolManagerProxyMessages.h"
    3230#import "DataReference.h"
    3331#import "NetworkProcess.h"
    34 #import "NetworkProcessCreationParameters.h"
    35 #import "WebCoreArgumentCoders.h"
    36 #import "WebProcessCreationParameters.h"
    3732#import <Foundation/NSURLSession.h>
    3833#import <WebCore/NSURLConnectionSPI.h>
     
    4540using namespace WebKit;
    4641
    47 namespace WebKit {
    48 
    49 static uint64_t generateCustomProtocolID()
    50 {
    51     static uint64_t uniqueCustomProtocolID = 0;
    52     return ++uniqueCustomProtocolID;
    53 }
    54 
    55 } // namespace WebKit
    56 
    5742@interface WKCustomProtocol : NSURLProtocol {
    5843@private
     
    9075    if (!self)
    9176        return nil;
    92    
    93     _customProtocolID = generateCustomProtocolID();
     77
     78    if (auto* customProtocolManager = NetworkProcess::singleton().supplement<CustomProtocolManager>())
     79        _customProtocolID = customProtocolManager->addCustomProtocol(self);
    9480    _initializationRunLoop = CFRunLoopGetCurrent();
     81
     82    return self;
     83}
     84
     85- (CFRunLoopRef)initializationRunLoop
     86{
     87    return _initializationRunLoop.get();
     88}
     89
     90- (void)startLoading
     91{
    9592    if (auto* customProtocolManager = NetworkProcess::singleton().supplement<CustomProtocolManager>())
    96         customProtocolManager->addCustomProtocol(self);
    97     return self;
    98 }
    99 
    100 - (CFRunLoopRef)initializationRunLoop
    101 {
    102     return _initializationRunLoop.get();
    103 }
    104 
    105 - (void)startLoading
    106 {
    107     if (auto* customProtocolManager = NetworkProcess::singleton().supplement<CustomProtocolManager>())
    108         customProtocolManager->childProcess()->send(Messages::CustomProtocolManagerProxy::StartLoading(self.customProtocolID, [self request]), 0);
     93        customProtocolManager->startLoading(self.customProtocolID, [self request]);
    10994}
    11095
     
    11297{
    11398    if (auto* customProtocolManager = NetworkProcess::singleton().supplement<CustomProtocolManager>()) {
    114         customProtocolManager->childProcess()->send(Messages::CustomProtocolManagerProxy::StopLoading(self.customProtocolID), 0);
    115         customProtocolManager->removeCustomProtocol(self);
     99        customProtocolManager->stopLoading(self.customProtocolID);
     100        customProtocolManager->removeCustomProtocol(self.customProtocolID);
    116101    }
    117102}
     
    121106namespace WebKit {
    122107
    123 const char* CustomProtocolManager::supplementName()
    124 {
    125     return "CustomProtocolManager";
    126 }
    127 
    128 CustomProtocolManager::CustomProtocolManager(ChildProcess* childProcess)
    129     : m_childProcess(childProcess)
    130     , m_messageQueue(WorkQueue::create("com.apple.WebKit.CustomProtocolManager"))
    131 {
    132     WebCore::UTF8Encoding();
    133 }
    134 
    135 void CustomProtocolManager::initializeConnection(IPC::Connection* connection)
    136 {
    137     connection->addWorkQueueMessageReceiver(Messages::CustomProtocolManager::messageReceiverName(), m_messageQueue.get(), this);
    138 }
    139 
    140 void CustomProtocolManager::initialize(const NetworkProcessCreationParameters& parameters)
     108void CustomProtocolManager::registerProtocolClass()
    141109{
    142110#if !USE(NETWORK_SESSION)
    143111    [NSURLProtocol registerClass:[WKCustomProtocol class]];
    144112#endif
    145 
    146     for (size_t i = 0; i < parameters.urlSchemesRegisteredForCustomProtocols.size(); ++i)
    147         registerScheme(parameters.urlSchemesRegisteredForCustomProtocols[i]);
    148 }
    149 
    150 void CustomProtocolManager::addCustomProtocol(WKCustomProtocol *customProtocol)
    151 {
    152     ASSERT(customProtocol);
    153     LockHolder locker(m_customProtocolMapMutex);
    154     m_customProtocolMap.add(customProtocol.customProtocolID, customProtocol);
    155 }
    156 
    157 void CustomProtocolManager::removeCustomProtocol(WKCustomProtocol *customProtocol)
    158 {
    159     ASSERT(customProtocol);
    160     LockHolder locker(m_customProtocolMapMutex);
    161     m_customProtocolMap.remove(customProtocol.customProtocolID);
    162113}
    163114
     
    175126    m_registeredSchemes.add(scheme);
    176127}
    177    
     128
    178129void CustomProtocolManager::unregisterScheme(const String& scheme)
    179130{
     
    211162    });
    212163
    213     removeCustomProtocol(protocol.get());
     164    removeCustomProtocol(customProtocolID);
    214165}
    215166
     
    250201    });
    251202
    252     removeCustomProtocol(protocol.get());
     203    removeCustomProtocol(customProtocolID);
    253204}
    254205
  • trunk/Source/WebKit2/NetworkProcess/CustomProtocols/CustomProtocolManager.h

    r208499 r210374  
    2424 */
    2525
    26 #ifndef CustomProtocolManager_h
    27 #define CustomProtocolManager_h
     26#pragma once
    2827
    29 #include "Connection.h"
     28#include "MessageReceiver.h"
    3029#include "NetworkProcessSupplement.h"
    31 #include <wtf/WorkQueue.h>
     30#include <wtf/HashMap.h>
     31#include <wtf/HashSet.h>
     32#include <wtf/text/StringHash.h>
    3233#include <wtf/text/WTFString.h>
    3334
    3435#if PLATFORM(COCOA)
    35 #include <wtf/HashMap.h>
    36 #include <wtf/HashSet.h>
    3736#include <wtf/RetainPtr.h>
    38 #include <wtf/Threading.h>
    39 #include <wtf/text/StringHash.h>
    4037OBJC_CLASS NSURLSessionConfiguration;
    4138OBJC_CLASS WKCustomProtocol;
    42 #else
    43 #include "CustomProtocolManagerImpl.h"
    4439#endif
    4540
     41#if USE(SOUP)
     42#include <wtf/glib/GRefPtr.h>
     43
     44typedef struct _GCancellable GCancellable;
     45typedef struct _GInputStream GInputStream;
     46typedef struct _GTask GTask;
     47typedef struct _WebKitSoupRequestGeneric WebKitSoupRequestGeneric;
     48#endif
    4649
    4750namespace IPC {
     
    6063struct NetworkProcessCreationParameters;
    6164
    62 class CustomProtocolManager : public NetworkProcessSupplement, public IPC::Connection::WorkQueueMessageReceiver {
     65class CustomProtocolManager : public NetworkProcessSupplement, public IPC::MessageReceiver {
    6366    WTF_MAKE_NONCOPYABLE(CustomProtocolManager);
    6467public:
     
    6770    static const char* supplementName();
    6871
    69     ChildProcess* childProcess() const { return m_childProcess; }
    70 
    7172    void registerScheme(const String&);
    7273    void unregisterScheme(const String&);
    7374    bool supportsScheme(const String&);
    74    
     75
    7576#if PLATFORM(COCOA)
    76     void addCustomProtocol(WKCustomProtocol *);
    77     void removeCustomProtocol(WKCustomProtocol *);
    78 #if USE(NETWORK_SESSION)
    79     void registerProtocolClass(NSURLSessionConfiguration *);
     77    typedef RetainPtr<WKCustomProtocol> CustomProtocol;
    8078#endif
     79#if USE(SOUP)
     80    struct WebSoupRequestAsyncData {
     81        WebSoupRequestAsyncData(GRefPtr<GTask>&&, WebKitSoupRequestGeneric*);
     82        ~WebSoupRequestAsyncData();
     83
     84        GRefPtr<GTask> task;
     85        WebKitSoupRequestGeneric* request;
     86        GRefPtr<GCancellable> cancellable;
     87        GRefPtr<GInputStream> stream;
     88    };
     89    typedef std::unique_ptr<WebSoupRequestAsyncData> CustomProtocol;
     90#endif
     91
     92    uint64_t addCustomProtocol(CustomProtocol&&);
     93    void removeCustomProtocol(uint64_t customProtocolID);
     94    void startLoading(uint64_t customProtocolID, const WebCore::ResourceRequest&);
     95    void stopLoading(uint64_t customProtocolID);
     96
     97#if PLATFORM(COCOA) && USE(NETWORK_SESSION)
     98    void registerProtocolClass(NSURLSessionConfiguration*);
    8199#endif
    82100
    83101private:
    84     // ChildProcessSupplement
    85     void initializeConnection(IPC::Connection*) override;
    86 
    87102    // NetworkProcessSupplement
    88103    void initialize(const NetworkProcessCreationParameters&) override;
     
    97112    void wasRedirectedToRequest(uint64_t customProtocolID, const WebCore::ResourceRequest&, const WebCore::ResourceResponse& redirectResponse);
    98113
     114    void registerProtocolClass();
     115
    99116    ChildProcess* m_childProcess;
    100     Ref<WorkQueue> m_messageQueue;
     117
     118    typedef HashMap<uint64_t, CustomProtocol> CustomProtocolMap;
     119    CustomProtocolMap m_customProtocolMap;
     120    Lock m_customProtocolMapMutex;
    101121
    102122#if PLATFORM(COCOA)
     
    104124    Lock m_registeredSchemesMutex;
    105125
    106     typedef HashMap<uint64_t, RetainPtr<WKCustomProtocol>> CustomProtocolMap;
    107     CustomProtocolMap m_customProtocolMap;
    108     Lock m_customProtocolMapMutex;
    109    
    110126    // WKCustomProtocol objects can be removed from the m_customProtocolMap from multiple threads.
    111127    // We return a RetainPtr here because it is unsafe to return a raw pointer since the object might immediately be destroyed from a different thread.
    112128    RetainPtr<WKCustomProtocol> protocolForID(uint64_t customProtocolID);
    113 #else
    114     // FIXME: Move mac specific code to CustomProtocolManagerImpl.
    115     std::unique_ptr<CustomProtocolManagerImpl> m_impl;
     129#endif
     130
     131#if USE(SOUP)
     132    GRefPtr<GPtrArray> m_registeredSchemes;
    116133#endif
    117134};
     
    119136} // namespace WebKit
    120137
    121 #endif // CustomProtocolManager_h
  • trunk/Source/WebKit2/NetworkProcess/CustomProtocols/soup/CustomProtocolManagerSoup.cpp

    r192796 r210374  
    2121#include "CustomProtocolManager.h"
    2222
    23 #include "ChildProcess.h"
    24 #include "CustomProtocolManagerImpl.h"
    2523#include "CustomProtocolManagerMessages.h"
    26 #include "NetworkProcessCreationParameters.h"
    27 #include "WebProcessCreationParameters.h"
     24#include "DataReference.h"
     25#include "NetworkProcess.h"
     26#include "WebKitSoupRequestInputStream.h"
    2827#include <WebCore/NotImplemented.h>
     28#include <WebCore/ResourceError.h>
     29#include <WebCore/ResourceRequest.h>
     30#include <WebCore/ResourceResponse.h>
     31#include <WebCore/SoupNetworkSession.h>
     32#include <WebCore/WebKitSoupRequestGeneric.h>
     33#include <wtf/NeverDestroyed.h>
     34
     35using namespace WebCore;
    2936
    3037namespace WebKit {
    3138
    32 const char* CustomProtocolManager::supplementName()
    33 {
    34     return "CustomProtocolManager";
    35 }
    36 
    37 CustomProtocolManager::CustomProtocolManager(ChildProcess* childProcess)
    38     : m_childProcess(childProcess)
    39     , m_messageQueue(WorkQueue::create("com.apple.WebKit.CustomProtocolManager"))
    40     , m_impl(std::make_unique<CustomProtocolManagerImpl>(childProcess))
    41 {
    42 }
    43 
    44 void CustomProtocolManager::initializeConnection(IPC::Connection* connection)
    45 {
    46     connection->addWorkQueueMessageReceiver(Messages::CustomProtocolManager::messageReceiverName(), m_messageQueue.get(), this);
    47 }
    48 
    49 void CustomProtocolManager::initialize(const NetworkProcessCreationParameters& parameters)
    50 {
    51     for (size_t i = 0; i < parameters.urlSchemesRegisteredForCustomProtocols.size(); ++i)
    52         registerScheme(parameters.urlSchemesRegisteredForCustomProtocols[i]);
     39
     40CustomProtocolManager::WebSoupRequestAsyncData::WebSoupRequestAsyncData(GRefPtr<GTask>&& requestTask, WebKitSoupRequestGeneric* requestGeneric)
     41    : task(WTFMove(requestTask))
     42    , request(requestGeneric)
     43    , cancellable(g_task_get_cancellable(task.get()))
     44{
     45    // If the struct contains a null request, it is because the request failed.
     46    g_object_add_weak_pointer(G_OBJECT(request), reinterpret_cast<void**>(&request));
     47}
     48
     49CustomProtocolManager::WebSoupRequestAsyncData::~WebSoupRequestAsyncData()
     50{
     51    if (request)
     52        g_object_remove_weak_pointer(G_OBJECT(request), reinterpret_cast<void**>(&request));
     53}
     54
     55class CustomProtocolRequestClient final : public WebKitSoupRequestGenericClient {
     56public:
     57    static CustomProtocolRequestClient& singleton()
     58    {
     59        static NeverDestroyed<CustomProtocolRequestClient> client;
     60        return client;
     61    }
     62
     63private:
     64    void startRequest(GRefPtr<GTask>&& task) override
     65    {
     66        WebKitSoupRequestGeneric* request = WEBKIT_SOUP_REQUEST_GENERIC(g_task_get_source_object(task.get()));
     67        auto* customProtocolManager = NetworkProcess::singleton().supplement<CustomProtocolManager>();
     68        if (!customProtocolManager)
     69            return;
     70
     71        auto customProtocolID = customProtocolManager->addCustomProtocol(std::make_unique<CustomProtocolManager::WebSoupRequestAsyncData>(WTFMove(task), request));
     72        customProtocolManager->startLoading(customProtocolID, webkitSoupRequestGenericGetRequest(request));
     73    }
     74};
     75
     76void CustomProtocolManager::registerProtocolClass()
     77{
     78    static_cast<WebKitSoupRequestGenericClass*>(g_type_class_ref(WEBKIT_TYPE_SOUP_REQUEST_GENERIC))->client = &CustomProtocolRequestClient::singleton();
    5379}
    5480
    5581void CustomProtocolManager::registerScheme(const String& scheme)
    5682{
    57     m_impl->registerScheme(scheme);
     83    if (!m_registeredSchemes)
     84        m_registeredSchemes = adoptGRef(g_ptr_array_new_with_free_func(g_free));
     85
     86    if (m_registeredSchemes->len)
     87        g_ptr_array_remove_index_fast(m_registeredSchemes.get(), m_registeredSchemes->len - 1);
     88    g_ptr_array_add(m_registeredSchemes.get(), g_strdup(scheme.utf8().data()));
     89    g_ptr_array_add(m_registeredSchemes.get(), nullptr);
     90
     91    auto* genericRequestClass = static_cast<SoupRequestClass*>(g_type_class_ref(WEBKIT_TYPE_SOUP_REQUEST_GENERIC));
     92    genericRequestClass->schemes = const_cast<const char**>(reinterpret_cast<char**>(m_registeredSchemes->pdata));
     93    soup_session_add_feature_by_type(SoupNetworkSession::defaultSession().soupSession(), WEBKIT_TYPE_SOUP_REQUEST_GENERIC);
    5894}
    5995
     
    65101bool CustomProtocolManager::supportsScheme(const String& scheme)
    66102{
    67     return m_impl->supportsScheme(scheme);
    68 }
    69 
    70 void CustomProtocolManager::didFailWithError(uint64_t customProtocolID, const WebCore::ResourceError& error)
    71 {
    72     m_impl->didFailWithError(customProtocolID, error);
     103    if (scheme.isNull())
     104        return false;
     105
     106    CString cScheme = scheme.utf8();
     107    for (unsigned i = 0; i < m_registeredSchemes->len; ++i) {
     108        if (cScheme == static_cast<char*>(g_ptr_array_index(m_registeredSchemes.get(), i)))
     109            return true;
     110    }
     111
     112    return false;
     113}
     114
     115void CustomProtocolManager::didFailWithError(uint64_t customProtocolID, const ResourceError& error)
     116{
     117    auto* data = m_customProtocolMap.get(customProtocolID);
     118    ASSERT(data);
     119
     120    // Either we haven't started reading the stream yet, in which case we need to complete the
     121    // task first, or we failed reading it and the task was already completed by didLoadData().
     122    ASSERT(!data->stream || !data->task);
     123
     124    if (!data->stream) {
     125        GRefPtr<GTask> task = std::exchange(data->task, nullptr);
     126        ASSERT(task.get());
     127        g_task_return_new_error(task.get(), g_quark_from_string(error.domain().utf8().data()),
     128            error.errorCode(), "%s", error.localizedDescription().utf8().data());
     129    } else
     130        webkitSoupRequestInputStreamDidFailWithError(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get()), error);
     131
     132    removeCustomProtocol(customProtocolID);
    73133}
    74134
    75135void CustomProtocolManager::didLoadData(uint64_t customProtocolID, const IPC::DataReference& dataReference)
    76136{
    77     m_impl->didLoadData(customProtocolID, dataReference);
    78 }
    79 
    80 void CustomProtocolManager::didReceiveResponse(uint64_t customProtocolID, const WebCore::ResourceResponse& response, uint32_t)
    81 {
    82     m_impl->didReceiveResponse(customProtocolID, response);
     137    auto* data = m_customProtocolMap.get(customProtocolID);
     138    // The data might have been removed from the request map if a previous chunk failed
     139    // and a new message was sent by the UI process before being notified about the failure.
     140    if (!data)
     141        return;
     142
     143    if (!data->stream) {
     144        GRefPtr<GTask> task = std::exchange(data->task, nullptr);
     145        ASSERT(task.get());
     146
     147        goffset soupContentLength = soup_request_get_content_length(SOUP_REQUEST(g_task_get_source_object(task.get())));
     148        uint64_t contentLength = soupContentLength == -1 ? 0 : static_cast<uint64_t>(soupContentLength);
     149        if (!dataReference.size()) {
     150            // Empty reply, just create and empty GMemoryInputStream.
     151            data->stream = g_memory_input_stream_new();
     152        } else if (dataReference.size() == contentLength) {
     153            // We don't expect more data, so we can just create a GMemoryInputStream with all the data.
     154            data->stream = g_memory_input_stream_new_from_data(g_memdup(dataReference.data(), dataReference.size()), contentLength, g_free);
     155        } else {
     156            // We expect more data chunks from the UI process.
     157            data->stream = webkitSoupRequestInputStreamNew(contentLength);
     158            webkitSoupRequestInputStreamAddData(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get()), dataReference.data(), dataReference.size());
     159        }
     160        g_task_return_pointer(task.get(), data->stream.get(), g_object_unref);
     161        return;
     162    }
     163
     164    if (g_cancellable_is_cancelled(data->cancellable.get()) || !data->request) {
     165        // ResourceRequest failed or it was cancelled. It doesn't matter here the error or if it was cancelled,
     166        // because that's already handled by the resource handle client, we just want to notify the UI process
     167        // to stop reading data from the user input stream. If UI process already sent all the data we simply
     168        // finish silently.
     169        if (!webkitSoupRequestInputStreamFinished(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get())))
     170            stopLoading(customProtocolID);
     171
     172        return;
     173    }
     174
     175    webkitSoupRequestInputStreamAddData(WEBKIT_SOUP_REQUEST_INPUT_STREAM(data->stream.get()), dataReference.data(), dataReference.size());
     176}
     177
     178void CustomProtocolManager::didReceiveResponse(uint64_t customProtocolID, const ResourceResponse& response, uint32_t)
     179{
     180    auto* data = m_customProtocolMap.get(customProtocolID);
     181    // The data might have been removed from the request map if an error happened even before this point.
     182    if (!data)
     183        return;
     184
     185    ASSERT(data->task);
     186
     187    WebKitSoupRequestGeneric* request = WEBKIT_SOUP_REQUEST_GENERIC(g_task_get_source_object(data->task.get()));
     188    webkitSoupRequestGenericSetContentLength(request, response.expectedContentLength() ? response.expectedContentLength() : -1);
     189    webkitSoupRequestGenericSetContentType(request, !response.mimeType().isEmpty() ? response.mimeType().utf8().data() : 0);
    83190}
    84191
    85192void CustomProtocolManager::didFinishLoading(uint64_t customProtocolID)
    86193{
    87     m_impl->didFinishLoading(customProtocolID);
    88 }
    89 
    90 void CustomProtocolManager::wasRedirectedToRequest(uint64_t, const WebCore::ResourceRequest&, const WebCore::ResourceResponse&)
     194    ASSERT(m_customProtocolMap.contains(customProtocolID));
     195    removeCustomProtocol(customProtocolID);
     196}
     197
     198void CustomProtocolManager::wasRedirectedToRequest(uint64_t, const ResourceRequest&, const ResourceResponse&)
    91199{
    92200    notImplemented();
  • trunk/Source/WebKit2/NetworkProcess/cocoa/NetworkSessionCocoa.mm

    r209898 r210374  
    321321}
    322322
    323 static RefPtr<CustomProtocolManager>& globalCustomProtocolManager()
    324 {
    325     static NeverDestroyed<RefPtr<CustomProtocolManager>> customProtocolManager;
    326     return customProtocolManager.get();
     323static CustomProtocolManager*& globalCustomProtocolManager()
     324{
     325    static CustomProtocolManager* customProtocolManager { nullptr };
     326    return customProtocolManager;
    327327}
    328328
     
    397397{
    398398    ASSERT(isMainThread());
    399     static NetworkSession* session = &NetworkSessionCocoa::create(WebCore::SessionID::defaultSessionID(), globalCustomProtocolManager().get()).leakRef();
     399    static NetworkSession* session = &NetworkSessionCocoa::create(WebCore::SessionID::defaultSessionID(), globalCustomProtocolManager()).leakRef();
    400400    return *session;
    401401}
  • trunk/Source/WebKit2/PlatformEfl.cmake

    r209700 r210374  
    22    DatabaseProcess/efl/DatabaseProcessMainEfl.cpp
    33
    4     NetworkProcess/CustomProtocols/soup/CustomProtocolManagerImpl.cpp
    54    NetworkProcess/CustomProtocols/soup/CustomProtocolManagerSoup.cpp
    65
  • trunk/Source/WebKit2/PlatformGTK.cmake

    r210238 r210374  
    2929    DatabaseProcess/gtk/DatabaseProcessMainGtk.cpp
    3030
    31     NetworkProcess/CustomProtocols/soup/CustomProtocolManagerImpl.cpp
    3231    NetworkProcess/CustomProtocols/soup/CustomProtocolManagerSoup.cpp
    3332
  • trunk/Source/WebKit2/WebKit2.xcodeproj/project.pbxproj

    r209896 r210374  
    11091109                5CBC9B8E1C652CA000A8FDCF /* NetworkDataTask.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CBC9B891C6524A500A8FDCF /* NetworkDataTask.h */; };
    11101110                5CE85B201C88E64B0070BFCE /* PingLoad.h in Headers */ = {isa = PBXBuildFile; fileRef = 5CE85B1F1C88E6430070BFCE /* PingLoad.h */; };
     1111                5CFECB041E1ED1CC00F88504 /* CustomProtocolManager.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5CFECB031E1ED1C800F88504 /* CustomProtocolManager.cpp */; };
    11111112                6501BD1A12F1243400E9F248 /* WKBundleInspector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65B86F1712F11D7B00B7DD8A /* WKBundleInspector.cpp */; };
    11121113                659C551E130006410025C0C2 /* InjectedBundlePageResourceLoadClient.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6546A82913000164000CEB1C /* InjectedBundlePageResourceLoadClient.cpp */; };
     
    32463247                5CBC9B8B1C65257300A8FDCF /* NetworkDataTaskCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = NetworkDataTaskCocoa.mm; path = NetworkProcess/cocoa/NetworkDataTaskCocoa.mm; sourceTree = "<group>"; };
    32473248                5CE85B1F1C88E6430070BFCE /* PingLoad.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PingLoad.h; path = NetworkProcess/PingLoad.h; sourceTree = "<group>"; };
     3249                5CFECB031E1ED1C800F88504 /* CustomProtocolManager.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = CustomProtocolManager.cpp; path = NetworkProcess/CustomProtocols/CustomProtocolManager.cpp; sourceTree = "<group>"; };
    32483250                5D442A5516D5856700AC3331 /* PluginService.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = PluginService.entitlements; sourceTree = "<group>"; };
    32493251                5DAD73F1116FF90C00EE5396 /* BaseTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = BaseTarget.xcconfig; sourceTree = "<group>"; };
     
    59225924                        isa = PBXGroup;
    59235925                        children = (
     5926                                5CFECB031E1ED1C800F88504 /* CustomProtocolManager.cpp */,
    59245927                                5C14271A1C23F8BF00D41183 /* Cocoa */,
    59255928                                5C1427141C23F8B000D41183 /* CustomProtocolManager.h */,
     
    94919494                                1A0EC907124C0AB8007EF4A5 /* PluginProcessConnection.cpp in Sources */,
    94929495                                1A0EC910124C0AF5007EF4A5 /* PluginProcessConnectionManager.cpp in Sources */,
     9496                                5CFECB041E1ED1CC00F88504 /* CustomProtocolManager.cpp in Sources */,
    94939497                                1A7865B916CAC71500ACE83A /* PluginProcessConnectionManagerMessageReceiver.cpp in Sources */,
    94949498                                1A2BB6D014117B4D000F35D4 /* PluginProcessConnectionMessageReceiver.cpp in Sources */,
Note: See TracChangeset for help on using the changeset viewer.