Search in sources :

Example 1 with ChunkedFile

use of io.netty.handler.stream.ChunkedFile in project flink by apache.

the class HistoryServerStaticFileServerHandler method respondWithFile.

/**
 * Response when running with leading JobManager.
 */
private void respondWithFile(ChannelHandlerContext ctx, HttpRequest request, String requestPath) throws IOException, ParseException, RestHandlerException {
    // make sure we request the "index.html" in case there is a directory request
    if (requestPath.endsWith("/")) {
        requestPath = requestPath + "index.html";
    }
    if (!requestPath.contains(".")) {
        // we assume that the path ends in either .html or .js
        requestPath = requestPath + ".json";
    }
    // convert to absolute path
    final File file = new File(rootPath, requestPath);
    if (!file.exists()) {
        // file does not exist. Try to load it with the classloader
        ClassLoader cl = HistoryServerStaticFileServerHandler.class.getClassLoader();
        try (InputStream resourceStream = cl.getResourceAsStream("web" + requestPath)) {
            boolean success = false;
            try {
                if (resourceStream != null) {
                    URL root = cl.getResource("web");
                    URL requested = cl.getResource("web" + requestPath);
                    if (root != null && requested != null) {
                        URI rootURI = new URI(root.getPath()).normalize();
                        URI requestedURI = new URI(requested.getPath()).normalize();
                        // expected scope.
                        if (!rootURI.relativize(requestedURI).equals(requestedURI)) {
                            LOG.debug("Loading missing file from classloader: {}", requestPath);
                            // ensure that directory to file exists.
                            file.getParentFile().mkdirs();
                            Files.copy(resourceStream, file.toPath());
                            success = true;
                        }
                    }
                }
            } catch (Throwable t) {
                LOG.error("error while responding", t);
            } finally {
                if (!success) {
                    LOG.debug("Unable to load requested file {} from classloader", requestPath);
                    throw new NotFoundException("File not found.");
                }
            }
        }
    }
    StaticFileServerHandler.checkFileValidity(file, rootPath, LOG);
    // cache validation
    final String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
    if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
        SimpleDateFormat dateFormatter = new SimpleDateFormat(StaticFileServerHandler.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) {
            if (LOG.isDebugEnabled()) {
                LOG.debug("Responding 'NOT MODIFIED' for file '" + file.getAbsolutePath() + '\'');
            }
            StaticFileServerHandler.sendNotModified(ctx);
            return;
        }
    }
    if (LOG.isDebugEnabled()) {
        LOG.debug("Responding with file '" + file.getAbsolutePath() + '\'');
    }
    // Don't need to close this manually. Netty's DefaultFileRegion will take care of it.
    final RandomAccessFile raf;
    try {
        raf = new RandomAccessFile(file, "r");
    } catch (FileNotFoundException e) {
        if (LOG.isDebugEnabled()) {
            LOG.debug("Could not find file {}.", file.getAbsolutePath());
        }
        HandlerUtils.sendErrorResponse(ctx, request, new ErrorResponseBody("File not found."), NOT_FOUND, Collections.emptyMap());
        return;
    }
    try {
        long fileLength = raf.length();
        HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
        StaticFileServerHandler.setContentTypeHeader(response, file);
        // the job overview should be updated as soon as possible
        if (!requestPath.equals("/joboverview.json")) {
            StaticFileServerHandler.setDateAndCacheHeaders(response, file);
        }
        if (HttpHeaders.isKeepAlive(request)) {
            response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        }
        HttpHeaders.setContentLength(response, fileLength);
        // write the initial line and the header.
        ctx.write(response);
        // write the content.
        ChannelFuture lastContentFuture;
        if (ctx.pipeline().get(SslHandler.class) == null) {
            ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength), ctx.newProgressivePromise());
            lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        } else {
            lastContentFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise());
        // HttpChunkedInput will write the end marker (LastHttpContent) for us.
        }
        // close the connection, if no keep-alive is needed
        if (!HttpHeaders.isKeepAlive(request)) {
            lastContentFuture.addListener(ChannelFutureListener.CLOSE);
        }
    } catch (Exception e) {
        raf.close();
        LOG.error("Failed to serve file.", e);
        throw new RestHandlerException("Internal server error.", INTERNAL_SERVER_ERROR);
    }
}
Also used : ChannelFuture(org.apache.flink.shaded.netty4.io.netty.channel.ChannelFuture) InputStream(java.io.InputStream) ChunkedFile(org.apache.flink.shaded.netty4.io.netty.handler.stream.ChunkedFile) FileNotFoundException(java.io.FileNotFoundException) NotFoundException(org.apache.flink.runtime.rest.NotFoundException) FileNotFoundException(java.io.FileNotFoundException) ErrorResponseBody(org.apache.flink.runtime.rest.messages.ErrorResponseBody) DefaultHttpResponse(org.apache.flink.shaded.netty4.io.netty.handler.codec.http.DefaultHttpResponse) HttpResponse(org.apache.flink.shaded.netty4.io.netty.handler.codec.http.HttpResponse) DefaultFileRegion(org.apache.flink.shaded.netty4.io.netty.channel.DefaultFileRegion) URI(java.net.URI) URL(java.net.URL) Date(java.util.Date) SslHandler(org.apache.flink.shaded.netty4.io.netty.handler.ssl.SslHandler) NotFoundException(org.apache.flink.runtime.rest.NotFoundException) ParseException(java.text.ParseException) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) RestHandlerException(org.apache.flink.runtime.rest.handler.RestHandlerException) RestHandlerException(org.apache.flink.runtime.rest.handler.RestHandlerException) HttpChunkedInput(org.apache.flink.shaded.netty4.io.netty.handler.codec.http.HttpChunkedInput) RandomAccessFile(java.io.RandomAccessFile) DefaultHttpResponse(org.apache.flink.shaded.netty4.io.netty.handler.codec.http.DefaultHttpResponse) RandomAccessFile(java.io.RandomAccessFile) File(java.io.File) ChunkedFile(org.apache.flink.shaded.netty4.io.netty.handler.stream.ChunkedFile) SimpleDateFormat(java.text.SimpleDateFormat)

Example 2 with ChunkedFile

use of io.netty.handler.stream.ChunkedFile in project netty by netty.

the class FileServerHandler method channelRead0.

@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");
}
Also used : RandomAccessFile(java.io.RandomAccessFile) ChunkedFile(io.netty.handler.stream.ChunkedFile) DefaultFileRegion(io.netty.channel.DefaultFileRegion) SslHandler(io.netty.handler.ssl.SslHandler)

Example 3 with ChunkedFile

use of io.netty.handler.stream.ChunkedFile in project netty by netty.

the class HttpStaticFileServerHandler method channelRead0.

@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
    this.request = request;
    if (!request.decoderResult().isSuccess()) {
        sendError(ctx, BAD_REQUEST);
        return;
    }
    if (!GET.equals(request.method())) {
        sendError(ctx, METHOD_NOT_ALLOWED);
        return;
    }
    final boolean keepAlive = HttpUtil.isKeepAlive(request);
    final String uri = request.uri();
    final String path = sanitizeUri(uri);
    if (path == null) {
        sendError(ctx, FORBIDDEN);
        return;
    }
    File file = new File(path);
    if (file.isHidden() || !file.exists()) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    if (file.isDirectory()) {
        if (uri.endsWith("/")) {
            sendListing(ctx, file, uri);
        } else {
            sendRedirect(ctx, uri + '/');
        }
        return;
    }
    if (!file.isFile()) {
        sendError(ctx, FORBIDDEN);
        return;
    }
    // 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 = file.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 = raf.length();
    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
    HttpUtil.setContentLength(response, fileLength);
    setContentTypeHeader(response, file);
    setDateAndCacheHeaders(response, file);
    if (!keepAlive) {
        response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.CLOSE);
    } else if (request.protocolVersion().equals(HTTP_1_0)) {
        response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }
    // Write the initial line and the header.
    ctx.write(response);
    // 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 {
        sendFileFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), 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
                System.err.println(future.channel() + " Transfer progress: " + progress);
            } else {
                System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total);
            }
        }

        @Override
        public void operationComplete(ChannelProgressiveFuture future) {
            System.err.println(future.channel() + " Transfer complete.");
        }
    });
    // Decide whether to close the connection or not.
    if (!keepAlive) {
        // Close the connection when the whole content is written out.
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) ChunkedFile(io.netty.handler.stream.ChunkedFile) FileNotFoundException(java.io.FileNotFoundException) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) HttpResponse(io.netty.handler.codec.http.HttpResponse) ChannelProgressiveFuture(io.netty.channel.ChannelProgressiveFuture) DefaultFileRegion(io.netty.channel.DefaultFileRegion) Date(java.util.Date) SslHandler(io.netty.handler.ssl.SslHandler) HttpChunkedInput(io.netty.handler.codec.http.HttpChunkedInput) RandomAccessFile(java.io.RandomAccessFile) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) RandomAccessFile(java.io.RandomAccessFile) ChunkedFile(io.netty.handler.stream.ChunkedFile) File(java.io.File) SimpleDateFormat(java.text.SimpleDateFormat) ChannelProgressiveFutureListener(io.netty.channel.ChannelProgressiveFutureListener)

Example 4 with ChunkedFile

use of io.netty.handler.stream.ChunkedFile in project netty by netty.

