@@ -203,37 +203,33 @@ int ConvertErrorCode(CURLcode curl_code) {
203203 }
204204}
205205
206- /* *
207- * @brief CURL get upload/download data.
208- * @param[in] handle CURL easy handle.
209- * @param[out] upload_bytes uploaded bytes(headers+data).
210- * @param[out] download_bytes downloaded bytes(headers+data).
211- */
212206void GetTrafficData (CURL* handle, uint64_t & upload_bytes,
213- uint64_t & download_bytes) {
207+ uint64_t & download_headers_size,
208+ uint64_t & download_body_bytes) {
214209 upload_bytes = 0 ;
215- download_bytes = 0 ;
210+ download_headers_size = 0 ;
211+ download_body_bytes = 0 ;
216212
217213 long headers_size;
218214 if (curl_easy_getinfo (handle, CURLINFO_HEADER_SIZE, &headers_size) ==
219215 CURLE_OK &&
220216 headers_size > 0 ) {
221- download_bytes + = headers_size;
217+ download_headers_size = headers_size;
222218 }
223219
224220#if CURL_AT_LEAST_VERSION(7, 55, 0)
225221 off_t length_downloaded = 0 ;
226222 if (curl_easy_getinfo (handle, CURLINFO_SIZE_DOWNLOAD_T, &length_downloaded) ==
227223 CURLE_OK &&
228224 length_downloaded > 0 ) {
229- download_bytes + = length_downloaded;
225+ download_body_bytes = length_downloaded;
230226 }
231227#else
232228 double length_downloaded;
233229 if (curl_easy_getinfo (handle, CURLINFO_SIZE_DOWNLOAD, &length_downloaded) ==
234230 CURLE_OK &&
235231 length_downloaded > 0.0 ) {
236- download_bytes += length_downloaded;
232+ download_body_bytes += length_downloaded;
237233 }
238234#endif
239235
@@ -357,6 +353,85 @@ const char* MethodName(NetworkRequest::HttpVerb verb) {
357353 return " UNKNOWN" ;
358354}
359355
356+ SessionRecording::Timings GetTimings (CURL* handle) {
357+ using Microseconds = SessionRecording::MicroSeconds;
358+
359+ SessionRecording::Timings timings{};
360+
361+ long queue_time_us = 0 ;
362+ #if CURL_AT_LEAST_VERSION(8, 6, 0)
363+ if (curl_easy_getinfo (handle, CURLINFO_QUEUE_TIME_T, &queue_time_us) ==
364+ CURLE_OK &&
365+ queue_time_us > 0 ) {
366+ timings.queue_time = Microseconds (queue_time_us);
367+ }
368+ #else
369+ timings.queue_time = Microseconds (queue_time_us);
370+ #endif
371+
372+ // 7.61.0
373+ long name_lookup_us = 0 ;
374+ if (curl_easy_getinfo (handle, CURLINFO_NAMELOOKUP_TIME_T, &name_lookup_us) ==
375+ CURLE_OK &&
376+ name_lookup_us > 0 ) {
377+ timings.name_lookup_time = Microseconds (name_lookup_us);
378+ }
379+
380+ // 7.61.0
381+ long connect_time_us = 0 ;
382+ if (curl_easy_getinfo (handle, CURLINFO_CONNECT_TIME_T, &connect_time_us) ==
383+ CURLE_OK &&
384+ connect_time_us > 0 ) {
385+ timings.connect_time = Microseconds (connect_time_us);
386+ }
387+
388+ // 7.61.0
389+ long app_connect_time_us = 0 ;
390+ if (curl_easy_getinfo (handle, CURLINFO_APPCONNECT_TIME_T,
391+ &app_connect_time_us) == CURLE_OK &&
392+ app_connect_time_us > 0 ) {
393+ timings.app_connect_time = Microseconds (app_connect_time_us);
394+ }
395+
396+ // 7.61.0
397+ long pre_transfer_time_us = 0 ;
398+ if (curl_easy_getinfo (handle, CURLINFO_PRETRANSFER_TIME_T,
399+ &pre_transfer_time_us) == CURLE_OK &&
400+ pre_transfer_time_us > 0 ) {
401+ timings.pre_transfer_time = Microseconds (pre_transfer_time_us);
402+ }
403+
404+ // 7.61.0
405+ long start_transfer_time_us = 0 ;
406+ if (curl_easy_getinfo (handle, CURLINFO_STARTTRANSFER_TIME_T,
407+ &start_transfer_time_us) == CURLE_OK &&
408+ start_transfer_time_us > 0 ) {
409+ timings.start_transfer_time = Microseconds (start_transfer_time_us);
410+ }
411+
412+ // 8.10.0
413+ #if CURL_AT_LEAST_VERSION(8, 10, 0)
414+ long post_transfer_time_us = 0 ;
415+ if (curl_easy_getinfo (handle, CURLINFO_POSTTRANSFER_TIME_T,
416+ &post_transfer_time_us) == CURLE_OK &&
417+ post_transfer_time_us > 0 ) {
418+ timings.post_transfer_time = Microseconds (post_transfer_time_us);
419+ }
420+ #else
421+ timings.post_transfer_time = timings.start_transfer_time ;
422+ #endif
423+
424+ // 7.61.0
425+ long total_time_us = 0 ;
426+ if (curl_easy_getinfo (handle, CURLINFO_TOTAL_TIME_T, &total_time_us) ==
427+ CURLE_OK &&
428+ total_time_us > 0 ) {
429+ timings.total_time = Microseconds (total_time_us);
430+ }
431+
432+ return timings;
433+ }
434+
360435} // anonymous namespace
361436
362437NetworkCurl::NetworkCurl (NetworkInitializationSettings settings)
@@ -386,6 +461,8 @@ NetworkCurl::NetworkCurl(NetworkInitializationSettings settings)
386461 }
387462 }
388463
464+ session_recording_.emplace (SessionRecording ());
465+
389466#ifdef OLP_SDK_CURL_HAS_SUPPORT_SSL_BLOBS
390467 SetupCertificateBlobs ();
391468#else
@@ -437,6 +514,11 @@ NetworkCurl::~NetworkCurl() {
437514 if (stderr_) {
438515 fclose (stderr_);
439516 }
517+ if (session_recording_) {
518+ session_recording_->locked ([](const SessionRecording& recording) {
519+ recording.ArchiveToFile (" /tmp/test.har" );
520+ });
521+ }
440522}
441523
442524bool NetworkCurl::Initialize () {
@@ -672,6 +754,14 @@ ErrorCode NetworkCurl::SendImplementation(
672754 handle->request_body = request.GetBody ();
673755 handle->request_headers = SetupHeaders (request.GetHeaders ());
674756
757+ if (session_recording_) {
758+ session_recording_->locked ([&](SessionRecording& recording) {
759+ recording.SetRequestParameters (
760+ id, handle->request_url , request.GetVerb (), request.GetHeaders (),
761+ handle->request_body ? handle->request_body ->size () : 0 );
762+ });
763+ }
764+
675765 OLP_SDK_LOG_DEBUG (kLogTag ,
676766 " Send request with url="
677767 << utils::CensorCredentialsInUrl (request.GetUrl ())
@@ -876,13 +966,21 @@ NetworkCurl::RequestHandle* NetworkCurl::InitRequestHandle() {
876966
877967void NetworkCurl::ReleaseHandleUnlocked (RequestHandle* handle,
878968 bool cleanup_easy_handle) {
969+ // Reset the RequestHandle to defaults, but keep the curl_handle and
970+ // response_headers allocated buffer.
879971 std::shared_ptr<CURL> curl_handle;
972+ std::vector<std::pair<std::string, std::string>> response_headers;
973+
880974 std::swap (curl_handle, handle->curl_handle );
975+ std::swap (response_headers, handle->response_headers );
881976
977+ response_headers.clear ();
882978 curl_easy_reset (curl_handle.get ());
979+
883980 *handle = RequestHandle{};
884981
885982 std::swap (curl_handle, handle->curl_handle );
983+ std::swap (response_headers, handle->response_headers );
886984
887985 // When using C-Ares on Android, DNS parameters are calculated in
888986 // curl_easy_init(). Those parameters are not reset in curl_easy_reset(...),
@@ -895,7 +993,7 @@ void NetworkCurl::ReleaseHandleUnlocked(RequestHandle* handle,
895993
896994#if defined(ANDROID)
897995 if (cleanup_easy_handle) {
898- handle->handle = nullptr ;
996+ handle->curl_handle = nullptr ;
899997 }
900998#endif
901999 OLP_SDK_CORE_UNUSED (cleanup_easy_handle);
@@ -994,6 +1092,7 @@ size_t NetworkCurl::HeaderFunction(char* ptr, size_t size, size_t nitems,
9941092
9951093 // Callback with header key+value
9961094 handle->out_header_callback (key, value);
1095+ handle->response_headers .emplace_back (std::move (key), std::move (value));
9971096
9981097 return len;
9991098}
@@ -1025,13 +1124,16 @@ void NetworkCurl::CompleteMessage(CURL* curl_handle, CURLcode result) {
10251124 }
10261125
10271126 uint64_t upload_bytes = 0u ;
1028- uint64_t download_bytes = 0u ;
1029- GetTrafficData (curl_handle, upload_bytes, download_bytes);
1127+ uint64_t download_headers_bytes = 0u ;
1128+ uint64_t download_body_bytes = 0u ;
1129+ GetTrafficData (curl_handle, upload_bytes, download_headers_bytes,
1130+ download_body_bytes);
10301131
1031- auto response = NetworkResponse ()
1032- .WithRequestId (request_handle->id )
1033- .WithBytesDownloaded (download_bytes)
1034- .WithBytesUploaded (upload_bytes);
1132+ auto response =
1133+ NetworkResponse ()
1134+ .WithRequestId (request_handle->id )
1135+ .WithBytesDownloaded (download_headers_bytes + download_body_bytes)
1136+ .WithBytesUploaded (upload_bytes);
10351137
10361138 if (request_handle->cancelled ) {
10371139 response.WithStatus (static_cast <int >(ErrorCode::CANCELLED_ERROR))
@@ -1074,19 +1176,44 @@ void NetworkCurl::CompleteMessage(CURL* curl_handle, CURLcode result) {
10741176 const char * url;
10751177 curl_easy_getinfo (curl_handle, CURLINFO_EFFECTIVE_URL, &url);
10761178
1077- OLP_SDK_LOG_DEBUG (
1078- kLogTag , " Message completed, id="
1079- << request_handle->id << " , url='"
1080- << utils::CensorCredentialsInUrl (url) << " ', status=("
1081- << status << " ) " << error
1082- << " , time=" << GetElapsedTime (request_handle->send_time )
1083- << " ms, bytes=" << download_bytes + upload_bytes);
1179+ if (session_recording_) {
1180+ long http_version = 0 ;
1181+ curl_easy_getinfo (curl_handle, CURLINFO_HTTP_VERSION, &http_version);
1182+
1183+ if (http_version == CURL_HTTP_VERSION_1_0 ||
1184+ http_version == CURL_HTTP_VERSION_1_1) {
1185+ http_version = 1 ;
1186+ } else if (http_version == CURL_HTTP_VERSION_2_0 ||
1187+ http_version == CURL_HTTP_VERSION_2TLS ||
1188+ http_version == CURL_HTTP_VERSION_2_PRIOR_KNOWLEDGE) {
1189+ http_version = 2 ;
1190+ } else {
1191+ http_version = 0 ;
1192+ }
10841193
1085- response.WithStatus (status).WithError (error);
1194+ const char * content_type;
1195+ curl_easy_getinfo (curl_handle, CURLINFO_CONTENT_TYPE, &content_type);
10861196
1087- if (harfile_ != nullptr ) {
1197+ session_recording_->locked ([&](SessionRecording& recording) {
1198+ recording.SetResponseParameters (
1199+ request_handle->id , static_cast <int >(http_version), status,
1200+ request_handle->response_headers , content_type,
1201+ download_headers_bytes, download_body_bytes);
1202+ recording.SetRequestTimings (request_handle->id , GetTimings (curl_handle));
1203+ });
10881204 }
10891205
1206+ OLP_SDK_LOG_DEBUG (
1207+ kLogTag ,
1208+ " Message completed, id="
1209+ << request_handle->id << " , url='"
1210+ << utils::CensorCredentialsInUrl (url) << " ', status=(" << status
1211+ << " ) " << error << " , time="
1212+ << GetElapsedTime (request_handle->send_time ) << " ms, bytes="
1213+ << download_headers_bytes + download_body_bytes + upload_bytes);
1214+
1215+ response.WithStatus (status).WithError (error);
1216+
10901217 ReleaseHandleUnlocked (request_handle, cleanup_easy_handle);
10911218
10921219 lock.unlock ();
@@ -1223,15 +1350,18 @@ void NetworkCurl::Run() {
12231350 lock.unlock ();
12241351
12251352 uint64_t upload_bytes = 0u ;
1226- uint64_t download_bytes = 0u ;
1227- GetTrafficData (curl_handle, upload_bytes, download_bytes);
1353+ uint64_t download_headers_bytes = 0u ;
1354+ uint64_t download_body_bytes = 0u ;
1355+ GetTrafficData (curl_handle, upload_bytes, download_headers_bytes,
1356+ download_body_bytes);
12281357
12291358 auto response =
12301359 NetworkResponse ()
12311360 .WithRequestId (request_handle->id )
12321361 .WithStatus (static_cast <int >(ErrorCode::IO_ERROR))
12331362 .WithError (" CURL error" )
1234- .WithBytesDownloaded (download_bytes)
1363+ .WithBytesDownloaded (download_headers_bytes +
1364+ download_body_bytes)
12351365 .WithBytesUploaded (upload_bytes);
12361366 callback (response);
12371367 lock.lock ();
0 commit comments