Skip to content

Commit cdc946f

Browse files
committed
Fix connection drops
- Remove default connection timeout - nodejs/node#27558. - Add client error listener.
1 parent 2f7a7b5 commit cdc946f

File tree

2 files changed

+56
-3
lines changed

2 files changed

+56
-3
lines changed

src/NodeJS/Javascript/Servers/OutOfProcess/Http/HttpServer.ts

+27-3
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,19 @@ patchLStat();
2323
// Set by NodeJSProcessFactory
2424
let projectDir = process.cwd();
2525

26+
// Create server
27+
const server = http.createServer(serverOnRequestListener);
28+
29+
// In Node.js v13+ this is the default, however for earlier versions it is 120 seconds.
30+
server.setTimeout(0);
31+
32+
// Send client error details to client for debugging
33+
server.on('clientError', serverOnClientError);
34+
2635
// Start server
27-
const server = http.createServer((req, res) => {
36+
server.listen(parseInt(args.port), 'localhost', serverOnListeningListener);
37+
38+
function serverOnRequestListener(req, res) {
2839
let bodyChunks = [];
2940
req.
3041
on('data', chunk => bodyChunks.push(chunk)).
@@ -158,12 +169,25 @@ const server = http.createServer((req, res) => {
158169
respondWithError(res, error);
159170
}
160171
});
161-
}).listen(parseInt(args.port), 'localhost', function () {
172+
}
173+
174+
// Send error details to client for debugging - https://nodejs.org/api/http.html#http_event_clienterror
175+
function serverOnClientError(error: Error, socket: stream.Duplex) {
176+
let errorJson = JSON.stringify({
177+
errorMessage: error.message,
178+
errorStack: error.stack
179+
});
180+
181+
let httpResponseMessage = `HTTP/1.1 500 Internal Server Error\r\nContent-Length: ${Buffer.byteLength(errorJson, 'utf8')}\r\nContent-Type: text/html\r\n\r\n${errorJson}`;
182+
socket.end(httpResponseMessage);
183+
}
184+
185+
function serverOnListeningListener() {
162186
// Signal to HttpNodeHost which loopback IP address (IPv4 or IPv6) and port it should make its HTTP connections on
163187
// and that we are ready to process invocations.
164188
let info = server.address() as AddressInfo;
165189
console.log(`[Jering.Javascript.NodeJS: Listening on IP - ${info.address} Port - ${info.port}]`);
166-
});
190+
}
167191

168192
function getTempIdentifier(invocationRequest: InvocationRequest): string {
169193
if (invocationRequest.newCacheIdentifier == null) {

test/NodeJS/HttpNodeJSServiceIntegrationTests.cs

+29
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
using System.Diagnostics;
77
using System.IO;
88
using System.Linq;
9+
using System.Net;
10+
using System.Net.Http;
11+
using System.Net.Sockets;
912
using System.Text;
13+
using System.Text.Json;
1014
using System.Threading;
1115
using Xunit;
1216
using Xunit.Abstractions;
@@ -954,6 +958,31 @@ public static IEnumerable<object[]> AllInvokeMethods_ReceiveAndLogStderrOutput_D
954958
};
955959
}
956960

961+
[Fact]
962+
public async void AllInvokeMethods_HandleHttpClientErrorsSuchAsMalformedRequests()
963+
{
964+
// Arrange
965+
HttpNodeJSService testSubject = CreateHttpNodeJSService();
966+
await testSubject.InvokeFromStringAsync("module.exports = callback => callback();").ConfigureAwait(false); // Starts the Node.js process
967+
Uri dummyEndpoint = testSubject.Endpoint;
968+
var dummyJsonService = new JsonService();
969+
970+
// Act
971+
using (var dummyHttpClient = new HttpClient())
972+
// Send a request with an invalid HTTP method. NodeJS drops the connection halfway through and fires the clientError event - https://nodejs.org/api/http.html#http_event_clienterror
973+
using (var dummyHttpRequestMessage = new HttpRequestMessage(new HttpMethod("INVALID"), dummyEndpoint))
974+
using (HttpResponseMessage dummyHttpResponseMessage = await dummyHttpClient.SendAsync(dummyHttpRequestMessage).ConfigureAwait(false))
975+
using (Stream dummyStream = await dummyHttpResponseMessage.Content.ReadAsStreamAsync().ConfigureAwait(false))
976+
{
977+
InvocationError result = await dummyJsonService.DeserializeAsync<InvocationError>(dummyStream).ConfigureAwait(false);
978+
979+
// Assert
980+
Assert.Equal(HttpStatusCode.InternalServerError, dummyHttpResponseMessage.StatusCode);
981+
Assert.False(string.IsNullOrWhiteSpace(result.ErrorMessage));
982+
Assert.False(string.IsNullOrWhiteSpace(result.ErrorStack));
983+
}
984+
}
985+
957986
/// <summary>
958987
/// Specify <paramref name="loggerStringBuilder"/> for access to all logging output.
959988
/// </summary>

0 commit comments

Comments
 (0)