public void forwardRequest(HttpBindBody body, AsyncContext context)
            throws HttpBindException, HttpConnectionClosedException, IOException
    {
        final HttpConnection connection = this.createConnection(body, context);
        final long rid = body.getRid();
        final StreamID streamid = getStreamID();

        // Check if security restraints are observed.
        if (isEncrypted && !connection.isEncrypted()) {
            throw new HttpBindException("Session was started from encrypted connection, all " +
                "connections on this session must be encrypted.", BoshBindingError.badRequest);
        }

        synchronized (connectionQueue)
        {
            // Check if the provided RID is in the to-be-expected window.
            if (rid > (lastSequentialRequestID + maxRequests)) {
                Log.warn("Request {} > {}, ending session {}", body.getRid(), (lastSequentialRequestID + maxRequests), getStreamID());
                throw new HttpBindException("Unexpected RID error.", BoshBindingError.itemNotFound);
            }

            // Check for retransmission.
            if (rid <= lastAnsweredRequestID) {
                Log.debug("Request {} on session {} appears to be a request for redelivery, as the last answered RID is {}", rid, getStreamID(), lastAnsweredRequestID);
                redeliver(connection);
                return;
            }

            /*
             * Search through the connection queue to see if this rid already exists on it. If it does then we
             * will close and deliver the existing connection (if appropriate), and close and deliver the same
             * deliverable on the new connection. This is under the assumption that a connection has been dropped,
             * and re-requested before jetty has realised.
             */
            final Iterator<HttpConnection> iter = connectionQueue.iterator();
            while (iter.hasNext()) {
                final HttpConnection queuedConnection = iter.next();
                if (queuedConnection.getRequestId() == rid) {
                    Log.debug("Found previous connection in queue with rid {}", rid);

                    // Note that the old connection is removed here, but the new connection will not be added back before the mutex is released. This leaves
                    // room for another thread to try and consume a connection before this connection has been restored. This should be safe, as the consumer
                    // should not be allowed to consume a connection with a RID that, compared to the previously consumed RID, leaves a 'gap'. In that case,
                    // the to-be-delivered data is expected to be queued, which will be picked up as soon as this connection (for which the RID 'fills the gap',
                    // is being processed by org.jivesoftware.openfire.http.HttpSession.processConnection.
                    iter.remove();

                    assert !queuedConnection.isClosed();
                    Log.debug("For session {} queued connection is still open - calling close() on the old connection (as the new connection will replace it).", streamid);
                    // TODO: OF-2447: implement section 14.3 of XEP 0124 instead of this!
                    deliver(queuedConnection, Collections.singletonList(new Deliverable("")), true);
                    queuedConnection.close();
                    break;
                }
            }
        }

        checkOveractivity(connection);

        // Schedule the connection for consumption.
        processConnection(connection, context);
        resetInactivityTimeout();
    }
Forwards a client request, which is related to a session, to the server. A connection is
created and queued up in the provided session. When a connection reaches the top of a queue
any pending packets bound for the client will be forwarded to the client through the
connection.

@param body the body element that was sent containing the request for a new session.
@param context the context of the asynchronous servlet call leading up to this method call.

@throws HttpBindException for several reasons: if the encoding inside an auth packet is not recognized by the
                          server, or if the packet type is not recognized.
@throws HttpConnectionClosedException if the session is no longer available.
@throws IOException if an input or output exception occurred
xmppserver/src/main/java/org/jivesoftware/openfire/http/HttpSession.java