11/*
2- * Copyright (C) 2019-2024 HERE Europe B.V.
2+ * Copyright (C) 2019-2026 HERE Europe B.V.
33 *
44 * Licensed under the Apache License, Version 2.0 (the "License");
55 * you may not use this file except in compliance with the License.
1919
2020#import " OLPHttpTask+Internal.h"
2121
22+ #include < limits>
23+
2224#include < olp/core/http/HttpStatusCode.h>
2325#include < olp/core/logging/Log.h>
26+ #include < olp/core/porting/optional.h>
2427
2528#import " OLPHttpClient+Internal.h"
2629#import " OLPNetworkConstants.h"
2730
2831namespace {
2932constexpr auto kLogTag = " OLPHttpTask" ;
33+
34+ constexpr uint64_t kMicrosecondsInSecond = 1000000u ;
35+
36+ uint64_t DurationInMicroseconds (NSDate * start, NSDate * end) {
37+ if (!start || !end) {
38+ return 0u ;
39+ }
40+
41+ const NSTimeInterval time_interval = [end timeIntervalSinceDate: start];
42+ if (time_interval <= 0.0 ) {
43+ return 0u ;
44+ }
45+
46+ return static_cast <uint64_t >(time_interval * kMicrosecondsInSecond );
47+ }
48+
49+ void AddTiming (olp::http::Diagnostics& diagnostics,
50+ olp::http::Diagnostics::Timings timing,
51+ const uint64_t time_in_microseconds) {
52+ if (time_in_microseconds == 0u ) {
53+ return ;
54+ }
55+
56+ const auto previous_duration =
57+ static_cast <uint64_t >(diagnostics.timings [timing].count ());
58+ const auto updated_duration = previous_duration + time_in_microseconds;
59+ const auto clamped_duration =
60+ std::min (updated_duration,
61+ static_cast <uint64_t >(std::numeric_limits<uint32_t >::max ()));
62+
63+ diagnostics.timings [timing] = olp::http::Diagnostics::MicroSeconds (
64+ static_cast <uint32_t >(clamped_duration));
65+ diagnostics.available_timings .set (timing);
66+ }
67+
68+ olp::http::Diagnostics BuildDiagnostics (NSURLSessionTaskMetrics * metrics) {
69+ olp::http::Diagnostics diagnostics;
70+ if (!metrics) {
71+ return diagnostics;
72+ }
73+
74+ NSDate * previous_response_end = metrics.taskInterval .startDate ;
75+ for (NSURLSessionTaskTransactionMetrics * transaction in metrics
76+ .transactionMetrics ) {
77+ AddTiming (diagnostics, olp::http::Diagnostics::Queue,
78+ DurationInMicroseconds (previous_response_end,
79+ transaction.fetchStartDate ));
80+
81+ AddTiming (diagnostics, olp::http::Diagnostics::NameLookup,
82+ DurationInMicroseconds (transaction.domainLookupStartDate ,
83+ transaction.domainLookupEndDate ));
84+
85+ const auto connect_duration = DurationInMicroseconds (
86+ transaction.connectStartDate , transaction.connectEndDate );
87+ const auto tls_duration =
88+ DurationInMicroseconds (transaction.secureConnectionStartDate ,
89+ transaction.secureConnectionEndDate );
90+ if (connect_duration >= tls_duration) {
91+ AddTiming (diagnostics, olp::http::Diagnostics::Connect,
92+ connect_duration - tls_duration);
93+ } else {
94+ AddTiming (diagnostics, olp::http::Diagnostics::Connect, connect_duration);
95+ }
96+
97+ AddTiming (diagnostics, olp::http::Diagnostics::SSL_Handshake, tls_duration);
98+
99+ AddTiming (diagnostics, olp::http::Diagnostics::Send,
100+ DurationInMicroseconds (transaction.requestStartDate ,
101+ transaction.requestEndDate ));
102+
103+ AddTiming (diagnostics, olp::http::Diagnostics::Wait,
104+ DurationInMicroseconds (transaction.requestEndDate ,
105+ transaction.responseStartDate ));
106+
107+ AddTiming (diagnostics, olp::http::Diagnostics::Receive,
108+ DurationInMicroseconds (transaction.responseStartDate ,
109+ transaction.responseEndDate ));
110+
111+ if (transaction.responseEndDate ) {
112+ previous_response_end = transaction.responseEndDate ;
113+ }
114+ }
115+
116+ AddTiming (diagnostics, olp::http::Diagnostics::Total,
117+ DurationInMicroseconds (metrics.taskInterval .startDate ,
118+ metrics.taskInterval .endDate ));
119+
120+ return diagnostics;
121+ }
30122} // namespace
31123
32124#pragma mark - OLPHttpTaskResponseData
@@ -59,6 +151,7 @@ @implementation OLPHttpTask {
59151 uint64_t _headersSizeReceived;
60152 uint64_t _headersSizeSent;
61153 uint64_t _contentLength;
154+ olp::porting::optional<olp::http::Diagnostics> _diagnostics;
62155}
63156
64157- (instancetype )initWithHttpClient : (OLPHttpClient*)client
@@ -73,6 +166,7 @@ - (instancetype)initWithHttpClient:(OLPHttpClient*)client
73166 _headersSizeReceived = 0 ;
74167 _headersSizeSent = 0 ;
75168 _contentLength = 0 ;
169+ _diagnostics = {};
76170 _backgroundMode = false ;
77171 }
78172 return self;
@@ -105,6 +199,8 @@ - (OLPHttpTaskStatus)restart {
105199 _dataTask = nil ;
106200 }
107201
202+ _diagnostics = {};
203+
108204 NSMutableURLRequest * request =
109205 [NSMutableURLRequest requestWithURL: [NSURL URLWithString: self .url]];
110206 request.timeoutInterval = self.connectionTimeout ;
@@ -264,6 +360,27 @@ - (void)didReceiveData:(NSData*)data withWholeData:(bool)wholeData {
264360 }
265361}
266362
363+ - (void )didCollectMetrics : (NSURLSessionTaskMetrics *)metrics {
364+ const auto diagnostics = BuildDiagnostics (metrics);
365+ if (!diagnostics.available_timings .any ()) {
366+ return ;
367+ }
368+
369+ @synchronized (self) {
370+ _diagnostics = diagnostics;
371+ }
372+ }
373+
374+ - (BOOL )getDiagnostics : (olp::http::Diagnostics&)diagnostics {
375+ @synchronized (self) {
376+ if (!_diagnostics) {
377+ return NO ;
378+ }
379+ diagnostics = *_diagnostics;
380+ return YES ;
381+ }
382+ }
383+
267384- (NSString *)createTaskDescription {
268385 return [NSString stringWithFormat: @" %llu " , self .requestId];
269386}
0 commit comments