Changeset 272908 in webkit


Ignore:
Timestamp:
Feb 16, 2021 8:59:26 AM (3 years ago)
Author:
achristensen@apple.com
Message:

Synthesize range responses if needed in WebCoreNSURLSession
https://bugs.webkit.org/show_bug.cgi?id=221072

Reviewed by Geoff Garen.

Source/WebCore:

When we make a media request with a Range HTTP header field and the server doesn't respond with a 206 with Content-Range header field,
until now we would just fail to play the video. In order to successfully play these videos, I introduce the RangeResponseGenerator class,
which will receive the data for a request for such a video and feed the data into WebCoreNSURLSession as the requested ranges are received.
Seeking is problematic, but at least we will try our best to play the video.

I added API tests that try to play a video that didn't play before using a server that doesn't support range requests. Manual verification is also necessary.

  • Sources.txt:
  • SourcesCocoa.txt:
  • WebCore.xcodeproj/project.pbxproj:
  • platform/graphics/PlatformMediaResourceLoader.h:

(WebCore::PlatformMediaResource::setClient):

  • platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm:

(WebCore::PlatformResourceMediaLoader::create):

  • platform/network/ParsedRequestRange.cpp: Added.

(WebCore::ParsedRequestRange::parse):

  • platform/network/ParsedRequestRange.h: Added.

(WebCore::ParsedRequestRange::begin const):
(WebCore::ParsedRequestRange::end const):
(WebCore::ParsedRequestRange::ParsedRequestRange):

  • platform/network/cocoa/RangeResponseGenerator.h: Added.
  • platform/network/cocoa/RangeResponseGenerator.mm: Added.

(WebCore::RangeResponseGenerator::Data::Data):
(WebCore::RangeResponseGenerator::Data::TaskData::TaskData):
(WebCore::synthesizedResponseForRange):
(WebCore::RangeResponseGenerator::removeTask):
(WebCore::RangeResponseGenerator::giveResponseToTaskIfBytesInRangeReceived):
(WebCore::RangeResponseGenerator::expectedContentLengthFromData):
(WebCore::RangeResponseGenerator::giveResponseToTasksWithFinishedRanges):
(WebCore::RangeResponseGenerator::willHandleRequest):
(WebCore::RangeResponseGenerator::willSynthesizeRangeResponses):

  • platform/network/cocoa/WebCoreNSURLSession.h:
  • platform/network/cocoa/WebCoreNSURLSession.mm:

(-[WebCoreNSURLSession rangeResponseGenerator]):
(-[WebCoreNSURLSession dataTaskWithURL:]):
(WebCore::WebCoreNSURLSessionDataTaskClient::dataSent):
(WebCore::WebCoreNSURLSessionDataTaskClient::responseReceived):
(WebCore::WebCoreNSURLSessionDataTaskClient::shouldCacheResponse):
(WebCore::WebCoreNSURLSessionDataTaskClient::dataReceived):
(WebCore::WebCoreNSURLSessionDataTaskClient::redirectReceived):
(WebCore::WebCoreNSURLSessionDataTaskClient::accessControlCheckFailed):
(WebCore::WebCoreNSURLSessionDataTaskClient::loadFailed):
(WebCore::WebCoreNSURLSessionDataTaskClient::loadFinished):
(-[WebCoreNSURLSessionDataTask _restart]):
(-[WebCoreNSURLSessionDataTask _finish]):
(-[WebCoreNSURLSessionDataTask resource:sentBytes:totalBytesToBeSent:]):
(-[WebCoreNSURLSessionDataTask resource:receivedResponse:completionHandler:]):
(-[WebCoreNSURLSessionDataTask resource:shouldCacheResponse:]):
(-[WebCoreNSURLSessionDataTask resource:receivedData:length:]):
(-[WebCoreNSURLSessionDataTask resource:receivedRedirect:request:completionHandler:]):
(-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:metrics:]):
(-[WebCoreNSURLSessionDataTask resource:accessControlCheckFailedWithError:]):
(-[WebCoreNSURLSessionDataTask resource:loadFailedWithError:]):
(-[WebCoreNSURLSessionDataTask resourceFinished:metrics:]):
(-[WebCoreNSURLSessionDataTask initWithSession:identifier:URL:]): Deleted.

Source/WebKit:

  • WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:

(WebKit::MediaPlayerPrivateRemote::requestResource):

Tools:

  • TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp:

(TestWebKitAPI::TEST):

  • TestWebKitAPI/Tests/WebKitCocoa/Challenge.mm:

(TestWebKitAPI::clientCertServer):

  • TestWebKitAPI/Tests/WebKitCocoa/MediaLoading.mm:

(TestWebKitAPI::testVideoBytes):
(TestWebKitAPI::runVideoTest):
(TestWebKitAPI::TEST):

  • TestWebKitAPI/cocoa/HTTPServer.h:

(TestWebKitAPI::HTTPResponse::HTTPResponse):
(TestWebKitAPI::HTTPServer::HTTPResponse::HTTPResponse): Deleted.

  • TestWebKitAPI/cocoa/HTTPServer.mm:

(TestWebKitAPI::HTTPServer::RequestData::RequestData):
(TestWebKitAPI::appendToVector):
(TestWebKitAPI::HTTPServer::parsePath):
(TestWebKitAPI::HTTPServer::respondToRequests):
(TestWebKitAPI::HTTPResponse::bodyFromString):
(TestWebKitAPI::HTTPResponse::serialize):

