zoukankan      html  css  js  c++  java
  • Netty5 + HTTPS 练习

      本次以《Netty权威指南》第十章里面的例子为基础修改而来

      HttpsFileServerHandler.java

      1 package com.jieli.nettytest.httpsfile;
      2 
      3 import java.io.File;
      4 import java.io.RandomAccessFile;
      5 import java.net.URLDecoder;
      6 import java.util.regex.Pattern;
      7 
      8 import javax.activation.MimetypesFileTypeMap;
      9 
     10 import io.netty.buffer.ByteBuf;
     11 import io.netty.buffer.Unpooled;
     12 import io.netty.channel.ChannelFuture;
     13 import io.netty.channel.ChannelFutureListener;
     14 import io.netty.channel.ChannelHandlerContext;
     15 import io.netty.channel.ChannelProgressiveFuture;
     16 import io.netty.channel.ChannelProgressiveFutureListener;
     17 import io.netty.channel.SimpleChannelInboundHandler;
     18 import io.netty.handler.codec.http.DefaultFullHttpResponse;
     19 import io.netty.handler.codec.http.DefaultHttpResponse;
     20 import io.netty.handler.codec.http.FullHttpRequest;
     21 import io.netty.handler.codec.http.FullHttpResponse;
     22 import io.netty.handler.codec.http.HttpHeaderNames;
     23 import io.netty.handler.codec.http.HttpHeaderUtil;
     24 import io.netty.handler.codec.http.HttpHeaderValues;
     25 import io.netty.handler.codec.http.HttpMethod;
     26 import io.netty.handler.codec.http.HttpResponse;
     27 import io.netty.handler.codec.http.HttpResponseStatus;
     28 import io.netty.handler.codec.http.HttpVersion;
     29 import io.netty.handler.codec.http.LastHttpContent;
     30 import io.netty.handler.stream.ChunkedFile;
     31 import io.netty.util.CharsetUtil;
     32 
     33 public class HttpsFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{
     34 
     35     private final String url;
     36     
     37     public HttpsFileServerHandler(String url){
     38         this.url = url;
     39     }
     40     
     41     @Override
     42     protected void messageReceived(ChannelHandlerContext ctx,
     43             FullHttpRequest request) throws Exception {
     44         if(!request.decoderResult().isSuccess()){
     45             sendError(ctx, HttpResponseStatus.BAD_REQUEST);
     46             return ;
     47         }
     48         if(request.method() != HttpMethod.GET){
     49             sendError(ctx, HttpResponseStatus.METHOD_NOT_ALLOWED);
     50             return ;
     51         }
     52         
     53         final String uri = request.uri();
     54         final String path = sanitizeUri(uri);
     55         if(path == null){
     56             sendError(ctx, HttpResponseStatus.FORBIDDEN);
     57             return ;
     58         }
     59         File file = new File(path);
     60         if(file.isHidden() || !file.exists()){
     61             sendError(ctx, HttpResponseStatus.NOT_FOUND);
     62             return ;
     63         }
     64         if(file.isDirectory()){
     65             if(uri.endsWith("/")){
     66                 sendListing(ctx, file);
     67             }else{
     68                 sendRedirect(ctx, uri+'/');
     69             }
     70             return ;
     71         }
     72         if(!file.isFile()){
     73             sendError(ctx, HttpResponseStatus.FORBIDDEN);
     74         }
     75         RandomAccessFile accessFile = null;
     76         try {
     77             accessFile = new RandomAccessFile(file, "r");
     78         } catch (Exception e) {
     79             e.printStackTrace();
     80             sendError(ctx, HttpResponseStatus.NOT_FOUND);
     81             return ;
     82         }
     83         long len = accessFile.length();
     84         HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
     85         HttpHeaderUtil.setContentLength(response, len);
     86         setContentTypeHeader(response, file);
     87         if(HttpHeaderUtil.isKeepAlive(request)){
     88             response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
     89         }
     90         ctx.write(response);
     91         ChannelFuture future;
     92         future = ctx.write(new ChunkedFile(accessFile, 0, len, 8192), ctx.newProgressivePromise());
     93         future.addListener(new ChannelProgressiveFutureListener() {
     94             
     95             @Override
     96             public void operationComplete(ChannelProgressiveFuture arg0)
     97                     throws Exception {
     98                 System.out.println("Transfer complete.");
     99             }
    100             
    101             @Override
    102             public void operationProgressed(ChannelProgressiveFuture future, long progress,
    103                     long total) throws Exception {
    104                 if(total < 0){
    105                     System.err.println("Transfer progress:" + progress);
    106                 }else{
    107                     System.err.println("Transfer progress:" + progress +"/" +total);
    108                 }
    109             }
    110         });
    111         ChannelFuture lastfuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    112         if(!HttpHeaderUtil.isKeepAlive(request)){
    113             lastfuture.addListener(ChannelFutureListener.CLOSE);
    114         }
    115     }
    116     
    117     @Override
    118     public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause)
    119             throws Exception {
    120         cause.printStackTrace();
    121         if(ctx.channel().isActive()){
    122             sendError(ctx, HttpResponseStatus.INTERNAL_SERVER_ERROR);
    123         }
    124     }
    125     
    126     private static final Pattern INSECURE_URI = Pattern.compile(".*[<>&"].*");
    127     private String sanitizeUri(String uri){
    128         try {
    129             uri = URLDecoder.decode(uri, "UTF-8");
    130         } catch (Exception e) {
    131             try {
    132                 uri = URLDecoder.decode(uri, "ISO-8859-1");
    133             } catch (Exception e2) {
    134                 throw new Error();
    135             }
    136         }
    137         
    138         if(!uri.startsWith(url)){
    139             return null;
    140         }
    141         
    142         if(!uri.startsWith("/")){
    143             return null;
    144         }
    145         
    146         uri = uri.replace('/', File.separatorChar);
    147         if(uri.contains('.'+File.separator) || uri.startsWith(".")
    148                 || uri.endsWith(".") || INSECURE_URI.matcher(uri).matches()){
    149             return null;
    150         }
    151         return System.getProperty("user.dir") + File.separator + uri;
    152     }
    153     
    154     private static final Pattern ALLOWED_FILE_NAME = Pattern.compile("[A-Za-z0-9][-_A-Za-z0-9\.]*");
    155     
    156     private static void sendListing(ChannelHandlerContext ctx, File dir){
    157         FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
    158         response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
    159         StringBuilder buf = new StringBuilder();
    160         String dirPath = dir.getPath();
    161         buf.append("<!DOCTYPE html
    ");
    162         buf.append("<html><head><title>");
    163         buf.append(dirPath);
    164         buf.append(" 目录: ");
    165         buf.append("</title></head><body>
    ");
    166         buf.append("<h3>");
    167         buf.append(dirPath).append(" 目录 :");
    168         buf.append("</h3>");
    169         buf.append("<ul>");
    170         buf.append("<li>链接: <a href="../">..</a></li>
    ");
    171         for(File f :dir.listFiles()){
    172             if(f.isHidden() || !f.canRead()){
    173                 continue;
    174             }
    175             String name = f.getName();
    176             if(!ALLOWED_FILE_NAME.matcher(name).matches()){
    177                 continue;
    178             }
    179             buf.append("<li>链接:<a href="");
    180             buf.append(name);
    181             buf.append("">");
    182             buf.append(name);
    183             buf.append("</a></li>
    ");
    184         }
    185         buf.append("</ul></body></html>
    ");
    186         ByteBuf buffer = Unpooled.copiedBuffer(buf, CharsetUtil.UTF_8);
    187         response.content().writeBytes(buffer);
    188         buffer.release();
    189         ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    190     }
    191     
    192     private static void sendRedirect(ChannelHandlerContext ctx, String newuri){
    193         FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FOUND);
    194         response.headers().set(HttpHeaderNames.LOCATION, newuri);
    195         ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);
    196     }
    197     
    198     private static void sendError(ChannelHandlerContext ctx, 
    199             HttpResponseStatus status){
    200         FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status,
    201                 Unpooled.copiedBuffer("Failure: " + status.toString()+"
    ", CharsetUtil.UTF_8));
    202         response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
    203         ctx.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE); //异步发送 发送完成后就关闭连接
    204     }
    205     
    206     private static void setContentTypeHeader(HttpResponse response, File file){
    207         MimetypesFileTypeMap typeMap = new MimetypesFileTypeMap();
    208         response.headers().set(HttpHeaderNames.CONTENT_TYPE, typeMap.getContentType(file.getPath()));
    209     }
    210 
    211 }
    View Code

      HttpsFileServer.java

     1 package com.jieli.nettytest.httpsfile;
     2 
     3 import io.netty.bootstrap.ServerBootstrap;
     4 import io.netty.channel.ChannelFuture;
     5 import io.netty.channel.ChannelInitializer;
     6 import io.netty.channel.EventLoopGroup;
     7 import io.netty.channel.nio.NioEventLoopGroup;
     8 import io.netty.channel.socket.SocketChannel;
     9 import io.netty.channel.socket.nio.NioServerSocketChannel;
    10 import io.netty.handler.codec.http.HttpObjectAggregator;
    11 import io.netty.handler.codec.http.HttpRequestDecoder;
    12 import io.netty.handler.codec.http.HttpResponseEncoder;
    13 import io.netty.handler.ssl.SslContext;
    14 import io.netty.handler.ssl.util.SelfSignedCertificate;
    15 import io.netty.handler.stream.ChunkedWriteHandler;
    16 
    17 public class HttpsFileServer {
    18     private static final String DEFAULT_URL = "/src/com/";
    19     
    20     
    21     public void run(final int port, final String url) throws Exception{
    22         
    23         final SslContext sslCtx;
    24         SelfSignedCertificate ssc = new SelfSignedCertificate();
    25          //具体场景要通过文件
    26         sslCtx = SslContext.newServerContext(ssc.certificate(), ssc.privateKey());
    27         
    28         EventLoopGroup bossGroup = new NioEventLoopGroup();
    29         EventLoopGroup workerGroup = new NioEventLoopGroup();
    30         try {
    31             ServerBootstrap b = new ServerBootstrap();
    32             b.group(bossGroup, workerGroup)
    33              .channel(NioServerSocketChannel.class)
    34              .childHandler(new ChannelInitializer<SocketChannel>() {
    35                  @Override
    36                  protected void initChannel(SocketChannel ch) throws Exception {
    37                      ch.pipeline().addLast(sslCtx.newHandler(ch.alloc()));
    38                      ch.pipeline().addLast("http_decoder", new HttpRequestDecoder())
    39                                    .addLast("http-aggregator", new HttpObjectAggregator(65536))
    40                                   .addLast("http-encoder", new HttpResponseEncoder())
    41                                   .addLast("http-chunked", new ChunkedWriteHandler())
    42                                   .addLast("fileserverhandler", new HttpsFileServerHandler(url));
    43                 }
    44             });
    45             
    46             ChannelFuture f = b.bind(port).sync();
    47             
    48             System.out.println("HTTP File Server Start..  http://localhost:"+port+url);
    49             f.channel().closeFuture().sync();
    50         } catch (Exception e) {
    51             e.printStackTrace();
    52         } finally {
    53             bossGroup.shutdownGracefully();
    54             workerGroup.shutdownGracefully();
    55         }
    56     }
    57     
    58     public static void main(String[] args) throws Exception {
    59         new HttpsFileServer().run(7777, DEFAULT_URL);
    60     }
    61 }

       运行结果

  • 相关阅读:
    绑定对象
    类与对象
    视音频技术干货专栏
    sqlite3把字段为int32(用c++的time(nullptr)获取的)的秒数显示为年月日时分秒
    微信小程序开发 --- 小白之路 --- 心得
    spring cloud --- config 配置中心 [本地、git获取配置文件]
    spring cloud --- Zuul --- 心得
    spring boot --- 注解 @Bean 和@Component
    spring cloud --- Feign --- 心得
    spring cloud --- Ribbon 客户端负载均衡 + RestTemplate + Hystrix 熔断器 [服务保护] ---心得
  • 原文地址:https://www.cnblogs.com/wunaozai/p/5280877.html
Copyright © 2011-2022 走看看