예제 #1
0
 @Override
 public int hashCode() {
   int result = 1;
   result = HASH_CODE_PRIME * result + status.hashCode();
   result = HASH_CODE_PRIME * result + super.hashCode();
   return result;
 }
  private void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, status);
    response.setHeader(CONTENT_TYPE, "text/plain; charset=UTF-8");
    response.setContent(
        ChannelBuffers.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));

    // Close the connection as soon as the error message is sent.
    ctx.getChannel().write(response).addListener(ChannelFutureListener.CLOSE);
  }
예제 #3
0
  private static void sendError(ChannelHandlerContext ctx, HttpResponseStatus status) {
    FullHttpResponse response =
        new DefaultFullHttpResponse(
            HttpVersion.HTTP_1_1,
            status,
            Unpooled.copiedBuffer("Failure: " + status.toString() + "\r\n", CharsetUtil.UTF_8));
    response.headers().set(HttpHeaderConstants.CONTENT_TYPE, "text/plain; charset=UTF-8");

    // Close the connection as soon as the error message is sent.
    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
  }
예제 #4
0
  @Override
  public void failover(FullHttpRequest request, FullHttpResponse response) {
    Response dumpedResponse = failoverResponse(request);
    response.setProtocolVersion(HttpVersion.valueOf(dumpedResponse.getVersion()));
    response.setStatus(HttpResponseStatus.valueOf(dumpedResponse.getStatusCode()));
    for (Map.Entry<String, String> entry : dumpedResponse.getHeaders().entrySet()) {
      response.headers().add(entry.getKey(), entry.getValue());
    }

    response.content().writeBytes(dumpedResponse.getContent().getBytes());
  }
  private static void parseHeaders(@NotNull HttpResponse response, @NotNull ByteBuf buffer) {
    StringBuilder builder = new StringBuilder();
    while (buffer.isReadable()) {
      builder.setLength(0);

      String key = null;
      boolean valueExpected = true;
      while (true) {
        int b = buffer.readByte();
        if (b < 0 || b == '\n') {
          break;
        }

        if (b != '\r') {
          if (valueExpected && b == ':') {
            valueExpected = false;

            key = builder.toString();
            builder.setLength(0);
            MessageDecoder.skipWhitespace(buffer);
          } else {
            builder.append((char) b);
          }
        }
      }

      if (builder.length() == 0) {
        // end of headers
        return;
      }

      // skip standard headers
      if (StringUtil.isEmpty(key)
          || StringUtilRt.startsWithIgnoreCase(key, "http")
          || StringUtilRt.startsWithIgnoreCase(key, "X-Accel-")) {
        continue;
      }

      String value = builder.toString();
      if (key.equalsIgnoreCase("status")) {
        int index = value.indexOf(' ');
        if (index == -1) {
          LOG.warn("Cannot parse status: " + value);
          response.setStatus(HttpResponseStatus.OK);
        } else {
          response.setStatus(
              HttpResponseStatus.valueOf(Integer.parseInt(value.substring(0, index))));
        }
      } else if (!(key.startsWith("http") || key.startsWith("HTTP"))) {
        response.headers().add(key, value);
      }
    }
  }
 @Override
 protected void encode(ChannelHandlerContext ctx, HttpResponse response, List<Object> out) {
   DefaultFullHttpResponse defaultFullHttpResponse =
       new DefaultFullHttpResponse(
           HttpVersion.HTTP_1_1,
           HttpResponseStatus.valueOf(
               (response.getStatusCode() != null ? response.getStatusCode() : 200)),
           getBody(response));
   setHeaders(response, defaultFullHttpResponse);
   setCookies(response, defaultFullHttpResponse);
   out.add(defaultFullHttpResponse);
 }
예제 #7
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");
  }
예제 #8
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");
  }
