Neety+SpringBoot写一个基于Http协议的文件服务器

来源:互联网 发布:香橙派 ubuntu 编辑:程序博客网 时间:2024/06/09 08:03

NettyApplication
package com.xh.netty;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplicationpublic class NettyApplication {   public static void main(String[] args) {      SpringApplication.run(NettyApplication.class, args);      String[] argList =args;      System.out.println("+++++++++++++Simple Netty HttpFileServer+++++++++++++++");      System.out.println("+            VERSION 1.0.1                            +");      System.out.println("+            AUTHER:XH                                +");      System.out.println("+++++++++++++++++++++++++++++++++++++++++++++++++++++++");      if (args.length==0){         System.out.println("Usage: java -var thisPackageName.jar [-options][args...]");         System.out.println("Use -h for more infomation");         System.out.println("default port is 8080 , webRoot is /root ");      }else {         for (int i=0;i<argList.length;i++){            if (argList[i].equalsIgnoreCase("-h")){               System.out.println("-p your Listern port");               System.out.println("-f your webRoot path");               System.out.println("Example:java -jar netty-0.0.1-SNAPSHOT.jar -p 80 -f /root");               return;            }else {               if (argList[i].equalsIgnoreCase("-p")){                  try{                     HttpFileServer.PORT=Integer.valueOf(argList[i+1]);                  }catch (NumberFormatException e){                     System.out.println("wrong number for you port");                     System.out.println("Use -h for more infomation");                     e.printStackTrace();                     return;                  }               }               if (argList[i].equalsIgnoreCase("-f")){                  try{                     HttpFileServer.WEBROOT=argList[i+1];                  }catch (Exception e){                     System.out.println("wrong path for you webRoot");                     System.out.println("Use -h for more infomation");                     e.printStackTrace();                     return;                  }               }            }         }      }      try {         HttpFileServer.main();      } catch (InterruptedException e) {         e.printStackTrace();      }   }}

HttpFileServer
package com.xh.netty;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.stream.ChunkedWriteHandler;/** * Created by root on 8/14/17. */public class HttpFileServer {    public static  String WEBROOT = "/root";    public static  int PORT = 8080;    public void run(final int port ,  final String url) throws InterruptedException {        EventLoopGroup bossGroup=new NioEventLoopGroup();        EventLoopGroup workerGroup=new NioEventLoopGroup();        try{            ServerBootstrap bootstrap=new ServerBootstrap();            bootstrap.group(bossGroup,workerGroup)                    .channel(NioServerSocketChannel.class)                    .childHandler(new ChannelInitializer<SocketChannel>() {                        protected void initChannel(SocketChannel socketChannel) throws Exception {                            socketChannel.pipeline().addLast("http-decoder",new HttpRequestDecoder());                            socketChannel.pipeline().addLast("http-aggregator",new HttpObjectAggregator(65536));                            socketChannel.pipeline().addLast("http-encoder",new HttpResponseEncoder());                            socketChannel.pipeline().addLast("http-chunked",new ChunkedWriteHandler());                            socketChannel.pipeline().addLast("fileServerHandler",new HttpFileServerHandler(url));                        }                    });            ChannelFuture future = bootstrap.bind("127.0.0.1",port).sync();            System.out.println("服务器已启动>>网址:"+"127.0.0.1:"+port+url);            future.channel().closeFuture().sync();        }catch (Exception e){            e.printStackTrace();        }finally {            bossGroup.shutdownGracefully();            workerGroup.shutdownGracefully();        }    }    public static void main() throws InterruptedException {        new HttpFileServer().run(PORT,WEBROOT);    }}