the class Http2StaticFileServerHandler method channelRead.

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    if (msg instanceof Http2HeadersFrame) {
        Http2HeadersFrame headersFrame = (Http2HeadersFrame) msg;
        this.stream = headersFrame.stream();
        if (!GET.toString().equals(headersFrame.headers().method().toString())) {
            sendError(ctx, METHOD_NOT_ALLOWED);
            return;
        }
        final String uri = headersFrame.headers().path().toString();
        final String path = sanitizeUri(uri);
        if (path == null) {
            sendError(ctx, FORBIDDEN);
            return;
        }
        File file = new File(path);
        if (file.isHidden() || !file.exists()) {
            sendError(ctx, NOT_FOUND);
            return;
        }
        if (file.isDirectory()) {
            if (uri.endsWith("/")) {
                sendListing(ctx, file, uri);
            } else {
                sendRedirect(ctx, uri + '/');
            }
            return;
        }
        if (!file.isFile()) {
            sendError(ctx, FORBIDDEN);
            return;
        }
        // Cache Validation
        CharSequence ifModifiedSince = headersFrame.headers().get(HttpHeaderNames.IF_MODIFIED_SINCE);
        if (ifModifiedSince != null && !ifModifiedSince.toString().isEmpty()) {
            SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
            Date ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince.toString());
            // 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) {
                sendNotModified(ctx);
                return;
            }
        }
        RandomAccessFile raf;
        try {
            raf = new RandomAccessFile(file, "r");
        } catch (FileNotFoundException ignore) {
            sendError(ctx, NOT_FOUND);
            return;
        }
        long fileLength = raf.length();
        Http2Headers headers = new DefaultHttp2Headers();
        headers.status("200");
        headers.setLong(HttpHeaderNames.CONTENT_LENGTH, fileLength);
        setContentTypeHeader(headers, file);
        setDateAndCacheHeaders(headers, file);
        // Write the initial line and the header.
        ctx.writeAndFlush(new DefaultHttp2HeadersFrame(headers).stream(stream));
        // Write the content.
        ChannelFuture sendFileFuture;
        sendFileFuture = ctx.writeAndFlush(new Http2DataChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192), stream), ctx.newProgressivePromise());
        sendFileFuture.addListener(new ChannelProgressiveFutureListener() {

            @Override
            public void operationProgressed(ChannelProgressiveFuture future, long progress, long total) {
                if (total < 0) {
                    // total unknown
                    System.err.println(future.channel() + " Transfer progress: " + progress);
                } else {
                    System.err.println(future.channel() + " Transfer progress: " + progress + " / " + total);
                }
            }

            @Override
            public void operationComplete(ChannelProgressiveFuture future) {
                System.err.println(future.channel() + " Transfer complete.");
            }
        });
    } else {
        // Unsupported message type
        System.out.println("Unsupported message type: " + msg);
    }
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) DefaultHttp2HeadersFrame(io.netty.handler.codec.http2.DefaultHttp2HeadersFrame) Http2HeadersFrame(io.netty.handler.codec.http2.Http2HeadersFrame) ChunkedFile(io.netty.handler.stream.ChunkedFile) FileNotFoundException(java.io.FileNotFoundException) ChannelProgressiveFuture(io.netty.channel.ChannelProgressiveFuture) Date(java.util.Date) DefaultHttp2HeadersFrame(io.netty.handler.codec.http2.DefaultHttp2HeadersFrame) RandomAccessFile(java.io.RandomAccessFile) Http2Headers(io.netty.handler.codec.http2.Http2Headers) DefaultHttp2Headers(io.netty.handler.codec.http2.DefaultHttp2Headers) Http2DataChunkedInput(io.netty.handler.codec.http2.Http2DataChunkedInput) DefaultHttp2Headers(io.netty.handler.codec.http2.DefaultHttp2Headers) RandomAccessFile(java.io.RandomAccessFile) ChunkedFile(io.netty.handler.stream.ChunkedFile) File(java.io.File) SimpleDateFormat(java.text.SimpleDateFormat) ChannelProgressiveFutureListener(io.netty.channel.ChannelProgressiveFutureListener)

Example 5 with ChunkedFile

use of io.netty.handler.stream.ChunkedFile in project blade by biezhi.

the class StaticFileHandler method handle.

/**
 * print static file to client
 *
 * @param webContext web context
 * @throws Exception
 */
