/*
* Copyright 2015 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package io.netty.example.http.router;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaders;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.HttpVersion;
import io.netty.handler.codec.http.router.RouteResult;
import io.netty.handler.codec.http.router.Router;
import io.netty.util.CharsetUtil;
@ChannelHandler.Sharable
public class HttpRouterServerHandler extends SimpleChannelInboundHandler<HttpRequest> {
private final Router<String> router;
public HttpRouterServerHandler(Router<String> router) {
this.router = router;
}
@Override
public void channelRead0(ChannelHandlerContext ctx, HttpRequest req) {
if (HttpHeaders.is100ContinueExpected(req)) {
ctx.writeAndFlush(new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.CONTINUE));
return;
}
HttpResponse res = createResponse(req, router);
flushResponse(ctx, req, res);
}
private static HttpResponse createResponse(HttpRequest req, Router<String> router) {
RouteResult<String> routeResult = router.route(req.getMethod(), req.getUri());
// Display debug info.
//
// For simplicity of this example, route targets are just simple strings.
// But you can make them classes, and here once you get a target class,
// you can create an instance of it and dispatch the request to the instance etc.
StringBuilder content = new StringBuilder();
content.append("router: \n" + router + "\n");
content.append("req: " + req + "\n\n");
content.append("routeResult: \n");
content.append("target: " + routeResult.target() + "\n");
content.append("pathParams: " + routeResult.pathParams() + "\n");
content.append("queryParams: " + routeResult.queryParams() + "\n\n");
content.append("allowedMethods: " + router.allowedMethods(req.getUri()));
FullHttpResponse res = new DefaultFullHttpResponse(
HttpVersion.HTTP_1_1, HttpResponseStatus.OK,
Unpooled.copiedBuffer(content.toString(), CharsetUtil.UTF_8)
);
res.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/plain");
res.headers().set(HttpHeaders.Names.CONTENT_LENGTH, res.content().readableBytes());
return res;
}
private static ChannelFuture flushResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
if (!HttpHeaders.isKeepAlive(req)) {
return ctx.writeAndFlush(res).addListener(ChannelFutureListener.CLOSE);
} else {
res.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
return ctx.writeAndFlush(res);
}
}
}