private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws Exception { // Handle a bad request. if (!req.getDecoderResult().isSuccess()) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); req.release(); return; } // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); req.release(); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory( getWebSocketLocation(req), null, false, Integer.MAX_VALUE); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } req.release(); }
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { // Handle a bad request. if (!req.getDecoderResult().isSuccess()) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, BAD_REQUEST)); return; } // Allow only GET methods. if (req.getMethod() != GET) { sendHttpResponse(ctx, req, new DefaultFullHttpResponse(HTTP_1_1, FORBIDDEN)); return; } // Send the demo page and favicon.ico if ("/".equals(req.getUri())) { ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content); res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8"); HttpHeaders.setContentLength(res, content.readableBytes()); sendHttpResponse(ctx, req, res); return; } if ("/favicon.ico".equals(req.getUri())) { FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND); sendHttpResponse(ctx, req, res); return; } // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(getWebSocketLocation(req), null, true); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } }
private void processHead(ChannelHandlerContext context, FullHttpRequest request) { HttpHeaders headers = request.headers(); FullHttpResponse response = null; if (headers.contains(Names.CONTENT_LENGTH)) { try { File file = getRequestedFile(request.getUri()); response = new DefaultFullHttpResponse( HTTP_1_1, request.getDecoderResult().isSuccess() ? OK : BAD_REQUEST); HttpHeaders.setContentLength(response, file.length()); } catch (FileNotFoundException | URISyntaxException e) { response = getBadRequest(e.getMessage()); } } context.writeAndFlush(response); }
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) { if (!req.getDecoderResult().isSuccess() || (!"websocket".equals(req.headers().get("Upgrade")))) { sendHttpResponse( ctx, req, new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory("ws://localhost:7397/websocket", null, false); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedWebSocketVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), req); } }
public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest nettyRequest) throws Exception { if (!nettyRequest.getDecoderResult().isSuccess()) { sendError(ctx, HttpResponseStatus.BAD_REQUEST); return; } final long startTime = System.nanoTime(); final Request request = new DefaultRequest( new NettyHeadersBackedHeaders(nettyRequest.headers()), nettyRequest.getMethod().name(), nettyRequest.getUri(), nettyRequest.content()); final Channel channel = ctx.channel(); final DefaultMutableStatus responseStatus = new DefaultMutableStatus(); final HttpHeaders httpHeaders = new DefaultHttpHeaders(false); final MutableHeaders responseHeaders = new NettyHeadersBackedMutableHeaders(httpHeaders); FileHttpTransmitter fileHttpTransmitter = new DefaultFileHttpTransmitter( nettyRequest, httpHeaders, channel, compressResponses, addResponseTimeHeader ? startTime : -1); final DefaultEventController<RequestOutcome> requestOutcomeEventController = new DefaultEventController<>(); // We own the lifecycle nettyRequest.content().retain(); final Response response = new DefaultResponse( responseStatus, responseHeaders, fileHttpTransmitter, ctx.alloc(), new Action<ByteBuf>() { @Override public void execute(final ByteBuf byteBuf) throws Exception { final HttpResponse nettyResponse = new CustomHttpResponse(responseStatus.getResponseStatus(), httpHeaders); nettyRequest.content().release(); responseHeaders.set(HttpHeaderConstants.CONTENT_LENGTH, byteBuf.writerIndex()); boolean shouldClose = true; if (channel.isOpen()) { if (isKeepAlive(nettyRequest)) { responseHeaders.set( HttpHeaderConstants.CONNECTION, HttpHeaderConstants.KEEP_ALIVE); shouldClose = false; } long stopTime = System.nanoTime(); if (addResponseTimeHeader) { responseHeaders.set( "X-Response-Time", NumberUtil.toMillisDiffString(startTime, stopTime)); } execController.getExecution().complete(); channel.writeAndFlush(nettyResponse); channel.write(new DefaultHttpContent(byteBuf)); ChannelFuture future = channel.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if (requestOutcomeEventController.isHasListeners()) { Headers headers = new DelegatingHeaders(responseHeaders); Status status = new DefaultStatus(responseStatus.getCode(), responseStatus.getMessage()); SentResponse sentResponse = new DefaultSentResponse(headers, status); RequestOutcome requestOutcome = new DefaultRequestOutcome( request, sentResponse, System.currentTimeMillis()); requestOutcomeEventController.fire(requestOutcome); } if (shouldClose) { future.addListener(ChannelFutureListener.CLOSE); } } } }); InetSocketAddress socketAddress = (InetSocketAddress) channel.localAddress(); final BindAddress bindAddress = new InetSocketAddressBackedBindAddress(socketAddress); Action<Action<Object>> subscribeHandler = new Action<Action<Object>>() { @Override public void execute(Action<Object> thing) throws Exception { channelSubscriptions.put(channel, thing); channel .closeFuture() .addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { channelSubscriptions.remove(channel); } }); } }; final DirectChannelAccess directChannelAccess = new DefaultDirectChannelAccess(channel, subscribeHandler); execController.start( new Action<Execution>() { @Override public void execute(Execution execution) throws Exception { DefaultContext.RequestConstants requestConstants = new DefaultContext.RequestConstants( applicationConstants, bindAddress, request, response, directChannelAccess, requestOutcomeEventController.getRegistry(), execution); new DefaultContext(requestConstants, registry, handlers, 0, return404).next(); } }); }
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest request) { // Handle a bad request. if (!request.getDecoderResult().isSuccess()) { sendHttpResponse( ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.BAD_REQUEST)); return; } if (RouterHits.checkIfMappingExit(request)) { // Do Router Mapping First RouterHits.execute(ctx, request); return; } if ("/websocket".equals(request.getUri())) { // Handshake WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(getWebSocketLocation(request), null, true); handshaker = wsFactory.newHandshaker(request); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { handshaker.handshake(ctx.channel(), request); channels.add(ctx.channel()); } return; } final String uri = request.getUri(); // System.out.println("uri: " + uri); final String path = sanitizeUri("www", uri); // System.out.println("path: " + path); if (path == null) { sendHttpResponse( ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN)); return; } File file = new File(path); if (file.isHidden() || !file.exists()) { sendHttpResponse( ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NOT_FOUND)); return; } if (file.isDirectory()) { if (uri.endsWith("/")) { File checkIndexFile = new File(file.getAbsolutePath() + File.separator + "index.html"); System.out.println(checkIndexFile.exists()); if (checkIndexFile.exists()) { file = checkIndexFile; } else { sendListing(ctx, file); return; } } else { sendRedirect(ctx, uri + '/'); } } if (!file.isFile()) { sendHttpResponse( ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN)); return; } // Cache Validation String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE); if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) { SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US); Date ifModifiedSinceDate = null; try { ifModifiedSinceDate = dateFormatter.parse(ifModifiedSince); } catch (ParseException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 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) { sendHttpResponse( ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.NOT_FOUND)); return; } long fileLength = 0; try { fileLength = raf.length(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); setContentTypeHeader(response, file); setDateAndCacheHeaders(response, file); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture = null; 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 { try { sendFileFuture = ctx.writeAndFlush( new HttpChunkedInput(new ChunkedFile(raf, 0, fileLength, 8192)), ctx.newProgressivePromise()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // 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 (!HttpHeaders.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } // // Send the demo page and favicon.ico // if ("/".equals(req.getUri()) && req.getMethod() == GET) { // ByteBuf content = WebSocketServerIndexPage.getContent(getWebSocketLocation(req)); // FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, OK, content); // // res.headers().set(CONTENT_TYPE, "text/html; charset=UTF-8"); // HttpHeaders.setContentLength(res, content.readableBytes()); // // sendHttpResponse(ctx, req, res); // return; // } // // if ("/favicon.ico".equals(req.getUri())) { // FullHttpResponse res = new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND); // sendHttpResponse(ctx, req, res); // return; // } sendHttpResponse( ctx, request, new DefaultFullHttpResponse(HTTP_1_1, HttpResponseStatus.FORBIDDEN)); return; }
@Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST); return; } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String uri = request.getUri(); final String path = sanitizeUri(uri); if (path == null) { sendError(ctx, FORBIDDEN); return; } // Cache Validation 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; // we use the start time of the JVM as last modified date long lastModifiedSeconds = ManagementFactory.getRuntimeMXBean().getStartTime(); if (ifModifiedSinceDateSeconds == lastModifiedSeconds) { sendNotModified(ctx); return; } } ClassLoader classLoader = HttpClasspathServerHandler.class.getClassLoader(); InputStream stream = classLoader.getResourceAsStream(path); if (stream == null) { sendError(ctx, NOT_FOUND); return; } HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, stream.available()); setContentTypeHeader(response, path); setDateAndCacheHeaders(response); if (HttpHeaders.isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } // Write the initial line and the header. ctx.write(response); // Write the content. ChannelFuture sendFileFuture = ctx.write(new ChunkedStream(stream), ctx.newProgressivePromise()); // Write the end marker. ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); // Decide whether to close the connection or not. if (!HttpHeaders.isKeepAlive(request)) { // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); } }
@Override protected void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { // TODO Auto-generated method stub if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST); return; } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED); return; } final String uri = request.getUri(); 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); } else { sendRedirect(ctx, uri + '/'); } return; } if (!file.isFile()) { sendError(ctx, FORBIDDEN); return; } RandomAccessFile randomAccessFile = null; try { randomAccessFile = new RandomAccessFile(file, "r"); // 以只读的方式打开文件 } catch (FileNotFoundException fnfe) { sendError(ctx, NOT_FOUND); return; } long fileLength = randomAccessFile.length(); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); setContentLength(response, fileLength); setContentTypeHeader(response, file); if (isKeepAlive(request)) { response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE); } ctx.write(response); ChannelFuture sendFileFuture; sendFileFuture = ctx.write( new ChunkedFile(randomAccessFile, 0, fileLength, 8192), ctx.newProgressivePromise()); sendFileFuture.addListener( new ChannelProgressiveFutureListener() { @Override public void operationProgressed( ChannelProgressiveFuture future, long progress, long total) { if (total < 0) { // total unknown System.err.println("Transfer progress: " + progress); } else { System.err.println("Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) throws Exception { System.out.println("Transfer complete."); } }); ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT); if (!isKeepAlive(request)) { lastContentFuture.addListener(ChannelFutureListener.CLOSE); } }
public void channelRead0(final ChannelHandlerContext ctx, final FullHttpRequest nettyRequest) throws Exception { if (!nettyRequest.getDecoderResult().isSuccess()) { sendError(ctx, HttpResponseStatus.BAD_REQUEST); return; } final long startTime = addResponseTimeHeader ? System.nanoTime() : 0; final Request request = new DefaultRequest( new NettyHeadersBackedHeaders(nettyRequest.headers()), nettyRequest.getMethod().name(), nettyRequest.getUri(), nettyRequest.content()); final Channel channel = ctx.channel(); final DefaultMutableStatus responseStatus = new DefaultMutableStatus(); final HttpHeaders nettyHeaders = new DefaultHttpHeaders(false); final MutableHeaders responseHeaders = new NettyHeadersBackedMutableHeaders(nettyHeaders); final MimeTypes mimeTypes = registry.get(MimeTypes.class); final DefaultEventController<RequestOutcome> requestOutcomeEventController = new DefaultEventController<>(); final AtomicBoolean transmitted = new AtomicBoolean(false); final ResponseTransmitter responseTransmitter = new DefaultResponseTransmitter( transmitted, channel, nettyRequest, request, nettyHeaders, responseStatus, requestOutcomeEventController, startTime); final Action<Action<? super ResponseTransmitter>> responseTransmitterWrapper = Actions.wrap(responseTransmitter); final FileHttpTransmitter fileHttpTransmitter = new DefaultFileHttpTransmitter( nettyHeaders, mimeTypes, compressResponses, compressionMinSize, compressionMimeTypeWhiteList, compressionMimeTypeBlackList, responseTransmitterWrapper); StreamTransmitter streamTransmitter = new DefaultStreamTransmitter(nettyRequest, nettyHeaders, channel); final Response response = new DefaultResponse( responseStatus, responseHeaders, fileHttpTransmitter, streamTransmitter, ctx.alloc(), new Action<ByteBuf>() { @Override public void execute(final ByteBuf byteBuf) throws Exception { responseTransmitterWrapper.execute( new Action<ResponseTransmitter>() { @Override public void execute(ResponseTransmitter responseTransmitter) throws Exception { nettyHeaders.set(HttpHeaders.Names.CONTENT_LENGTH, byteBuf.writerIndex()); responseTransmitter.transmit(new DefaultHttpContent(byteBuf)); } }); } }); InetSocketAddress socketAddress = (InetSocketAddress) channel.localAddress(); final BindAddress bindAddress = new InetSocketAddressBackedBindAddress(socketAddress); Action<Action<Object>> subscribeHandler = new Action<Action<Object>>() { @Override public void execute(Action<Object> thing) throws Exception { transmitted.set(true); channelSubscriptions.put(channel, thing); channel .closeFuture() .addListener( new ChannelFutureListener() { @Override public void operationComplete(ChannelFuture future) throws Exception { channelSubscriptions.remove(channel); } }); } }; final DirectChannelAccess directChannelAccess = new DefaultDirectChannelAccess(channel, subscribeHandler); final DefaultContext.RequestConstants requestConstants = new DefaultContext.RequestConstants( applicationConstants, bindAddress, request, response, directChannelAccess, requestOutcomeEventController.getRegistry()); DefaultContext.start( execController.getControl(), requestConstants, registry, handlers, return404, new Action<Execution>() { @Override public void execute(Execution execution) throws Exception { if (!transmitted.get()) { Handler lastHandler = requestConstants.handler; StringBuilder description = new StringBuilder(); description .append("No response sent for ") .append(request.getMethod().getName()) .append(" request to ") .append(request.getUri()) .append(" (last handler: "); if (lastHandler instanceof DescribingHandler) { ((DescribingHandler) lastHandler).describeTo(description); } else { DescribingHandlers.describeTo(lastHandler, description); } description.append(")"); String message = description.toString(); LOGGER.warn(message); response.status(500); if (launchConfig.isDevelopment()) { response.send(message); } else { response.send(); } } } }); }
private void handleHttpRequest(ChannelHandlerContext ctx, FullHttpRequest req) throws SuspendExecution { // Handle a bad request. if (!req.getDecoderResult().isSuccess()) { sendHttpResponse( ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), BAD_REQUEST), false); return; } final String uri = req.getUri(); final Context actorCtx = selector.get(ctx, req); assert actorCtx != null; final ReentrantLock lock = actorCtx.getLock(); assert lock != null; lock.lock(); try { final ActorRef<? extends WebMessage> userActorRef = actorCtx.getRef(); ActorImpl internalActor = (ActorImpl) actorCtx.getAttachments().get(ACTOR_KEY); if (userActorRef != null) { if (actorCtx.handlesWithWebSocket(uri)) { if (internalActor == null || !(internalActor instanceof WebSocketActorAdapter)) { //noinspection unchecked webSocketActor = new WebSocketActorAdapter(ctx, (ActorRef<? super WebMessage>) userActorRef); addActorToContextAndUnlock(actorCtx, webSocketActor, lock); } // Handshake final WebSocketServerHandshakerFactory wsFactory = new WebSocketServerHandshakerFactory(uri, null, true); handshaker = wsFactory.newHandshaker(req); if (handshaker == null) { WebSocketServerHandshakerFactory.sendUnsupportedVersionResponse(ctx.channel()); } else { @SuppressWarnings("unchecked") final ActorRef<WebMessage> userActorRef0 = (ActorRef<WebMessage>) webSocketActor.userActor; handshaker .handshake(ctx.channel(), req) .addListener( new GenericFutureListener<ChannelFuture>() { @Override public void operationComplete(ChannelFuture future) throws Exception { FiberUtil.runInFiber( new SuspendableRunnable() { @Override public void run() throws SuspendExecution, InterruptedException { userActorRef0.send( new WebSocketOpened(WebActorHandler.this.webSocketActor.ref())); } }); } }); } return; } else if (actorCtx.handlesWithHttp(uri)) { if (internalActor == null || !(internalActor instanceof HttpActorAdapter)) { //noinspection unchecked internalActor = new HttpActorAdapter( (ActorRef<HttpRequest>) userActorRef, actorCtx, httpResponseEncoderName); addActorToContextAndUnlock(actorCtx, internalActor, lock); } //noinspection unchecked ((HttpActorAdapter) internalActor).service(ctx, req); return; } } } finally { if (lock.isHeldByCurrentStrand() && lock.isLocked()) lock.unlock(); } sendHttpResponse( ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), NOT_FOUND), false); }
@Override public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception { if (!request.getDecoderResult().isSuccess()) { sendError(ctx, BAD_REQUEST, request); return; } if (request.getMethod() != GET) { sendError(ctx, METHOD_NOT_ALLOWED, request); return; } File file = null; RandomAccessFile raf = null; boolean found = true; for (String p : paths) { String path = p + sanitizeUri(request.getUri()); if (path == null) { path = "/index.html"; } if (path.endsWith("/") || path.endsWith(File.separator)) { path += "index.html"; } if (path.endsWith("/favicon.ico") || path.endsWith(File.separator)) { request.headers().add(SERVICED, "true"); found = false; continue; } file = new File(path); if (file.isHidden() || !file.exists()) { found = false; continue; } // if (file.isDirectory()) { // if (uri.endsWith("/")) { // sendListing(ctx, file); // } else { // sendRedirect(ctx, uri + '/'); // } // return; // } if (!file.isFile()) { found = false; continue; } try { raf = new RandomAccessFile(file, "r"); found = true; break; } catch (FileNotFoundException ignore) { sendError(ctx, NOT_FOUND, request); return; } } if (!found) { sendError(ctx, NOT_FOUND, request); return; } request.headers().add(SERVICED, "true"); // Cache Validation 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) { sendNotModified(ctx); return; } } long fileLength = raf.length(); ctx.pipeline().addBefore(BridgeRuntime.class.getName(), "encoder", new HttpResponseEncoder()); HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK); HttpHeaders.setContentLength(response, fileLength); contentType(request, response, file); setDateAndCacheHeaders(response, file); // if (HttpHeaders.isKeepAlive(request)) { // response.headers().set(CONNECTION, HttpHeaders.Values.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 logger.trace(future.channel() + " Transfer progress: " + progress); } else { logger.trace(future.channel() + " Transfer progress: " + progress + " / " + total); } } @Override public void operationComplete(ChannelProgressiveFuture future) { logger.trace(future.channel() + " Transfer complete."); } }); // Close the connection when the whole content is written out. lastContentFuture.addListener(ChannelFutureListener.CLOSE); }