TimeSinceEpoch is not correct
rickywei opened this issue · comments
It seems that the time should multiply time.Millisecond (1e6) rather than time.Second (1e9)
The corresponding code in cdproto are https://github.com/chromedp/cdproto/blob/8501c74e8228308e0dbd4aedb1f24ea1c103dd6e/network/types.go#LL1027
and
https://github.com/chromedp/cdproto/blob/8501c74e8228308e0dbd4aedb1f24ea1c103dd6e/cdp/types.go#L742
The following code snapshot is what I tried
package main
import (
"fmt"
"time"
)
func main() {
// a response time from cdp log
t := 1.685446691349539e+12
// correct time 2023-05-30 19:38:11.349539072 +0800 CST
fmt.Println(time.Unix(0, int64(t*float64(time.Millisecond))))
// wrong time 1677-09-21 08:12:43.145224192 +0800 CST
fmt.Println(time.Unix(0, int64(t*float64(time.Second))))
}
@rickywei Thanks for bringing this to my attention. I'll look at this. I don't recall specifically why I implemented this as I did at the time, except to mention that the behavior has at time been incorrect on Chromium's code base, and documented incorrectly.
In the interim, I'd suggest just multiplying the time value if you need the different value at the moment.
@rickywei I've changed this, but I'm not yet going to update this on the chromedp
package. In the interim, you can update to the latest cdproto
package. I will need to do some testing against the many other places TimeSinceEpoch
is used to determine if this is sound/correct, or it's only with the network.Response
type where this differs.
Good morning Ken!
I checked the Network.requestWillBeSent
and Network.responseReceived
events, only response.responseTime
in Network.responseReceived
contains the number of milliseconds (which is conflicted with the document).
- Network.requestWillBeSent
- wallTime
- Network.responseReceived
- response.responseTime
- response.securityDetails.validFrom
- response.securityDetails.validTo
Network.requestWillBeSent (truncated)
{
"requestId": "4393E3633F10D1113C22E7A368A550C4",
"loaderId": "4393E3633F10D1113C22E7A368A550C4",
"documentURL": "https://bing.com/",
"request": {
"url": "https://bing.com/",
"method": "GET"
},
"timestamp": 13720.870149,
"wallTime": 1685659975.297646
}
Network.responseReceived (truncated):
{
"type": "Document",
"response": {
"url": "https://cn.bing.com/",
"status": 200,
"statusText": "",
"responseTime": 1685659975757.947,
"securityDetails": {
"protocol": "TLS 1.2",
"keyExchange": "ECDHE_RSA",
"keyExchangeGroup": "P-384",
"cipher": "AES_256_GCM",
"certificateId": 0,
"subjectName": "www.bing.com",
"issuer": "Microsoft RSA TLS CA 02",
"validFrom": 1676519265,
"validTo": 1692157665
}
}
}
@ZekeLu much appreciated. I haven't had time to go through all the places where there are timestamps in the cdproto
code to check everything. Obviously before tagging anything, this should be done, and confirmed. My greatest concern is with the input.*
events, as those are likely being used by actual complex programs.
I will try to go through all of them today.
@ZekeLu you're amazing man. I appreciate the help!
Below is the full list of the places where Network.TimeSinceEpoch
or Input.TimeSinceEpoch
are used. Among them, only Response.responseTime
does not carry the correct value (in respect of the CDP doc).
Please note that I'm not familiar with Chromium, and the listed Chromium Implementation could be wrong. But I think it's enough for finding out whether the implementation is consistent with the CDP doc.
Network.TimeSinceEpoch
- CDP doc: Network.TimeSinceEpoch
- cdproto package: cdp.TimeSinceEpoch
Seq | CDP doc | Chromium Implementation | cdproto package | Chromium |
---|---|---|---|---|
1 | Network Response responseTime |
response.ResponseTime().ToJsTimeIgnoringNull() |
network Response ResponseTime |
BuildObjectForResourceResponse |
2 | Network SecurityDetails validFrom validTo |
ssl_info.cert->valid_start().ToDoubleT() ssl_info.cert->valid_expiry().ToDoubleT() |
network SecurityDetails ValidFrom ValidTo |
BuildSecurityDetails |
3 | Network requestWillBeSent wallTime |
base::Time::Now().ToDoubleT() |
network EventRequestWillBeSent WallTime |
InspectorNetworkAgent:: WillSendRequestInternal |
4 | Network webSocketWillSendHandshakeRequest wallTime |
base::Time::Now().ToDoubleT() |
network EventWebSocketWillSendHandshakeRequest WallTime |
InspectorNetworkAgent:: WillSendWebSocketHandshakeRequest |
5 | Page OriginTrialToken expiryTime |
blink_trial_token.expiry_time().ToDoubleT() |
cdp OriginTrialToken ExpiryTime |
CreateOriginTrialToken |
6 | Page FrameResource lastModified |
last_modified.value().ToDoubleT() |
page FrameResource LastModified |
InspectorPageAgent:: BuildObjectForResourceTree |
7 | Page ScreencastFrameMetadata timestamp |
base::Time::Now().ToDoubleT() |
page ScreencastFrameMetadata Timestamp |
BuildScreencastFrameMetadata |
8 | Security CertificateSecurityState validFrom validTo |
state.certificate->valid_start().ToDoubleT() state.certificate->valid_expiry().ToDoubleT() |
security CertificateSecurityState ValidFrom ValidTo |
CreateCertificateSecurityState |
9 | Storage interestGroupAccessed accessTime |
access_time.ToDoubleT() |
storage EventInterestGroupAccessed AccessTime |
StorageHandler:: OnInterestGroupAccessed |
10 | Storage sharedStorageAccessed accessTime |
access_time.ToDoubleT() |
storage EventSharedStorageAccessed AccessTime |
StorageHandler:: NotifySharedStorageAccessed |
11 | Storage InterestGroupDetails expirationTime |
group.expiry.ToDoubleT() |
storage InterestGroupDetails ExpirationTime |
SendGetInterestGroup |
418 | Storage SharedStorageMetadata creationTime |
metadata.creation_time.ToDoubleT() |
storage SharedStorageMetadata CreationTime |
SendSharedStorageMetadata |
420 | Storage StorageBucketInfo expiration |
bucket.expiration.ToDoubleT() |
storage BucketInfo Expiration |
BuildBucketInfo |
14 | BackgroundService BackgroundServiceEvent Timestamp |
timestamp.ToJsTime() / 1'000 |
backgroundservice Event Timestamp |
ToBackgroundServiceEvent |
15 | Network ReportingApiReport timestamp |
(report.queued - base::TimeTicks::UnixEpoch()).InSecondsF()) |
network ReportingAPIReport Timestamp |
NetworkHandler:: BuildProtocolReport |
16 | PerformanceTimeline LargestContentfulPaint renderTime loadTime |
ToProtocolTime(timeOrigin, lcp.renderTime()) ToProtocolTime(timeOrigin, lcp.loadTime()) |
performancetimeline LargestContentfulPaint RenderTime LoadTime |
BuildEventDetails |
17 | PerformanceTimeline LayoutShift lastInputTime |
ToProtocolTime(timeOrigin, ls.lastInputTime()) |
performancetimeline LayoutShift LastInputTime |
BuildEventDetails |
18 | PerformanceTimeline TimelineEvent time |
ToProtocolTime(timeOrigin, entry->startTime()) |
performancetimeline TimelineEvent Time |
BuildProtocolEvent |
19 | Emulation setVirtualTimePolicy initialVirtualTime |
base::Time::FromDoubleT(initial_virtual_time.fromJust()) |
emulation SetVirtualTimePolicyParams InitialVirtualTime |
InspectorEmulationAgent:: setVirtualTimePolicy |
20 | Network setCookie expires |
MakeCookieFromProtocolValues |
network SetCookieParams Expires |
NetworkHandler:: SetCookie |
21 | Network CookieParam expires |
MakeCookieFromProtocolValues |
network CookieParam Expires |
NetworkHandler:: SetCookies |
double ToProtocolTime(DOMHighResTimeStamp timeOrigin,
DOMHighResTimeStamp time) {
return time ? ConvertDOMHighResTimeStampToSeconds(timeOrigin + time) : 0.0;
}
if (expires >= 0) {
expiration_date =
expires ? base::Time::FromDoubleT(expires) : base::Time::UnixEpoch();
}
Input.TimeSinceEpoch
- CDP doc: Input.TimeSinceEpoch
- cdproto package: input.TimeSinceEpoch
Seq | CDP doc | Chromium Implementation | cdproto package | Chromium |
---|---|---|---|---|
1 | Input dispatchKeyEvent timestamp |
GetEventTimeTicks(timestamp) |
input DispatchKeyEventParams Timestamp |
InputHandler:: DispatchKeyEvent |
2 | Input dispatchMouseEvent timestamp |
GetEventTimeTicks(timestamp) |
input DispatchMouseEventParams Timestamp |
CreateWebMouseEvent |
3 | Input dispatchTouchEvent timestamp |
GetEventTimeTicks(timestamp) |
input DispatchTouchEventParams Timestamp |
CreateWebTouchEvents |
4 | Input emulateTouchFromMouseEvent timestamp |
GetEventTimeTicks(timestamp) |
input EmulateTouchFromMouseEventParams Timestamp |
InputHandler:: EmulateTouchFromMouseEvent |
base::TimeTicks GetEventTimeTicks(const Maybe<double>& timestamp) {
// Convert timestamp, in seconds since unix epoch, to an event timestamp
// which is time ticks since platform start time.
return timestamp.isJust() ? base::Seconds(timestamp.fromJust()) +
base::TimeTicks::UnixEpoch()
: base::TimeTicks::Now();
}
We can add some code to correct responseTime
for the cdproto
users. But since this issue is not noticed for a long time, I think it's OK to leave it as what it is now and just wait for the upstream (Chromium) to fix it. BTW, I have just reported the issue to the Chromium team: https://bugs.chromium.org/p/chromium/issues/detail?id=1451082.
@ZekeLu in your opinion should we revert/change back the Millisecond
resolution on pdlgen
/cdproto-gen
?
@ZekeLu There are other possibilities as well: we can manually mark certain fields in the generator's fixup
package, and add an additional field to the TimeSinceEpoch
that tells the resolution. Alternately, I can write some code that tries to "guess" what the time is supposed to be, based on how large/small the value is.
Hi Ken. Yes I think we should revert the Millisecond
resolution on pdlgen
because the initial implementation is correct. And only responseTime
in the Response
type is wrong.
Alternately, I can write some code that tries to "guess" what the time is supposed to be, based on how large/small the value is
This is what came up to my mind too.
I think it's better to limit the change to the responseTime
field only. But I can not find a easy fix to pdlgen
to do this.
I just pushed a commit to cdproto
that uses a different type just for the responseTime
field (cdp.TimeSinceEpochMilli
). It has the same interface as cdp.TimeSinceEpoch
, but uses millisecond resolution. Should the Chromium code change, this will need to be change accordingly.
@ZekeLu if you can check this out, assuming all the various time times are correct, we should tag a new version of chromedp
with the updated cdproto
dependency.
Thank you @kenshaw ! I have sent a PR to upgrade cdproto. And I have modified an existing test to check the responseTime
so that we will be noticed once chromium fixed the issue.
If you're OK with the PR, I will tag a new release as 0.9.2
.
https://bugs.chromium.org/p/chromium/issues/detail?id=1451082 is closed as "WontFix". So it's good to go with cdp.TimeSinceEpochMilli
. I'm going to tag a new release.