Location:
trunk
Files:
5 added
18 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r272906 r272908  
     12021-02-16  Alex Christensen  <achristensen@webkit.org>
     2
     3        Synthesize range responses if needed in WebCoreNSURLSession
     4        https://bugs.webkit.org/show_bug.cgi?id=221072
     5
     6        Reviewed by Geoff Garen.
     7
     8        When we make a media request with a Range HTTP header field and the server doesn't respond with a 206 with Content-Range header field,
     9        until now we would just fail to play the video.  In order to successfully play these videos, I introduce the RangeResponseGenerator class,
     10        which will receive the data for a request for such a video and feed the data into WebCoreNSURLSession as the requested ranges are received.
     11        Seeking is problematic, but at least we will try our best to play the video.
     12
     13        I added API tests that try to play a video that didn't play before using a server that doesn't support range requests.  Manual verification is also necessary.
     14
     15        * Sources.txt:
     16        * SourcesCocoa.txt:
     17        * WebCore.xcodeproj/project.pbxproj:
     18        * platform/graphics/PlatformMediaResourceLoader.h:
     19        (WebCore::PlatformMediaResource::setClient):
     20        * platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm:
     21        (WebCore::PlatformResourceMediaLoader::create):
     22        * platform/network/ParsedRequestRange.cpp: Added.
     23        (WebCore::ParsedRequestRange::parse):
     24        * platform/network/ParsedRequestRange.h: Added.
     25        (WebCore::ParsedRequestRange::begin const):
     26        (WebCore::ParsedRequestRange::end const):
     27        (WebCore::ParsedRequestRange::ParsedRequestRange):
     28        * platform/network/cocoa/RangeResponseGenerator.h: Added.
     29        * platform/network/cocoa/RangeResponseGenerator.mm: Added.
     30        (WebCore::RangeResponseGenerator::Data::Data):
     31        (WebCore::RangeResponseGenerator::Data::TaskData::TaskData):
     32        (WebCore::synthesizedResponseForRange):
     33        (WebCore::RangeResponseGenerator::removeTask):
     34        (WebCore::RangeResponseGenerator::giveResponseToTaskIfBytesInRangeReceived):
     35        (WebCore::RangeResponseGenerator::expectedContentLengthFromData):
     36        (WebCore::RangeResponseGenerator::giveResponseToTasksWithFinishedRanges):
     37        (WebCore::RangeResponseGenerator::willHandleRequest):
     38        (WebCore::RangeResponseGenerator::willSynthesizeRangeResponses):
     39        * platform/network/cocoa/WebCoreNSURLSession.h:
     40        * platform/network/cocoa/WebCoreNSURLSession.mm:
     41        (-[WebCoreNSURLSession rangeResponseGenerator]):
     42        (-[WebCoreNSURLSession dataTaskWithURL:]):
     43        (WebCore::WebCoreNSURLSessionDataTaskClient::dataSent):
     44        (WebCore::WebCoreNSURLSessionDataTaskClient::responseReceived):
     45        (WebCore::WebCoreNSURLSessionDataTaskClient::shouldCacheResponse):
     46        (WebCore::WebCoreNSURLSessionDataTaskClient::dataReceived):
     47        (WebCore::WebCoreNSURLSessionDataTaskClient::redirectReceived):
     48        (WebCore::WebCoreNSURLSessionDataTaskClient::accessControlCheckFailed):
     49        (WebCore::WebCoreNSURLSessionDataTaskClient::loadFailed):
     50        (WebCore::WebCoreNSURLSessionDataTaskClient::loadFinished):
     51        (-[WebCoreNSURLSessionDataTask _restart]):
     52        (-[WebCoreNSURLSessionDataTask _finish]):
     53        (-[WebCoreNSURLSessionDataTask resource:sentBytes:totalBytesToBeSent:]):
     54        (-[WebCoreNSURLSessionDataTask resource:receivedResponse:completionHandler:]):
     55        (-[WebCoreNSURLSessionDataTask resource:shouldCacheResponse:]):
     56        (-[WebCoreNSURLSessionDataTask resource:receivedData:length:]):
     57        (-[WebCoreNSURLSessionDataTask resource:receivedRedirect:request:completionHandler:]):
     58        (-[WebCoreNSURLSessionDataTask _resource:loadFinishedWithError:metrics:]):
     59        (-[WebCoreNSURLSessionDataTask resource:accessControlCheckFailedWithError:]):
     60        (-[WebCoreNSURLSessionDataTask resource:loadFailedWithError:]):
     61        (-[WebCoreNSURLSessionDataTask resourceFinished:metrics:]):
     62        (-[WebCoreNSURLSessionDataTask initWithSession:identifier:URL:]): Deleted.
     63
    1642021-02-16  Antti Koivisto  <antti@apple.com>
    265
  • trunk/Source/WebCore/Headers.cmake

    r272764 r272908  
    14131413    platform/network/ParsedContentRange.h
    14141414    platform/network/ParsedContentType.h
     1415    platform/network/ParsedRequestRange.h
    14151416    platform/network/ProtectionSpace.h
    14161417    platform/network/ProtectionSpaceBase.h
  • trunk/Source/WebCore/Sources.txt

    r272878 r272908  
    21262126platform/network/ParsedContentRange.cpp
    21272127platform/network/ParsedContentType.cpp
     2128platform/network/ParsedRequestRange.cpp
    21282129platform/network/ProtectionSpaceBase.cpp
    21292130platform/network/ProxyServer.cpp
  • trunk/Source/WebCore/SourcesCocoa.txt

    r272878 r272908  
    570570platform/network/cocoa/NetworkStorageSessionCocoa.mm
    571571platform/network/cocoa/ProtectionSpaceCocoa.mm
     572platform/network/cocoa/RangeResponseGenerator.mm
    572573platform/network/cocoa/ResourceRequestCocoa.mm
    573574platform/network/cocoa/ResourceResponseCocoa.mm @no-unify // Unsafe to unify until rdar://problem/48853137 is resolved
  • trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj

    r272878 r272908  
    19461946                5C4304B1191AC908000E2BC0 /* EXTShaderTextureLOD.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C4304AE191AC908000E2BC0 /* EXTShaderTextureLOD.h */; };
    19471947                5C4304B6191AEF46000E2BC0 /* JSEXTShaderTextureLOD.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C4304B4191AEF46000E2BC0 /* JSEXTShaderTextureLOD.h */; };
     1948                5C4A0FD725C3435000D9EE97 /* RangeResponseGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C4A0FD525C342C800D9EE97 /* RangeResponseGenerator.h */; settings = {ATTRIBUTES = (Private, ); }; };
     1949                5C4A0FDA25C3449A00D9EE97 /* ParsedRequestRange.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C4A0FD825C3446C00D9EE97 /* ParsedRequestRange.h */; settings = {ATTRIBUTES = (Private, ); }; };
    19481950                5C53DCE124465DFC00A93124 /* ApplePaySetupFeatureWebCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C53DCCF2446449900A93124 /* ApplePaySetupFeatureWebCore.h */; settings = {ATTRIBUTES = (Private, ); }; };
    19491951                5C53DCE724468AD200A93124 /* PaymentInstallmentConfigurationWebCore.h in Headers */ = {isa = PBXBuildFile; fileRef = 5C53DCCE2446449900A93124 /* PaymentInstallmentConfigurationWebCore.h */; settings = {ATTRIBUTES = (Private, ); }; };
     
    95029504                5C4304B3191AEF46000E2BC0 /* JSEXTShaderTextureLOD.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSEXTShaderTextureLOD.cpp; sourceTree = "<group>"; };
    95039505                5C4304B4191AEF46000E2BC0 /* JSEXTShaderTextureLOD.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSEXTShaderTextureLOD.h; sourceTree = "<group>"; };
     9506                5C4A0FD325C342C700D9EE97 /* RangeResponseGenerator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = RangeResponseGenerator.mm; sourceTree = "<group>"; };
     9507                5C4A0FD525C342C800D9EE97 /* RangeResponseGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RangeResponseGenerator.h; sourceTree = "<group>"; };
     9508                5C4A0FD625C342DB00D9EE97 /* CertificateInfoCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = CertificateInfoCocoa.mm; sourceTree = "<group>"; };
     9509                5C4A0FD825C3446C00D9EE97 /* ParsedRequestRange.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParsedRequestRange.h; sourceTree = "<group>"; };
     9510                5C4A0FD925C3446D00D9EE97 /* ParsedRequestRange.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ParsedRequestRange.cpp; sourceTree = "<group>"; };
    95049511                5C5381AF1D8793E000E2EBE6 /* URLSearchParams.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = URLSearchParams.idl; sourceTree = "<group>"; };
    95059512                5C5381B01D87D45700E2EBE6 /* URLSearchParams.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = URLSearchParams.cpp; sourceTree = "<group>"; };
     
    2184921856                                447958021643B47B001E0A7F /* ParsedContentType.cpp */,
    2185021857                                447958031643B47B001E0A7F /* ParsedContentType.h */,
     21858                                5C4A0FD925C3446D00D9EE97 /* ParsedRequestRange.cpp */,
     21859                                5C4A0FD825C3446C00D9EE97 /* ParsedRequestRange.h */,
    2185121860                                37BAAE571980D1DD005DFE71 /* ProtectionSpace.h */,
    2185221861                                514C765F0CE923A1007EF3CD /* ProtectionSpaceBase.cpp */,
     
    2293322942                        isa = PBXGroup;
    2293422943                        children = (
     22944                                5C4A0FD625C342DB00D9EE97 /* CertificateInfoCocoa.mm */,
    2293522945                                51D1248C1E736456002B2820 /* CookieCocoa.mm */,
    2293622946                                5120BBAD1F1CE77000EFEBF1 /* CookieStorageObserver.h */,
     
    2294322953                                372ADA37197F47B900FC501E /* ProtectionSpaceCocoa.h */,
    2294422954                                372ADA39197F687600FC501E /* ProtectionSpaceCocoa.mm */,
     22955                                5C4A0FD525C342C800D9EE97 /* RangeResponseGenerator.h */,
     22956                                5C4A0FD325C342C700D9EE97 /* RangeResponseGenerator.mm */,
    2294522957                                7E7DE1FC195CEF260035363B /* ResourceRequestCocoa.mm */,
    2294622958                                A1F78D0B1C25422C00245446 /* ResourceResponseCocoa.mm */,
     
    3401634028                                CDCD41E81C3DDB0A00965D99 /* ParsedContentRange.h in Headers */,
    3401734029                                447958041643B49A001E0A7F /* ParsedContentType.h in Headers */,
     34030                                5C4A0FDA25C3449A00D9EE97 /* ParsedRequestRange.h in Headers */,
    3401834031                                536D5A23193E8E0C00CE4CAB /* ParsingUtilities.h in Headers */,
    3401934032                                F55B3DCA1251F12D003EF269 /* PasswordInputType.h in Headers */,
     
    3421934232                                93D9D53C0DA27E180077216C /* RangeBoundaryPoint.h in Headers */,
    3422034233                                F55B3DCE1251F12D003EF269 /* RangeInputType.h in Headers */,
     34234                                5C4A0FD725C3435000D9EE97 /* RangeResponseGenerator.h in Headers */,
    3422134235                                6E84E9E117668BF100815B68 /* RasterShape.h in Headers */,
    3422234236                                A84D827C11D333ED00972990 /* RawDataDocumentParser.h in Headers */,
  • trunk/Source/WebCore/platform/graphics/PlatformMediaResourceLoader.h

    r272764 r272908  
    4242class ResourceResponse;
    4343
    44 class PlatformMediaResourceClient {
     44class PlatformMediaResourceClient : public RefCounted<PlatformMediaResourceClient> {
    4545public:
    4646    virtual ~PlatformMediaResourceClient() = default;
     
    8282    virtual bool didPassAccessControlCheck() const { return false; }
    8383
    84     void setClient(std::unique_ptr<PlatformMediaResourceClient>&& client) { m_client = WTFMove(client); }
     84    void setClient(RefPtr<PlatformMediaResourceClient>&& client) { m_client = WTFMove(client); }
    8585    PlatformMediaResourceClient* client() { return m_client.get(); }
    8686
    8787protected:
    88     std::unique_ptr<PlatformMediaResourceClient> m_client;
     88    RefPtr<PlatformMediaResourceClient> m_client;
    8989};
    9090
  • trunk/Source/WebCore/platform/graphics/avfoundation/objc/WebCoreAVFResourceLoader.mm

    r272764 r272908  
    171171        return nullptr;
    172172    auto* resourcePointer = resource.get();
    173     auto client = std::unique_ptr<PlatformResourceMediaLoader>(new PlatformResourceMediaLoader { parent, resource.releaseNonNull() });
     173    auto client = adoptRef(*new PlatformResourceMediaLoader { parent, resource.releaseNonNull() });
    174174    auto result = makeWeakPtr(client.get());
    175175
  • trunk/Source/WebCore/platform/graphics/gstreamer/WebKitWebSourceGStreamer.cpp

    r272764 r272908  
    700700        members->resource = members->loader->requestResource(ResourceRequest(request), loadOptions);
    701701        if (members->resource) {
    702             members->resource->setClient(makeUnique<CachedResourceStreamingClient>(protector.get(), ResourceRequest(request), requestNumber));
     702            members->resource->setClient(adoptRef(*new CachedResourceStreamingClient(protector.get(), ResourceRequest(request), requestNumber)));
    703703            GST_DEBUG_OBJECT(protector.get(), "Started request R%u", requestNumber);
    704704        } else {
  • trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.h

    r272764 r272908  
    2424 */
    2525
     26#import "RangeResponseGenerator.h"
    2627#import "SecurityOrigin.h"
    2728#import <Foundation/NSURLSession.h>
     29#import <wtf/CompletionHandler.h>
    2830#import <wtf/HashSet.h>
    2931#import <wtf/Lock.h>
     
    4244namespace WebCore {
    4345class CachedResourceRequest;
     46class NetworkLoadMetrics;
    4447class PlatformMediaResource;
    4548class PlatformMediaResourceLoader;
     49class ResourceError;
     50class ResourceRequest;
     51class ResourceResponse;
    4652class WebCoreNSURLSessionDataTaskClient;
     53enum class ShouldContinuePolicyCheck : bool;
    4754}
    4855
    49 enum class WebCoreNSURLSessionCORSAccessCheckResults {
     56enum class WebCoreNSURLSessionCORSAccessCheckResults : uint8_t {
    5057    Unknown,
    5158    Pass,
     
    6875    OSObjectPtr<dispatch_queue_t> _internalQueue;
    6976    WebCoreNSURLSessionCORSAccessCheckResults _corsResults;
     77    WebCore::RangeResponseGenerator _rangeResponseGenerator;
    7078}
    7179- (id)initWithResourceLoader:(WebCore::PlatformMediaResourceLoader&)loader delegate:(id<NSURLSessionTaskDelegate>)delegate delegateQueue:(NSOperationQueue*)queue;
     
    111119
    112120@interface WebCoreNSURLSessionDataTask : NSObject {
    113     __unsafe_unretained WebCoreNSURLSession *_session;
     121    WeakObjCPtr<WebCoreNSURLSession> _session;
    114122    RefPtr<WebCore::PlatformMediaResource> _resource;
    115123    RetainPtr<NSURLResponse> _response;
     
    144152@end
    145153
     154@interface WebCoreNSURLSessionDataTask (WebKitInternal)
     155- (void)resource:(nullable WebCore::PlatformMediaResource*)resource sentBytes:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent;
     156- (void)resource:(nullable WebCore::PlatformMediaResource*)resource receivedResponse:(const WebCore::ResourceResponse&)response completionHandler:(CompletionHandler<void(WebCore::ShouldContinuePolicyCheck)>&&)completionHandler;
     157- (BOOL)resource:(nullable WebCore::PlatformMediaResource*)resource shouldCacheResponse:(const WebCore::ResourceResponse&)response;
     158- (void)resource:(nullable WebCore::PlatformMediaResource*)resource receivedData:(const char*)data length:(int)length;
     159- (void)resource:(nullable WebCore::PlatformMediaResource*)resource receivedRedirect:(const WebCore::ResourceResponse&)response request:(WebCore::ResourceRequest&&)request completionHandler:(CompletionHandler<void(WebCore::ResourceRequest&&)>&&)completionHandler;
     160- (void)resource:(nullable WebCore::PlatformMediaResource*)resource accessControlCheckFailedWithError:(const WebCore::ResourceError&)error;
     161- (void)resource:(nullable WebCore::PlatformMediaResource*)resource loadFailedWithError:(const WebCore::ResourceError&)error;
     162- (void)resourceFinished:(nullable WebCore::PlatformMediaResource*)resource metrics:(const WebCore::NetworkLoadMetrics&)metrics;
     163@end
     164
    146165NS_ASSUME_NONNULL_END
  • trunk/Source/WebCore/platform/network/cocoa/WebCoreNSURLSession.mm

    r272764 r272908  
    2828
    2929#import "CachedResourceRequest.h"
     30#import "ParsedRequestRange.h"
    3031#import "PlatformMediaResourceLoader.h"
    3132#import "SubresourceLoader.h"
    3233#import <wtf/BlockPtr.h>
    3334#import <wtf/CompletionHandler.h>
     35#import <wtf/WeakObjCPtr.h>
    3436#import <wtf/cocoa/VectorCocoa.h>
    3537
     
    204206- (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveCORSAccessCheckResult:(BOOL)result;
    205207- (void)task:(WebCoreNSURLSessionDataTask *)task didReceiveResponseFromOrigin:(Ref<WebCore::SecurityOrigin>&&)origin;
     208- (WebCore::RangeResponseGenerator&)rangeResponseGenerator;
    206209@end
    207210
    208211@interface WebCoreNSURLSessionDataTask ()
    209212- (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier request:(NSURLRequest *)request;
    210 - (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier URL:(NSURL *)url;
    211213- (void)_restart;
    212214- (void)_cancel;
    213 - (void)_finish;
    214215@property (assign) WebCoreNSURLSession * _Nullable session;
    215216
    216 - (void)resource:(PlatformMediaResource&)resource sentBytes:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent;
    217 - (void)resource:(PlatformMediaResource&)resource receivedResponse:(const ResourceResponse&)response completionHandler:(CompletionHandler<void(ShouldContinuePolicyCheck)>&&)completionHandler;
    218 - (BOOL)resource:(PlatformMediaResource&)resource shouldCacheResponse:(const ResourceResponse&)response;
    219 - (void)resource:(PlatformMediaResource&)resource receivedData:(const char*)data length:(int)length;
    220 - (void)resource:(PlatformMediaResource&)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&&)request completionHandler:(CompletionHandler<void(ResourceRequest&&)>&&)completionHandler;
    221 - (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error;
    222 - (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error;
    223 - (void)resourceFinished:(PlatformMediaResource&)resource metrics:(const NetworkLoadMetrics&)metrics;
    224217@end
    225218
     
    312305}
    313306
     307- (WebCore::RangeResponseGenerator&)rangeResponseGenerator
     308{
     309    return _rangeResponseGenerator;
     310}
     311
    314312#pragma mark - NSURLSession API
    315313@dynamic delegate;
     
    456454- (NSURLSessionDataTask *)dataTaskWithURL:(NSURL *)url
    457455{
    458     if (_invalidated)
    459         return nil;
    460 
    461     WebCoreNSURLSessionDataTask *task = [[WebCoreNSURLSessionDataTask alloc] initWithSession:self identifier:_nextTaskIdentifier++ URL:url];
    462     {
    463         Locker<Lock> locker(_dataTasksLock);
    464         _dataTasks.add(task);
    465     }
    466     return (NSURLSessionDataTask *)[task autorelease];
     456    return [self dataTaskWithRequest:[NSURLRequest requestWithURL:url]];
    467457}
    468458
     
    572562private:
    573563    Lock m_taskLock;
    574     WebCoreNSURLSessionDataTask *m_task;
     564    WeakObjCPtr<WebCoreNSURLSessionDataTask> m_task;
    575565};
    576566
     
    587577        return;
    588578
    589     [m_task resource:resource sentBytes:bytesSent totalBytesToBeSent:totalBytesToBeSent];
     579    [m_task resource:&resource sentBytes:bytesSent totalBytesToBeSent:totalBytesToBeSent];
    590580}
    591581
    592582void WebCoreNSURLSessionDataTaskClient::responseReceived(PlatformMediaResource& resource, const ResourceResponse& response, CompletionHandler<void(ShouldContinuePolicyCheck)>&& completionHandler)
    593583{
     584    auto protectedThis = makeRef(*this);
    594585    LockHolder locker(m_taskLock);
    595586    if (!m_task)
    596587        return completionHandler(ShouldContinuePolicyCheck::No);
    597588
    598     [m_task resource:resource receivedResponse:response completionHandler:WTFMove(completionHandler)];
     589    [m_task resource:&resource receivedResponse:response completionHandler:WTFMove(completionHandler)];
    599590}
    600591
     
    605596        return false;
    606597
    607     return [m_task resource:resource shouldCacheResponse:response];
     598    return [m_task resource:&resource shouldCacheResponse:response];
    608599}
    609600
     
    614605        return;
    615606
    616     [m_task resource:resource receivedData:data length:length];
     607    [m_task resource:&resource receivedData:data length:length];
    617608}
    618609
     
    623614        return;
    624615
    625     [m_task resource:resource receivedRedirect:response request:WTFMove(request) completionHandler: [completionHandler = WTFMove(completionHandler)] (auto&& request) mutable {
     616    [m_task resource:&resource receivedRedirect:response request:WTFMove(request) completionHandler: [completionHandler = WTFMove(completionHandler)] (auto&& request) mutable {
    626617        callOnMainThread([request = request.isolatedCopy(), completionHandler = WTFMove(completionHandler)] () mutable {
    627618            completionHandler(WTFMove(request));
     
    636627        return;
    637628
    638     [m_task resource:resource accessControlCheckFailedWithError:error];
     629    [m_task resource:&resource accessControlCheckFailedWithError:error];
    639630}
    640631
     
    645636        return;
    646637
    647     [m_task resource:resource loadFailedWithError:error];
     638    [m_task resource:&resource loadFailedWithError:error];
    648639}
    649640
     
    654645        return;
    655646
    656     [m_task resourceFinished:resource metrics:metrics];
     647    [m_task resourceFinished:&resource metrics:metrics];
    657648}
    658649
     
    662653
    663654@implementation WebCoreNSURLSessionDataTask
    664 - (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier URL:(NSURL *)url
    665 {
    666     self.taskIdentifier = identifier;
    667     self.session = session;
    668     self.state = NSURLSessionTaskStateSuspended;
    669     self.priority = NSURLSessionTaskPriorityDefault;
    670     self.originalRequest = self.currentRequest = [NSURLRequest requestWithURL:url];
    671 
    672     return self;
    673 }
    674 
    675655- (id)initWithSession:(WebCoreNSURLSession *)session identifier:(NSUInteger)identifier request:(NSURLRequest *)request
    676656{
     
    709689    [self _cancel];
    710690
     691    if ([self.session rangeResponseGenerator].willHandleRequest(self, self.originalRequest))
     692        return;
     693
    711694    _resource = self.session.loader.requestResource(self.originalRequest, PlatformMediaResourceLoader::LoadOption::DisallowCaching);
    712695    if (_resource)
    713         _resource->setClient(makeUnique<WebCoreNSURLSessionDataTaskClient>(self));
     696        _resource->setClient(adoptRef(*new WebCoreNSURLSessionDataTaskClient(self)));
    714697}
    715698
     
    724707}
    725708
    726 - (void)_finish
    727 {
    728     ASSERT(isMainThread());
    729     if (_resource)
    730         [self resourceFinished:*_resource metrics:NetworkLoadMetrics { }];
    731 }
    732 
    733709#pragma mark - NSURLSession API
    734 @synthesize session = _session;
    735710@synthesize taskIdentifier = _taskIdentifier;
    736711@synthesize originalRequest = _originalRequest;
     
    745720@synthesize priority = _priority;
    746721
     722- (WebCoreNSURLSession *)session
     723{
     724    return _session.get().get();
     725}
     726
     727- (void)setSession:(WebCoreNSURLSession *)session
     728{
     729    _session = session;
     730}
     731
    747732- (NSURLResponse *)response
    748733{
     
    752737- (void)cancel
    753738{
     739    if (self.state == NSURLSessionTaskStateCompleted)
     740        return;
    754741    self.state = NSURLSessionTaskStateCanceling;
    755     callOnMainThread([protectedSelf = RetainPtr<WebCoreNSURLSessionDataTask>(self)] {
     742    callOnMainThread([protectedSelf = retainPtr(self)] {
    756743        [protectedSelf _cancel];
    757         [protectedSelf _finish];
     744        [protectedSelf _resource:nullptr loadFinishedWithError:[NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:nil] metrics:NetworkLoadMetrics { }];
    758745    });
    759746}
     
    807794#pragma mark - PlatformMediaResourceClient callbacks
    808795
    809 - (void)resource:(PlatformMediaResource&)resource sentBytes:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent
    810 {
    811     ASSERT_UNUSED(resource, &resource == _resource);
     796- (void)resource:(PlatformMediaResource*)resource sentBytes:(unsigned long long)bytesSent totalBytesToBeSent:(unsigned long long)totalBytesToBeSent
     797{
     798    ASSERT_UNUSED(resource, !resource || resource == _resource);
    812799    UNUSED_PARAM(bytesSent);
    813800    UNUSED_PARAM(totalBytesToBeSent);
     
    815802}
    816803
    817 - (void)resource:(PlatformMediaResource&)resource receivedResponse:(const ResourceResponse&)response completionHandler:(CompletionHandler<void(ShouldContinuePolicyCheck)>&&)completionHandler
     804- (void)resource:(PlatformMediaResource*)resource receivedResponse:(const ResourceResponse&)response completionHandler:(CompletionHandler<void(ShouldContinuePolicyCheck)>&&)completionHandler
    818805{
    819806    ASSERT(response.source() == ResourceResponse::Source::Network || response.source() == ResourceResponse::Source::DiskCache || response.source() == ResourceResponse::Source::DiskCacheAfterValidation || response.source() == ResourceResponse::Source::ServiceWorker);
    820     ASSERT_UNUSED(resource, &resource == _resource);
     807    ASSERT_UNUSED(resource, !resource || resource == _resource);
    821808    ASSERT(isMainThread());
    822809    [self.session task:self didReceiveResponseFromOrigin:SecurityOrigin::create(response.url())];
    823     [self.session task:self didReceiveCORSAccessCheckResult:resource.didPassAccessControlCheck()];
     810    // FIXME: Think about this and make sure it's safe.
     811    [self.session task:self didReceiveCORSAccessCheckResult:resource ? resource->didPassAccessControlCheck() : YES];
    824812    self.countOfBytesExpectedToReceive = response.expectedContentLength();
    825     RetainPtr<NSURLResponse> strongResponse { response.nsURLResponse() };
     813    RetainPtr<NSURLResponse> strongResponse = response.nsURLResponse();
     814
     815    if (resource && self.session && [self.session rangeResponseGenerator].willSynthesizeRangeResponses(self, *resource, response))
     816        return completionHandler(ShouldContinuePolicyCheck::Yes);
     817   
    826818    RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
    827819    if (!self.session)
     
    851843}
    852844
    853 - (BOOL)resource:(PlatformMediaResource&)resource shouldCacheResponse:(const ResourceResponse&)response
    854 {
    855     ASSERT_UNUSED(resource, &resource == _resource);
     845- (BOOL)resource:(PlatformMediaResource*)resource shouldCacheResponse:(const ResourceResponse&)response
     846{
     847    ASSERT_UNUSED(resource, !resource || resource == _resource);
    856848
    857849    ASSERT(isMainThread());
     
    861853}
    862854
    863 - (void)resource:(PlatformMediaResource&)resource receivedData:(const char*)data length:(int)length
    864 {
    865     ASSERT_UNUSED(resource, &resource == _resource);
     855- (void)resource:(PlatformMediaResource*)resource receivedData:(const char*)data length:(int)length
     856{
     857    ASSERT_UNUSED(resource, !resource || resource == _resource);
    866858    RetainPtr<NSData> nsData = adoptNS([[NSData alloc] initWithBytes:data length:length]);
    867859    RetainPtr<WebCoreNSURLSessionDataTask> strongSelf { self };
     
    874866}
    875867
    876 - (void)resource:(PlatformMediaResource&)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&&)request completionHandler:(CompletionHandler<void(ResourceRequest&&)>&&)completionHandler
    877 {
    878     ASSERT_UNUSED(resource, &resource == _resource);
     868- (void)resource:(PlatformMediaResource*)resource receivedRedirect:(const ResourceResponse&)response request:(ResourceRequest&&)request completionHandler:(CompletionHandler<void(ResourceRequest&&)>&&)completionHandler
     869{
     870    ASSERT_UNUSED(resource, !resource || resource == _resource);
    879871    [self.session addDelegateOperation:[strongSelf = retainPtr(self), response = retainPtr(response.nsURLResponse()), request = request.isolatedCopy(), completionHandler = WTFMove(completionHandler)] () mutable {
    880872        if (![response isKindOfClass:[NSHTTPURLResponse class]]) {
     
    906898}
    907899
    908 - (void)_resource:(PlatformMediaResource&)resource loadFinishedWithError:(NSError *)error metrics:(const NetworkLoadMetrics&)metrics
    909 {
    910     ASSERT_UNUSED(resource, &resource == _resource);
     900- (void)_resource:(PlatformMediaResource*)resource loadFinishedWithError:(NSError *)error metrics:(const NetworkLoadMetrics&)metrics
     901{
     902    ASSERT_UNUSED(resource, !resource || resource == _resource);
    911903    if (self.state == NSURLSessionTaskStateCompleted)
    912904        return;
     
    931923}
    932924
    933 - (void)resource:(PlatformMediaResource&)resource accessControlCheckFailedWithError:(const ResourceError&)error
     925- (void)resource:(PlatformMediaResource*)resource accessControlCheckFailedWithError:(const ResourceError&)error
    934926{
    935927    [self _resource:resource loadFinishedWithError:error.nsError() metrics:NetworkLoadMetrics { }];
    936928}
    937929
    938 - (void)resource:(PlatformMediaResource&)resource loadFailedWithError:(const ResourceError&)error
     930- (void)resource:(PlatformMediaResource*)resource loadFailedWithError:(const ResourceError&)error
    939931{
    940932    [self _resource:resource loadFinishedWithError:error.nsError() metrics:NetworkLoadMetrics { }];
    941933}
    942934
    943 - (void)resourceFinished:(PlatformMediaResource&)resource metrics:(const NetworkLoadMetrics&)metrics
     935- (void)resourceFinished:(PlatformMediaResource*)resource metrics:(const NetworkLoadMetrics&)metrics
    944936{
    945937    [self _resource:resource loadFinishedWithError:nil metrics:metrics];
  • trunk/Source/WebKit/ChangeLog

    r272905 r272908  
     12021-02-16  Alex Christensen  <achristensen@webkit.org>
     2
     3        Synthesize range responses if needed in WebCoreNSURLSession
     4        https://bugs.webkit.org/show_bug.cgi?id=221072
     5
     6        Reviewed by Geoff Garen.
     7
     8        * WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp:
     9        (WebKit::MediaPlayerPrivateRemote::requestResource):
     10
    1112021-02-16  Kimmo Kinnunen  <kkinnunen@apple.com>
    212
  • trunk/Source/WebKit/WebProcess/GPU/media/MediaPlayerPrivateRemote.cpp

    r272764 r272908  
    11811181    }
    11821182    // PlatformMediaResource owns the PlatformMediaResourceClient
    1183     resource->setClient(makeUnique<RemoteMediaResourceProxy>(connection(), *resource, remoteMediaResourceIdentifier));
     1183    resource->setClient(adoptRef(*new RemoteMediaResourceProxy(connection(), *resource, remoteMediaResourceIdentifier)));
    11841184    m_mediaResources.add(remoteMediaResourceIdentifier, WTFMove(resource));
    11851185
  • trunk/Tools/ChangeLog

    r272894 r272908  
     12021-02-16  Alex Christensen  <achristensen@webkit.org>
     2
     3        Synthesize range responses if needed in WebCoreNSURLSession
     4        https://bugs.webkit.org/show_bug.cgi?id=221072
     5
     6        Reviewed by Geoff Garen.
     7
     8        * TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp:
     9        (TestWebKitAPI::TEST):
     10        * TestWebKitAPI/Tests/WebKitCocoa/Challenge.mm:
     11        (TestWebKitAPI::clientCertServer):
     12        * TestWebKitAPI/Tests/WebKitCocoa/MediaLoading.mm:
     13        (TestWebKitAPI::testVideoBytes):
     14        (TestWebKitAPI::runVideoTest):
     15        (TestWebKitAPI::TEST):
     16        * TestWebKitAPI/cocoa/HTTPServer.h:
     17        (TestWebKitAPI::HTTPResponse::HTTPResponse):
     18        (TestWebKitAPI::HTTPServer::HTTPResponse::HTTPResponse): Deleted.
     19        * TestWebKitAPI/cocoa/HTTPServer.mm:
     20        (TestWebKitAPI::HTTPServer::RequestData::RequestData):
     21        (TestWebKitAPI::appendToVector):
     22        (TestWebKitAPI::HTTPServer::parsePath):
     23        (TestWebKitAPI::HTTPServer::respondToRequests):
     24        (TestWebKitAPI::HTTPResponse::bodyFromString):
     25        (TestWebKitAPI::HTTPResponse::serialize):
     26
    1272021-02-15  John Wilander  <wilander@apple.com>
    228
  • trunk/Tools/TestWebKitAPI/Tests/WebCore/ParsedContentRange.cpp

    r272764 r272908  
    2727
    2828#include <WebCore/ParsedContentRange.h>
     29#include <WebCore/ParsedRequestRange.h>
    2930#include <wtf/text/WTFString.h>
    3031
     
    9697}
    9798
     99TEST(WebCore, ParsedRequestRange)
     100{
     101    Vector<String> failureCases {
     102        { },
     103        "",
     104        "abc",
     105        "bytes=",
     106        "bytes=-",
     107        "bytes=abc-",
     108        "bytes=1-abc",
     109        "bytes=2-1",
     110        "bytes=1-",
     111        "bytes=-1",
     112        "bytes=1-999999999999999999999999"
     113    };
     114    for (const auto& input : failureCases)
     115        EXPECT_EQ(WTF::nullopt, ParsedRequestRange::parse(input));
     116
     117    auto compare = [] (const String& input, Optional<size_t> begin, Optional<size_t> end) {
     118        auto range = ParsedRequestRange::parse(input);
     119        EXPECT_NE(WTF::nullopt, range);
     120       
     121    };
     122    compare("bytes=1-1", 1, 1);
     123    compare("bytes=1-2", 1, 2);
    98124}
     125
     126}
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/Challenge.mm

    r272764 r272908  
    590590        { "/6.png", { longString } },
    591591        { "/redirectToError", { 301, {{ "Location", "/error" }} } },
    592         { "/error", { HTTPServer::HTTPResponse::TerminateConnection::Yes } },
     592        { "/error", { HTTPResponse::TerminateConnection::Yes } },
    593593    }, HTTPServer::Protocol::Https, [] (auto, auto, auto certificateAllowed) {
    594594        certificateAllowed(true);
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/MediaLoading.mm

    r272764 r272908  
    2828#import "HTTPServer.h"
    2929#import "PlatformUtilities.h"
     30#import "TestUIDelegate.h"
    3031#import "TestWKWebView.h"
    3132#import <wtf/text/StringConcatenateNumbers.h>
     
    117118}
    118119
     120const char* videoPlayTestHTML ="<script>"
     121    "function createVideoElement() {"
     122        "let video = document.createElement('video');"
     123        "video.addEventListener('error', ()=>{alert('error')});"
     124        "video.addEventListener('playing', ()=>{alert('playing')});"
     125        "video.src='video.mp4';"
     126        "video.autoplay=1;"
     127        "document.body.appendChild(video);"
     128    "}"
     129"</script>"
     130"<body onload='createVideoElement()'></body>";
     131
     132static Vector<uint8_t> testVideoBytes()
     133{
     134    NSData *data = [NSData dataWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"test" withExtension:@"mp4" subdirectory:@"TestWebKitAPI.resources"]];
     135    Vector<uint8_t> vector;
     136    vector.append(static_cast<const uint8_t*>(data.bytes), data.length);
     137    return vector;
    119138}
    120139
     140static void runVideoTest(NSURLRequest *request, const char* expectedMessage = "playing")
     141{
     142    auto configuration = adoptNS([[WKWebViewConfiguration alloc] init]);
     143    configuration.get().mediaTypesRequiringUserActionForPlayback = WKAudiovisualMediaTypeNone;
     144    auto webView = adoptNS([[TestWKWebView alloc] initWithFrame:NSMakeRect(0, 0, 300, 300) configuration:configuration.get() addToWindow:YES]);
     145    [webView loadRequest:request];
     146    EXPECT_WK_STREQ([webView _test_waitForAlert], expectedMessage);
     147}
     148
     149TEST(MediaLoading, RangeRequestSynthesisWithContentLength)
     150{
     151    HTTPServer server({
     152        {"/", { videoPlayTestHTML }},
     153        {"/video.mp4", { testVideoBytes() }}
     154    });
     155    runVideoTest(server.request());
     156    EXPECT_EQ(server.totalRequests(), 2u);
     157}
     158
     159TEST(MediaLoading, RangeRequestSynthesisWithoutContentLength)
     160{
     161    size_t totalRequests { 0 };
     162    Function<void(Connection)> respondToRequests;
     163    respondToRequests = [&] (Connection connection) {
     164        connection.receiveHTTPRequest([&, connection] (Vector<char>&& request) {
     165            auto sendResponse = [&, connection] (HTTPResponse response, HTTPResponse::IncludeContentLength includeContentLength) {
     166                connection.send(response.serialize(includeContentLength), [&, connection] {
     167                    respondToRequests(connection);
     168                });
     169            };
     170            totalRequests++;
     171            auto path = HTTPServer::parsePath(request);
     172            if (path == "/")
     173                sendResponse({ videoPlayTestHTML }, HTTPResponse::IncludeContentLength::Yes);
     174            else if (path == "/video.mp4")
     175                sendResponse(testVideoBytes(), HTTPResponse::IncludeContentLength::No);
     176            else
     177                ASSERT(path.isNull());
     178        });
     179    };
     180
     181    HTTPServer server([&](Connection connection) {
     182        respondToRequests(connection);
     183    });
     184    runVideoTest(server.request(), "error");
     185    EXPECT_EQ(totalRequests, 2u);
     186}
     187
     188} // namespace TestWebKitAPI
     189
    121190#endif // ENABLE(VIDEO) && USE(AVFOUNDATION)
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.h

    r272764 r272908  
    3636
    3737class Connection;
     38struct HTTPResponse;
    3839
    3940class HTTPServer {
    4041public:
    41     struct HTTPResponse;
    4242    struct RequestData;
    4343    enum class Protocol : uint8_t { Http, Https, HttpsWithLegacyTLS, Http2 };
     
    5454    static void respondWithOK(Connection);
    5555    static void respondWithChallengeThenOK(Connection);
     56    static String parsePath(const Vector<char>& request);
    5657
    5758private:
     
    8283};
    8384
    84 struct HTTPServer::HTTPResponse {
     85struct HTTPResponse {
    8586    enum class TerminateConnection { No, Yes };
    86    
     87
     88    HTTPResponse(Vector<uint8_t>&& body)
     89        : body(WTFMove(body)) { }
    8790    HTTPResponse(const String& body)
    88         : body(body) { }
    89     HTTPResponse(HashMap<String, String>&& headerFields, String&& body)
     91        : body(bodyFromString(body)) { }
     92    HTTPResponse(HashMap<String, String>&& headerFields, const String& body)
    9093        : headerFields(WTFMove(headerFields))
    91         , body(WTFMove(body)) { }
    92     HTTPResponse(unsigned statusCode, HashMap<String, String>&& headerFields = { }, String&& body = { })
     94        , body(bodyFromString(body)) { }
     95    HTTPResponse(unsigned statusCode, HashMap<String, String>&& headerFields = { }, const String& body = { })
    9396        : statusCode(statusCode)
    9497        , headerFields(WTFMove(headerFields))
    95         , body(WTFMove(body)) { }
     98        , body(bodyFromString(body)) { }
    9699    HTTPResponse(TerminateConnection terminateConnection)
    97100        : terminateConnection(terminateConnection) { }
     
    102105    HTTPResponse& operator=(const HTTPResponse&) = default;
    103106    HTTPResponse& operator=(HTTPResponse&&) = default;
    104    
     107
     108    enum class IncludeContentLength : bool { No, Yes };
     109    Vector<uint8_t> serialize(IncludeContentLength = IncludeContentLength::Yes);
     110    static Vector<uint8_t> bodyFromString(const String&);
     111
    105112    unsigned statusCode { 200 };
    106113    HashMap<String, String> headerFields;
    107     String body;
     114    Vector<uint8_t> body;
    108115    TerminateConnection terminateConnection { TerminateConnection::No };
    109116};
  • trunk/Tools/TestWebKitAPI/cocoa/HTTPServer.mm

    r272764 r272908  
    3939struct HTTPServer::RequestData : public ThreadSafeRefCounted<RequestData, WTF::DestructionThread::MainRunLoop> {
    4040    RequestData(std::initializer_list<std::pair<String, HTTPResponse>> responses)
    41     : requestMap([](std::initializer_list<std::pair<String, HTTPServer::HTTPResponse>> list) {
    42         HashMap<String, HTTPServer::HTTPResponse> map;
     41    : requestMap([](std::initializer_list<std::pair<String, HTTPResponse>> list) {
     42        HashMap<String, HTTPResponse> map;
    4343        for (auto& pair : list)
    4444            map.add(pair.first, pair.second);
     
    213213}
    214214
     215static void appendUTF8ToVector(Vector<uint8_t>& vector, const String& string)
     216{
     217    auto utf8 = string.utf8();
     218    vector.append(reinterpret_cast<const uint8_t*>(utf8.data()), utf8.length());
     219}
     220
     221String HTTPServer::parsePath(const Vector<char>& request)
     222{
     223    if (!request.size())
     224        return { };
     225    const char* getPathPrefix = "GET ";
     226    const char* postPathPrefix = "POST ";
     227    const char* pathSuffix = " HTTP/1.1\r\n";
     228    const char* pathEnd = strnstr(request.data(), pathSuffix, request.size());
     229    ASSERT_WITH_MESSAGE(pathEnd, "HTTPServer assumes request is HTTP 1.1");
     230    size_t pathPrefixLength = 0;
     231    if (!memcmp(request.data(), getPathPrefix, strlen(getPathPrefix)))
     232        pathPrefixLength = strlen(getPathPrefix);
     233    else if (!memcmp(request.data(), postPathPrefix, strlen(postPathPrefix)))
     234        pathPrefixLength = strlen(postPathPrefix);
     235    ASSERT_WITH_MESSAGE(pathPrefixLength, "HTTPServer assumes request is GET or POST");
     236    size_t pathLength = pathEnd - request.data() - pathPrefixLength;
     237    return String(request.data() + pathPrefixLength, pathLength);
     238}
     239
    215240void HTTPServer::respondToRequests(Connection connection, Ref<RequestData> requestData)
    216241{
     
    220245        requestData->requestCount++;
    221246
    222         const char* getPathPrefix = "GET ";
    223         const char* postPathPrefix = "POST ";
    224         const char* pathSuffix = " HTTP/1.1\r\n";
    225         const char* pathEnd = strnstr(request.data(), pathSuffix, request.size());
    226         ASSERT_WITH_MESSAGE(pathEnd, "HTTPServer assumes request is HTTP 1.1");
    227         size_t pathPrefixLength = 0;
    228         if (!memcmp(request.data(), getPathPrefix, strlen(getPathPrefix)))
    229             pathPrefixLength = strlen(getPathPrefix);
    230         else if (!memcmp(request.data(), postPathPrefix, strlen(postPathPrefix)))
    231             pathPrefixLength = strlen(postPathPrefix);
    232         ASSERT_WITH_MESSAGE(pathPrefixLength, "HTTPServer assumes request is GET or POST");
    233         size_t pathLength = pathEnd - request.data() - pathPrefixLength;
    234         String path(request.data() + pathPrefixLength, pathLength);
     247        auto path = parsePath(request);
    235248        ASSERT_WITH_MESSAGE(requestData->requestMap.contains(path), "This HTTPServer does not know how to respond to a request for %s", path.utf8().data());
    236249
     
    238251        if (response.terminateConnection == HTTPResponse::TerminateConnection::Yes)
    239252            return connection.terminate();
    240         StringBuilder responseBuilder;
    241         responseBuilder.append("HTTP/1.1 ", response.statusCode, ' ', statusText(response.statusCode), "\r\n");
    242         responseBuilder.append("Content-Length: ", response.body.length(), "\r\n");
    243         for (auto& pair : response.headerFields)
    244             responseBuilder.append(pair.key, ": ", pair.value, "\r\n");
    245         responseBuilder.append("\r\n");
    246         responseBuilder.append(response.body);
    247         connection.send(responseBuilder.toString(), [connection, requestData] {
     253
     254        connection.send(response.serialize(), [connection, requestData] {
    248255            respondToRequests(connection, requestData);
    249256        });
     
    333340    Util::run(&cancelled);
    334341    m_connection = nullptr;
     342}
     343
     344Vector<uint8_t> HTTPResponse::bodyFromString(const String& string)
     345{
     346    Vector<uint8_t> vector;
     347    appendUTF8ToVector(vector, string);
     348    return vector;
     349}
     350
     351Vector<uint8_t> HTTPResponse::serialize(IncludeContentLength includeContentLength)
     352{
     353    StringBuilder responseBuilder;
     354    responseBuilder.append("HTTP/1.1 ", statusCode, ' ', statusText(statusCode), "\r\n");
     355    if (includeContentLength == IncludeContentLength::Yes)
     356        responseBuilder.append("Content-Length: ", body.size(), "\r\n");
     357    for (auto& pair : headerFields)
     358        responseBuilder.append(pair.key, ": ", pair.value, "\r\n");
     359    responseBuilder.append("\r\n");
     360   
     361    Vector<uint8_t> bytesToSend;
     362    appendUTF8ToVector(bytesToSend, responseBuilder.toString());
     363    bytesToSend.appendVector(body);
     364    return bytesToSend;
    335365}
    336366
Note: See TracChangeset for help on using the changeset viewer.