private IoHandler selectReadHandler(ResourceAddress readAddress) { Protocol protocol = bridgeServiceFactory.getTransportFactory().getProtocol(readAddress.getResource()); if (protocol instanceof HttpProtocol) { return readHandler; } throw new RuntimeException("Cannot select read handler for address " + readAddress); }
@Override protected void doSessionClosed(HttpSession createSession) throws Exception { final WsebSession wsebSession = WSE_SESSION_KEY.get(createSession); assert (wsebSession != null); IoBufferEx buf = CREATE_RESPONSE_KEY.remove(createSession); if (buf == null || createSession.getStatus() != HttpStatus.SUCCESS_CREATED) { throw new IllegalStateException("Create handshake failed: invalid response"); } buf.flip(); String responseText = buf.getString(UTF_8.newDecoder()); String[] locations = responseText.split("\n"); if (locations.length < 2) { throw new IllegalStateException("Create handshake failed: invalid response"); } URI writeURI = URI.create(locations[0]); URI readURI = URI.create(locations[1]); ResourceAddress writeAddress = resourceAddressFactory.newResourceAddress(writeURI); ResourceAddress readAddress = resourceAddressFactory.newResourceAddress(readURI); if (!wsebSession.isClosing()) { wsebSession.setWriteAddress(writeAddress); wsebSession.setReadAddress(readAddress); sessionMap.put(writeAddress, wsebSession); sessionMap.put(readAddress, wsebSession); // attach downstream for read final BridgeConnector bridgeConnector = bridgeServiceFactory.newBridgeConnector(readAddress); bridgeConnector.connect( readAddress, selectReadHandler(readAddress), new IoSessionInitializer<ConnectFuture>() { @Override public void initializeSession(IoSession ioSession, ConnectFuture connectFuture) { HttpSession httpSession = (HttpSession) ioSession; httpSession.setWriteHeader( HttpHeaders.HEADER_X_SEQUENCE_NO, Long.toString(wsebSession.nextReaderSequenceNo())); } }); // activate upstream for write // TODO: Replace usage of suspendWrite/resumeWrite with a WSEB-specific "send queue" // upon which // TODO: locking of writes can be achieved. wsebSession.resumeWrite(); // We are always aligned now. if (session.isIoAligned()) { wsebSession.getProcessor().flush(wsebSession); } }
private IoHandler selectConnectHandler(ResourceAddress address) { Protocol protocol = bridgeServiceFactory.getTransportFactory().getProtocol(address.getResource()); if (protocol instanceof HttpProtocol) { return createHandler; } throw new RuntimeException( getClass() + ": Cannot select a connect handler for address " + address); }
private URI locateSecureAcceptURI(HttpAcceptSession session) throws Exception { // TODO: same-origin requests must consider cross-origin access control // internal redirect to secure resource should not trigger 403 Forbidden ResourceAddress localAddress = session.getLocalAddress(); URI resource = localAddress.getResource(); Protocol resourceProtocol = bridgeServiceFactory.getTransportFactory().getProtocol(resource); if (WsebProtocol.WSEB_SSL == resourceProtocol || WsProtocol.WSS == resourceProtocol) { return resource; } return null; }
@Override protected void doMessageReceived(HttpSession readSession, Object message) throws Exception { ResourceAddress readAddress = BridgeSession.REMOTE_ADDRESS.get(readSession); WsebSession wsebSession = sessionMap.get(readAddress); // handle parallel closure of WSE session during streaming read if (wsebSession == null) { if (logger.isDebugEnabled()) { logger.debug( String.format("Could not find WsebSession for read address:\n" + readAddress)); } return; } WsMessage wsebMessage = (WsMessage) message; IoBufferEx messageBytes = wsebMessage.getBytes(); IoFilterChain filterChain = wsebSession.getTransportSession().getFilterChain(); switch (wsebMessage.getKind()) { case COMMAND: for (Command command : ((WsCommandMessage) wsebMessage).getCommands()) { if (command == Command.reconnect()) { // received a RECONNECT command wsebSession.detachReader(readSession); // re-attach downstream for read final BridgeConnector bridgeConnector = bridgeServiceFactory.newBridgeConnector(readAddress); bridgeConnector.connect(readAddress, selectReadHandler(readAddress), null); break; } else if (command == Command.close()) { // Following should take care of sending CLOSE response and closing reader // (downstream) // Close case was not handled before 3.5.9 filterChain.fireMessageReceived(new WsCloseMessage()); break; } // no-op (0x00) - continue reading commands } break; default: filterChain.fireMessageReceived(wsebMessage); break; } }
@Override protected <T extends ConnectFuture> ConnectFuture connectInternal( ResourceAddress connectAddress, IoHandler handler, final IoSessionInitializer<T> initializer) { final DefaultConnectFuture wseConnectFuture = new DefaultConnectFuture(); // propagate connection failure, if necessary IoFutureListener<ConnectFuture> parentConnectListener = new IoFutureListener<ConnectFuture>() { @Override public void operationComplete(ConnectFuture future) { // fail bridge connect future if parent connect fails if (!future.isConnected()) { wseConnectFuture.setException(future.getException()); } } }; IoSessionInitializer<ConnectFuture> parentInitializer = createParentInitializer(connectAddress, handler, initializer, wseConnectFuture); ResourceAddress httpxeAddress = connectAddress.getTransport(); URI createURI = appendURI(httpxeAddress.getExternalURI(), CREATE_SUFFIX); // default options but clear the transports so they get rebuilt by default ResourceOptions createOptions = ResourceOptions.FACTORY.newResourceOptions(httpxeAddress); createOptions.setOption(ResourceAddress.TRANSPORT, null); createOptions.setOption(ResourceAddress.TRANSPORT_URI, null); ResourceAddress createAddress = resourceAddressFactory.newResourceAddress(createURI, createOptions); BridgeConnector connector = bridgeServiceFactory.newBridgeConnector(createAddress); // TODO: proxy detection, append ?.ki=p on timeout connector .connect(createAddress, selectConnectHandler(createAddress), parentInitializer) .addListener(parentConnectListener); return wseConnectFuture; }
private <T extends ConnectFuture> IoSessionInitializer<ConnectFuture> createParentInitializer( final ResourceAddress connectAddressNext, final IoHandler handler, final IoSessionInitializer<T> initializer, final DefaultConnectFuture wseConnectFuture) { final ResourceAddress connectAddress = connectAddressNext.getTransport(); Protocol protocol = bridgeServiceFactory.getTransportFactory().getProtocol(connectAddress.getResource()); if (!(protocol instanceof HttpProtocol)) { final String message = format( "Cannot create WSEB parent session initializer for address %s", connectAddressNext); if (logger.isInfoEnabled()) { logger.info(message); } throw new RuntimeException(message); } // initialize parent session before connection attempt return new IoSessionInitializer<ConnectFuture>() { @Override public void initializeSession(final IoSession parent, ConnectFuture future) { // initializer for bridge session to specify bridge handler, // and call user-defined bridge session initializer if present final IoSessionInitializer<T> wseSessionInitializer = new IoSessionInitializer<T>() { @Override public void initializeSession(IoSession session, T future) { WsebSession wseSession = (WsebSession) session; wseSession.setHandler(handler); // TODO: add extension filters when we adopt the new webSocket extension SPI wseSession.getTransportSession().getFilterChain().fireSessionCreated(); wseSession.getTransportSession().getFilterChain().fireSessionOpened(); if (initializer != null) { initializer.initializeSession(session, future); } } }; final long sequenceNo = 0; final HttpSession httpSession = (HttpSession) parent; httpSession.setWriteHeader(HEADER_X_ACCEPT_COMMANDS, "ping"); httpSession.setWriteHeader(HttpHeaders.HEADER_X_SEQUENCE_NO, Long.toString(sequenceNo)); final IoBufferAllocatorEx<WsBuffer> allocator = new WsebBufferAllocator(httpSession.getBufferAllocator()); // factory to create a new bridge session Callable<WsebSession> createSession = new Callable<WsebSession>() { @Override public WsebSession call() throws Exception { Callable<WsebSession> wseSessionFactory = new Callable<WsebSession>() { @Override public WsebSession call() throws Exception { WsebSession wsebSession = new WsebSession( httpSession.getIoLayer(), httpSession.getIoThread(), httpSession.getIoExecutor(), WsebConnector.this, getProcessor(), connectAddressNext, connectAddressNext, allocator, null, 0, connectAddressNext.getOption(INACTIVITY_TIMEOUT), false, /* no sequence validation */ sequenceNo, /* starting sequence no */ null); // ability to write will be reactivated when create response returns with // write address wsebSession.suspendWrite(); return wsebSession; } }; return newSession(wseSessionInitializer, wseConnectFuture, wseSessionFactory); } }; WSE_SESSION_FACTORY_KEY.set(httpSession, createSession); WSE_CONNECT_FUTURE_KEY.set(httpSession, wseConnectFuture); } }; }