HttpFileServerHandler
package com.xh.netty;import io.netty.buffer.ByteBuf;import io.netty.buffer.Unpooled;import io.netty.channel.*;import io.netty.handler.codec.http.*;import io.netty.handler.codec.http.HttpResponseStatus;import io.netty.handler.stream.ChunkedFile;import io.netty.util.CharsetUtil;import javax.activation.MimetypesFileTypeMap;import java.io.File;import java.io.FileNotFoundException;import java.io.RandomAccessFile;import java.net.URLDecoder;import java.util.regex.Pattern;import static io.netty.handler.codec.http.HttpHeaderNames.*;import static io.netty.handler.codec.http.HttpHeaderUtil.isKeepAlive;import static io.netty.handler.codec.http.HttpHeaderUtil.setContentLength;import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;import static io.netty.handler.codec.http.HttpResponseStatus.*;import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;/** * Created by root on 8/14/17. */public class HttpFileServerHandler extends SimpleChannelInboundHandler<FullHttpRequest>{    private final String url;    String WEBROOT = HttpFileServer.WEBROOT;    public HttpFileServerHandler(String url) {        this.url = url;    }    protected void messageReceived(ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) throws Exception {        if (!fullHttpRequest.decoderResult().isSuccess()){            sendError(channelHandlerContext, HttpResponseStatus.BAD_REQUEST);            return;        }        if (fullHttpRequest.method()!= HttpMethod.GET){            sendError(channelHandlerContext,HttpResponseStatus.METHOD_NOT_ALLOWED);            return;        }        String uri=fullHttpRequest.uri();        if (uri==null||uri.trim().equalsIgnoreCase("")){            uri="/";        }        if (uri.trim().equalsIgnoreCase("/")){            uri= WEBROOT;        }        if(!uri.startsWith(WEBROOT)){            uri= WEBROOT +uri;        }        final String path=sanitizeUri(uri);        if (path==null){            sendError(channelHandlerContext,HttpResponseStatus.FORBIDDEN);            return;        }        File file=new File(path);        if (file.isHidden()||!file.exists()){            sendError(channelHandlerContext,HttpResponseStatus.NOT_FOUND);            return;        }        if (file.isDirectory()){            if (uri.endsWith("/")){                senfListing(channelHandlerContext,file);            }else {                sendRedirect(channelHandlerContext,uri+"/");            }            return;        }        if (!file.isFile()){            sendError(channelHandlerContext,HttpResponseStatus.FORBIDDEN);            return;        }        RandomAccessFile randomAccessFile=null;        try{            randomAccessFile=new RandomAccessFile(file,"r");        }catch (FileNotFoundException e){            e.printStackTrace();            sendError(channelHandlerContext,HttpResponseStatus.NOT_FOUND);            return;        }        Long fileLength=randomAccessFile.length();        HttpResponse httpResponse=new DefaultHttpResponse(HTTP_1_1,OK);        setContentLength(httpResponse,fileLength);        setContentTypeHeader(httpResponse,file);        if (isKeepAlive(fullHttpRequest)){            httpResponse.headers().set(CONNECTION,KEEP_ALIVE);        }        channelHandlerContext.writeAndFlush(httpResponse);        ChannelFuture sendFileFuture = channelHandlerContext.write(                new ChunkedFile(randomAccessFile,0,fileLength,8192),channelHandlerContext.newProgressivePromise());        sendFileFuture.addListener(new ChannelProgressiveFutureListener() {            public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {                if (total<0){                    System.err.println("progress:"+progress);                }else {                    System.err.println("progress:"+progress+"/"+total);                }            }            public void operationComplete(ChannelProgressiveFuture future) {                System.err.println("complete");            }        });        ChannelFuture lastChannelFuture=channelHandlerContext.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);        if (!isKeepAlive(fullHttpRequest)){            lastChannelFuture.addListener(ChannelFutureListener.CLOSE );        }    }    @Override    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {        cause.printStackTrace();        if (ctx.channel().isActive()){            sendError(ctx,INTERNAL_SERVER_ERROR);        }    }    private static final Pattern INSECURE_URI=Pattern.compile(".*[<>&\"].*");    public String sanitizeUri(String uri){        try{            uri= URLDecoder.decode(uri,"UTF-8");        }catch (Exception e){            try{                uri= URLDecoder.decode(uri,"ISO-8859-1");            }catch (Exception ew){                ew.printStackTrace();            }        }        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 uri;//System.getProperty("user.dir")+uri    }    private static final Pattern ALLOWED_FILE_NAME=Pattern.compile("[a-zA-Z0-9\\.]*");    private void senfListing(ChannelHandlerContext channelHandlerContext, File dir) {        FullHttpResponse response=new DefaultFullHttpResponse(HTTP_1_1,OK);        response.headers().set(CONTENT_TYPE,"text/html;charset=UTF-8");        StringBuilder builder =new StringBuilder();        String dirPath=dir.getPath();        builder.append("<!DOCTYPE html> \r\n");        builder.append("<html><head><title>");        builder.append(dirPath);        builder.append("目录:");        builder.append("</title></head><body>\r\n");        builder.append("<h3>");        builder.append(dirPath).append("目录:");        builder.append("</h3>\r\n");        builder.append("<ul>");        builder.append("<li>链接:<a href=\"../\">..</a></li>\r\n");        for (File f:dir.listFiles()){            if (f.isHidden()||!f.canRead()){                continue;            }            String fname=f.getName();            if (!ALLOWED_FILE_NAME.matcher(fname).matches()){                continue;            }            builder.append("<li>链接:<a href=\" ");            builder.append(fname);            builder.append("\" >");            builder.append(fname);            builder.append("</a></li>\r\n");        }        builder.append("</ul></body></html>\r\n");        ByteBuf byteBuf= Unpooled.copiedBuffer(builder, CharsetUtil.UTF_8);        response.content().writeBytes(byteBuf);        byteBuf.release();        channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);    }    private void sendRedirect(ChannelHandlerContext channelHandlerContext, String newUri) {        FullHttpResponse response=new DefaultFullHttpResponse(HTTP_1_1,FOUND);        response.headers().set(LOCATION,newUri);        channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);    }    private void sendError(ChannelHandlerContext channelHandlerContext, HttpResponseStatus status) {        FullHttpResponse response=new DefaultFullHttpResponse(                HTTP_1_1,status,Unpooled.copiedBuffer("Failure: "+status.toString()+"\r\n",                CharsetUtil.UTF_8));        response.headers().set(CONTENT_TYPE,"text/plain; charset=UTF-8");        channelHandlerContext.writeAndFlush(response).addListener(ChannelFutureListener.CLOSE);    }    private void setContentTypeHeader(HttpResponse httpResponse, File file) {        MimetypesFileTypeMap mimetypesFileTypeMap=new MimetypesFileTypeMap();        httpResponse.headers().set(CONTENT_TYPE,mimetypesFileTypeMap.getContentType(file.getPath()));    }}


打包发布:

cd 到项目target同级目录

mvn clean package

然后 cd target/

 java -jar netty-0.0.1-SNAPSHOT.jar -h运行