Skip to content

Reconnection hangs indefinitely when ConnectFuture fails or stalls through an HTTP proxy (IoSessionInitiator) #1274

Description

@rishabhagl

Describe the bug
IoSessionInitiator.pollConnectFuture() does not correctly handle two failure
modes that occur specifically when connecting through an HTTP proxy
(ProxyType=http):

  1. Exceptional future completion is silently ignored in the "still pending" path.
    When a ConnectFuture completes with getSession() == null but
    getException() != null (e.g. proxy returns 407, or the CONNECT handshake
    is rejected), the original code path only checked getSession() != null
    before falling through to logic that treats the future as still pending.
    This left connectFuture non-null indefinitely, which blocks
    shouldReconnect() from ever returning true again — the initiator never
    retries.

  2. A stalled proxy CONNECT handshake with no exception and no session
    never times out.
    MINA's proxy filter can get stuck mid-handshake
    (no session resolved, no exception thrown) if the proxy accepts the TCP
    connection but never completes the CONNECT response. There is no watchdog
    to cancel this and force a reconnect.

This matches the underlying pattern described in #295 (authenticating HTTP
proxy connections) and the older reconnection issues QFJ-868 / QFJ-895, but
those were not addressing the exception-completion and stall-timeout cases
specifically for proxy connects.

To Reproduce

  1. Configure an initiator session with:
    ProxyType=http
    ProxyHost=
    ProxyPort=
    ProxyUser=
    ProxyPassword=

  2. Point the proxy at an endpoint that either:

  • rejects the CONNECT with a 407/4xx (simulates auth failure), or
  • accepts the TCP connection but never responds to the CONNECT request
    (simulates a hung/misbehaving proxy).
  1. Observe that after the first failed connect attempt, the initiator never
    attempts to reconnect again, even though ReconnectInterval is configured.

Expected behavior

  • On an exceptional ConnectFuture completion, connectFuture should be
    cleared immediately and handleConnectException() should fire so normal
    reconnect backoff resumes.
  • On a stalled proxy handshake (no session, no exception) that exceeds
    connectTimeoutMillis (max pending wait), the pending attempt should be
    cancelled, the ProxyConnector recreated, and the reconnect timers reset
    so the next scheduled reconnect fires correctly instead of firing
    immediately or never.

system information:

  • OS: [Linux/Windows]
  • Java version [JDK8 and above]
  • QFJ Version [3.0.1]

Additional context
Reconnect is not attempted even after endpoint becomes available.
App restart fixes it.

Related issues

Proposed fix

I've patched pollConnectFuture() to:

  • Check future.getException() explicitly and route it through
    handleConnectException(), clearing connectFuture right away.
  • Add a maxPendingMillis (connectTimeoutMillis) watchdog: if a connect
    attempt has been pending longer than this, call a new
    cancelAndResetPendingConnectAttempt() helper that:
  • force-closes any half-open IoSession and cancels the future,
  • if ioConnector instanceof ProxyConnector, cancels the proxy connector's
    internal connect future and recreates the connector via
    setupIoConnector(),
  • resets lastConnectTime and lastReconnectAttemptTime to the current
    time so the next reconnect timer tick doesn't fire immediately (since
    pendingMillis would otherwise already exceed ReconnectInterval).

I have a working patch and a JUnit test suite covering the changes.

Happy to open a PR with the diff and tests attached if maintainers confirm
this is the right approach — wanted to raise the issue first in case there's
a preferred design (e.g. exposing connectTimeoutMillis as a new session
setting rather than reusing an existing timeout field).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions