Search in sources :

Example 1 with HttpChunkedInput

use of io.netty.handler.codec.http.HttpChunkedInput in project jersey by jersey.

the class NettyResponseWriter method writeResponseStatusAndHeaders.

@Override
public synchronized OutputStream writeResponseStatusAndHeaders(long contentLength, ContainerResponse responseContext) throws ContainerException {
    if (responseWritten) {
        LOGGER.log(Level.FINE, "Response already written.");
        return null;
    }
    responseWritten = true;
    String reasonPhrase = responseContext.getStatusInfo().getReasonPhrase();
    int statusCode = responseContext.getStatus();
    HttpResponseStatus status = reasonPhrase == null ? HttpResponseStatus.valueOf(statusCode) : new HttpResponseStatus(statusCode, reasonPhrase);
    DefaultHttpResponse response;
    if (contentLength == 0) {
        response = new DefaultFullHttpResponse(req.protocolVersion(), status);
    } else {
        response = new DefaultHttpResponse(req.protocolVersion(), status);
    }
    for (final Map.Entry<String, List<String>> e : responseContext.getStringHeaders().entrySet()) {
        response.headers().add(e.getKey(), e.getValue());
    }
    if (contentLength == -1) {
        HttpUtil.setTransferEncodingChunked(response, true);
    } else {
        response.headers().set(HttpHeaderNames.CONTENT_LENGTH, contentLength);
    }
    if (HttpUtil.isKeepAlive(req)) {
        response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }
    ctx.writeAndFlush(response);
    if (req.method() != HttpMethod.HEAD && (contentLength > 0 || contentLength == -1)) {
        JerseyChunkedInput jerseyChunkedInput = new JerseyChunkedInput(ctx.channel());
        if (HttpUtil.isTransferEncodingChunked(response)) {
            ctx.write(new HttpChunkedInput(jerseyChunkedInput)).addListener(FLUSH_FUTURE);
        } else {
            ctx.write(new HttpChunkedInput(jerseyChunkedInput)).addListener(FLUSH_FUTURE);
        }
        return jerseyChunkedInput;
    } else {
        ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        return null;
    }
}
Also used : DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) HttpChunkedInput(io.netty.handler.codec.http.HttpChunkedInput) HttpResponseStatus(io.netty.handler.codec.http.HttpResponseStatus) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) List(java.util.List) Map(java.util.Map) JerseyChunkedInput(org.glassfish.jersey.netty.connector.internal.JerseyChunkedInput)

Example 2 with HttpChunkedInput

use of io.netty.handler.codec.http.HttpChunkedInput in project jersey by jersey.

the class NettyConnector method apply.

