Example #1
0
  public static void serve404(
      NotFound e, ChannelHandlerContext ctx, Request request, HttpRequest nettyRequest) {
    Logger.trace("serve404: begin");
    HttpResponse nettyResponse =
        new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.NOT_FOUND);
    nettyResponse.setHeader(SERVER, signature);

    nettyResponse.setHeader(CONTENT_TYPE, "text/html");
    Map<String, Object> binding = getBindingForErrors(e, false);

    String format = Request.current().format;
    if (format == null) {
      format = "txt";
    }
    nettyResponse.setHeader(
        CONTENT_TYPE, (MimeTypes.getContentType("404." + format, "text/plain")));

    String errorHtml = TemplateLoader.load("errors/404." + format).render(binding);
    try {
      ChannelBuffer buf = ChannelBuffers.copiedBuffer(errorHtml.getBytes("utf-8"));
      nettyResponse.setContent(buf);
      ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse);
      writeFuture.addListener(ChannelFutureListener.CLOSE);
    } catch (UnsupportedEncodingException fex) {
      Logger.error(fex, "(utf-8 ?)");
    }
    Logger.trace("serve404: end");
  }
Example #2
0
  protected static void writeResponse(
      ChannelHandlerContext ctx,
      Response response,
      HttpResponse nettyResponse,
      HttpRequest nettyRequest) {
    Logger.trace("writeResponse: begin");
    byte[] content = null;

    final boolean keepAlive = isKeepAlive(nettyRequest);
    if (nettyRequest.getMethod().equals(HttpMethod.HEAD)) {
      content = new byte[0];
    } else {
      content = response.out.toByteArray();
    }

    ChannelBuffer buf = ChannelBuffers.copiedBuffer(content);
    nettyResponse.setContent(buf);

    if (keepAlive) {
      // Add 'Content-Length' header only for a keep-alive connection.
      Logger.trace("writeResponse: content length [" + response.out.size() + "]");
      setContentLength(nettyResponse, response.out.size());
    }

    ChannelFuture f = ctx.getChannel().write(nettyResponse);

    // Decide whether to close the connection or not.
    if (!keepAlive) {
      // Close the connection when the whole content is written out.
      f.addListener(ChannelFutureListener.CLOSE);
    }
    Logger.trace("writeResponse: end");
  }
Example #3
0
  public void serveStatic(
      RenderStatic renderStatic,
      ChannelHandlerContext ctx,
      Request request,
      Response response,
      HttpRequest nettyRequest,
      MessageEvent e) {
    Logger.trace("serveStatic: begin");
    HttpResponse nettyResponse =
        new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(response.status));
    if (exposePlayServer) {
      nettyResponse.setHeader(SERVER, signature);
    }
    try {
      VirtualFile file = Play.getVirtualFile(renderStatic.file);
      if (file != null && file.exists() && file.isDirectory()) {
        file = file.child("index.html");
        if (file != null) {
          renderStatic.file = file.relativePath();
        }
      }
      if ((file == null || !file.exists())) {
        serve404(
            new NotFound("The file " + renderStatic.file + " does not exist"),
            ctx,
            request,
            nettyRequest);
      } else {
        boolean raw = false;
        for (PlayPlugin plugin : Play.plugins) {
          if (plugin.serveStatic(file, Request.current(), Response.current())) {
            raw = true;
            break;
          }
        }
        if (raw) {
          copyResponse(ctx, request, response, nettyRequest);
        } else {
          final File localFile = file.getRealFile();
          final boolean keepAlive = isKeepAlive(nettyRequest);
          nettyResponse = addEtag(nettyRequest, nettyResponse, localFile);

          if (nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) {

            Channel ch = e.getChannel();

            // Write the initial line and the header.
            ChannelFuture writeFuture = ch.write(nettyResponse);
            if (!keepAlive) {
              // Write the content.
              writeFuture.addListener(ChannelFutureListener.CLOSE);
            }
          } else {

            final RandomAccessFile raf = new RandomAccessFile(localFile, "r");
            try {
              long fileLength = raf.length();

              Logger.trace("keep alive " + keepAlive);
              Logger.trace(
                  "content type " + (MimeTypes.getContentType(localFile.getName(), "text/plain")));

              if (keepAlive && !nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) {
                // Add 'Content-Length' header only for a keep-alive connection.
                Logger.trace("file length " + fileLength);
                setContentLength(nettyResponse, fileLength);
              }

              nettyResponse.setHeader(
                  CONTENT_TYPE, (MimeTypes.getContentType(localFile.getName(), "text/plain")));

              Channel ch = e.getChannel();

              // Write the initial line and the header.
              ChannelFuture writeFuture = ch.write(nettyResponse);

              // Write the content.
              if (!nettyRequest.getMethod().equals(HttpMethod.HEAD)) {
                writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192));
              } else {
                raf.close();
              }

              if (!keepAlive) {
                // Close the connection when the whole content is written out.
                writeFuture.addListener(ChannelFutureListener.CLOSE);
              }
            } catch (Throwable exx) {
              try {
                raf.close();
              } catch (Throwable ex) {
                /* Left empty */
              }
              try {
                ctx.getChannel().close();
              } catch (Throwable ex) {
                /* Left empty */
              }
            }
          }
        }
      }
    } catch (Throwable ez) {
      Logger.error(ez, "serveStatic for request %s", request.method + " " + request.url);
      try {
        HttpResponse errorResponse =
            new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
        ChannelBuffer buf =
            ChannelBuffers.copiedBuffer("Internal Error (check logs)".getBytes("utf-8"));
        errorResponse.setContent(buf);
        ChannelFuture future = ctx.getChannel().write(errorResponse);
        future.addListener(ChannelFutureListener.CLOSE);
      } catch (Exception ex) {
        Logger.error(ez, "serveStatic for request %s", request.method + " " + request.url);
      }
    }
    Logger.trace("serveStatic: end");
  }
