2

I have a certain piece of code that integrates with a third party using HTTP connection, which handles socket timeout and connection timeout differently.

I have been trying to simulate and test all the scenarios which could arise from the third party. was able to test connection timeout by connecting to a port which is blocked by the servers firewall e.g. port 81.

However I'm unable to simulate a socket timeout. If my understanding is not wrong socket timeout is associated with continuous packet flow, and the connection dropping in between. Is there a way I can simulate this?

Varghese Tony
  • 21
  • 1
  • 3

2 Answers2

1

So we are talking about to kinds of timeouts here, one is to connect to the server (connect timeout), the other timeout will happen when no data is send or received via the socket for a while (idle timeout).

Node sockets have a socket timeout, that can be used to synthesize both the connect and the idle timeout. This can be done by setting the socket timeout to the connect timeout and then when connected, setting it to the idle timeout.

example:

        const request = http.request(url, {
            timeout: connectTimeout,
        });
        request.setTimeout(idleTimeout);

This works because the timeout in the options is set immediately when creating the socket, the setTimeout function is run on the socket when connected!

Anyway, the question was about how to test the connect timeout. Ok so let's first park the idle timeout. We can simply test that by not sending any data for some time, that would cause the timeout. Check!

The connect timeout is a bit harder to test, the first thing that comes to mind is that we need a place to connect to that will not error, but also not connect. This would cause a timeout. But how the hell do we simulate that, in node?

If we think a little bit outside the box then we might figure out that this timeout is about the time it takes to connect. It does not matter why the connection takes as long as it does. We simply need to delay the time it takes to connect. This is not necessarily a server thing, we could also do it on the client. After all this is the part connecting, if we can delay it there, we can test the timeout.

So how could we delay the connection on the client side? Well, we can use the DNS lookup for that. Before the connection is made, a DNS lookup is done. If we simply delay that by 5 seconds or so we can test for the connect timeout very easily.

This is what the code could look like:

import * as dns from "dns";
import * as http from "http";

const url = new URL("http://localhost:8080");

const request = http.request(url, {
    timeout: 3 * 1000, // connect timeout
    lookup(hostname, options, callback) {
        setTimeout(
            () => dns.lookup(hostname, options, callback),
            5 * 1000,
        );
    },
});
request.setTimeout(10 * 1000); // idle timeout

request.addListener("timeout", () => {
    const message = !request.socket || request.socket.connecting ?
        `connect timeout while connecting to ${url.href}` :
        `idle timeout while connected to ${url.href}`;

    request.destroy(new Error(message));
});

In my projects I usually use an agent that I inject. The agent then has the delayed lookup. Like this:

import * as dns from "dns";
import * as http from "http";

const url = new URL("http://localhost:8080");

const agent = new http.Agent({
    lookup(hostname, options, callback) {
        setTimeout(
            () => dns.lookup(hostname, options, callback),
            5 * 1000,
        );
    },
});

const request = http.request(url, {
    timeout: 3 * 1000, // connect timeout
    agent,
});
request.setTimeout(10 * 1000); // idle timeout

request.addListener("timeout", () => {
    const message = !request.socket || request.socket.connecting ?
        `connect timeout while connecting to ${url.href}` :
        `idle timeout while connected to ${url.href}`;

    request.destroy(new Error(message));
});

Happy coding!

Elmer
  • 9,147
  • 2
  • 48
  • 38
  • Whahaha I just realized that this question is about Java! The solution I provide is in node.js, but I guess it could also be done in Java :-) – Elmer Jul 12 '21 at 09:43
-1

"Connection timeout" determines how long it may take for a TCP connection to be established and this all happens before any HTTP related data is send over the line. By connecting to a blocked port, you have only partially tested the connection timeout since no connection was being made. Typically, a TCP connection on your local network is created (established) very fast. But when connecting to a server on the other side of the world, establishing a TCP connection can take seconds.

"Socket timeout" is a somewhat misleading name - it just determines how long you (the client) will wait for an answer (data) from the server. In other words, how long the Socket.read() function will block while waiting for data.

Properly testing these functions involves creating a server socket or a (HTTP) web-server that you can modify to be very slow. Describing how to create and use a server socket for connection timeout testing (if that is possible) is too much to answer here, but socket timeout testing is a common question - see for example here (I just googled "mock web server for testing timeouts") which leads to a tool like MockWebServer. "MockWebServer" might have an option for testing connection timeouts as well (I have not used "MockWebServer"), but if not, another tool might have.

On a final note: it is good you are testing your usage of the third-party HTTP library with respect to timeout settings, even if this takes some effort. The worst that can happen is that a socket timeout setting in your code is somehow not used by the library and the default socket timeout of "wait forever" is used. That can result in your application doing absolutely nothing ("hanging") for no apparent reason.

vanOekel
  • 6,358
  • 1
  • 21
  • 56
  • 'By connecting to a blocked port, you have only partially tested the connection timeout since no connection was being made': false. He has completely tested it. – user207421 Aug 08 '20 at 06:42