@Override
public void handle(WebContext webContext) throws Exception {
    Request request = webContext.getRequest();
    ChannelHandlerContext ctx = webContext.getChannelHandlerContext();
    if (!HttpConst.METHOD_GET.equals(request.method())) {
        sendError(ctx, METHOD_NOT_ALLOWED);
        return;
    }
    Instant start = Instant.now();
    String uri = URLDecoder.decode(request.uri(), "UTF-8");
    String method = StringKit.padRight(request.method(), 6);
    String cleanURL = getCleanURL(request, uri);
    // webjars
    if (cleanURL.startsWith(Const.WEB_JARS)) {
        InputStream input = getResourceStreamFromJar(uri);
        writeWithJarFile(request, ctx, uri, start, cleanURL, method, input);
        return;
    }
    // jar file
    if (BladeKit.runtimeIsJAR()) {
        InputStream input = StaticFileHandler.class.getResourceAsStream(cleanURL);
        writeWithJarFile(request, ctx, uri, start, cleanURL, method, input);
        return;
    }
    // disk file
    final String path = sanitizeUri(cleanURL);
    if (path == null) {
        log403(log, method, uri);
        throw new ForbiddenException();
    }
    File file = new File(path);
    if (file.isHidden() || !file.exists()) {
        // gradle resources path
        File resourcesDirectory = getGradleResourcesDirectory();
        if (resourcesDirectory.isDirectory()) {
            file = new File(resourcesDirectory.getPath() + "/" + cleanURL.substring(1));
            if (file.isHidden() || !file.exists()) {
                throw new NotFoundException(uri);
            }
        } else {
            throw new NotFoundException(uri);
        }
    }
    if (file.isDirectory() && showFileList) {
        sendListing(ctx, uri, getFileMetas(file), cleanURL);
        return;
    }
    if (!file.isFile()) {
        sendError(ctx, FORBIDDEN);
        return;
    }
    // Cache Validation
    if (isHttp304(ctx, request, file.length(), file.lastModified())) {
        log304(log, method, uri);
        return;
    }
    HttpResponse httpResponse = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
    setContentTypeHeader(httpResponse, file);
    setDateAndCacheHeaders(httpResponse, file);
    if (request.useGZIP()) {
        File output = new File(file.getPath() + ".gz");
        IOKit.compressGZIP(file, output);
        file = output;
        setGzip(httpResponse);
    }
    RandomAccessFile raf;
    try {
        raf = new RandomAccessFile(file, "r");
    } catch (FileNotFoundException ignore) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    long fileLength = raf.length();
    httpResponse.headers().set(HttpConst.CONTENT_LENGTH, fileLength);
    if (request.keepAlive()) {
        httpResponse.headers().set(HttpConst.CONNECTION, HttpConst.KEEP_ALIVE);
    }
    // Write the initial line and the header.
    ctx.write(httpResponse);
    // 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 {
        sendFileFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise());
        // HttpChunkedInput will write the end marker (LastHttpContent) for us.
        lastContentFuture = sendFileFuture;
    }
    sendFileFuture.addListener(ProgressiveFutureListener.build(raf));
    // Decide whether to close the connection or not.
    if (!request.keepAlive()) {
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
    log200AndCost(log, start, method, uri);
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) ForbiddenException(com.blade.exception.ForbiddenException) Instant(java.time.Instant) ChunkedFile(io.netty.handler.stream.ChunkedFile) Request(com.blade.mvc.http.Request) NotFoundException(com.blade.exception.NotFoundException) ChannelHandlerContext(io.netty.channel.ChannelHandlerContext) DefaultFileRegion(io.netty.channel.DefaultFileRegion) SslHandler(io.netty.handler.ssl.SslHandler) ChunkedFile(io.netty.handler.stream.ChunkedFile) JarFile(java.util.jar.JarFile)

Aggregations

RandomAccessFile (java.io.RandomAccessFile)9 ChunkedFile (io.netty.handler.stream.ChunkedFile)8 File (java.io.File)8 FileNotFoundException (java.io.FileNotFoundException)8 ChannelFuture (io.netty.channel.ChannelFuture)6 DefaultFileRegion (io.netty.channel.DefaultFileRegion)6 SimpleDateFormat (java.text.SimpleDateFormat)6 SslHandler (io.netty.handler.ssl.SslHandler)5 IOException (java.io.IOException)5 Date (java.util.Date)5 HttpChunkedInput (io.netty.handler.codec.http.HttpChunkedInput)4 ChannelProgressiveFuture (io.netty.channel.ChannelProgressiveFuture)3 ChannelProgressiveFutureListener (io.netty.channel.ChannelProgressiveFutureListener)3 DefaultHttpResponse (io.netty.handler.codec.http.DefaultHttpResponse)3 HttpResponse (io.netty.handler.codec.http.HttpResponse)3 InputStream (java.io.InputStream)3 URI (java.net.URI)3 URL (java.net.URL)3 ChannelFuture (org.apache.flink.shaded.netty4.io.netty.channel.ChannelFuture)3 DefaultFileRegion (org.apache.flink.shaded.netty4.io.netty.channel.DefaultFileRegion)3