private static Object toContent(Object content) { if (content instanceof File) { File file = (File) content; return new DefaultFileRegion(file, 0, file.length()); } if (content instanceof InputStream) { return new ChunkedStream((InputStream) content); } if (content instanceof ReadableByteChannel) { return new ChunkedNioStream((ReadableByteChannel) content); } if (content instanceof byte[]) { return Unpooled.wrappedBuffer((byte[]) content); } throw new IllegalArgumentException("unknown content type : " + content.getClass().getName()); }
private static Object toContent(Object content) { if (content instanceof File) { File file = (File) content; return new DefaultFileRegion(file, 0, file.length()); } if (content instanceof InputStream) { return new ChunkedStream((InputStream) content); } if (content instanceof ReadableByteChannel) { return new ChunkedNioStream((ReadableByteChannel) content); } if (content instanceof byte[]) { return Unpooled.wrappedBuffer((byte[]) content); } throw new IllegalArgumentException( "unknown content type : " + content.getClass().getName()); }
@Override protected void messageReceived(ChannelHandlerContext cxt, String msg) throws Exception { File file = new File(msg); if(file.exists()) { if(!file.isFile()){ cxt.writeAndFlush("No file " + file + CR); } cxt.writeAndFlush("file " + file.length() + CR); RandomAccessFile randomAccessFile = new RandomAccessFile(msg, "r"); FileRegion fileRegion = new DefaultFileRegion(randomAccessFile.getChannel(), 0, randomAccessFile.length()); cxt.write(fileRegion); cxt.writeAndFlush(CR); randomAccessFile.close(); }else{ cxt.writeAndFlush("File not found: " + file + CR); } }
@Override public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { RandomAccessFile raf = null; long length = -1; try { raf = new RandomAccessFile(msg, "r"); length = raf.length(); } catch (Exception e) { ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n'); return; } finally { if (length < 0 && raf != null) { raf.close(); } } ctx.write("OK: " + raf.length() + '\n'); if (ctx.pipeline().get(SslHandler.class) == null) { // SSL not enabled - can use zero-copy file transfer. ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length)); } else { // SSL enabled - cannot use zero-copy file transfer. ctx.write(new ChunkedFile(raf)); } ctx.writeAndFlush("\n"); }
/** * This unit test case ensures that {@link FileRegionEncoder} indeed wraps {@link FileRegion} to * {@link ByteBuf}. * @throws IOException if there is an error. */ @Test public void testEncode() throws IOException { FileRegionEncoder fileRegionEncoder = new FileRegionEncoder(); EmbeddedChannel channel = new EmbeddedChannel(fileRegionEncoder); File file = File.createTempFile(UUID.randomUUID().toString(), ".data"); file.deleteOnExit(); Random random = new Random(System.currentTimeMillis()); int dataLength = 1 << 10; byte[] data = new byte[dataLength]; random.nextBytes(data); write(file, data); FileRegion fileRegion = new DefaultFileRegion(file, 0, dataLength); Assert.assertEquals(0, fileRegion.transfered()); Assert.assertEquals(dataLength, fileRegion.count()); Assert.assertTrue(channel.writeOutbound(fileRegion)); ByteBuf out = (ByteBuf) channel.readOutbound(); byte[] arr = new byte[out.readableBytes()]; out.getBytes(0, arr); Assert.assertArrayEquals("Data should be identical", data, arr); }
public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { File file = new File(msg); if (file.exists()) { if (!file.isFile()) { ctx.writeAndFlush("Not a file : " + file + CR); return; } ctx.write(file + " " + file.length() + CR); RandomAccessFile randomAccessFile = new RandomAccessFile(msg, "r"); FileRegion region = new DefaultFileRegion( randomAccessFile.getChannel(), 0, randomAccessFile.length()); ctx.write(region); ctx.writeAndFlush(CR); randomAccessFile.close(); } else { ctx.writeAndFlush("File not found: " + file + CR); } }
protected boolean doWriteSingle(ChannelOutboundBuffer in, int writeSpinCount) throws Exception { // The outbound buffer contains only one message or it contains a file region. Object msg = in.current(); if (msg instanceof ByteBuf) { ByteBuf buf = (ByteBuf) msg; if (!writeBytes(in, buf, writeSpinCount)) { // was not able to write everything so break here we will get notified later again once // the network stack can handle more writes. return false; } } else if (msg instanceof DefaultFileRegion) { DefaultFileRegion region = (DefaultFileRegion) msg; if (!writeFileRegion(in, region, writeSpinCount)) { // was not able to write everything so break here we will get notified later again once // the network stack can handle more writes. return false; } } else { // Should never reach here. throw new Error(); } return true; }
@Override protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { File file = new File(msg); if (file.exists()) { if (!file.isFile()) { ctx.writeAndFlush("not a file :" + file + CR); return; } ctx.write(file + " " + file.length() + CR); RandomAccessFile raf = new RandomAccessFile(file, "r"); FileRegion fileRegion = new DefaultFileRegion(raf.getChannel(), 0, raf.length()); ctx.write(fileRegion); ctx.writeAndFlush(CR); raf.close(); } else { ctx.writeAndFlush("file not found: " + file + CR); } }
@Override protected void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { RandomAccessFile raf = null; long length = -1; try { raf = new RandomAccessFile(msg, "r"); length = raf.length(); } catch (Exception e) { ctx.writeAndFlush("ERR: " + e.getClass().getSimpleName() + ": " + e.getMessage() + '\n'); return; } finally { if (length < 0 && raf != null) { raf.close(); } } ctx.write("OK: " + raf.length() + '\n'); if (ctx.pipeline().get(SslHandler.class) == null) { // SSL not enabled - can use zero-copy file transfer. ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length)); } else { // SSL enabled - cannot use zero-copy file transfer. ctx.write(new ChunkedFile(raf)); } ctx.writeAndFlush("\n"); }
@Override public void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { File file = new File(msg); if (file.exists()) { if (!file.isFile()) { ctx.writeAndFlush("Not a file: " + file + '\n'); return; } ctx.write(file + " " + file.length() + '\n'); FileInputStream fis = new FileInputStream(file); FileRegion region = new DefaultFileRegion(fis.getChannel(), 0, file.length()); ctx.write(region); ctx.writeAndFlush("\n"); fis.close(); } else { ctx.writeAndFlush("File not found: " + file + '\n'); } }
@Override protected void channelRead0(ChannelHandlerContext ctx, String msg) throws Exception { File file = new File(msg); if (file.exists()) { if (!file.isFile()) { ctx.writeAndFlush("Not a file: " + file + '\n'); return; } ctx.write(file + " " + file.length() + '\n'); FileInputStream fis = new FileInputStream(file); FileRegion region = new DefaultFileRegion(fis.getChannel(), 0, file.length()); ctx.write(region); ctx.writeAndFlush("\n"); fis.close(); } else { ctx.writeAndFlush("File not found: " + file + '\n'); } }
@Override public void messageReceived(ChannelHandlerContext ctx, String msg) throws Exception { File file = new File(msg); if (file.exists()) { if (!file.isFile()) { ctx.writeAndFlush("Not a file: " + file + '\n'); return; } ctx.write(file + " " + file.length() + '\n'); FileInputStream fis = new FileInputStream(file); FileRegion region = new DefaultFileRegion(fis.getChannel(), 0, file.length()); ctx.write(region); ctx.writeAndFlush("\n"); fis.close(); } else { ctx.writeAndFlush("File not found: " + file + '\n'); } }
/** * Send response immediately for a file response * * @param raf RandomAccessFile */ public void sendFile(RandomAccessFile raf, long length) { setDate(); setPowerBy(); setResponseTime(); header(CONTENT_LENGTH, Long.toString(length)); setHttpResponse(new DefaultHttpResponse(HTTP_1_1, getStatus(), true)); // Write initial line and headers channelCxt.write(httpResponse); // Write content ChannelFuture sendFileFuture; ChannelFuture lastContentFuture; if (false /* if has ssl handler */) { // TODO support ssl } else { sendFileFuture = channelCxt.write(new DefaultFileRegion(raf.getChannel(), 0, length), channelCxt.newProgressivePromise()); lastContentFuture = channelCxt.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } sendFileFuture.addListener(new ProgressiveFutureListener(raf)); if (!keepAlive) { lastContentFuture.addListener(ChannelFutureListener.CLOSE); } flush(); }
@Override public Object convertToNetty() throws IOException { if (conf.lazyFileDescriptor()) { return new DefaultFileRegion(file, offset, length); } else { FileChannel fileChannel = new FileInputStream(file).getChannel(); return new DefaultFileRegion(fileChannel, offset, length); } }
@Override public void write(Channel channel, NettyResponseFuture<?> future) throws IOException { @SuppressWarnings("resource") // Netty will close the ChunkedNioFile or the DefaultFileRegion final FileChannel fileChannel = new RandomAccessFile(file, "r").getChannel(); Object message = (ChannelManager.isSslHandlerConfigured(channel.pipeline()) || config.isDisableZeroCopy()) ? // new ChunkedNioFile(fileChannel, offset, length, config.getChunkedFileChunkSize()) : new DefaultFileRegion(fileChannel, offset, length); channel.write(message, channel.newProgressivePromise())// .addListener(new ProgressListener(future.getAsyncHandler(), future, false, getContentLength())); channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); }
/** * Write a {@link DefaultFileRegion} * * @param region the {@link DefaultFileRegion} from which the bytes should be written * @return amount the amount of written bytes */ private boolean writeFileRegion( ChannelOutboundBuffer in, DefaultFileRegion region, int writeSpinCount) throws Exception { final long regionCount = region.count(); if (region.transfered() >= regionCount) { in.remove(); return true; } final long baseOffset = region.position(); boolean done = false; long flushedAmount = 0; for (int i = writeSpinCount - 1; i >= 0; i--) { final long offset = region.transfered(); final long localFlushedAmount = Native.sendfile(fd().intValue(), region, baseOffset, offset, regionCount - offset); if (localFlushedAmount == 0) { break; } flushedAmount += localFlushedAmount; if (region.transfered() >= regionCount) { done = true; break; } } if (flushedAmount > 0) { in.progress(flushedAmount); } if (done) { in.remove(); } else { // Returned EAGAIN need to set EPOLLOUT setFlag(Native.EPOLLOUT); } return done; }
public static long sendfile( int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException { // Open the file-region as it may be created via the lazy constructor. This is needed as we directly access // the FileChannel field directly via JNI src.open(); long res = sendfile0(dest, src, baseOffset, offset, length); if (res >= 0) { return res; } return ioResult("sendfile", (int) res, CONNECTION_RESET_EXCEPTION_SENDFILE); }
@Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if( wsURI.equalsIgnoreCase(request.getUri()) ) { ctx.fireChannelRead(request.retain()); } else { if( HttpHeaders.is100ContinueExpected(request) ) { send100Continue(ctx); } try ( RandomAccessFile rFile = new RandomAccessFile(indexHTML, "r") ) { HttpResponse response = new DefaultHttpResponse( request.getProtocolVersion(), HttpResponseStatus.OK ); response.headers().set(HttpHeaders.Names.CONTENT_TYPE, "text/html; charset=UTF-8"); boolean keepAlive = HttpHeaders.isKeepAlive(request); if( keepAlive ) { response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, rFile.length()); response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } ctx.write(response); if( ctx.pipeline().get(SslHandler.class) == null ) { ctx.write(new DefaultFileRegion(rFile.getChannel(), 0, rFile.length())); } else { ctx.write(new ChunkedNioFile(rFile.getChannel())); } ChannelFuture future = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if( !keepAlive ) { future.addListener(ChannelFutureListener.CLOSE); } } } }
@Override public void download(@NonNull String fileName, @NonNull File file) throws Exception { if (!file.exists() || !file.isFile()) { throw new NotFoundException("Not found file: " + file.getPath()); } RandomAccessFile raf = new RandomAccessFile(file, "r"); Long fileLength = raf.length(); this.contentType = StringKit.mimeType(file.getName()); io.netty.handler.codec.http.HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); HttpHeaders httpHeaders = httpResponse.headers().add(getDefaultHeader()); boolean keepAlive = WebContext.request().keepAlive(); if (keepAlive) { httpResponse.headers().set(HttpConst.CONNECTION, KEEP_ALIVE); } httpHeaders.set(HttpConst.CONTENT_TYPE, this.contentType); httpHeaders.set("Content-Disposition", "attachment; filename=" + new String(fileName.getBytes("UTF-8"), "ISO8859_1")); httpHeaders.setInt(HttpConst.CONTENT_LENGTH, fileLength.intValue()); // Write the initial line and the header. ctx.write(httpResponse); ChannelFuture sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); sendFileFuture.addListener(ProgressiveFutureListener.build(raf)); // Decide whether to close the connection or not. if (!keepAlive) { lastContentFuture.addListener(ChannelFutureListener.CLOSE); } isCommit = true; }
@Override public void close() throws IOException { try { this.flush(); FileChannel file = new FileInputStream(this.file).getChannel(); long fileLength = file.size(); HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); httpResponse.headers().set(HttpConst.CONTENT_LENGTH, fileLength); httpResponse.headers().set(HttpConst.DATE, DateKit.gmtDate()); httpResponse.headers().set(HttpConst.SERVER, "blade/" + Const.VERSION); boolean keepAlive = WebContext.request().keepAlive(); if (keepAlive) { httpResponse.headers().set(HttpConst.CONNECTION, HttpConst.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(httpResponse); ctx.write(new DefaultFileRegion(file, 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } finally { if(null != outputStream){ outputStream.close(); } } }
default void stream(FuseRequestMessage message, Path path) { if (!message.flushed()) { ChannelHandlerContext ctx = message.getChannelContext(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, HttpResponseStatus.OK); long size = WireProtocol.getFileSize(path); response.headers().set(CONTENT_LENGTH, size); ctx.write(response); try { ctx.write( new DefaultFileRegion(FileChannel.open(path), 0, size) ); ChannelFuture cfuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if (!isKeepAlive(message.getRequest())) { cfuture.addListener(ChannelFutureListener.CLOSE); } } catch (Exception ex) { log.error("Error streaming file !", ex); ctx.close(); } } }
void sendFile(File file) throws Exception { long length = file.length(); LOG.debug("Got request of sending file {} of length {}.", file, length); Message handshake = MessageBuilder.buildFileHeader(length); byte[] bytes = handshake.toByteArray(); // Sends HANDSHAKE first before transferring actual file data, the // HANDSHAKE will tell the peer's channel to prepare for the file // transferring. channel.writeAndFlush(Unpooled.wrappedBuffer(bytes)).sync(); ChannelHandler prepender = channel.pipeline().get("frameEncoder"); // Removes length prepender, we don't need this handler for file // transferring. channel.pipeline().remove(prepender); // Adds ChunkedWriteHandler for file transferring. ChannelHandler cwh = new ChunkedWriteHandler(); channel.pipeline().addLast(cwh); // Begins file transferring. RandomAccessFile raf = new RandomAccessFile(file, "r"); if (channel.pipeline().get(SslHandler.class) != null) { // Zero-Copy file transferring is not supported for ssl. channel.writeAndFlush(new ChunkedFile(raf, 0, length, 8912)); } else { // Use Zero-Copy file transferring in non-ssl mode. FileRegion region = new DefaultFileRegion(raf.getChannel(), 0, length); channel.writeAndFlush(region); } // Restores pipeline to original state. channel.pipeline().remove(cwh); channel.pipeline().addLast("frameEncoder", prepender); }
@Override public void close(File file) { if(this.request.websocket().active()) return; LoggerFactory.getLogger(getClass()).debug("Sending file as response"); if(!file.exists()) { status(404); close(); return; } RandomAccessFile raf; long length; FileChannel channel; try { raf = new RandomAccessFile(file, "r"); length = raf.length(); channel = raf.getChannel(); } catch (IOException e) { status(500); close(); return; } header("Content-Length", String.valueOf(length)); MimetypesFileTypeMap mimeTypesMap = new MimetypesFileTypeMap(); header("Content-Type", mimeTypesMap.getContentType(file)); commit(); this.channelContext.writeAndFlush(new DefaultFileRegion(channel, 0, length)); this.close(); }
public FileRegion serve(String path) throws IOException { path = rewrite(path); if (codeOnly && !path.matches("^/(jogl_\\d_\\d\\.lib|(loader|loader_gl|runescape)\\.jar|(jogl|runescape|runescape_gl)\\.pack200|unpackclass.pack)$")) return null; File f = new File(root, path); if (!f.getAbsolutePath().startsWith(root.getAbsolutePath())) return null; if (!f.exists() || !f.isFile()) return null; return new DefaultFileRegion(FileChannel.open(f.toPath(), StandardOpenOption.READ), 0, f.length()); }
FileOperationEncoder(File file) { long length = file.length(); this.content = new DefaultFileRegion(file, 0, length); this.size = length; }
/** * Send content from given {@link Path} using * {@link java.nio.channels.FileChannel#transferTo(long, long, WritableByteChannel)} * support. If the system supports it and the path resolves to a local file * system {@link File} then transfer will use zero-byte copy * to the peer. * <p>It will * listen for any error on * write and close * on terminal signal (complete|error). If more than one publisher is attached * (multiple calls to send()) completion occurs after all publishers complete. * <p> * Note: this will emit {@link io.netty.channel.FileRegion} in the outbound * {@link io.netty.channel.ChannelPipeline} * * @param file the file Path * @param position where to start * @param count how much to transfer * * @return A Publisher to signal successful sequence write (e.g. after "flush") or any * error during write */ default NettyOutbound sendFile(Path file, long position, long count) { Objects.requireNonNull(file); if (context().channel().pipeline().get(SslHandler.class) != null) { return sendFileChunked(file, position, count); } return then(Mono.using(() -> FileChannel.open(file, StandardOpenOption.READ), fc -> FutureMono.from(context().channel().writeAndFlush(new DefaultFileRegion(fc, position, count))), fc -> { try { fc.close(); } catch (IOException ioe) {/*IGNORE*/} })); }
public static void sendFile(@NotNull HttpRequest request, @NotNull Channel channel, @NotNull File file) throws IOException { HttpResponse response = prepareSend(request, channel, file.lastModified(), file.getPath()); if (response == null) { return; } boolean keepAlive = addKeepAliveIfNeed(response, request); boolean fileWillBeClosed = false; RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignored) { send(response(HttpResponseStatus.NOT_FOUND), channel, request); return; } try { long fileLength = raf.length(); HttpUtil.setContentLength(response, fileLength); channel.write(response); if (request.method() != HttpMethod.HEAD) { if (channel.pipeline().get(SslHandler.class) == null) { // no encryption - use zero-copy channel.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength)); } else { // cannot use zero-copy with HTTPS channel.write(new ChunkedFile(raf)); } } fileWillBeClosed = true; } finally { if (!fileWillBeClosed) { raf.close(); } } ChannelFuture future = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if (!keepAlive) { future.addListener(ChannelFutureListener.CLOSE); } }
private static native long sendfile0( int dest, DefaultFileRegion src, long baseOffset, long offset, long length) throws IOException;
public static void sendFile(ChannelHandlerContext ctx, FullHttpRequest request, File file) throws ParseException, IOException { long lastModified = file.lastModified(); String path = file.getPath(); // Cache Validation String ifModifiedSince = request.headers().get(HttpHeaderNames.IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = lastModified / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { sendNotModified(ctx); return; } } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND); return; } long fileLength = file.length(); beginHTTPResponse(ctx, request, lastModified, path, fileLength); // Write the content. ChannelFuture sendFileFuture; ChannelFuture lastContentFuture; if (ctx.pipeline().get(SslHandler.class) == null) { sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise()); // Write the end marker. lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } else { FileInputStream input = new FileInputStream(file); byte[] data = new byte[(int)fileLength]; //big hack to convert into byteBuf int pos = 0; int remaining = (int)fileLength; while (remaining>0) { int len = input.read(data, pos, remaining); remaining-=len; pos+=len; } sendFileFuture = ctx.write(Unpooled.wrappedBuffer(data), ctx.newProgressivePromise()); lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } progressAndClose(request, sendFileFuture, lastContentFuture); }
@Override public void translate(ChannelHandlerContext ctx, FullHttpRequest req, ResponseWrapper responseWrapper) { try { RandomAccessFile file; try { file = new RandomAccessFile(responseWrapper.getFile(), "r"); } catch (FileNotFoundException ignore) { ignore.printStackTrace(); responseWrapper.setMediaType(MediaType.TEXT_PLAIN.getValue()); responseWrapper.setStatus(NOT_FOUND); sendError(ctx, req, responseWrapper); return; } HttpResponse res = new DefaultHttpResponse(HTTP_1_1, OK); long contentLength = file.length(); res.headers().set(CONTENT_LENGTH, contentLength); res.headers().set(CONTENT_TYPE, responseWrapper.getMediaType()); setDateAndCacheHeaders(res, responseWrapper.getFile()); boolean keepAlive = HttpUtil.isKeepAlive(req); if (keepAlive) { res.headers().set(CONNECTION, HttpHeaderValues.KEEP_ALIVE); } ctx.write(res); ChannelFuture lastContentFuture; if (null == ctx.pipeline().get(SslHandler.class)) { ctx.write(new DefaultFileRegion(file.getChannel(), 0, contentLength), ctx.newProgressivePromise()); lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); } else { lastContentFuture = ctx.writeAndFlush( new HttpChunkedInput(new ChunkedFile(file, 0, contentLength, 8192)), ctx.newProgressivePromise() ); } if (!keepAlive) { lastContentFuture.addListener(ChannelFutureListener.CLOSE); } } catch (IOException e) { LOGGER.error(e.getMessage(), e); responseWrapper.setStatus(INTERNAL_SERVER_ERROR); responseWrapper.setContent(INTERNAL_SERVER_ERROR.reasonPhrase().getBytes()); sendError(ctx, req, responseWrapper); } }
@Override public void handle(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { //Check for index final String path = webDir + File.separator + request.getUri(); final String uri = request.getUri(); if (uri.endsWith("/")) { for (String index : indexFiles) { File checkFile = new File(path, index); if (checkFile.exists()) { HandlerUtil.sendRedirect(ctx, uri + index); return; } } } File file = new File(path.replace("/", File.separator)); if (file.isHidden() || !file.exists()) { HandlerUtil.sendError(ctx, NOT_FOUND); return; } if (file.isDirectory()) { if (uri.endsWith("/")) { HandlerUtil.sendError(ctx, FORBIDDEN); } else { HandlerUtil.sendRedirect(ctx, uri + '/'); } return; } if (!file.isFile()) { HandlerUtil.sendError(ctx, FORBIDDEN); return; } // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HandlerUtil.HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); // Only compare up to the second because the datetime format we send to the client // does not have milliseconds long ifModifiedSinceDateSeconds = ifModifiedSinceDate.getTime() / 1000; long fileLastModifiedSeconds = file.lastModified() / 1000; if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) { HandlerUtil.sendNotModified(ctx); return; } } RandomAccessFile raf; try { raf = new RandomAccessFile(file, "r"); } catch (FileNotFoundException fnfe) { HandlerUtil.sendError(ctx, NOT_FOUND); return; } long fileLength = raf.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HandlerUtil.setContentTypeHeader(response, file.getName()); HandlerUtil.setDateAndCacheHeaders(response, file.lastModified()); response.headers().set(CONTENT_LENGTH, fileLength); response.headers().set(CONNECTION, HttpHeaders.Values.CLOSE); response.headers().set(VARY, ACCEPT_ENCODING); // Write the initial line and the header. ctx.write(response); // Write the content. ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength)); ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); }