Example usage for io.netty.handler.codec.http LastHttpContent EMPTY_LAST_CONTENT

List of usage examples for io.netty.handler.codec.http LastHttpContent EMPTY_LAST_CONTENT

Introduction

In this page you can find the example usage for io.netty.handler.codec.http LastHttpContent EMPTY_LAST_CONTENT.

Prototype

LastHttpContent EMPTY_LAST_CONTENT

To view the source code for io.netty.handler.codec.http LastHttpContent EMPTY_LAST_CONTENT.

Click Source Link

Document

The 'end of content' marker in chunked encoding.

Usage

From source file:bean.lee.demo.netty.learn.http.file.HttpStaticFileServerHandler.java

License:Apache License

@Override
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
    // ????/*ww  w.ja  v  a 2s .  c o  m*/
    if (!request.getDecoderResult().isSuccess()) {
        sendError(ctx, BAD_REQUEST);
        return;
    }

    // ?get
    if (request.getMethod() != GET) {
        sendError(ctx, METHOD_NOT_ALLOWED);
        return;
    }

    // uri??
    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;
    }

    // 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;
        }
    }

    RandomAccessFile raf;
    try {
        raf = new RandomAccessFile(file, "r");
    } catch (FileNotFoundException fnfe) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    long fileLength = raf.length();

    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
    setContentLength(response, fileLength);
    setContentTypeHeader(response, file);
    setDateAndCacheHeaders(response, file);
    if (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;
    if (useSendFile) {
        sendFileFuture = ctx.write(new DefaultFileRegion(raf.getChannel(), 0, fileLength),
                ctx.newProgressivePromise());
    } else {
        sendFileFuture = ctx.write(new ChunkedFile(raf, 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.err.println("Transfer complete.");
        }
    });

    // Write the end marker
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);

    // Decide whether to close the connection or not.
    if (!isKeepAlive(request)) {
        // Close the connection when the whole content is written out.
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
}

From source file:books.netty.protocol.http.fileServer.HttpFileServerHandler.java

License:Apache License

@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
    if (!request.getDecoderResult().isSuccess()) {
        sendError(ctx, BAD_REQUEST);//from  w w w .  j  a v a2s .  c o m
        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) {
            System.out.println("Transfer complete.");
        }
    });
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    if (!isKeepAlive(request)) {
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
}

From source file:cn.yesway.demo.book.protocol.http.fileServer.HttpFileServerHandler.java

License:Apache License

@Override
public void messageReceived(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
    if (!request.getDecoderResult().isSuccess()) {
        sendError(ctx, BAD_REQUEST);//www .  j  av a2 s . com
        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);
    }
}

From source file:com.addthis.hydra.query.tracker.DetailedStatusHandler.java

License:Apache License

private void onSuccess(QueryEntryInfo queryEntryInfo) {
    try {// ww  w .  j a  va  2 s .c  om
        JSONObject entryJSON = CodecJSON.encodeJSON(queryEntryInfo);
        writer.write(entryJSON.toString());
        ByteBuf textResponse = ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(writer.getBuilder()),
                CharsetUtil.UTF_8);
        HttpContent content = new DefaultHttpContent(textResponse);
        response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, textResponse.readableBytes());
        if (HttpHeaders.isKeepAlive(request)) {
            response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
        }
        ctx.write(response);
        ctx.write(content);
        ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
        if (!HttpHeaders.isKeepAlive(request)) {
            lastContentFuture.addListener(ChannelFutureListener.CLOSE);
        }
    } catch (Throwable t) {
        onFailure(t);
    }
}

From source file:com.addthis.hydra.query.web.DataChannelOutputToNettyBridge.java

License:Apache License

@Override
public void sendComplete() { // TODO: keep alive logic
    log.trace("Writing sendComplete to pipeline {}", ctx.pipeline());
    ctx.write(SEND_COMPLETE);/* w ww.j  a  v  a  2  s .  c om*/
    // no need to make the frame reader wait on the async flush to finish
    overallQueryPromise.trySuccess();
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT,
            ctx.channel().newPromise());
    lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}

From source file:com.addthis.hydra.query.web.DetailedStatusHandler.java

License:Apache License

private void onSuccess(QueryEntryInfo queryEntryInfo) throws Exception {
    JSONObject entryJSON = CodecJSON.encodeJSON(queryEntryInfo);
    writer.write(entryJSON.toString());/*from   www .j a v a  2s .co  m*/
    ByteBuf textResponse = ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(writer.getBuilder()),
            CharsetUtil.UTF_8);
    HttpContent content = new DefaultHttpContent(textResponse);
    response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, textResponse.readableBytes());
    if (HttpHeaders.isKeepAlive(request)) {
        response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
    }
    ctx.write(response);
    ctx.write(content);
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    if (!HttpHeaders.isKeepAlive(request)) {
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
}

From source file:com.addthis.hydra.query.web.GoogleDriveAuthentication.java

License:Apache License

/**
 * Send an HTML formatted error message.
 *//*w ww. j  a  va 2  s.c o  m*/
private static void sendErrorMessage(ChannelHandlerContext ctx, String message) throws IOException {
    HttpResponse response = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
    response.headers().set(CONTENT_TYPE, "text/html; charset=utf-8");
    StringBuilderWriter writer = new StringBuilderWriter(50);
    writer.append("<html><head><title>Hydra Query Master</title></head><body>");
    writer.append("<h3>");
    writer.append(message);
    writer.append("</h3></body></html>");
    ByteBuf textResponse = ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(writer.getBuilder()),
            CharsetUtil.UTF_8);
    HttpContent content = new DefaultHttpContent(textResponse);
    response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, textResponse.readableBytes());
    ctx.write(response);
    ctx.write(content);
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}

From source file:com.addthis.hydra.query.web.GoogleDriveAuthentication.java

License:Apache License

/**
 * Obtain a Google authorization token. This token is worthless by itself. It
 * is an intermediate step to obtain an access token. We need to do these two
 * steps because...reasons./*from w  ww . ja v a  2  s  .  c  om*/
 */
static void gdriveAuthorization(KVPairs kv, ChannelHandlerContext ctx) throws Exception {
    if (gdriveClientId == null && gdriveClientSecret == null) {
        sendErrorMessage(ctx, "The system properties \"qmaster.export.gdrive.clientId\""
                + " and \"qmaster.export.gdrive.clientSecret\" are both null.");
        return;
    } else if (gdriveClientId == null) {
        sendErrorMessage(ctx, "The system property \"qmaster.export.gdrive.clientId\"" + " is null.");
        return;
    } else if (gdriveClientSecret == null) {
        sendErrorMessage(ctx, "The system property \"qmaster.export.gdrive.clientSecret\"" + " is null.");
        return;
    } else if (!gdriveEnabled) {
        sendErrorMessage(ctx, "The system property \"qmaster.export.gdrive.enable\"" + " is false.");
        return;
    }
    QueryStringEncoder encoder = new QueryStringEncoder("");
    Iterator<KVPair> iterator = kv.iterator();
    while (iterator.hasNext()) {
        KVPair pair = iterator.next();
        encoder.addParam(pair.getKey(), pair.getValue());
    }
    String state = encoder.toString().substring(1);
    URI uri = new URIBuilder().setScheme("https").setHost("accounts.google.com").setPath("/o/oauth2/auth")
            .setParameter("scope", "https://www.googleapis.com/auth/drive.file").setParameter("state", state)
            .setParameter("redirect_uri", "http://" + generateTargetHostName() + ":2222/query/google/submit")
            .setParameter("response_type", "code").setParameter("client_id", gdriveClientId).build();
    FullHttpResponse response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.FOUND);
    response.headers().set(HttpHeaders.Names.LOCATION, uri);
    ctx.write(response);
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    log.trace("response pending");
    log.trace("Setting close listener");
    lastContentFuture.addListener(ChannelFutureListener.CLOSE);
}

From source file:com.addthis.hydra.query.web.HttpQueryHandler.java

License:Apache License