Example #4
0
  // TODO: add request and response as parameter
  public static void serve500(Exception e, ChannelHandlerContext ctx, HttpRequest nettyRequest) {
    Logger.trace("serve500: begin");
    HttpResponse nettyResponse =
        new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.INTERNAL_SERVER_ERROR);
    if (exposePlayServer) {
      nettyResponse.setHeader(SERVER, signature);
    }

    Request request = Request.current();
    Response response = Response.current();

    try {
      if (!(e instanceof PlayException)) {
        e = new play.exceptions.UnexpectedException(e);
      }

      // Flush some cookies
      try {

        Map<String, Http.Cookie> cookies = response.cookies;
        for (Http.Cookie cookie : cookies.values()) {
          CookieEncoder encoder = new CookieEncoder(true);
          Cookie c = new DefaultCookie(cookie.name, cookie.value);
          c.setSecure(cookie.secure);
          c.setPath(cookie.path);
          if (cookie.domain != null) {
            c.setDomain(cookie.domain);
          }
          if (cookie.maxAge != null) {
            c.setMaxAge(cookie.maxAge);
          }
          c.setHttpOnly(cookie.httpOnly);
          encoder.addCookie(c);
          nettyResponse.addHeader(SET_COOKIE, encoder.encode());
        }

      } catch (Exception exx) {
        Logger.error(e, "Trying to flush cookies");
        // humm ?
      }
      Map<String, Object> binding = getBindingForErrors(e, true);

      String format = request.format;
      if (format == null) {
        format = "txt";
      }

      nettyResponse.setHeader(
          "Content-Type", (MimeTypes.getContentType("500." + format, "text/plain")));
      try {
        String errorHtml = TemplateLoader.load("errors/500." + format).render(binding);

        ChannelBuffer buf = ChannelBuffers.copiedBuffer(errorHtml.getBytes("utf-8"));
        nettyResponse.setContent(buf);
        ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse);
        writeFuture.addListener(ChannelFutureListener.CLOSE);
        Logger.error(
            e, "Internal Server Error (500) for request %s", request.method + " " + request.url);
      } catch (Throwable ex) {
        Logger.error(
            e, "Internal Server Error (500) for request %s", request.method + " " + request.url);
        Logger.error(ex, "Error during the 500 response generation");
        try {
          ChannelBuffer buf =
              ChannelBuffers.copiedBuffer("Internal Error (check logs)".getBytes("utf-8"));
          nettyResponse.setContent(buf);
          ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse);
          writeFuture.addListener(ChannelFutureListener.CLOSE);
        } catch (UnsupportedEncodingException fex) {
          Logger.error(fex, "(utf-8 ?)");
        }
      }
    } catch (Throwable exxx) {
      try {
        ChannelBuffer buf =
            ChannelBuffers.copiedBuffer("Internal Error (check logs)".getBytes("utf-8"));
        nettyResponse.setContent(buf);
        ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse);
        writeFuture.addListener(ChannelFutureListener.CLOSE);
      } catch (Exception fex) {
        Logger.error(fex, "(utf-8 ?)");
      }
      if (exxx instanceof RuntimeException) {
        throw (RuntimeException) exxx;
      }
      throw new RuntimeException(exxx);
    }
    Logger.trace("serve500: end");
  }
