Netty5 + HTTPS 练习
本次以《Netty权威指南》第十章里面的例子为基础修改而来
HttpsFileServerHandler.java
package com.jieli.nettytest.httpsfile; import java.io.File;
import java.io.RandomAccessFile;
import java.net.URLDecoder;
import java.util.regex.Pattern; import javax.activation.MimetypesFileTypeMap; import io.netty.buffer.ByteBuf;
import io.netty.buffer.Unpooled;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelProgressiveFuture;
import io.netty.channel.ChannelProgressiveFutureListener;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.DefaultFullHttpResponse;
import io.netty.handler.codec.http.DefaultHttpResponse;
import io.netty.handler.codec.http.FullHttpRequest;
import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpHeaderNames;
import io.netty.handler.codec.http.HttpHeaderUtil;
import io.netty.handler.codec.http.HttpHeaderValues;
import io.netty.handler.codec.http.HttpMethod;
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.LastHttpContent;
import io.netty.handler.stream.ChunkedFile;
import io.netty.util.CharsetUtil; public class HttpsFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{ private final String url; public HttpsFileServerHandler(String url){
this.url = url;
} @Override
protected void messageReceived(ChannelHandlerContext ctx,
FullHttpRequest request) throws Exception {
if(!request.decoderResult().isSuccess()){
sendError(ctx, HttpResponseStatus.BAD_REQUEST);
return ;
}
if(request.method() != HttpMethod.GET){
sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);
return ;
} final String uri = request.uri();
final String path = sanitizeUri(uri);
if(path == null){
sendError(ctx, HttpResponseStatus.FORBIDDEN);
return ;
}
File file = new File(path);
if(file.isHidden() || !file.exists()){
sendError(ctx, HttpResponseStatus.NOT_FOUND);
return ;
}
if(file.isDirectory()){
if(uri.endsWith("/")){
sendListing(ctx, file);
}else{
sendRedirect(ctx, uri+'/');
}
return ;
}
if(!file.isFile()){
sendError(ctx, HttpResponseStatus.FORBIDDEN);
}
RandomAccessFile accessFile = null;
try {
accessFile = new RandomAccessFile(file, "r");
} catch (Exception e) {
e.printStackTrace();
sendError(ctx, HttpResponseStatus.NOT_FOUND);
return ;
}
long len = accessFile.length();
HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
HttpHeaderUtil.setContentLength(response, len);
setContentTypeHeader(response, file);
if(HttpHeaderUtil.isKeepAlive(request)){
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
ctx.write(response);
ChannelFuture future;
future = ctx.write(new ChunkedFile(accessFile, 0, len, 8192), ctx.newProgressivePromise());
future.addListener(new ChannelProgressiveFutureListener() { @Override
public void operationComplete(ChannelProgressiveFuture arg0)
throws Exception {
System.out.println("Transfer complete.");
} @Override
public void operationProgressed(ChannelProgressiveFuture future, long progress,
long total) throws Exception {
if(total < 0){
System.err.println("Transfer progress:" + progress);
}else{
System.err.println("Transfer progress:" + progress +"/" +total);
}
}
});
ChannelFuture lastfuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
if(!HttpHeaderUtil.isKeepAlive(request)){
lastfuture.addListener(ChannelFutureListener.CLOSE);
}
} @Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
throws Exception {
cause.printStackTrace();
if(ctx.channel().isActive()){
sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
}
} private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&\"].*");
private String sanitizeUri(String uri){
try {
uri = URLDecoder.decode(uri, "UTF-8");
} catch (Exception e) {
try {
uri = URLDecoder.decode(uri, "ISO-8859-1");
} catch (Exception e2) {
throw new Error();
}
} if(!uri.startsWith(url)){
return null;
} if(!uri.startsWith("/")){
return null;
} uri = uri.replace('/', File.separatorChar);
if(uri.contains('.'+File.separator) || uri.startsWith(".")
|| uri.endsWith(".") || INSECURE_URI.matcher(uri).matches()){
return null;
}
return System.getProperty("user.dir") + File.separator + uri;
} private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\\.]*"); private static void sendListing(ChannelHandlerContext ctx, File dir){
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
StringBuilder buf = new StringBuilder();
String dirPath = dir.getPath();
buf.append("<!DOCTYPE html\r\n");
buf.append("<html><head><title>");
buf.append(dirPath);
buf.append(" 目录: ");
buf.append("</title></head><body>\r\n");
buf.append("<h3>");
buf.append(dirPath).append(" 目录 :");
buf.append("</h3>");
buf.append("<ul>");
buf.append("<li>链接: <a href=\"../\">..</a></li>\r\n");
for(File f :dir.listFiles()){
if(f.isHidden() || !f.canRead()){
continue;
}
String name = f.getName();
if(!ALLOWED_FILE_NAME.matcher(name).matches()){
continue;
}
buf.append("<li>链接:<a href=\"");
buf.append(name);
buf.append("\">");
buf.append(name);
buf.append("</a></li>\r\n");
}
buf.append("</ul></body></html>\r\n");
ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);
response.content().writeBytes(buffer);
buffer.release();
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
} private static void sendRedirect(ChannelHandlerContext ctx, String newuri){
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FOUND);
response.headers().set(HttpHeaderNames.LOCATION, newuri);
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
} private static void sendError(ChannelHandlerContext ctx,
HttpResponseStatus status){
FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,
Unpooled.copiedBuffer("Failure: " + status.toString()+"\r\n", CharsetUtil.UTF_8));
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); //异步发送 发送完成后就关闭连接
} private static void setContentTypeHeader(HttpResponse response, File file){
MimetypesFileTypeMap typeMap = new MimetypesFileTypeMap();
response.headers().set(HttpHeaderNames.CONTENT_TYPE, typeMap.getContentType(file.getPath()));
} }
HttpsFileServer.java
package com.jieli.nettytest.httpsfile; import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.handler.stream.ChunkedWriteHandler; public class HttpsFileServer {
private static final String DEFAULT_URL = "/src/com/"; public void run(final int port, final String url) throws Exception{ final SslContext sslCtx;
SelfSignedCertificate ssc = new SelfSignedCertificate();
//具体场景要通过文件
sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey()); EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try {
ServerBootstrap b = new ServerBootstrap();
b.group(bossGroup, workerGroup)
.channel(NioServerSocketChannel.class)
.childHandler(new ChannelInitializer<SocketChannel>() {
@Override
protected void initChannel(SocketChannel ch) throws Exception {
ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()));
ch.pipeline().addLast("http_decoder", new HttpRequestDecoder())
.addLast("http-aggregator", new HttpObjectAggregator(65536))
.addLast("http-encoder", new HttpResponseEncoder())
.addLast("http-chunked", new ChunkedWriteHandler())
.addLast("fileserverhandler", new HttpsFileServerHandler(url));
}
}); ChannelFuture f = b.bind(port).sync(); System.out.println("HTTP File Server Start.. http://localhost:"+port+url);
f.channel().closeFuture().sync();
} catch (Exception e) {
e.printStackTrace();
} finally {
bossGroup.shutdownGracefully();
workerGroup.shutdownGracefully();
}
} public static void main(String[] args) throws Exception {
new HttpsFileServer().run(7777, DEFAULT_URL);
}
}
运行结果
Netty5 + HTTPS 练习的更多相关文章
- netty5 HTTP协议栈浅析与实践
一.说在前面的话 前段时间,工作上需要做一个针对视频质量的统计分析系统,各端(PC端.移动端和 WEB端)将视频质量数据放在一个 HTTP 请求中上报到服务器,服务器对数据进行解析.分拣后从不同的 ...
- Netty5 + WebSocket 练习
1. 了解WebSocket知识 略2. websocket实现系统简单反馈时间 WebSocketServerHandler.java package com.jieli.nettytest.web ...
- Netty5 + Protobuf 使用
1. 安装开发环境 1.1 Netty环境 这里我使用Netty5.0.0版本 到这里下载即可http://netty.io/ 下载netty-all-5.0.0.Alpha2.jar 这个jar包简 ...
- 《Netty5.0架构剖析和源码解读》【PDF】下载
<Netty5.0架构剖析和源码解读>[PDF]下载链接: https://u253469.pipipan.com/fs/253469-230062545 内容简介 Netty 是个异步的 ...
- Netty5客户端源码解析
Netty5客户端源码解析 今天来分析下netty5的客户端源码,示例代码如下: import io.netty.bootstrap.Bootstrap; import io.netty.channe ...
- Netty5服务端源码解析
Netty5源码解析 今天让我来总结下netty5的服务端代码. 服务端(ServerBootstrap) 示例代码如下: import io.netty.bootstrap.ServerBootst ...
- SSM整合Netty5.0详细说明
阅读本文约“3.2分钟” 最近又有粉丝加Q群讨论netty整合SSM项目的方式等,我在这里抽了休息日的时候整理一下,一步一步的记录,注意的是,本案例仅实现了用netty整合SSM后与单片机等类TCP应 ...
- Netty5.x 和3.x、4.x的区别及注意事项(官方翻译)
Netty5.x 和3.x.4.x的区别及注意事项 (官方翻译) 本文档列出了Netty5新版本中值得注意变化和新特性列表.帮助你的应用更好的适应新的版本. 不像Netty3.x和4.x之间的变化 ...
- nio之netty5应用
1.netty5和netty4的区别不是很大,但是与netty3差别还是有的.这里不介绍netty4,因为和netty5的方式都差不多.netty5的复杂性相对于netty3要多很多了.基本上架构都被 ...
随机推荐
- paip.slap工具与于64位win7与JDBC的性能对比
paip.slap工具与于64位win7与JDBC的性能对比 作者Attilax 艾龙, EMAIL:1466519819@qq.com 来源:attilax的专栏 地址:http://blog ...
- paip.哈米架构CAO.txt
paip.哈米架构CAO.txt 智能语义搜索方法,建立了学习机,通过对用户点击情况的处理,对知识库进行及时更新,并将搜索结果根据关联度进行排序及重新排序,使用户能快速查询信息,从而能不断适应用户使用 ...
- iOS开发-xCode代码格式化xAlign
xCode默认是可以进行代码格式化的,能满足基础开发需求,如果想要个性一些代码对齐方式宏对齐,等号对齐,属性对齐,xAlign就提供了以上三种功能,参考文中效果~ 基础效果 等号对齐: 属性对齐: 宏 ...
- python星号变量
python 元组 tupletup1 = ('physics', 'chemistry', 1998, 2000)tup2 = (1, 2, 3, 4, 5)tup3 = 'a', 'b', 'c' ...
- 通过MSSQl作业定时执行批处理BAT文件
前言 有些时候,我们可能会需要定时执行一下批处理来达到一定的目的,比如Oracle数据库的定时备份,当然Oracle也可以通过Rman实现定时备份.我们大多数的时候是通过操作系统的计划任务实现定时执行 ...
- android: PendingIntent的使用
PendingIntent的Flags的类型: * Flags的类型: FLAG_ONE_SHOT:得到的pi只能使用一次,第二次使用该pi时报错 FLAG_NO_CREATE: 当pi不存在时,不创 ...
- 解决 Android Studio 乱码问题
http://www.eoeandroid.com/thread-275485-1-1.html 很多同学都安装了Android Studio,但是发现中文是乱码,其实这个很好解决的.在IDE里点击F ...
- [苏飞开发助手V1.0测试版]官方教程与升级报告
[苏飞开发助手V1.0测试版]官方教程与升级报告导读部分----------------------------------------------------------------- ...
- 一个优秀windows C++程序员的知识体系
思考一个优秀windows C++ 程序员该有哪些知识,可最终发现什么知识都不能少, 看下图: 除了上面知识,程序员还要不断学习, 保持对新知识的热情. 转自http://www.cppblog.co ...
- 21个高质量的Swift开源iOS App
原文:21 Amazing Open Source iOS Apps Written in Swift 对Swift初学者来说,学习开源项目,阅读源码是个不错的方法.在这篇文章中,基于对代码质量和排名 ...