private void fastHandle(ChannelHandlerContext ctx, FullHttpRequest request, String target, KVPairs kv)
        throws Exception {
    StringBuilderWriter writer = new StringBuilderWriter(50);
    HttpResponse response = HttpUtils.startResponse(writer);
    response.headers().add("Access-Control-Allow-Origin", "*");

    switch (target) {
    case "/metrics":
        fakeMetricsServlet.writeMetrics(writer, kv);
        break;//  w  ww.j a va2s. c  o  m
    case "/query/list":
        writer.write("[\n");
        for (QueryEntryInfo stat : tracker.getRunning()) {
            writer.write(CodecJSON.encodeString(stat).concat(",\n"));
        }
        writer.write("]");
        break;
    case "/completed/list":
        writer.write("[\n");
        for (QueryEntryInfo stat : tracker.getCompleted()) {
            writer.write(CodecJSON.encodeString(stat).concat(",\n"));
        }
        writer.write("]");
        break;
    case "/v2/host/list":
    case "/host/list":
        String queryStatusUuid = kv.getValue("uuid");
        QueryEntry queryEntry = tracker.getQueryEntry(queryStatusUuid);
        if (queryEntry != null) {
            DetailedStatusHandler hostDetailsHandler = new DetailedStatusHandler(writer, response, ctx, request,
                    queryEntry);
            hostDetailsHandler.handle();
            return;
        } else {
            QueryEntryInfo queryEntryInfo = tracker.getCompletedQueryInfo(queryStatusUuid);
            if (queryEntryInfo != null) {
                JSONObject entryJSON = CodecJSON.encodeJSON(queryEntryInfo);
                writer.write(entryJSON.toString());
            } else {
                throw new RuntimeException("could not find query");
            }
            break;
        }
    case "/query/cancel":
        if (tracker.cancelRunning(kv.getValue("uuid"))) {
            writer.write("canceled " + kv.getValue("uuid"));
        } else {
            writer.write("canceled failed for " + kv.getValue("uuid"));
            response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
        }
        break;
    case "/query/encode": {
        Query q = new Query(null, kv.getValue("query", kv.getValue("path", "")), null);
        JSONArray path = CodecJSON.encodeJSON(q).getJSONArray("path");
        writer.write(path.toString());
        break;
    }
    case "/query/decode": {
        String qo = "{path:" + kv.getValue("query", kv.getValue("path", "")) + "}";
        Query q = CodecJSON.decodeString(new Query(), qo);
        writer.write(q.getPaths()[0]);
        break;
    }
    case "/v2/queries/finished.list": {
        JSONArray runningEntries = new JSONArray();
        for (QueryEntryInfo entryInfo : tracker.getCompleted()) {
            JSONObject entryJSON = CodecJSON.encodeJSON(entryInfo);
            //TODO: replace this with some high level summary
            entryJSON.put("hostInfoSet", "");
            runningEntries.put(entryJSON);
        }
        writer.write(runningEntries.toString());
        break;
    }
    case "/v2/queries/running.list": {
        JSONArray runningEntries = new JSONArray();
        for (QueryEntryInfo entryInfo : tracker.getRunning()) {
            JSONObject entryJSON = CodecJSON.encodeJSON(entryInfo);
            //TODO: replace this with some high level summary
            entryJSON.put("hostInfoSet", "");
            runningEntries.put(entryJSON);
        }
        writer.write(runningEntries.toString());
        break;
    }
    case "/v2/queries/workers": {
        JSONObject jsonObject = new JSONObject();
        for (WorkerData workerData : meshQueryMaster.worky().values()) {
            jsonObject.put(workerData.hostName, workerData.queryLeases.availablePermits());
        }
        writer.write(jsonObject.toString());
        break;
    }
    case "/v2/queries/list":
        JSONArray queries = new JSONArray();
        for (QueryEntryInfo entryInfo : tracker.getCompleted()) {
            JSONObject entryJSON = CodecJSON.encodeJSON(entryInfo);
            entryJSON.put("state", 0);
            queries.put(entryJSON);
        }
        for (QueryEntryInfo entryInfo : tracker.getRunning()) {
            JSONObject entryJSON = CodecJSON.encodeJSON(entryInfo);
            entryJSON.put("state", 3);
            queries.put(entryJSON);
        }
        writer.write(queries.toString());
        break;
    case "/v2/job/list": {
        StringWriter swriter = new StringWriter();
        final JsonGenerator json = QueryServer.factory.createJsonGenerator(swriter);
        json.writeStartArray();
        for (IJob job : meshQueryMaster.keepy().getJobs()) {
            if (job.getQueryConfig() != null && job.getQueryConfig().getCanQuery()) {
                List<JobTask> tasks = job.getCopyOfTasks();
                String uuid = job.getId();
                json.writeStartObject();
                json.writeStringField("id", uuid);
                json.writeStringField("description", Optional.fromNullable(job.getDescription()).or(""));
                json.writeNumberField("state", job.getState().ordinal());
                json.writeStringField("creator", job.getCreator());
                json.writeNumberField("submitTime", Optional.fromNullable(job.getSubmitTime()).or(-1L));
                json.writeNumberField("startTime", Optional.fromNullable(job.getStartTime()).or(-1L));
                json.writeNumberField("endTime", Optional.fromNullable(job.getStartTime()).or(-1L));
                json.writeNumberField("replicas", Optional.fromNullable(job.getReplicas()).or(0));
                json.writeNumberField("backups", Optional.fromNullable(job.getBackups()).or(0));
                json.writeNumberField("nodes", tasks.size());
                json.writeEndObject();
            }
        }
        json.writeEndArray();
        json.close();
        writer.write(swriter.toString());
        break;
    }
    case "/v2/settings/git.properties": {
        StringWriter swriter = new StringWriter();
        final JsonGenerator json = QueryServer.factory.createJsonGenerator(swriter);
        Properties gitProperties = new Properties();
        json.writeStartObject();
        try {
            InputStream in = queryServer.getClass().getResourceAsStream("/git.properties");
            gitProperties.load(in);
            in.close();
            json.writeStringField("commitIdAbbrev", gitProperties.getProperty("git.commit.id.abbrev"));
            json.writeStringField("commitUserEmail", gitProperties.getProperty("git.commit.user.email"));
            json.writeStringField("commitMessageFull", gitProperties.getProperty("git.commit.message.full"));
            json.writeStringField("commitId", gitProperties.getProperty("git.commit.id"));
            json.writeStringField("commitUserName", gitProperties.getProperty("git.commit.user.name"));
            json.writeStringField("buildUserName", gitProperties.getProperty("git.build.user.name"));
            json.writeStringField("commitIdDescribe", gitProperties.getProperty("git.commit.id.describe"));
            json.writeStringField("buildUserEmail", gitProperties.getProperty("git.build.user.email"));
            json.writeStringField("branch", gitProperties.getProperty("git.branch"));
            json.writeStringField("commitTime", gitProperties.getProperty("git.commit.time"));
            json.writeStringField("buildTime", gitProperties.getProperty("git.build.time"));
        } catch (Exception ex) {
            log.warn("Error loading git.properties, possibly jar was not compiled with maven.");
        }
        json.writeEndObject();
        json.close();
        writer.write(swriter.toString());
        break;
    }
    default:
        // forward to static file server
        ctx.pipeline().addLast(staticFileHandler);
        request.retain();
        ctx.fireChannelRead(request);
        return; // don't do text response clean up
    }
    log.trace("response being sent {}", writer);
    ByteBuf textResponse = ByteBufUtil.encodeString(ctx.alloc(), CharBuffer.wrap(writer.getBuilder()),
            CharsetUtil.UTF_8);
    HttpContent content = new DefaultHttpContent(textResponse);
    response.headers().set(HttpHeaders.Names.CONTENT_LENGTH, textResponse.readableBytes());
    if (HttpHeaders.isKeepAlive(request)) {
        response.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
    }
    ctx.write(response);
    ctx.write(content);
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);
    log.trace("response pending");
    if (!HttpHeaders.isKeepAlive(request)) {
        log.trace("Setting close listener");
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    }
}

