public StreamConnection performUpgrade() throws IOException { // Upgrade the connection // Set the upgraded flag already to prevent new requests after this one if (allAreSet(state, UPGRADED | CLOSE_REQ | CLOSED)) { throw new IOException(UndertowClientMessages.MESSAGES.connectionClosed()); } state |= UPGRADED; return connection; }
@Override public void sendRequest( final ClientRequest request, final ClientCallback<ClientExchange> clientCallback) { if (anyAreSet(state, UPGRADE_REQUESTED | UPGRADED | CLOSE_REQ | CLOSED)) { throw UndertowClientMessages.MESSAGES.invalidConnectionState(); } final HttpClientExchange httpClientExchange = new HttpClientExchange(clientCallback, request, this); if (currentRequest == null) { initiateRequest(httpClientExchange); } else { pendingQueue.add(httpClientExchange); } }
private void initiateRequest(HttpClientExchange httpClientExchange) { currentRequest = httpClientExchange; pendingResponse = new HttpResponseBuilder(); ClientRequest request = httpClientExchange.getRequest(); String connectionString = request.getRequestHeaders().getFirst(CONNECTION); if (connectionString != null) { HttpString connectionHttpString = new HttpString(connectionString); if (connectionHttpString.equals(CLOSE)) { state |= CLOSE_REQ; } else if (connectionHttpString.equals(UPGRADE)) { state |= UPGRADE_REQUESTED; } } else if (request.getProtocol() != Protocols.HTTP_1_1) { state |= CLOSE_REQ; } if (request.getRequestHeaders().contains(UPGRADE)) { state |= UPGRADE_REQUESTED; } // setup the client request conduits final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(clientReadListener); sourceChannel.resumeReads(); ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); StreamSinkConduit conduit = originalSinkConduit; conduit = new HttpRequestConduit(conduit, bufferPool, request); String fixedLengthString = request.getRequestHeaders().getFirst(CONTENT_LENGTH); String transferEncodingString = request.getRequestHeaders().getLast(TRANSFER_ENCODING); boolean hasContent = true; if (fixedLengthString != null) { try { long length = Long.parseLong(fixedLengthString); conduit = new ClientFixedLengthStreamSinkConduit(conduit, length, false, false, currentRequest); hasContent = length != 0; } catch (NumberFormatException e) { handleError(new IOException(e)); return; } } else if (transferEncodingString != null) { if (!transferEncodingString .toLowerCase(Locale.ENGLISH) .contains(Headers.CHUNKED.toString())) { handleError( UndertowClientMessages.MESSAGES.unknownTransferEncoding(transferEncodingString)); return; } conduit = new ChunkedStreamSinkConduit( conduit, httpClientExchange.getConnection().getBufferPool(), false, false, httpClientExchange.getRequest().getRequestHeaders(), requestFinishListener, httpClientExchange); } else { conduit = new ClientFixedLengthStreamSinkConduit(conduit, 0, false, false, currentRequest); hasContent = false; } sinkChannel.setConduit(conduit); httpClientExchange.invokeReadReadyCallback(httpClientExchange); if (!hasContent) { // if there is no content we flush the response channel. // otherwise it is up to the user try { sinkChannel.shutdownWrites(); if (!sinkChannel.flush()) { sinkChannel.setWriteListener( ChannelListeners.flushingChannelListener( null, new ChannelExceptionHandler<ConduitStreamSinkChannel>() { @Override public void handleException( ConduitStreamSinkChannel channel, IOException exception) { handleError(exception); } })); } } catch (IOException e) { handleError(e); } } else if (!sinkChannel.isWriteResumed()) { try { // TODO: this needs some more thought if (!sinkChannel.flush()) { sinkChannel.setWriteListener( new ChannelListener<ConduitStreamSinkChannel>() { @Override public void handleEvent(ConduitStreamSinkChannel channel) { try { if (channel.flush()) { channel.suspendWrites(); } } catch (IOException e) { handleError(e); } } }); sinkChannel.resumeWrites(); } } catch (IOException e) { handleError(e); } } }