netty实现 nsf文件系统_Netty+SpringBoot写一个基于Http协议的文件服务器

论坛 期权论坛 脚本     
已经匿名di用户   2022-4-26 15:50   2627   0

本文参考《Netty权威指南》

NettyApplication

package com.xh.netty;

import org.springframework.boot.SpringApplication;

import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication

public 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

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() {

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{

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(" \r\n");

builder.append("

");

builder.append(dirPath);

builder.append("目录:");

builder.append("

\r\n");

builder.append("

");

builder.append(dirPath).append("目录:");

builder.append("\r\n");

builder.append("

  • ");

builder.append("

链接: ..\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("

链接:

builder.append(fname);

builder.append("\" >");

builder.append(fname);

builder.append("

\r\n");

}

builder.append("

\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运行

分享到 :
0 人收藏
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

积分:81
帖子:4969
精华:0
期权论坛 期权论坛
发布
内容

下载期权论坛手机APP