@Override public final boolean trySend(WebDataMessage message) { if (!message.isBinary()) ctx.writeAndFlush(new TextWebSocketFrame(message.getStringBody())); else ctx.writeAndFlush( new BinaryWebSocketFrame(Unpooled.wrappedBuffer(message.getByteBufferBody()))); return true; }
@Override protected final void die(Throwable cause) { super.die(cause); if (ctx.channel().isOpen()) ctx.close(); // Ensure to release server references userActor = null; ctx = null; }
private void handleWebSocketFrame(ChannelHandlerContext ctx, WebSocketFrame frame) { // Check for closing frame if (frame instanceof CloseWebSocketFrame) { handshaker.close(ctx.channel(), (CloseWebSocketFrame) frame.retain()); return; } if (frame instanceof PingWebSocketFrame) { ctx.channel().writeAndFlush(new PongWebSocketFrame(frame.content().retain())); return; } if (frame instanceof ContinuationWebSocketFrame) return; if (frame instanceof TextWebSocketFrame) webSocketActor.onMessage(((TextWebSocketFrame) frame).text()); else webSocketActor.onMessage(frame.content().nioBuffer()); }
@Override public final boolean trySend(WebDataMessage res) { final ByteBuf buf; final String stringBody = res.getStringBody(); if (stringBody != null) { byte[] bs = stringBody.getBytes(encoding); buf = Unpooled.wrappedBuffer(bs); } else { buf = Unpooled.wrappedBuffer(res.getByteBufferBody()); } ctx.writeAndFlush(buf); return true; }
private static void writeHttpResponse( ChannelHandlerContext ctx, FullHttpRequest req, FullHttpResponse res, Boolean close) { if (!omitDateHeader && !res.headers().contains(DefaultHttpHeaders.Names.DATE)) DefaultHttpHeaders.addDateHeader(res, DefaultHttpHeaders.Names.DATE, new Date()); // Send the response and close the connection if necessary. if (!HttpHeaders.isKeepAlive(req) || res.getStatus().code() != 200 || close == null || close) { res.headers().set(CONNECTION, HttpHeaders.Values.CLOSE); ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE); } else { res.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); write(ctx, res); } }
private static ChannelFuture write(ChannelHandlerContext ctx, Object res) { return ctx.writeAndFlush(res); // : ctx.write(res); }
@Override public final void close() { if (ctx.channel().isOpen()) ctx.close(); if (actor != null) actor.die(null); }
@Override public final boolean trySend(HttpResponse message) { try { final HttpRequestWrapper nettyRequest = (HttpRequestWrapper) message.getRequest(); final FullHttpRequest req = nettyRequest.req; final ChannelHandlerContext ctx = nettyRequest.ctx; final HttpResponseStatus status = HttpResponseStatus.valueOf(message.getStatus()); if (message.getStatus() >= 400 && message.getStatus() < 600) { sendHttpResponse( ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), status), false); close(); return true; } if (message.getRedirectPath() != null) { sendHttpRedirect(ctx, req, message.getRedirectPath()); close(); return true; } FullHttpResponse res; if (message.getStringBody() != null) res = new DefaultFullHttpResponse( req.getProtocolVersion(), status, Unpooled.wrappedBuffer(message.getStringBody().getBytes())); else if (message.getByteBufferBody() != null) res = new DefaultFullHttpResponse( req.getProtocolVersion(), status, Unpooled.wrappedBuffer(message.getByteBufferBody())); else res = new DefaultFullHttpResponse(req.getProtocolVersion(), status); if (message.getCookies() != null) { final ServerCookieEncoder enc = ServerCookieEncoder.STRICT; for (final Cookie c : message.getCookies()) HttpHeaders.setHeader(res, COOKIE, enc.encode(getNettyCookie(c))); } if (message.getHeaders() != null) { for (final Map.Entry<String, String> h : message.getHeaders().entries()) HttpHeaders.setHeader(res, h.getKey(), h.getValue()); } if (message.getContentType() != null) { String ct = message.getContentType(); if (message.getCharacterEncoding() != null) ct = ct + "; charset=" + message.getCharacterEncoding().name(); HttpHeaders.setHeader(res, CONTENT_TYPE, ct); } final boolean sseStarted = message.shouldStartActor(); if (trackSession(sseStarted)) { final String sessionId = UUID.randomUUID().toString(); res.headers() .add(SET_COOKIE, ServerCookieEncoder.STRICT.encode(SESSION_COOKIE_KEY, sessionId)); startSession(sessionId, actorContext); } if (!sseStarted) { final String stringBody = message.getStringBody(); long contentLength = 0L; if (stringBody != null) contentLength = stringBody.getBytes().length; else { final ByteBuffer byteBufferBody = message.getByteBufferBody(); if (byteBufferBody != null) contentLength = byteBufferBody.remaining(); } res.headers().add(CONTENT_LENGTH, contentLength); } final HttpStreamActorAdapter httpStreamActorAdapter; if (sseStarted) // This will copy the request content, which must still be referenceable, doing before the // request handler // unallocates it (unfortunately it is explicitly reference-counted in Netty) httpStreamActorAdapter = new HttpStreamActorAdapter(ctx, req); else httpStreamActorAdapter = null; sendHttpResponse(ctx, req, res, false); if (sseStarted) { if (httpResponseEncoderName != null) { ctx.pipeline().remove(httpResponseEncoderName); } else { final ChannelPipeline pl = ctx.pipeline(); final List<String> handlerKeysToBeRemoved = new ArrayList<>(); for (final Map.Entry<String, ChannelHandler> e : pl) { if (e.getValue() instanceof HttpResponseEncoder) handlerKeysToBeRemoved.add(e.getKey()); } for (final String k : handlerKeysToBeRemoved) pl.remove(k); } try { message.getFrom().send(new HttpStreamOpened(httpStreamActorAdapter.ref(), message)); } catch (SuspendExecution e) { throw new AssertionError(e); } } return true; } finally { if (actor != null) actor.unwatch(); } }
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws SuspendExecution { // Handle a bad request. if (!req.getDecoderResult().isSuccess()) { sendHttpResponse( ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), BAD_REQUEST), false); return; } final String uri = req.getUri(); final Context actorCtx = selector.get(ctx, req); assert actorCtx != null; final ReentrantLock lock = actorCtx.getLock(); assert lock != null; lock.lock(); try { final ActorRef<? extends WebMessage> userActorRef = actorCtx.getRef(); ActorImpl internalActor = (ActorImpl) actorCtx.getAttachments().get(ACTOR_KEY); if (userActorRef != null) { if (actorCtx.handlesWithWebSocket(uri)) { if (internalActor == null || !(internalActor instanceof WebSocketActorAdapter)) { //noinspection unchecked webSocketActor = new WebSocketActorAdapter(ctx, (ActorRef<? super WebMessage>) userActorRef); addActorToContextAndUnlock(actorCtx, webSocketActor, lock); } // Handshake final WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(uri, null, true); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { @SuppressWarnings("unchecked") final ActorRef<WebMessage> userActorRef0 = (ActorRef<WebMessage>) webSocketActor.userActor; handshaker .handshake(ctx.channel(), req) .addListener( new GenericFutureListener<ChannelFuture>() { @Override public void operationComplete(ChannelFuture future) throws Exception { FiberUtil.runInFiber( new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { userActorRef0.send( new WebSocketOpened(WebActorHandler.this.webSocketActor.ref())); } }); } }); } return; } else if (actorCtx.handlesWithHttp(uri)) { if (internalActor == null || !(internalActor instanceof HttpActorAdapter)) { //noinspection unchecked internalActor = new HttpActorAdapter( (ActorRef<HttpRequest>) userActorRef, actorCtx, httpResponseEncoderName); addActorToContextAndUnlock(actorCtx, internalActor, lock); } //noinspection unchecked ((HttpActorAdapter) internalActor).service(ctx, req); return; } } } finally { if (lock.isHeldByCurrentStrand() && lock.isLocked()) lock.unlock(); } sendHttpResponse( ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), NOT_FOUND), false); }
@Override public final void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) { if (ctx.channel().isOpen()) ctx.close(); log.error("Exception caught", cause); }
@Override public final void channelReadComplete(ChannelHandlerContext ctx) { ctx.flush(); }