Web relay can now stream http content-length requests to the device, #4172
Ylian Saint-Hilaire committed
Jun 27, 2022 at 13:18 UTC
e351e839db1cdc9d6f790e6ad020eb547f6f4563
1 file changed
+9
-81
apprelays.js
+9
-81
@@ -197,11 +197,17 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
197
if (parent.webCookie != null) { request += 'cookie: ' + parent.webCookie + '\r\n' } // If we have a sessin cookie, use it.
198
request += '\r\n';
199
200
- if ((req.headers['transfer-encoding'] != null) || (req.headers['content-length'] != null)) {
200
+ if (req.headers['content-length'] != null) {
201
+ // Stream the HTTP request and body, this is a content-length HTTP request, just forward the body dataf
202
+ send(Buffer.from(request));
203
+ req.on('data', function (data) { send(data); }); // TODO: Flow control (Not sure how to do this in ExpressJS)
204
+ req.on('end', function () { });
205
+ } else if (req.headers['transfer-encoding'] != null) {
206
// Read the HTTP body and send the request to the device
207
+ console.log('chunk stream start');
208
obj.requestBinary = [Buffer.from(request)];
203
- req.on('data', function (data) { obj.requestBinary.push(data); });
204
- req.on('end', function () { send(Buffer.concat(obj.requestBinary)); delete obj.requestBinary; });
209
+ req.on('data', function (data) { console.log('chunk stream data'); obj.requestBinary.push(data); });
210
+ req.on('end', function () { console.log('chunk stream end');send(Buffer.concat(obj.requestBinary)); delete obj.requestBinary; });
211
} else {
212
// Request has no body, send it now
213
send(Buffer.from(request));
@@ -333,84 +339,6 @@ module.exports.CreateWebRelay = function (parent, db, args, domain) {
339
}
340
}
341
336
- /*
337
- // Process incoming HTTP data
338
- obj.socketAccumulator = '';
339
- obj.socketParseState = 0;
340
- function processHttpData(data) {
341
- obj.socketAccumulator += data;
342
- while (true) {
343
- //console.log('ACC(' + obj.socketAccumulator + '): ' + obj.socketAccumulator);
344
- if (obj.socketParseState == 0) {
345
- var headersize = obj.socketAccumulator.indexOf('\r\n\r\n');
346
- if (headersize < 0) return;
347
- //obj.Debug("Header: "+obj.socketAccumulator.substring(0, headersize)); // Display received HTTP header
348
- obj.socketHeader = obj.socketAccumulator.substring(0, headersize).split('\r\n');
349
- obj.socketAccumulator = obj.socketAccumulator.substring(headersize + 4);
350
- obj.socketParseState = 1;
351
- obj.socketData = '';
352
- obj.socketXHeader = { Directive: obj.socketHeader[0].split(' ') };
353
- for (var i in obj.socketHeader) {
354
- if (i != 0) {
355
- var x2 = obj.socketHeader[i].indexOf(':');
356
- obj.socketXHeader[obj.socketHeader[i].substring(0, x2).toLowerCase()] = obj.socketHeader[i].substring(x2 + 2);
357
- }
358
- }
359
- }
360
- if (obj.socketParseState == 1) {
361
- var csize = -1;
362
- if ((obj.socketXHeader['connection'] != null) && (obj.socketXHeader['connection'].toLowerCase() == 'close') && ((obj.socketXHeader["transfer-encoding"] == null) || (obj.socketXHeader["transfer-encoding"].toLowerCase() != 'chunked'))) {
363
- // The body ends with a close, in this case, we will only process the header
364
- csize = 0;
365
- } else if (obj.socketXHeader['content-length'] != null) {
366
- // The body length is specified by the content-length
367
- csize = parseInt(obj.socketXHeader['content-length']);
368
- if (obj.socketAccumulator.length < csize) return;
369
- var data = obj.socketAccumulator.substring(0, csize);
370
- obj.socketAccumulator = obj.socketAccumulator.substring(csize);
371
- obj.socketData = data;
372
- csize = 0;
373
- } else {
374
- // The body is chunked
375
- var clen = obj.socketAccumulator.indexOf('\r\n');
376
- if (clen < 0) return; // Chunk length not found, exit now and get more data.
377
- // Chunk length if found, lets see if we can get the data.
378
- csize = parseInt(obj.socketAccumulator.substring(0, clen), 16);
379
- if (obj.socketAccumulator.length < clen + 2 + csize + 2) return;
380
- // We got a chunk with all of the data, handle the chunck now.
381
- var data = obj.socketAccumulator.substring(clen + 2, clen + 2 + csize);
382
- obj.socketAccumulator = obj.socketAccumulator.substring(clen + 2 + csize + 2);
383
- try { obj.socketData += data; } catch (ex) { console.log(ex, typeof data, data.length); }
384
- }
385
- if (csize == 0) {
386
- //obj.Debug("xxOnSocketData DONE: (" + obj.socketData.length + "): " + obj.socketData);
387
- processHttpResponse(obj.socketXHeader, obj.socketData);
388
- obj.socketParseState = 0;
389
- obj.socketHeader = null;
390
- }
391
- }
392
- }
393
- }
394
-
395
- // This is a fully parsed HTTP response from the remote device
396
- function processHttpResponse(header, data) {
397
- //console.log('processHttpResponse', header);
398
- obj.res.status(parseInt(header.Directive[1])); // Set the status
399
- const blockHeaders = ['Directive' ]; // These are headers we do not forward
400
- for (var i in header) {
401
- if (i == 'set-cookie') { parent.webCookie = header[i]; } // Keep the cookie, don't forward it
402
- else if (blockHeaders.indexOf(i) == -1) { obj.res.set(i, header[i]); } // Set the headers if not blocked
403
- }
404
- obj.res.set('Content-Security-Policy', "default-src 'self' 'unsafe-inline' 'unsafe-eval' data: blob:;"); // Set an "allow all" policy, see if the can restrict this in the future
405
- obj.res.end(data, 'binary'); // Write the data
406
- delete obj.res;
407
- parent.lastOperation = obj.lastOperation = Date.now(); // Update time of last opertion performed
408
-
409
- // Event completion
410
- if (obj.oncompleted) { obj.oncompleted(obj.tunnelId); }
411
- }
412
- */
413
-
342
// Process incoming HTTP data
343
obj.socketAccumulator = '';
344
obj.socketParseState = 0;