@@ -9,19 +9,35 @@ import { ViewHost } from "../types/view-devices";
99import { TOOLTIP_KEYS } from "../utils/constants/tooltips_constants" ;
1010import { ProgramBase } from "./program_base" ;
1111
12+ const RESOURCE_MAP = new Map ( [
13+ [ "/small" , generateResource ( 1024 ) ] ,
14+ [ "/medium" , generateResource ( 102400 ) ] ,
15+ [ "/large" , generateResource ( 10485760 ) ] ,
16+ ] ) ;
17+
18+ function generateResource ( size : number ) : Uint8Array {
19+ const resource = new Uint8Array ( size ) ;
20+ for ( let i = 0 ; i < size ; i ++ ) {
21+ resource [ i ] = Math . floor ( Math . random ( ) * 256 ) ;
22+ }
23+ return resource ;
24+ }
25+
1226export class HttpClient extends ProgramBase {
1327 static readonly PROGRAM_NAME = TOOLTIP_KEYS . SEND_HTTP_REQUEST ;
1428
1529 private dstId : DeviceId ;
30+ private resource : string ;
1631
1732 protected _parseInputs ( inputs : string [ ] ) : void {
18- if ( inputs . length !== 1 ) {
33+ if ( inputs . length !== 2 ) {
1934 console . error (
20- "HttpClient requires 1 input. " + inputs . length + " were given." ,
35+ "HttpClient requires 2 input. " + inputs . length + " were given." ,
2136 ) ;
2237 return ;
2338 }
2439 this . dstId = parseInt ( inputs [ 0 ] ) ;
40+ this . resource = inputs [ 1 ] ;
2541 }
2642
2743 protected _run ( ) {
@@ -51,19 +67,19 @@ export class HttpClient extends ProgramBase {
5167 return ;
5268 }
5369
54- // Encode dummy HTTP request
55- const httpRequest = "GET / HTTP/1.1\r\nHost: " + dstDevice . ip + "\r\n\r\n" ;
56- const content = new TextEncoder ( ) . encode ( httpRequest ) ;
70+ // Encode HTTP request
71+ const httpRequest = getContentRequest (
72+ this . runner . ip . toString ( ) ,
73+ this . resource ,
74+ ) ;
5775
5876 // Write request
5977 const socket = await this . runner . tcpConnect ( this . dstId ) ;
6078 if ( ! socket ) {
61- console . warn (
62- "HttpClient failed to connect to socket. Program cancelled." ,
63- ) ;
79+ console . warn ( "HttpClient failed to connect" ) ;
6480 return ;
6581 }
66- const wrote = await socket . write ( content ) ;
82+ const wrote = await socket . write ( httpRequest ) ;
6783 if ( wrote < 0 ) {
6884 console . error ( "HttpClient failed to write to socket" ) ;
6985 return ;
@@ -74,20 +90,39 @@ export class HttpClient extends ProgramBase {
7490
7591 // Read response
7692 const buffer = new Uint8Array ( 1024 ) ;
77- const readLength = await socket . readAll ( buffer ) ;
78- if ( readLength < 0 ) {
79- console . error ( "HttpClient failed to read from socket" ) ;
80- return ;
93+ const expectedLength = RESOURCE_MAP . get ( this . resource ) ?. length || 0 ;
94+ let totalRead = 0 ;
95+ while ( totalRead < expectedLength ) {
96+ const readLength = await socket . read ( buffer ) ;
97+ if ( readLength < 0 ) {
98+ console . error ( "HttpClient failed to read from socket" ) ;
99+ return ;
100+ }
101+ totalRead += readLength ;
81102 }
82103 }
83104
84105 static getProgramInfo ( viewgraph : ViewGraph , srcId : DeviceId ) : ProgramInfo {
106+ const sizeOptions = [
107+ { value : "/small" , text : "1 KB" } ,
108+ { value : "/medium" , text : "100 KB" } ,
109+ { value : "/large" , text : "10 MB" } ,
110+ ] ;
111+
85112 const programInfo = new ProgramInfo ( this . PROGRAM_NAME ) ;
86113 programInfo . withDestinationDropdown ( viewgraph , srcId , Layer . App ) ;
114+ programInfo . withDropdown ( "Size of requested resource" , sizeOptions ) ;
87115 return programInfo ;
88116 }
89117}
90118
119+ function getContentRequest ( host : string , resource : string ) : Uint8Array {
120+ const httpRequest =
121+ "GET " + resource + " HTTP/1.1\r\nHost: " + host + "\r\n\r\n" ;
122+ const content = new TextEncoder ( ) . encode ( httpRequest ) ;
123+ return content ;
124+ }
125+
91126export class HttpServer extends ProgramBase {
92127 static readonly PROGRAM_NAME = TOOLTIP_KEYS . SERVE_HTTP_REQUESTS ;
93128
@@ -156,20 +191,37 @@ export class HttpServer extends ProgramBase {
156191 const buffer = new Uint8Array ( 1024 ) . fill ( 0 ) ;
157192 const readLength = await socket . readAll ( buffer ) ;
158193
159- // eslint-disable-next-line @typescript-eslint/no-unused-vars
160194 const readContents = buffer . slice ( 0 , readLength ) ;
161195 if ( readLength < 0 ) {
162196 console . error ( "HttpServer failed to read from socket" ) ;
163197 return ;
164198 }
165199
166- // TODO: validate request
200+ const requestContents = new TextDecoder ( ) . decode ( readContents ) ;
201+ const matches = requestContents . match ( / G E T ( .+ ) H T T P \/ 1 .1 / ) ;
202+ if ( ! matches || matches . length < 2 ) {
203+ console . error ( "HttpServer failed to parse request" ) ;
204+ return ;
205+ }
206+ const resourceContents = RESOURCE_MAP . get ( matches [ 1 ] ) ;
207+ if ( ! resourceContents ) {
208+ console . error ( "HttpServer failed to find requested resource" ) ;
209+ return ;
210+ }
167211
168212 // Encode dummy HTTP response
169- const httpResponse = "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" ;
213+ const httpResponse =
214+ "HTTP/1.1 200 OK\r\nContent-Length: " +
215+ resourceContents . length +
216+ "\r\n\r\n" ;
170217 const content = new TextEncoder ( ) . encode ( httpResponse ) ;
171218 const wrote = await socket . write ( content ) ;
172- if ( wrote < 0 ) {
219+ if ( wrote <= 0 ) {
220+ console . error ( "HttpServer failed to write to socket" ) ;
221+ return ;
222+ }
223+ const wrote2 = await socket . write ( resourceContents ) ;
224+ if ( wrote2 <= 0 ) {
173225 console . error ( "HttpServer failed to write to socket" ) ;
174226 return ;
175227 }
0 commit comments