예제 #9
0
    @Override
    public final boolean trySend(HttpResponse message) {
      try {
        final HttpRequestWrapper nettyRequest = (HttpRequestWrapper) message.getRequest();
        final FullHttpRequest req = nettyRequest.req;
        final ChannelHandlerContext ctx = nettyRequest.ctx;

        final HttpResponseStatus status = HttpResponseStatus.valueOf(message.getStatus());

        if (message.getStatus() >= 400 && message.getStatus() < 600) {
          sendHttpResponse(
              ctx, req, new DefaultFullHttpResponse(req.getProtocolVersion(), status), false);
          close();
          return true;
        }

        if (message.getRedirectPath() != null) {
          sendHttpRedirect(ctx, req, message.getRedirectPath());
          close();
          return true;
        }

        FullHttpResponse res;
        if (message.getStringBody() != null)
          res =
              new DefaultFullHttpResponse(
                  req.getProtocolVersion(),
                  status,
                  Unpooled.wrappedBuffer(message.getStringBody().getBytes()));
        else if (message.getByteBufferBody() != null)
          res =
              new DefaultFullHttpResponse(
                  req.getProtocolVersion(),
                  status,
                  Unpooled.wrappedBuffer(message.getByteBufferBody()));
        else res = new DefaultFullHttpResponse(req.getProtocolVersion(), status);

        if (message.getCookies() != null) {
          final ServerCookieEncoder enc = ServerCookieEncoder.STRICT;
          for (final Cookie c : message.getCookies())
            HttpHeaders.setHeader(res, COOKIE, enc.encode(getNettyCookie(c)));
        }
        if (message.getHeaders() != null) {
          for (final Map.Entry<String, String> h : message.getHeaders().entries())
            HttpHeaders.setHeader(res, h.getKey(), h.getValue());
        }

        if (message.getContentType() != null) {
          String ct = message.getContentType();
          if (message.getCharacterEncoding() != null)
            ct = ct + "; charset=" + message.getCharacterEncoding().name();
          HttpHeaders.setHeader(res, CONTENT_TYPE, ct);
        }

        final boolean sseStarted = message.shouldStartActor();
        if (trackSession(sseStarted)) {
          final String sessionId = UUID.randomUUID().toString();
          res.headers()
              .add(SET_COOKIE, ServerCookieEncoder.STRICT.encode(SESSION_COOKIE_KEY, sessionId));
          startSession(sessionId, actorContext);
        }
        if (!sseStarted) {
          final String stringBody = message.getStringBody();
          long contentLength = 0L;
          if (stringBody != null) contentLength = stringBody.getBytes().length;
          else {
            final ByteBuffer byteBufferBody = message.getByteBufferBody();
            if (byteBufferBody != null) contentLength = byteBufferBody.remaining();
          }
          res.headers().add(CONTENT_LENGTH, contentLength);
        }

        final HttpStreamActorAdapter httpStreamActorAdapter;
        if (sseStarted)
          // This will copy the request content, which must still be referenceable, doing before the
          // request handler
          // unallocates it (unfortunately it is explicitly reference-counted in Netty)
          httpStreamActorAdapter = new HttpStreamActorAdapter(ctx, req);
        else httpStreamActorAdapter = null;

        sendHttpResponse(ctx, req, res, false);

        if (sseStarted) {
          if (httpResponseEncoderName != null) {
            ctx.pipeline().remove(httpResponseEncoderName);
          } else {
            final ChannelPipeline pl = ctx.pipeline();
            final List<String> handlerKeysToBeRemoved = new ArrayList<>();
            for (final Map.Entry<String, ChannelHandler> e : pl) {
              if (e.getValue() instanceof HttpResponseEncoder)
                handlerKeysToBeRemoved.add(e.getKey());
            }
            for (final String k : handlerKeysToBeRemoved) pl.remove(k);
          }

          try {
            message.getFrom().send(new HttpStreamOpened(httpStreamActorAdapter.ref(), message));
          } catch (SuspendExecution e) {
            throw new AssertionError(e);
          }
        }

        return true;
      } finally {
        if (actor != null) actor.unwatch();
      }
    }