Created
April 12, 2020 12:52
-
-
Save uzumaki-narut0/e8d7b51ca7cc02b932316719803a8dd0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Simulates a network download of a particular number of bytes over an optional maximum amount of time | |
* and returns information about the ending state. | |
* | |
* See https://hpbn.co/building-blocks-of-tcp/#three-way-handshake and | |
* https://hpbn.co/transport-layer-security-tls/#tls-handshake for details. | |
* | |
* @param {number} bytesToDownload | |
* @param {DownloadOptions} [options] | |
* @return {DownloadResults} | |
*/ | |
simulateDownloadUntil(bytesToDownload, options) { | |
const {timeAlreadyElapsed = 0, maximumTimeToElapse = Infinity, dnsResolutionTime = 0} = | |
options || {}; | |
if (this._warmed && this._h2) { | |
bytesToDownload -= this._h2OverflowBytesDownloaded; | |
} | |
const twoWayLatency = this._rtt; // 150 ms | |
const oneWayLatency = twoWayLatency / 2; // 75 ms | |
const maximumCongestionWindow = this._computeMaximumCongestionWindowInSegments(); // 20 | |
let handshakeAndRequest = oneWayLatency; // 75ms | |
if (!this._warmed) { | |
handshakeAndRequest = | |
// DNS lookup | |
dnsResolutionTime + // 169 | |
// SYN | |
oneWayLatency + | |
// SYN ACK | |
oneWayLatency + | |
// ACK + initial request | |
oneWayLatency + | |
// ClientHello/ServerHello assuming TLS False Start is enabled (https://istlsfastyet.com/#server-performance). | |
(this._ssl ? twoWayLatency : 0); // 150 | |
} | |
let roundTrips = Math.ceil(handshakeAndRequest / twoWayLatency); // 3 | |
let timeToFirstByte = handshakeAndRequest + this._serverLatency + oneWayLatency; // 544 ms + Server response time | |
if (this._warmed && this._h2) timeToFirstByte = 0; | |
const timeElapsedForTTFB = Math.max(timeToFirstByte - timeAlreadyElapsed, 0); | |
const maximumDownloadTimeToElapse = maximumTimeToElapse - timeElapsedForTTFB; | |
let congestionWindow = Math.min(this._congestionWindow, maximumCongestionWindow); // 10 | |
let totalBytesDownloaded = 0; | |
if (timeElapsedForTTFB > 0) { | |
totalBytesDownloaded = congestionWindow * TCP_SEGMENT_SIZE; // 1460 * 10 | |
} else { | |
roundTrips = 0; | |
} | |
let downloadTimeElapsed = 0; | |
let bytesRemaining = bytesToDownload - totalBytesDownloaded; | |
while (bytesRemaining > 0 && downloadTimeElapsed <= maximumDownloadTimeToElapse) { | |
roundTrips++; | |
downloadTimeElapsed += twoWayLatency; | |
congestionWindow = Math.max(Math.min(maximumCongestionWindow, congestionWindow * 2), 1); | |
const bytesDownloadedInWindow = congestionWindow * TCP_SEGMENT_SIZE; // 1460 * 20 | |
totalBytesDownloaded += bytesDownloadedInWindow; | |
bytesRemaining -= bytesDownloadedInWindow; | |
} | |
const timeElapsed = timeElapsedForTTFB + downloadTimeElapsed; | |
const extraBytesDownloaded = this._h2 ? Math.max(totalBytesDownloaded - bytesToDownload, 0) : 0; | |
const bytesDownloaded = Math.max(Math.min(totalBytesDownloaded, bytesToDownload), 0); | |
return { | |
roundTrips, | |
timeElapsed, | |
bytesDownloaded, | |
extraBytesDownloaded, | |
congestionWindow, | |
}; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment