コード例 #1
0
 @SuppressWarnings("argument.type.incompatible")
 private void sendFullResponse(
     ChannelHandlerContext ctx, FullHttpRequest request, FullHttpResponse response)
     throws Exception {
   boolean keepAlive = HttpUtil.isKeepAlive(request);
   if (httpSessionManager.getSessionId(request) != null
       && httpSessionManager.getAuthenticatedUser(request) == null
       && !response.headers().contains("Set-Cookie")) {
     httpSessionManager.deleteSessionCookie(response);
   }
   response.headers().add("Glowroot-Layout-Version", layoutService.getLayoutVersion());
   if (response.headers().contains("Glowroot-Port-Changed")) {
     // current connection is the only open channel on the old port, keepAlive=false will add
     // the listener below to close the channel after the response completes
     //
     // remove the hacky header, no need to send it back to client
     response.headers().remove("Glowroot-Port-Changed");
     response.headers().add("Connection", "close");
     keepAlive = false;
   }
   response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
   if (keepAlive && !request.protocolVersion().isKeepAliveDefault()) {
     response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
   }
   ChannelFuture f = ctx.write(response);
   if (!keepAlive) {
     f.addListener(ChannelFutureListener.CLOSE);
   }
 }
コード例 #2
0
 @Override
 public @Nullable FullHttpResponse handleRequest(ChannelHandlerContext ctx, HttpRequest request)
     throws Exception {
   QueryStringDecoder decoder = new QueryStringDecoder(request.uri());
   List<String> agentIds = decoder.parameters().get("agent-id");
   if (agentIds == null) {
     agentIds = ImmutableList.of("");
   }
   String agentId = agentIds.get(0);
   List<String> traceIds = decoder.parameters().get("trace-id");
   checkNotNull(traceIds, "Missing trace id in query string: %s", request.uri());
   String traceId = traceIds.get(0);
   // check-live-traces is an optimization so glowroot server only has to check with remote
   // agents when necessary
   List<String> checkLiveTracesParams = decoder.parameters().get("check-live-traces");
   boolean checkLiveTraces = false;
   if (checkLiveTracesParams != null && !checkLiveTracesParams.isEmpty()) {
     checkLiveTraces = Boolean.parseBoolean(checkLiveTracesParams.get(0));
   }
   logger.debug(
       "handleRequest(): agentId={}, traceId={}, checkLiveTraces={}",
       agentId,
       traceId,
       checkLiveTraces);
   TraceExport traceExport = traceCommonService.getExport(agentId, traceId, checkLiveTraces);
   if (traceExport == null) {
     logger.warn("no trace found for id: {}", traceId);
     return new DefaultFullHttpResponse(HTTP_1_1, NOT_FOUND);
   }
   ChunkedInput<HttpContent> in = getExportChunkedInput(traceExport);
   HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
   response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
   response.headers().set(HttpHeaderNames.CONTENT_TYPE, MediaType.ZIP.toString());
   response
       .headers()
       .set("Content-Disposition", "attachment; filename=" + traceExport.fileName() + ".zip");
   boolean keepAlive = HttpUtil.isKeepAlive(request);
   if (keepAlive && !request.protocolVersion().isKeepAliveDefault()) {
     response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
   }
   HttpServices.preventCaching(response);
   ctx.write(response);
   ChannelFuture future = ctx.write(in);
   HttpServices.addErrorListener(future);
   if (!keepAlive) {
     HttpServices.addCloseListener(future);
   }
   // return null to indicate streaming
   return null;
 }
コード例 #3
0
  @Override
  protected void handleOversizedMessage(final ChannelHandlerContext ctx, HttpMessage oversized)
      throws Exception {
    if (oversized instanceof HttpRequest) {
      // send back a 413 and close the connection
      ChannelFuture future =
          ctx.writeAndFlush(TOO_LARGE.duplicate().retain())
              .addListener(
                  new ChannelFutureListener() {
                    @Override
                    public void operationComplete(ChannelFuture future) throws Exception {
                      if (!future.isSuccess()) {
                        logger.debug(
                            "Failed to send a 413 Request Entity Too Large.", future.cause());
                        ctx.close();
                      }
                    }
                  });

      // If the client started to send data already, close because it's impossible to recover.
      // If keep-alive is off and 'Expect: 100-continue' is missing, no need to leave the connection
      // open.
      if (oversized instanceof FullHttpMessage
          || !HttpUtil.is100ContinueExpected(oversized) && !HttpUtil.isKeepAlive(oversized)) {
        future.addListener(ChannelFutureListener.CLOSE);
      }

      // If an oversized request was handled properly and the connection is still alive
      // (i.e. rejected 100-continue). the decoder should prepare to handle a new message.
      HttpObjectDecoder decoder = ctx.pipeline().get(HttpObjectDecoder.class);
      if (decoder != null) {
        decoder.reset();
      }
    } else if (oversized instanceof HttpResponse) {
      ctx.close();
      throw new TooLongFrameException("Response entity too large: " + oversized);
    } else {
      throw new IllegalStateException();
    }
  }
コード例 #4
0
  /** Write the response */
  private void writeResponse(ChannelHandlerContext ctx) {
    // Convert the response content to a ByteBuf.
    ByteBuf buf = Unpooled.copiedBuffer(responseContent.toString(), WaarpStringUtils.UTF8);
    responseContent.setLength(0);

    // Decide whether to close the connection or not.
    boolean keepAlive = HttpUtil.isKeepAlive(request);
    boolean close =
        HttpHeaderValues.CLOSE.contentEqualsIgnoreCase(
                request.headers().get(HttpHeaderNames.CONNECTION))
            || (!keepAlive)
            || forceClose;

    // Build the response object.
    FullHttpResponse response =
        new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, buf);
    response.headers().add(HttpHeaderNames.CONTENT_LENGTH, response.content().readableBytes());
    response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/html");
    if (keepAlive) {
      response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }
    if (!close) {
      // There's no need to add 'Content-Length' header
      // if this is the last response.
      response.headers().set(HttpHeaderNames.CONTENT_LENGTH, String.valueOf(buf.readableBytes()));
    }

    handleCookies(response);

    // Write the response.
    ChannelFuture future = ctx.writeAndFlush(response);
    // Close the connection after the write operation is done if necessary.
    if (close) {
      future.addListener(WaarpSslUtility.SSLCLOSE);
    }
    if (shutdown) {
      ChannelUtils.startShutdown();
    }
  }
コード例 #5
0
  @Override
  protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
    ChannelFuture lastWrite = null;
    boolean keepAlive = true;

    if (msg instanceof FullHttpRequest) {
      FullHttpRequest request = (FullHttpRequest) msg;
      keepAlive = HttpUtil.isKeepAlive(request);
      lastWrite = handleHttpRequest(ctx, request);
    } else if (msg instanceof WebSocketFrame) {
      lastWrite = handleWebSocketFrame(ctx, (WebSocketFrame) msg);
    }

    if (!keepAlive) {
      // Close the connection when the whole content is written out.
      if (lastWrite != null) {
        lastWrite.addListener(ChannelFutureListener.CLOSE);
      } else {
        ctx.close();
      }
    }
  }
コード例 #6
0
  @Override
  public @Nullable FullHttpResponse handleRequest(ChannelHandlerContext ctx, HttpRequest request)
      throws Exception {

    File glowrootLogFile = new File(logDir, "glowroot.log");
    CharSource glowrootLogCharSource = Files.asCharSource(glowrootLogFile, Charsets.UTF_8);

    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);
    response.headers().set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
    response.headers().set(HttpHeaderNames.CONTENT_TYPE, "text/plain; charset=UTF-8");
    boolean keepAlive = HttpUtil.isKeepAlive(request);
    if (keepAlive && !request.protocolVersion().isKeepAliveDefault()) {
      response.headers().set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }
    HttpServices.preventCaching(response);
    ctx.write(response);
    ChannelFuture future = ctx.write(ChunkedInputs.from(ChunkSource.from(glowrootLogCharSource)));
    HttpServices.addErrorListener(future);
    if (!keepAlive) {
      HttpServices.addCloseListener(future);
    }
    // return null to indicate streaming
    return null;
  }
コード例 #7
0
  protected void sendFile(
      final ChannelHandlerContext channelHandlerContext,
      FullHttpRequest fullHttpRequest,
      SyncFile syncFile)
      throws Exception {

    Path path = Paths.get(syncFile.getFilePathName());

    if (Files.notExists(path)) {
      _syncTrafficShapingHandler.decrementConnectionsCount();

      if (_logger.isTraceEnabled()) {
        Channel channel = channelHandlerContext.channel();

        _logger.trace("Client {}: file not found {}", channel.remoteAddress(), path);
      }

      _sendError(channelHandlerContext, NOT_FOUND);

      return;
    }

    if (_logger.isDebugEnabled()) {
      Channel channel = channelHandlerContext.channel();

      _logger.debug("Client {}: sending file {}", channel.remoteAddress(), path);
    }

    long modifiedTime = syncFile.getModifiedTime();
    long previousModifiedTime = syncFile.getPreviousModifiedTime();

    if (OSDetector.isApple()) {
      modifiedTime = modifiedTime / 1000 * 1000;
      previousModifiedTime = previousModifiedTime / 1000 * 1000;
    }

    FileTime currentFileTime = Files.getLastModifiedTime(path, LinkOption.NOFOLLOW_LINKS);

    long currentTime = currentFileTime.toMillis();

    if ((currentTime != modifiedTime) && (currentTime != previousModifiedTime)) {

      _syncTrafficShapingHandler.decrementConnectionsCount();

      Channel channel = channelHandlerContext.channel();

      _logger.error(
          "Client {}: file modified {}, currentTime {}, modifiedTime "
              + "{}, previousModifiedTime {}",
          channel.remoteAddress(),
          path,
          currentTime,
          modifiedTime,
          previousModifiedTime);

      _sendError(channelHandlerContext, NOT_FOUND);

      return;
    }

    HttpResponse httpResponse = new DefaultHttpResponse(HTTP_1_1, OK);

    long size = Files.size(path);

    HttpUtil.setContentLength(httpResponse, size);

    HttpHeaders httpHeaders = httpResponse.headers();

    MimetypesFileTypeMap mimetypesFileTypeMap = new MimetypesFileTypeMap();

    httpHeaders.set(
        HttpHeaderNames.CONTENT_TYPE, mimetypesFileTypeMap.getContentType(syncFile.getName()));

    if (HttpUtil.isKeepAlive(fullHttpRequest)) {
      httpHeaders.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }

    channelHandlerContext.write(httpResponse);

    SyncChunkedFile syncChunkedFile = new SyncChunkedFile(path, size, 4 * 1024 * 1024, currentTime);

    ChannelFuture channelFuture =
        channelHandlerContext.writeAndFlush(
            new HttpChunkedInput(syncChunkedFile), channelHandlerContext.newProgressivePromise());

    channelFuture.addListener(
        new ChannelFutureListener() {

          @Override
          public void operationComplete(ChannelFuture channelFuture) throws Exception {

            _syncTrafficShapingHandler.decrementConnectionsCount();

            if (channelFuture.isSuccess()) {
              return;
            }

            Throwable exception = channelFuture.cause();

            Channel channel = channelHandlerContext.channel();

            _logger.error(
                "Client {}: {}", channel.remoteAddress(), exception.getMessage(), exception);

            channelHandlerContext.close();
          }
        });

    if (!HttpUtil.isKeepAlive(fullHttpRequest)) {
      channelFuture.addListener(ChannelFutureListener.CLOSE);
    }
  }