blob: 6312e0684297b43c3311e4739b681ab445c33672 [file] [log] [blame]
/*
* Copyright (C) 2015 Apple, Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#import "config.h"
#import "NetworkLoadMetrics.h"
#import "ResourceHandle.h"
#import <pal/spi/cocoa/NSURLConnectionSPI.h>
namespace WebCore {
static MonotonicTime dateToMonotonicTime(NSDate *date)
{
if (auto interval = date.timeIntervalSince1970)
return WallTime::fromRawSeconds(interval).approximateMonotonicTime();
return { };
}
static Box<NetworkLoadMetrics> packageTimingData(MonotonicTime redirectStart, NSDate *fetchStart, NSDate *domainLookupStart, NSDate *domainLookupEnd, NSDate *connectStart, NSDate *secureConnectionStart, NSDate *connectEnd, NSDate *requestStart, NSDate *responseStart, bool reusedTLSConnection, NSString *protocol, uint16_t redirectCount, bool failsTAOCheck, bool hasCrossOriginRedirect)
{
auto timing = Box<NetworkLoadMetrics>::create();
timing->redirectStart = redirectStart;
timing->fetchStart = dateToMonotonicTime(fetchStart);
timing->domainLookupStart = dateToMonotonicTime(domainLookupStart);
timing->domainLookupEnd = dateToMonotonicTime(domainLookupEnd);
timing->connectStart = dateToMonotonicTime(connectStart);
if (reusedTLSConnection && [protocol isEqualToString:@"https"])
timing->secureConnectionStart = reusedTLSConnectionSentinel;
else
timing->secureConnectionStart = dateToMonotonicTime(secureConnectionStart);
timing->connectEnd = dateToMonotonicTime(connectEnd);
timing->requestStart = dateToMonotonicTime(requestStart);
timing->responseStart = dateToMonotonicTime(responseStart);
timing->redirectCount = redirectCount;
timing->failsTAOCheck = failsTAOCheck;
timing->hasCrossOriginRedirect = hasCrossOriginRedirect;
// NOTE: responseEnd is not populated in this code path.
return timing;
}
Box<NetworkLoadMetrics> copyTimingData(NSURLSessionTaskMetrics *incompleteMetrics, const NetworkLoadMetrics& metricsFromTask)
{
NSArray<NSURLSessionTaskTransactionMetrics *> *transactionMetrics = incompleteMetrics.transactionMetrics;
NSURLSessionTaskTransactionMetrics *metrics = transactionMetrics.lastObject;
return packageTimingData(
dateToMonotonicTime(transactionMetrics.firstObject.fetchStartDate),
metrics.fetchStartDate,
metrics.domainLookupStartDate,
metrics.domainLookupEndDate,
metrics.connectStartDate,
metrics.secureConnectionStartDate,
metrics.connectEndDate,
metrics.requestStartDate,
metrics.responseStartDate,
metrics.reusedConnection,
metrics.response.URL.scheme,
incompleteMetrics.redirectCount,
metricsFromTask.failsTAOCheck,
metricsFromTask.hasCrossOriginRedirect
);
}
Box<NetworkLoadMetrics> copyTimingData(NSURLConnection *connection, const ResourceHandle& handle)
{
NSDictionary *timingData = [connection _timingData];
auto timingValue = [&](NSString *key) -> RetainPtr<NSDate> {
if (NSNumber *number = [timingData objectForKey:key]) {
if (double doubleValue = number.doubleValue)
return adoptNS([[NSDate alloc] initWithTimeIntervalSinceReferenceDate:doubleValue]);
}
return { };
};
auto data = packageTimingData(
handle.startTimeBeforeRedirects(),
timingValue(@"_kCFNTimingDataFetchStart").get(),
timingValue(@"_kCFNTimingDataDomainLookupStart").get(),
timingValue(@"_kCFNTimingDataDomainLookupEnd").get(),
timingValue(@"_kCFNTimingDataConnectStart").get(),
timingValue(@"_kCFNTimingDataSecureConnectionStart").get(),
timingValue(@"_kCFNTimingDataConnectEnd").get(),
timingValue(@"_kCFNTimingDataRequestStart").get(),
timingValue(@"_kCFNTimingDataResponseStart").get(),
timingValue(@"_kCFNTimingDataConnectionReused").get(),
connection.currentRequest.URL.scheme,
handle.redirectCount(),
handle.failsTAOCheck(),
handle.hasCrossOriginRedirect()
);
if (!data->fetchStart)
data->fetchStart = data->redirectStart;
return data;
}
}