@Override
public Future<?> apply(final ClientRequest jerseyRequest, final AsyncConnectorCallback jerseyCallback) {
    final CompletableFuture<Object> settableFuture = new CompletableFuture<>();
    final URI requestUri = jerseyRequest.getUri();
    String host = requestUri.getHost();
    int port = requestUri.getPort() != -1 ? requestUri.getPort() : "https".equals(requestUri.getScheme()) ? 443 : 80;
    try {
        Bootstrap b = new Bootstrap();
        b.group(group).channel(NioSocketChannel.class).handler(new ChannelInitializer<SocketChannel>() {

            @Override
            protected void initChannel(SocketChannel ch) throws Exception {
                ChannelPipeline p = ch.pipeline();
                // Enable HTTPS if necessary.
                if ("https".equals(requestUri.getScheme())) {
                    // making client authentication optional for now; it could be extracted to configurable property
                    JdkSslContext jdkSslContext = new JdkSslContext(client.getSslContext(), true, ClientAuth.NONE);
                    p.addLast(jdkSslContext.newHandler(ch.alloc()));
                }
                // http proxy
                Configuration config = jerseyRequest.getConfiguration();
                final Object proxyUri = config.getProperties().get(ClientProperties.PROXY_URI);
                if (proxyUri != null) {
                    final URI u = getProxyUri(proxyUri);
                    final String userName = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_USERNAME, String.class);
                    final String password = ClientProperties.getValue(config.getProperties(), ClientProperties.PROXY_PASSWORD, String.class);
                    p.addLast(new HttpProxyHandler(new InetSocketAddress(u.getHost(), u.getPort() == -1 ? 8080 : u.getPort()), userName, password));
                }
                p.addLast(new HttpClientCodec());
                p.addLast(new ChunkedWriteHandler());
                p.addLast(new HttpContentDecompressor());
                p.addLast(new JerseyClientHandler(NettyConnector.this, jerseyRequest, jerseyCallback, settableFuture));
            }
        });
        // connect timeout
        Integer connectTimeout = ClientProperties.getValue(jerseyRequest.getConfiguration().getProperties(), ClientProperties.CONNECT_TIMEOUT, 0);
        if (connectTimeout > 0) {
            b.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, connectTimeout);
        }
        // Make the connection attempt.
        final Channel ch = b.connect(host, port).sync().channel();
        // guard against prematurely closed channel
        final GenericFutureListener<io.netty.util.concurrent.Future<? super Void>> closeListener = new GenericFutureListener<io.netty.util.concurrent.Future<? super Void>>() {

            @Override
            public void operationComplete(io.netty.util.concurrent.Future<? super Void> future) throws Exception {
                if (!settableFuture.isDone()) {
                    settableFuture.completeExceptionally(new IOException("Channel closed."));
                }
            }
        };
        ch.closeFuture().addListener(closeListener);
        HttpRequest nettyRequest;
        if (jerseyRequest.hasEntity()) {
            nettyRequest = new DefaultHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(jerseyRequest.getMethod()), requestUri.getRawPath());
        } else {
            nettyRequest = new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, HttpMethod.valueOf(jerseyRequest.getMethod()), requestUri.getRawPath());
        }
        // headers
        for (final Map.Entry<String, List<String>> e : jerseyRequest.getStringHeaders().entrySet()) {
            nettyRequest.headers().add(e.getKey(), e.getValue());
        }
        // host header - http 1.1
        nettyRequest.headers().add(HttpHeaderNames.HOST, jerseyRequest.getUri().getHost());
        if (jerseyRequest.hasEntity()) {
            if (jerseyRequest.getLengthLong() == -1) {
                HttpUtil.setTransferEncodingChunked(nettyRequest, true);
            } else {
                nettyRequest.headers().add(HttpHeaderNames.CONTENT_LENGTH, jerseyRequest.getLengthLong());
            }
        }
        if (jerseyRequest.hasEntity()) {
            // Send the HTTP request.
            ch.writeAndFlush(nettyRequest);
            final JerseyChunkedInput jerseyChunkedInput = new JerseyChunkedInput(ch);
            jerseyRequest.setStreamProvider(new OutboundMessageContext.StreamProvider() {

                @Override
                public OutputStream getOutputStream(int contentLength) throws IOException {
                    return jerseyChunkedInput;
                }
            });
            if (HttpUtil.isTransferEncodingChunked(nettyRequest)) {
                ch.write(new HttpChunkedInput(jerseyChunkedInput));
            } else {
                ch.write(jerseyChunkedInput);
            }
            executorService.execute(new Runnable() {

                @Override
                public void run() {
                    // close listener is not needed any more.
                    ch.closeFuture().removeListener(closeListener);
                    try {
                        jerseyRequest.writeEntity();
                    } catch (IOException e) {
                        jerseyCallback.failure(e);
                        settableFuture.completeExceptionally(e);
                    }
                }
            });
            ch.flush();
        } else {
            // close listener is not needed any more.
            ch.closeFuture().removeListener(closeListener);
            // Send the HTTP request.
            ch.writeAndFlush(nettyRequest);
        }
    } catch (InterruptedException e) {
        settableFuture.completeExceptionally(e);
        return settableFuture;
    }
    return settableFuture;
}
Also used : NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) SocketChannel(io.netty.channel.socket.SocketChannel) Configuration(javax.ws.rs.core.Configuration) InetSocketAddress(java.net.InetSocketAddress) OutputStream(java.io.OutputStream) HttpClientCodec(io.netty.handler.codec.http.HttpClientCodec) URI(java.net.URI) OutboundMessageContext(org.glassfish.jersey.message.internal.OutboundMessageContext) CompletableFuture(java.util.concurrent.CompletableFuture) HttpChunkedInput(io.netty.handler.codec.http.HttpChunkedInput) DefaultHttpRequest(io.netty.handler.codec.http.DefaultHttpRequest) Bootstrap(io.netty.bootstrap.Bootstrap) List(java.util.List) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) JerseyChunkedInput(org.glassfish.jersey.netty.connector.internal.JerseyChunkedInput) DefaultFullHttpRequest(io.netty.handler.codec.http.DefaultFullHttpRequest) DefaultHttpRequest(io.netty.handler.codec.http.DefaultHttpRequest) HttpRequest(io.netty.handler.codec.http.HttpRequest) JdkSslContext(io.netty.handler.ssl.JdkSslContext) DefaultFullHttpRequest(io.netty.handler.codec.http.DefaultFullHttpRequest) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) SocketChannel(io.netty.channel.socket.SocketChannel) Channel(io.netty.channel.Channel) IOException(java.io.IOException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) ProcessingException(javax.ws.rs.ProcessingException) ChannelPipeline(io.netty.channel.ChannelPipeline) HttpContentDecompressor(io.netty.handler.codec.http.HttpContentDecompressor) NioSocketChannel(io.netty.channel.socket.nio.NioSocketChannel) ChunkedWriteHandler(io.netty.handler.stream.ChunkedWriteHandler) CompletableFuture(java.util.concurrent.CompletableFuture) Future(java.util.concurrent.Future) HttpProxyHandler(io.netty.handler.proxy.HttpProxyHandler) Map(java.util.Map)

