Skip to content

Commit 1d3355c

Browse files
committed
Fix client error timings further for multi-request connections
The previous fix handled simple cases OK, but assumed a request started when the connection started, which isn't true for various cases. This is starting to get overly precise about poorly defined details really, but still - it's better if we use the time of the preceeding request as the start, if there was one (either the start of this incomplete request, or the previous request as a rough benchmark).
1 parent 6c83f42 commit 1d3355c

File tree

3 files changed

+40
-16
lines changed

3 files changed

+40
-16
lines changed

src/server/mockttp-server.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { Buffer } from 'buffer';
22
import * as net from "net";
3-
import * as url from "url";
43
import * as tls from "tls";
54
import * as http from "http";
65
import * as http2 from "http2";
@@ -62,7 +61,8 @@ import {
6261
buildRawSocketEventData,
6362
buildTlsSocketEventData,
6463
isSocketLoop,
65-
resetOrDestroy
64+
resetOrDestroy,
65+
buildSocketErrorRequestTimings
6666
} from "../util/socket-util";
6767
import {
6868
ClientErrorInProgress,
@@ -708,6 +708,12 @@ export class MockttpServer extends AbstractMockttp implements Mockttp {
708708
startTimestamp: now()
709709
};
710710

711+
// Set/update the last request time on the socket
712+
let socketTimingInfo = req.socket[SocketTimingInfo];
713+
if (socketTimingInfo) {
714+
socketTimingInfo.lastRequestTimestamp = timingEvents.startTimestamp;
715+
}
716+
711717
req.on('end', () => {
712718
timingEvents.bodyReceivedTimestamp ||= now();
713719
});
@@ -1090,13 +1096,7 @@ ${await this.suggestRule(request)}`
10901096
`client-error:${error.code || 'UNKNOWN'}`,
10911097
...getSocketMetadataTags(socket[SocketMetadata])
10921098
],
1093-
timingEvents: (socket?.[SocketTimingInfo]
1094-
? {
1095-
startTime: socket[SocketTimingInfo].initialSocket,
1096-
startTimestamp: socket[SocketTimingInfo].initialSocketTimestamp
1097-
}
1098-
: { startTime: Date.now(), startTimestamp: now() }
1099-
) as TimingEvents
1099+
timingEvents: buildSocketErrorRequestTimings(socket)
11001100
};
11011101

11021102
const rawPacket = socket[ClientErrorInProgress]?.rawPacket
@@ -1190,13 +1190,7 @@ ${await this.suggestRule(request)}`
11901190
? pairFlatRawHeaders(error.badRequest?.rawHeaders as string[])
11911191
: error.badRequest?.rawHeaders as RawHeaders | undefined;
11921192

1193-
const timingEvents: TimingEvents = socket?.[SocketTimingInfo]
1194-
? {
1195-
startTime: socket[SocketTimingInfo].initialSocket,
1196-
startTimestamp: socket[SocketTimingInfo].initialSocketTimestamp
1197-
}
1198-
: { startTime: Date.now(), startTimestamp: now() };
1199-
1193+
const timingEvents = buildSocketErrorRequestTimings(socket);
12001194
timingEvents.abortedTimestamp = now();
12011195

12021196
this.announceClientErrorAsync(session.initialSocket, {

src/util/socket-extensions.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ declare module 'net' {
5454
initialSocketTimestamp: number;
5555
tunnelSetupTimestamp?: number; // Latest CONNECT completion, if any
5656
tlsConnectedTimestamp?: number; // Latest TLS handshake completion, if any
57+
lastRequestTimestamp?: number; // Latest request or websocket request time, if any
5758
}
5859

5960
// Set on TLSSocket, defined here for convenient access on _all_ sockets

src/util/socket-util.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { isNode } from './util';
99
import {
1010
OngoingRequest,
1111
RawPassthroughEvent,
12+
TimingEvents,
1213
TlsConnectionEvent
1314
} from '../types';
1415
import {
@@ -210,3 +211,31 @@ export function buildSocketTimingInfo(): Required<net.Socket>[typeof SocketTimin
210211
return { initialSocket: Date.now(), initialSocketTimestamp: now() };
211212
}
212213

214+
// If we get an error linked to a socket, we want to calculate a rough estimate of when the
215+
// request was started, using the socket timing data:
216+
export function buildSocketErrorRequestTimings(socket: net.Socket | undefined): TimingEvents {
217+
if (socket?.[SocketTimingInfo]) {
218+
if (socket[SocketTimingInfo].lastRequestTimestamp) {
219+
// If this isn't the first request (or was partially received) we use the
220+
// most recent received request time as the start of this request:
221+
const startTimestamp = socket[SocketTimingInfo].lastRequestTimestamp;
222+
const startTime = socket[SocketTimingInfo].initialSocket +
223+
(startTimestamp - socket[SocketTimingInfo].initialSocketTimestamp);
224+
return {
225+
startTime,
226+
startTimestamp
227+
};
228+
} else {
229+
// If this is the first request, treat socket creation as the start:
230+
return {
231+
startTime: socket[SocketTimingInfo].initialSocket,
232+
startTimestamp: socket[SocketTimingInfo].initialSocketTimestamp
233+
};
234+
}
235+
} else {
236+
return {
237+
startTime: Date.now(),
238+
startTimestamp: now()
239+
};
240+
}
241+
}

0 commit comments

Comments
 (0)