in labs/arthas-grpc-web-proxy/src/main/java/com/taobao/arthas/grpcweb/grpc/server/httpServer/NettyHttpStaticFileHandler.java [43:130]
protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws URISyntaxException, IOException {
// 获取URI
String uri = new URI(request.uri()).getPath();
// 设置不支持favicon.ico文件
if ("/favicon.ico".equals(uri)) {
return;
}
if ("/".equals(uri)) {
uri = "/index.html";
}
// 根据路径地址构建文件
String path = Paths.get(this.STATIC_LOCATION, uri).toString();
File file = new File(path);
// 状态为1xx的话,继续请求
if (HttpUtil.is100ContinueExpected(request)) {
send100Continue(ctx);
}
// 当文件隐藏/不存在/是目录/非文件的时候,将资源指向NOT_FOUND
if (file.isHidden() || !file.exists() || file.isDirectory() || !file.isFile()) {
sendNotFound(ctx);
return;
}
final RandomAccessFile randomAccessFile;
try {
randomAccessFile = new RandomAccessFile(file, "r");
} catch (FileNotFoundException e) {
sendNotFound(ctx);
throw new RuntimeException(e);
}
HttpResponse response = new DefaultHttpResponse(request.protocolVersion(), HttpResponseStatus.OK);
// 设置文件格式内容
if (path.endsWith(".html")){
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html; charset=UTF-8");
}else if(path.endsWith(".js")){
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "application/x-javascript");
}else if(path.endsWith(".css")){
response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/css; charset=UTF-8");
}else{
MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();
response.headers().set(HttpHeaderNames.CONTENT_TYPE, mimetypesFileTypeMap.getContentType(path));
}
boolean keepAlive = HttpUtil.isKeepAlive(request);
if (keepAlive) {
response.headers().set(HttpHeaderNames.CONTENT_LENGTH, randomAccessFile.length());
response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
}
ctx.write(response);
ChannelFuture sendFileFuture;
ChannelFuture lastContentFuture;
if (ctx.pipeline().get(SslHandler.class) == null) {
sendFileFuture =
ctx.write(new DefaultFileRegion(randomAccessFile.getChannel(), 0, randomAccessFile.length()), ctx.newProgressivePromise());
// Write the end marker.
lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
} else {
sendFileFuture =
ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(randomAccessFile, 0, randomAccessFile.length(), 10 * 1024 * 1024)),
ctx.newProgressivePromise());
// HttpChunkedInput will write the end marker (LastHttpContent) for us.
lastContentFuture = sendFileFuture;
}
sendFileFuture.addListener(new ChannelProgressiveFutureListener() {
@Override
public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
if (total < 0) { // total unknown
logger.info(future.channel() + " Transfer progress: " + progress);
} else {
logger.info(future.channel() + " Transfer progress: " + progress + " / " + total);
}
}
@Override
public void operationComplete(ChannelProgressiveFuture future) {
logger.info(future.channel() + " Transfer complete.");
}
});
// Decide whether to close the connection or not.
if (!HttpUtil.isKeepAlive(request)) {
// Close the connection when the whole content is written out.
lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}
}