Example #5
0
  public void copyResponse(
      ChannelHandlerContext ctx, Request request, Response response, HttpRequest nettyRequest)
      throws Exception {
    Logger.trace("copyResponse: begin");
    // response.out.flush();

    // Decide whether to close the connection or not.

    HttpResponse nettyResponse =
        new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.valueOf(response.status));
    if (exposePlayServer) {
      nettyResponse.setHeader(SERVER, signature);
    }

    if (response.contentType != null) {
      nettyResponse.setHeader(
          CONTENT_TYPE,
          response.contentType
              + (response.contentType.startsWith("text/")
                      && !response.contentType.contains("charset")
                  ? "; charset=utf-8"
                  : ""));
    } else {
      nettyResponse.setHeader(CONTENT_TYPE, "text/plain; charset=utf-8");
    }

    addToResponse(response, nettyResponse);

    final Object obj = response.direct;
    File file = null;
    ChunkedInput stream = null;
    InputStream is = null;
    if (obj instanceof File) {
      file = (File) obj;
    } else if (obj instanceof InputStream) {
      is = (InputStream) obj;
    } else if (obj instanceof ChunkedInput) {
      stream = (ChunkedInput) obj;
    }

    final boolean keepAlive = isKeepAlive(nettyRequest);
    if (file != null && file.isFile()) {
      try {
        nettyResponse = addEtag(nettyRequest, nettyResponse, file);
        if (nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) {

          Channel ch = ctx.getChannel();

          // Write the initial line and the header.
          ChannelFuture writeFuture = ch.write(nettyResponse);

          if (!keepAlive) {
            // Close the connection when the whole content is written out.
            writeFuture.addListener(ChannelFutureListener.CLOSE);
          }
        } else {
          nettyResponse.setHeader(
              CONTENT_TYPE, MimeTypes.getContentType(file.getName(), "text/plain"));
          final RandomAccessFile raf = new RandomAccessFile(file, "r");
          try {
            long fileLength = raf.length();

            if (keepAlive) {
              // Add 'Content-Length' header only for a keep-alive connection.
              Logger.trace("file length is [" + fileLength + "]");
              setContentLength(nettyResponse, fileLength);
            }

            Channel ch = ctx.getChannel();

            // Write the initial line and the header.
            ChannelFuture writeFuture = ch.write(nettyResponse);

            // Write the content.
            // If it is not a HEAD
            if (!nettyRequest.getMethod().equals(HttpMethod.HEAD)) {
              writeFuture = ch.write(new ChunkedFile(raf, 0, fileLength, 8192));
            } else {
              raf.close();
            }
            if (!keepAlive) {
              // Close the connection when the whole content is written out.
              writeFuture.addListener(ChannelFutureListener.CLOSE);
            }
          } catch (Throwable exx) {
            try {
              raf.close();
            } catch (Throwable ex) {
              /* Left empty */
            }
            try {
              ctx.getChannel().close();
            } catch (Throwable ex) {
              /* Left empty */
            }
          }
        }
      } catch (Exception e) {
        throw e;
      }
    } else if (is != null) {
      ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse);
      if (!nettyRequest.getMethod().equals(HttpMethod.HEAD)
          && !nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) {
        writeFuture = ctx.getChannel().write(new ChunkedStream(is));
      } else {
        is.close();
      }
      if (!keepAlive) {
        writeFuture.addListener(ChannelFutureListener.CLOSE);
      }
    } else if (stream != null) {
      ChannelFuture writeFuture = ctx.getChannel().write(nettyResponse);
      if (!nettyRequest.getMethod().equals(HttpMethod.HEAD)
          && !nettyResponse.getStatus().equals(HttpResponseStatus.NOT_MODIFIED)) {
        writeFuture = ctx.getChannel().write(stream);
      } else {
        stream.close();
      }
      if (!keepAlive) {
        writeFuture.addListener(ChannelFutureListener.CLOSE);
      }
    } else {
      writeResponse(ctx, response, nettyResponse, nettyRequest);
    }
    Logger.trace("copyResponse: end");
  }