
io.jsync.http.impl.AsyncHttpHandler Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jsync.io Show documentation
Show all versions of jsync.io Show documentation
jsync.io is a non-blocking, event-driven networking framework for Java
/*
* Copyright (c) 2011-2013 The original author or authors
* ------------------------------------------------------
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* and Apache License v2.0 which accompanies this distribution.
*
* The Eclipse Public License is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* The Apache License v2.0 is available at
* http://www.opensource.org/licenses/apache2.0.php
*
* You may elect to redistribute this code under either of these licenses.
*/
package io.jsync.http.impl;
import io.jsync.http.WebSocketFrame.FrameType;
import io.jsync.http.impl.ws.DefaultWebSocketFrame;
import io.jsync.http.impl.ws.WebSocketFrameInternal;
import io.jsync.impl.AsyncInternal;
import io.jsync.impl.DefaultContext;
import io.jsync.net.impl.AsyncHandler;
import io.jsync.net.impl.ConnectionBase;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufAllocator;
import io.netty.buffer.ByteBufHolder;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelPromise;
import io.netty.handler.codec.DecoderResult;
import io.netty.handler.codec.http.DefaultHttpContent;
import io.netty.handler.codec.http.HttpContent;
import io.netty.handler.codec.http.HttpObject;
import io.netty.handler.codec.http.LastHttpContent;
import io.netty.handler.codec.http.websocketx.*;
import java.util.Map;
import static io.jsync.http.WebSocketFrame.FrameType.*;
/**
* @author Norman Maurer
*/
public abstract class AsyncHttpHandler extends AsyncHandler {
private final AsyncInternal async;
protected AsyncHttpHandler(AsyncInternal async, Map connectionMap) {
super(async, connectionMap);
this.async = async;
}
private static ByteBuf safeBuffer(ByteBufHolder holder, ByteBufAllocator allocator) {
return safeBuffer(holder.content(), allocator);
}
@Override
protected void channelRead(final C connection, final DefaultContext context, final ChannelHandlerContext chctx, final Object msg) throws Exception {
if (msg instanceof HttpObject) {
DecoderResult result = ((HttpObject) msg).getDecoderResult();
if (result.isFailure()) {
chctx.pipeline().fireExceptionCaught(result.cause());
return;
}
}
if (connection != null) {
// we are reading from the channel
Channel ch = chctx.channel();
// We need to do this since it's possible the server is being used from a worker context
if (context.isOnCorrectWorker(ch.eventLoop())) {
try {
async.setContext(context);
doMessageReceived(connection, chctx, msg);
} catch (Throwable t) {
context.reportException(t);
}
} else {
context.execute(new Runnable() {
public void run() {
try {
doMessageReceived(connection, chctx, msg);
} catch (Throwable t) {
context.reportException(t);
}
}
});
}
} else {
try {
doMessageReceived(connection, chctx, msg);
} catch (Throwable t) {
chctx.pipeline().fireExceptionCaught(t);
}
}
}
@Override
protected Object safeObject(Object msg, ByteBufAllocator allocator) throws Exception {
if (msg instanceof HttpContent) {
HttpContent content = (HttpContent) msg;
ByteBuf buf = content.content();
if (buf != Unpooled.EMPTY_BUFFER && buf.isDirect()) {
ByteBuf newBuf = safeBuffer(content, allocator);
if (msg instanceof LastHttpContent) {
LastHttpContent last = (LastHttpContent) msg;
return new AssembledLastHttpContent(newBuf, last.trailingHeaders(), last.getDecoderResult());
} else {
return new DefaultHttpContent(newBuf);
}
}
} else if (msg instanceof WebSocketFrame) {
ByteBuf payload = safeBuffer((WebSocketFrame) msg, allocator);
boolean isFinal = ((WebSocketFrame) msg).isFinalFragment();
FrameType frameType;
if (msg instanceof BinaryWebSocketFrame) {
frameType = BINARY;
} else if (msg instanceof CloseWebSocketFrame) {
frameType = CLOSE;
} else if (msg instanceof PingWebSocketFrame) {
frameType = PING;
} else if (msg instanceof PongWebSocketFrame) {
frameType = PONG;
} else if (msg instanceof TextWebSocketFrame) {
frameType = TEXT;
} else if (msg instanceof ContinuationWebSocketFrame) {
frameType = CONTINUATION;
} else {
throw new IllegalStateException("Unsupported websocket msg " + msg);
}
return new DefaultWebSocketFrame(frameType, payload, isFinal);
}
return msg;
}
@Override
public void write(ChannelHandlerContext ctx, Object msg, ChannelPromise promise) throws Exception {
if (msg instanceof WebSocketFrameInternal) {
WebSocketFrameInternal frame = (WebSocketFrameInternal) msg;
ByteBuf buf = frame.getBinaryData();
if (buf != Unpooled.EMPTY_BUFFER) {
buf = safeBuffer(buf, ctx.alloc());
}
switch (frame.type()) {
case BINARY:
msg = new BinaryWebSocketFrame(buf);
break;
case TEXT:
msg = new TextWebSocketFrame(buf);
break;
case CLOSE:
msg = new CloseWebSocketFrame(true, 0, buf);
break;
case CONTINUATION:
msg = new ContinuationWebSocketFrame(buf);
break;
case PONG:
msg = new PongWebSocketFrame(buf);
break;
case PING:
msg = new PingWebSocketFrame(buf);
break;
default:
throw new IllegalStateException("Unsupported websocket msg " + msg);
}
}
ctx.write(msg, promise);
}
protected abstract void doMessageReceived(C connection, ChannelHandlerContext ctx, Object msg) throws Exception;
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy