@@ -18,6 +18,14 @@ import type { BrowserWindow } from 'electron';
1818import { IPC_CHANNELS } from '../../shared/ipc' ;
1919
2020const HOST = 'speed.cloudflare.com' ;
21+ // Cloudflare returns 403 for requests without a recognizable User-Agent
22+ // (bot/abuse protection), so identify ourselves as a real client.
23+ const DEFAULT_HEADERS : Record < string , string | number > = {
24+ 'User-Agent' :
25+ 'Mozilla/5.0 (Restbro Speed Test) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' ,
26+ Accept : '*/*' ,
27+ 'Accept-Encoding' : 'identity' ,
28+ } ;
2129const STREAMS = 4 ; // parallel connections
2230const DL_DURATION_MS = 7_000 ; // download phase length
2331const UL_DURATION_MS = 6_000 ; // upload phase length
@@ -105,6 +113,7 @@ function measurePing(isAborted: () => boolean): Promise<number> {
105113 method : 'GET' ,
106114 host : HOST ,
107115 path : '/__down?bytes=0' ,
116+ headers : { ...DEFAULT_HEADERS } ,
108117 timeout : 5_000 ,
109118 } ;
110119 const req = httpsRequest ( opts , ( res : IncomingMessage ) => {
@@ -168,6 +177,7 @@ function measureDownload(
168177 method : 'GET' ,
169178 host : HOST ,
170179 path : `/__down?bytes=${ DL_BYTES_PER_STREAM } ` ,
180+ headers : { ...DEFAULT_HEADERS } ,
171181 timeout : HARD_TIMEOUT_MS ,
172182 } ,
173183 ( res : IncomingMessage ) => {
@@ -260,6 +270,7 @@ function measureUpload(
260270 host : HOST ,
261271 path : '/__up' ,
262272 headers : {
273+ ...DEFAULT_HEADERS ,
263274 'Content-Type' : 'application/octet-stream' ,
264275 'Content-Length' : UL_BYTES_PER_STREAM ,
265276 } ,
0 commit comments