@@ -12,7 +12,6 @@ import {
1212 Presentation as TPresentation ,
1313 Commit ,
1414 NotaryServer ,
15- Transcript ,
1615 mapStringToRange ,
1716 subtractRanges ,
1817} from 'tlsn-js' ;
@@ -33,18 +32,24 @@ export const TLSNProveOffscreenHandler = new SimpleOffscreenHandler<TLSNProveOff
3332 async ( request ) => {
3433 const serverURL = getSteamRequestURL ( request . notary_request , request . access_token ) ;
3534
36- // Getting max sent bytes as close as possible to the real req size is crucial for performance
37- const maxSentData = calculateRequestSize ( serverURL , 'GET' , {
35+ const maxSentData = calculateRequestSize ( serverURL , 'GET' , {
3836 'Connection' : 'close' ,
3937 'Host' : 'api.steampowered.com' ,
4038 'Accept-Encoding' : 'gzip' ,
4139 } ) ;
4240
41+ const maxRecvData = await calculateResponseSize ( serverURL , 'GET' , {
42+ 'Connection' : 'close' ,
43+ 'Host' : 'api.steampowered.com' ,
44+ 'Accept-Encoding' : 'gzip' ,
45+ } ) ;
46+
47+ console . log ( maxSentData , maxRecvData ) ;
4348 const notary = NotaryServer . from ( environment . notary . tlsn ) ;
4449
4550 const prover = ( await new Prover ( {
4651 serverDns : 'api.steampowered.com' ,
47- maxRecvData : 12000 ,
52+ maxRecvData,
4853 maxSentData,
4954 } ) ) as TProver ;
5055
@@ -61,12 +66,6 @@ export const TLSNProveOffscreenHandler = new SimpleOffscreenHandler<TLSNProveOff
6166 const transcript = await prover . transcript ( ) ;
6267 const { sent, recv } = transcript ;
6368
64- const {
65- info : recvInfo ,
66- headers : recvHeaders ,
67- body : recvBody ,
68- } = parseHttpMessage ( Buffer . from ( recv ) , 'response' ) ;
69-
7069 const commit : Commit = {
7170 sent : subtractRanges (
7271 { start : 0 , end : sent . length } ,
@@ -98,38 +97,6 @@ export const TLSNProveOffscreenHandler = new SimpleOffscreenHandler<TLSNProveOff
9897 }
9998) ;
10099
101- function parseHttpMessage ( buffer : Buffer , type : 'request' | 'response' ) {
102- const parser = new HTTPParser (
103- type === 'request' ? HTTPParser . REQUEST : HTTPParser . RESPONSE ,
104- ) ;
105- const body : Buffer [ ] = [ ] ;
106- let complete = false ;
107- let headers : string [ ] = [ ] ;
108-
109- parser . onBody = ( t ) => {
110- body . push ( t ) ;
111- } ;
112-
113- parser . onHeadersComplete = ( res ) => {
114- headers = res . headers ;
115- } ;
116-
117- parser . onMessageComplete = ( ) => {
118- complete = true ;
119- } ;
120-
121- parser . execute ( buffer ) ;
122- parser . finish ( ) ;
123-
124- if ( ! complete ) throw new Error ( `Could not parse ${ type . toUpperCase ( ) } ` ) ;
125-
126- return {
127- info : buffer . toString ( 'utf-8' ) . split ( '\r\n' ) [ 0 ] + '\r\n' ,
128- headers,
129- body,
130- } ;
131- }
132-
133100/**
134101 * Estimates the total request byte size over the wire if sent over HTTP 1.1
135102 *
@@ -142,7 +109,7 @@ function parseHttpMessage(buffer: Buffer, type: 'request' | 'response') {
142109 * @param headers HTTP request headers
143110 * @param body Optional request body
144111 */
145- export function calculateRequestSize ( url : string , method : 'GET' | 'POST' , headers : Record < string , string > , body ?: string ) : number {
112+ function calculateRequestSize ( url : string , method : 'GET' | 'POST' , headers : Record < string , string > , body ?: string ) : number {
146113 const requestLineSize = new TextEncoder ( ) . encode (
147114 `${ method } ${ url } HTTP/1.1\r\n` ,
148115 ) . length ;
@@ -158,4 +125,45 @@ export function calculateRequestSize(url: string, method: 'GET'|'POST', headers:
158125 : 0 ;
159126
160127 return requestLineSize + headersSize + 2 + bodySize ; // +2 for CRLF after headers
128+ }
129+
130+ /**
131+ * Calculates the exact response byte size for the HTTP request by making the request itself and counting the response
132+ *
133+ * @param url Full request uRL including protocol, domain, path
134+ * @param method HTTP method (ie. "GET")
135+ * @param headers HTTP request headers
136+ * @param body Optional request body
137+ */
138+ async function calculateResponseSize ( url : string , method : 'GET' | 'POST' , headers : Record < string , string > , body ?: string ) : Promise < number > {
139+ const opts : RequestInit = { method, headers} ;
140+ if ( body ) {
141+ opts . body = body ;
142+ }
143+ const response = await fetch ( url , opts ) ;
144+
145+ const statusLine = `HTTP/1.1 ${ response . status } ${ response . statusText } ` ;
146+ let headersSize = statusLine . length + 2 ; // +2 for CRLF (\r\n)
147+
148+ response . headers . forEach ( ( value , name ) => {
149+ console . log ( name , value ) ;
150+ headersSize += name . length + value . length + 4 ; // for ": " and "\r\n"
151+ } ) ;
152+
153+ // Not included in fetch headers, but is in the network response
154+ headersSize += 'Connection: close' . length + 2 ;
155+ headersSize += 'X-N: S' . length + 2 ;
156+
157+ // Add the final CRLF that separates the headers from the body.
158+ headersSize += 2 ;
159+
160+ const contentLength = response . headers . get ( 'content-length' ) ;
161+
162+ if ( ! contentLength ) {
163+ throw new Error ( 'no content length in response headers' )
164+ }
165+
166+ const bodySize = parseInt ( contentLength , 10 ) ;
167+
168+ return headersSize + bodySize ;
161169}
0 commit comments