Changeset 149520 in webkit


Ignore:
Timestamp:
May 3, 2013 12:10:20 AM (11 years ago)
Author:
aestes@apple.com
Message:

[WK2][CustomProtocols] NSURLProtocolClient methods should be dispatched on NSURLConnection's resource loader run loop
https://bugs.webkit.org/show_bug.cgi?id=115539

Reviewed by Alexey Proskuryakov.

It turns out that calling NSURLProtocolClient methods from a different
thread than the one running the NSURLConnection run loop is unsafe.
Although I can't capture it reliably in a test case, doing so can
sometimes result in a load timing out because the call to
-[NSURLProtocolClient URLProtocolDidFinishLoading:] was ignored by
NSURLConnection.

Fix this by dispatching these methods on the NSURLConnection resource
load run loop. This matches where NSURLProtocolClient methods are
dispatched by typical NSURLProtocol implementations, and in my testing
this solves the timeout issue.

  • Shared/Network/CustomProtocols/CustomProtocolManager.h: Declare

dispatchOnResourceLoaderRunLoop().

  • Shared/Network/CustomProtocols/mac/CustomProtocolManagerMac.mm:

Declare +[NSURLConnection resourceLoaderRunLoop] on a category of
NSURLConnection. Also include the header that declares it if it's present.
(WebKit::CustomProtocolManager::didFailWithError): Call the
NSURLProtocolClient method via dispatchOnResourceLoaderRunLoop().
(WebKit::CustomProtocolManager::didLoadData): Ditto.
(WebKit::CustomProtocolManager::didReceiveResponse): Ditto.
(WebKit::CustomProtocolManager::didFinishLoading): Ditto.
(WebKit::CustomProtocolManager::dispatchOnResourceLoaderRunLoop):
Dispatch a block on the NSURLConnection resource loader run loop and
then wake up the run loop.

Location:
trunk/Source/WebKit2
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebKit2/ChangeLog

    r149499 r149520  
     12013-05-02  Andy Estes  <aestes@apple.com>
     2
     3        [WK2][CustomProtocols] NSURLProtocolClient methods should be dispatched on NSURLConnection's resource loader run loop
     4        https://bugs.webkit.org/show_bug.cgi?id=115539
     5
     6        Reviewed by Alexey Proskuryakov.
     7
     8        It turns out that calling NSURLProtocolClient methods from a different
     9        thread than the one running the NSURLConnection run loop is unsafe.
     10        Although I can't capture it reliably in a test case, doing so can
     11        sometimes result in a load timing out because the call to
     12        -[NSURLProtocolClient URLProtocolDidFinishLoading:] was ignored by
     13        NSURLConnection.
     14
     15        Fix this by dispatching these methods on the NSURLConnection resource
     16        load run loop. This matches where NSURLProtocolClient methods are
     17        dispatched by typical NSURLProtocol implementations, and in my testing
     18        this solves the timeout issue.
     19
     20        * Shared/Network/CustomProtocols/CustomProtocolManager.h: Declare
     21        dispatchOnResourceLoaderRunLoop().
     22        * Shared/Network/CustomProtocols/mac/CustomProtocolManagerMac.mm:
     23        Declare +[NSURLConnection resourceLoaderRunLoop] on a category of
     24        NSURLConnection. Also include the header that declares it if it's present.
     25        (WebKit::CustomProtocolManager::didFailWithError): Call the
     26        NSURLProtocolClient method via dispatchOnResourceLoaderRunLoop().
     27        (WebKit::CustomProtocolManager::didLoadData): Ditto.
     28        (WebKit::CustomProtocolManager::didReceiveResponse): Ditto.
     29        (WebKit::CustomProtocolManager::didFinishLoading): Ditto.
     30        (WebKit::CustomProtocolManager::dispatchOnResourceLoaderRunLoop):
     31        Dispatch a block on the NSURLConnection resource loader run loop and
     32        then wake up the run loop.
     33
    1342013-05-02  Brady Eidson  <beidson@apple.com>
    235
  • trunk/Source/WebKit2/Shared/Network/CustomProtocols/mac/CustomProtocolManagerMac.mm

    r149198 r149520  
    4444#endif
    4545
     46#ifdef __has_include
     47#if __has_include(<Foundation/NSURLConnectionPrivate.h>)
     48#import <Foundation/NSURLConnectionPrivate.h>
     49#endif
     50#endif
     51
     52@interface NSURLConnection (Details)
     53+ (CFRunLoopRef)resourceLoaderRunLoop;
     54@end
     55
    4656using namespace WebKit;
    4757
     
    187197}
    188198
     199static inline void dispatchOnResourceLoaderRunLoop(void (^block)())
     200{
     201    CFRunLoopPerformBlock([NSURLConnection resourceLoaderRunLoop], kCFRunLoopDefaultMode, block);
     202    CFRunLoopWakeUp([NSURLConnection resourceLoaderRunLoop]);
     203}
     204
    189205void CustomProtocolManager::didFailWithError(uint64_t customProtocolID, const WebCore::ResourceError& error)
    190206{
     
    193209        return;
    194210
    195     [[protocol.get() client] URLProtocol:protocol.get() didFailWithError:error.nsError()];
     211    RetainPtr<NSError> nsError = error.nsError();
     212
     213    dispatchOnResourceLoaderRunLoop(^ {
     214        [[protocol.get() client] URLProtocol:protocol.get() didFailWithError:nsError.get()];
     215    });
     216
    196217    removeCustomProtocol(protocol.get());
    197218}
     
    202223    if (!protocol)
    203224        return;
    204    
    205     [[protocol.get() client] URLProtocol:protocol.get() didLoadData:[NSData dataWithBytes:(void*)data.data() length:data.size()]];
     225
     226    RetainPtr<NSData> nsData = adoptNS([[NSData alloc] initWithBytes:data.data() length:data.size()]);
     227
     228    dispatchOnResourceLoaderRunLoop(^ {
     229        [[protocol.get() client] URLProtocol:protocol.get() didLoadData:nsData.get()];
     230    });
    206231}
    207232
     
    211236    if (!protocol)
    212237        return;
    213    
    214     [[protocol.get() client] URLProtocol:protocol.get() didReceiveResponse:response.nsURLResponse() cacheStoragePolicy:static_cast<NSURLCacheStoragePolicy>(cacheStoragePolicy)];
     238
     239    RetainPtr<NSURLResponse> nsResponse = response.nsURLResponse();
     240
     241    dispatchOnResourceLoaderRunLoop(^ {
     242        [[protocol.get() client] URLProtocol:protocol.get() didReceiveResponse:nsResponse.get() cacheStoragePolicy:static_cast<NSURLCacheStoragePolicy>(cacheStoragePolicy)];
     243    });
    215244}
    216245
     
    220249    if (!protocol)
    221250        return;
    222    
    223     [[protocol.get() client] URLProtocolDidFinishLoading:protocol.get()];
     251
     252    dispatchOnResourceLoaderRunLoop(^ {
     253        [[protocol.get() client] URLProtocolDidFinishLoading:protocol.get()];
     254    });
     255
    224256    removeCustomProtocol(protocol.get());
    225257}
Note: See TracChangeset for help on using the changeset viewer.