Example 3 with HttpChunkedInput

use of io.netty.handler.codec.http.HttpChunkedInput in project netty by netty.

the class HttpStaticFileServerHandler method channelRead0.

@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
    if (!request.decoderResult().isSuccess()) {
        sendError(ctx, BAD_REQUEST);
        return;
    }
    if (request.method() != GET) {
        sendError(ctx, METHOD_NOT_ALLOWED);
        return;
    }
    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 (HttpUtil.isKeepAlive(request)) {
        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 (!HttpUtil.isKeepAlive(request)) {
        // 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 HttpChunkedInput

use of io.netty.handler.codec.http.HttpChunkedInput in project flink by apache.

the class TaskManagerLogHandler method respondAsLeader.

/**
	 * Response when running with leading JobManager.
	 */
@Override
protected void respondAsLeader(final ChannelHandlerContext ctx, final Routed routed, final ActorGateway jobManager) {
    if (cache == null) {
        scala.concurrent.Future<Object> portFuture = jobManager.ask(JobManagerMessages.getRequestBlobManagerPort(), timeout);
        scala.concurrent.Future<BlobCache> cacheFuture = portFuture.map(new Mapper<Object, BlobCache>() {

            @Override
            public BlobCache checkedApply(Object result) throws IOException {
                Option<String> hostOption = jobManager.actor().path().address().host();
                String host = hostOption.isDefined() ? hostOption.get() : "localhost";
                int port = (int) result;
                return new BlobCache(new InetSocketAddress(host, port), config);
            }
        }, executor);
        cache = new FlinkFuture<>(cacheFuture);
    }
    final String taskManagerID = routed.pathParams().get(TaskManagersHandler.TASK_MANAGER_ID_KEY);
    final HttpRequest request = routed.request();
    //fetch TaskManager logs if no other process is currently doing it
    if (lastRequestPending.putIfAbsent(taskManagerID, true) == null) {
        try {
            InstanceID instanceID = new InstanceID(StringUtils.hexStringToByte(taskManagerID));
            scala.concurrent.Future<JobManagerMessages.TaskManagerInstance> scalaTaskManagerFuture = jobManager.ask(new JobManagerMessages.RequestTaskManagerInstance(instanceID), timeout).mapTo(ClassTag$.MODULE$.<JobManagerMessages.TaskManagerInstance>apply(JobManagerMessages.TaskManagerInstance.class));
            Future<JobManagerMessages.TaskManagerInstance> taskManagerFuture = new FlinkFuture<>(scalaTaskManagerFuture);
            Future<BlobKey> blobKeyFuture = taskManagerFuture.thenCompose(new ApplyFunction<JobManagerMessages.TaskManagerInstance, Future<BlobKey>>() {

                @Override
                public Future<BlobKey> apply(JobManagerMessages.TaskManagerInstance value) {
                    Instance taskManager = value.instance().get();
                    if (serveLogFile) {
                        return taskManager.getTaskManagerGateway().requestTaskManagerLog(timeTimeout);
                    } else {
                        return taskManager.getTaskManagerGateway().requestTaskManagerStdout(timeTimeout);
                    }
                }
            });
            Future<String> logPathFuture = blobKeyFuture.thenCombine(cache, new BiFunction<BlobKey, BlobCache, Tuple2<BlobKey, BlobCache>>() {

                @Override
                public Tuple2<BlobKey, BlobCache> apply(BlobKey blobKey, BlobCache blobCache) {
                    return Tuple2.of(blobKey, blobCache);
                }
            }).thenComposeAsync(new ApplyFunction<Tuple2<BlobKey, BlobCache>, Future<String>>() {

                @Override
                public Future<String> apply(Tuple2<BlobKey, BlobCache> value) {
                    final BlobKey blobKey = value.f0;
                    final BlobCache blobCache = value.f1;
                    //delete previous log file, if it is different than the current one
                    HashMap<String, BlobKey> lastSubmittedFile = serveLogFile ? lastSubmittedLog : lastSubmittedStdout;
                    if (lastSubmittedFile.containsKey(taskManagerID)) {
                        if (!blobKey.equals(lastSubmittedFile.get(taskManagerID))) {
                            try {
                                blobCache.deleteGlobal(lastSubmittedFile.get(taskManagerID));
                            } catch (IOException e) {
                                return FlinkCompletableFuture.completedExceptionally(new Exception("Could not delete file for " + taskManagerID + '.', e));
                            }
                            lastSubmittedFile.put(taskManagerID, blobKey);
                        }
                    } else {
                        lastSubmittedFile.put(taskManagerID, blobKey);
                    }
                    try {
                        return FlinkCompletableFuture.completed(blobCache.getURL(blobKey).getFile());
                    } catch (IOException e) {
                        return FlinkCompletableFuture.completedExceptionally(new Exception("Could not retrieve blob for " + blobKey + '.', e));
                    }
                }
            }, executor);
            logPathFuture.exceptionally(new ApplyFunction<Throwable, Void>() {

                @Override
                public Void apply(Throwable failure) {
                    display(ctx, request, "Fetching TaskManager log failed.");
                    LOG.error("Fetching TaskManager log failed.", failure);
                    lastRequestPending.remove(taskManagerID);
                    return null;
                }
            });
            logPathFuture.thenAccept(new AcceptFunction<String>() {

                @Override
                public void accept(String filePath) {
                    File file = new File(filePath);
                    final RandomAccessFile raf;
                    try {
                        raf = new RandomAccessFile(file, "r");
                    } catch (FileNotFoundException e) {
                        display(ctx, request, "Displaying TaskManager log failed.");
                        LOG.error("Displaying TaskManager log failed.", e);
                        return;
                    }
                    long fileLength;
                    try {
                        fileLength = raf.length();
                    } catch (IOException ioe) {
                        display(ctx, request, "Displaying TaskManager log failed.");
                        LOG.error("Displaying TaskManager log failed.", ioe);
                        try {
                            raf.close();
                        } catch (IOException e) {
                            LOG.error("Could not close random access file.", e);
                        }
                        return;
                    }
                    final FileChannel fc = raf.getChannel();
                    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
                    response.headers().set(CONTENT_TYPE, "text/plain");
                    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;
                    final GenericFutureListener<io.netty.util.concurrent.Future<? super Void>> completionListener = new GenericFutureListener<io.netty.util.concurrent.Future<? super Void>>() {

                        @Override
                        public void operationComplete(io.netty.util.concurrent.Future<? super Void> future) throws Exception {
                            lastRequestPending.remove(taskManagerID);
                            fc.close();
                            raf.close();
                        }
                    };
                    if (ctx.pipeline().get(SslHandler.class) == null) {
                        ctx.write(new DefaultFileRegion(fc, 0, fileLength), ctx.newProgressivePromise()).addListener(completionListener);
                        lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
                    } else {
                        try {
                            lastContentFuture = ctx.writeAndFlush(new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()).addListener(completionListener);
                        } catch (IOException e) {
                            display(ctx, request, "Displaying TaskManager log failed.");
                            LOG.warn("Could not write http data.", e);
                            return;
                        }
                    // 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) {
            display(ctx, request, "Error: " + e.getMessage());
            LOG.error("Fetching TaskManager log failed.", e);
            lastRequestPending.remove(taskManagerID);
        }
    } else {
        display(ctx, request, "loading...");
    }
}
Also used : InstanceID(org.apache.flink.runtime.instance.InstanceID) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) HashMap(java.util.HashMap) InetSocketAddress(java.net.InetSocketAddress) FileNotFoundException(java.io.FileNotFoundException) FlinkFuture(org.apache.flink.runtime.concurrent.impl.FlinkFuture) BlobKey(org.apache.flink.runtime.blob.BlobKey) GenericFutureListener(io.netty.util.concurrent.GenericFutureListener) ChannelFuture(io.netty.channel.ChannelFuture) ChunkedFile(io.netty.handler.stream.ChunkedFile) JobManagerMessages(org.apache.flink.runtime.messages.JobManagerMessages) DefaultFileRegion(io.netty.channel.DefaultFileRegion) RandomAccessFile(java.io.RandomAccessFile) Option(scala.Option) RandomAccessFile(java.io.RandomAccessFile) ChunkedFile(io.netty.handler.stream.ChunkedFile) File(java.io.File) Instance(org.apache.flink.runtime.instance.Instance) BlobCache(org.apache.flink.runtime.blob.BlobCache) HttpChunkedInput(io.netty.handler.codec.http.HttpChunkedInput) HttpRequest(io.netty.handler.codec.http.HttpRequest) FileChannel(java.nio.channels.FileChannel) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) HttpResponse(io.netty.handler.codec.http.HttpResponse) IOException(java.io.IOException) FileNotFoundException(java.io.FileNotFoundException) IOException(java.io.IOException) BiFunction(org.apache.flink.runtime.concurrent.BiFunction) Tuple2(org.apache.flink.api.java.tuple.Tuple2) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) FlinkFuture(org.apache.flink.runtime.concurrent.impl.FlinkFuture) Future(org.apache.flink.runtime.concurrent.Future) FlinkCompletableFuture(org.apache.flink.runtime.concurrent.impl.FlinkCompletableFuture) ChannelFuture(io.netty.channel.ChannelFuture)

Example 5 with HttpChunkedInput

use of io.netty.handler.codec.http.HttpChunkedInput in project flink by apache.

the class StaticFileServerHandler method respondAsLeader.

/**
	 * Response when running with leading JobManager.
	 */
private void respondAsLeader(ChannelHandlerContext ctx, HttpRequest request, String requestPath) throws IOException, ParseException, URISyntaxException {
    // 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 = StaticFileServerHandler.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)) {
                            logger.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) {
                logger.error("error while responding", t);
            } finally {
                if (!success) {
                    logger.debug("Unable to load requested file {} from classloader", requestPath);
                    sendError(ctx, NOT_FOUND);
                    return;
                }
            }
        }
    }
    if (!file.exists() || file.isHidden() || file.isDirectory() || !file.isFile()) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    if (!file.getCanonicalFile().toPath().startsWith(rootPath.toPath())) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    // cache validation
    final String ifModifiedSince = request.headers().get(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) {
            if (logger.isDebugEnabled()) {
                logger.debug("Responding 'NOT MODIFIED' for file '" + file.getAbsolutePath() + '\'');
            }
            sendNotModified(ctx);
            return;
        }
    }
    if (logger.isDebugEnabled()) {
        logger.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) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    long fileLength = raf.length();
    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
    setContentTypeHeader(response, file);
    // since the log and out files are rapidly changing, we don't want to browser to cache them
    if (!(requestPath.contains("log") || requestPath.contains("out"))) {
        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);
    }
}
Also used : ChannelFuture(io.netty.channel.ChannelFuture) InputStream(java.io.InputStream) ChunkedFile(io.netty.handler.stream.ChunkedFile) FileNotFoundException(java.io.FileNotFoundException) DefaultHttpResponse(io.netty.handler.codec.http.DefaultHttpResponse) DefaultFullHttpResponse(io.netty.handler.codec.http.DefaultFullHttpResponse) HttpResponse(io.netty.handler.codec.http.HttpResponse) FullHttpResponse(io.netty.handler.codec.http.FullHttpResponse) DefaultFileRegion(io.netty.channel.DefaultFileRegion) URI(java.net.URI) URL(java.net.URL) 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)