From source file:com.addthis.hydra.query.web.HttpStaticFileHandler.java

License:Apache License

@Override
public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) throws Exception {
    if (!request.getDecoderResult().isSuccess()) {
        sendError(ctx, BAD_REQUEST);/*from   w  ww . j  a  v  a  2s  .  c  o  m*/
        return;
    }
    // since we are using send file, we must remove the compression unit or it will donk out
    ChannelHandler compressor = ctx.pipeline().get("compressor");
    if (compressor != null) {
        ctx.pipeline().remove("compressor");
    }

    if (request.getMethod() != GET) {
        sendError(ctx, METHOD_NOT_ALLOWED);
        return;
    }

    QueryStringDecoder urlDecoder = new QueryStringDecoder(request.getUri());
    String target = urlDecoder.path();

    final String path = sanitizeUri(target);
    if (path == null) {
        sendError(ctx, FORBIDDEN);
        return;
    }

    Path file = Paths.get(webDir + path);
    log.trace("trying to serve static file {}", file);
    if (Files.isHidden(file) || Files.notExists(file)) {
        sendError(ctx, NOT_FOUND);
        return;
    }

    if (!Files.isRegularFile(file)) {
        sendError(ctx, FORBIDDEN);
        return;
    }

    log.trace("cache validation occuring for {}", file);
    // Cache Validation
    String ifModifiedSince = request.headers().get(IF_MODIFIED_SINCE);
    if (ifModifiedSince != null && !ifModifiedSince.isEmpty()) {
        SimpleDateFormat dateFormatter = new SimpleDateFormat(HttpUtils.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 = Files.getLastModifiedTime(file).toMillis() / 1000;
        if (ifModifiedSinceDateSeconds == fileLastModifiedSeconds) {
            sendNotModified(ctx);
            return;
        }
    }

    log.trace("sending {}", file);

    FileChannel fileChannel;
    try {
        fileChannel = FileChannel.open(file, StandardOpenOption.READ);
    } catch (IOException fnfe) {
        sendError(ctx, NOT_FOUND);
        return;
    }
    long fileLength = fileChannel.size();

    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
    setContentLength(response, fileLength);
    setContentTypeHeader(response, file);
    try {
        setDateAndCacheHeaders(response, file);
    } catch (IOException ioex) {
        fileChannel.close();
        sendError(ctx, NOT_FOUND);
        return;
    }
    if (isKeepAlive(request)) {
        response.headers().set(CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
    }

    // Write the initial line and the header.
    ctx.write(response);

    // Write the content.
    ctx.write(new DefaultFileRegion(fileChannel, 0, fileLength));

    // Write the end marker
    ChannelFuture lastContentFuture = ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT);

    // Decide whether to close the connection or not.
    if (!isKeepAlive(request)) {
        // Close the connection when the whole content is written out.
        lastContentFuture.addListener(ChannelFutureListener.CLOSE);
    } else {
        ctx.pipeline().remove(this);
        if (compressor != null) {
            ctx.pipeline().addBefore("query", "compressor", compressor);
        }
    }
}