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要多很多了.基本上架构都被 ...
随机推荐
- 记录js的一些小技巧
1.取数组最大值,最小值 Math.max.apply(null,[1,2,3,32,3]); Math.min.apply(null,[1,2,3,32,3]); 2.旧版IE setTimeout ...
- 【Android】Android内存机制,了解Android堆和栈
1.dalvik的Heap和Stack 这里说的只是dalvik java部分的内存,实际上除了dalvik部分,还有native. 下面针对上面列出的数据类型进行说明,只有了解了我们申请的数 ...
- 搭建wamp环境,数据库基础知识
服务器管理软件php Apache.net IISjava Tomcat 服务器管理软件起到的作用:管理服务器工作,具体的工作如下:1.静态页面用户将请求发送到服务器,服务器中的服务器管理软件将请求发 ...
- js程序设计01——基本概念
本文为js高级程序设计学习笔记,笔记中不乏本人学习js的一些心得demo,喜欢的朋友可以直接参考原书“javascript高级程序设计”,写本笔记的目的是对js中容易出错.不易理解的地方作个笔记,以免 ...
- GO語言基礎教程:序章
首先自我介紹一下我自己,我是一個coder,目前主要從事B/S程序開發工作,懂點PHP;ASP;JSP;JS;VB;C;DELPHI;JAVA,另外知道幾個數據庫,除此之外別無所長,那麼我為何會選擇學 ...
- Visual Studio 2013 无法正常打开项目文件
提示:无法打开 vcxproj 因为此版本的应用程序不支持其项目类型 ,若要打开它 请使用支持此类型项目的版本. 检查 AppData\Roaming\Microsoft\VisualStudio\ ...
- ACPI I/O resource conflict with SMBus
ACPI I/O resource conflict with SMBus 以電子郵件傳送這篇文章BlogThis!分享至 Twitter分享至 Facebook分享到 Pinterest 這幾天遇到 ...
- [leetcode]Maximum Product Subarray @ Python
原题地址:https://oj.leetcode.com/problems/maximum-product-subarray/ 解题思路:主要需要考虑负负得正这种情况,比如之前的最小值是一个负数,再乘 ...
- 转:简单的RTSP消息交互过程
简单的RTSP消息交互过程 C表示RTSP客户端,S表示RTSP服务端 1. 第一步:查询服务器端可用方法 1.C->S:OPTION request //询问S有哪些方法可用 ...
- requirejs、backbone.js配置
requirejs初探 参考资料官网:http://requirejs.org中文译文:http://makingmobile.org/docs/tools/requirejs-api-zh reuq ...