Aggregations

HttpChunkedInput (io.netty.handler.codec.http.HttpChunkedInput)6 DefaultHttpResponse (io.netty.handler.codec.http.DefaultHttpResponse)5 ChannelFuture (io.netty.channel.ChannelFuture)4 DefaultFileRegion (io.netty.channel.DefaultFileRegion)4 DefaultFullHttpResponse (io.netty.handler.codec.http.DefaultFullHttpResponse)4 HttpResponse (io.netty.handler.codec.http.HttpResponse)4 ChunkedFile (io.netty.handler.stream.ChunkedFile)4 File (java.io.File)4 FileNotFoundException (java.io.FileNotFoundException)4 RandomAccessFile (java.io.RandomAccessFile)4 FullHttpResponse (io.netty.handler.codec.http.FullHttpResponse)3 SslHandler (io.netty.handler.ssl.SslHandler)3 SimpleDateFormat (java.text.SimpleDateFormat)3 Date (java.util.Date)3 ChannelProgressiveFuture (io.netty.channel.ChannelProgressiveFuture)2 ChannelProgressiveFutureListener (io.netty.channel.ChannelProgressiveFutureListener)2 HttpRequest (io.netty.handler.codec.http.HttpRequest)2 GenericFutureListener (io.netty.util.concurrent.GenericFutureListener)2 IOException (java.io.IOException)2 InetSocketAddress (java.net.InetSocketAddress)2