@Override
  public void messageReceived(ChannelInboundHandlerContext<Object> ctx, Object msg)
      throws Exception {
    Channel ch = ctx.channel();
    if (!handshaker.isHandshakeComplete()) {
      handshaker.finishHandshake(ch, (HttpResponse) msg);
      System.out.println("WebSocket Client connected!");
      return;
    }

    if (msg instanceof HttpResponse) {
      HttpResponse response = (HttpResponse) msg;
      throw new Exception(
          "Unexpected HttpResponse (status="
              + response.getStatus()
              + ", content="
              + response.getContent().toString(CharsetUtil.UTF_8)
              + ")");
    }

    WebSocketFrame frame = (WebSocketFrame) msg;
    if (frame instanceof TextWebSocketFrame) {
      TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
      System.out.println("WebSocket Client received message: " + textFrame.getText());
    } else if (frame instanceof PongWebSocketFrame) {
      System.out.println("WebSocket Client received pong");
    } else if (frame instanceof CloseWebSocketFrame) {
      System.out.println("WebSocket Client received closing");
      ch.close();
    }
  }
Exemple #2
0
  @SuppressWarnings("deprecation")
  private SpdySynReplyFrame createSynReplyFrame(HttpResponse httpResponse) throws Exception {
    // Get the Stream-ID from the headers
    final HttpHeaders httpHeaders = httpResponse.headers();
    int streamID = httpHeaders.getInt(Names.STREAM_ID);
    httpHeaders.remove(Names.STREAM_ID);

    // The Connection, Keep-Alive, Proxy-Connection, and Transfer-Encoding
    // headers are not valid and MUST not be sent.
    httpHeaders.remove(HttpHeaders.Names.CONNECTION);
    httpHeaders.remove(HttpHeaders.Names.KEEP_ALIVE);
    httpHeaders.remove(HttpHeaders.Names.PROXY_CONNECTION);
    httpHeaders.remove(HttpHeaders.Names.TRANSFER_ENCODING);

    SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);
    SpdyHeaders frameHeaders = spdySynReplyFrame.headers();
    // Unfold the first line of the response into name/value pairs
    frameHeaders.set(STATUS, httpResponse.status());
    frameHeaders.set(VERSION, httpResponse.protocolVersion());

    // Transfer the remaining HTTP headers
    for (Map.Entry<String, String> entry : httpHeaders) {
      spdySynReplyFrame.headers().add(entry.getKey(), entry.getValue());
    }

    currentStreamId = streamID;
    spdySynReplyFrame.setLast(isLast(httpResponse));

    return spdySynReplyFrame;
  }
  public static String extractCookie(HttpResponse response) {
    if (response.containsHeader(HttpHeaders.Names.SET_COOKIE)) {
      return response.getHeader(HttpHeaders.Names.SET_COOKIE);
    }

    return null;
  }
  @Override
  public void sendError(int status, String message) throws IOException {
    if (committed) {
      throw new IllegalStateException();
    }

    final HttpResponseStatus responseStatus;
    if (message != null) {
      responseStatus = new HttpResponseStatus(status, message);
      setStatus(status);
    } else {
      responseStatus = HttpResponseStatus.valueOf(status);
      setStatus(status);
    }
    io.netty.handler.codec.http.HttpResponse response = null;
    if (message != null) {
      ByteBuf byteBuf = ctx.alloc().buffer();
      byteBuf.writeBytes(message.getBytes());

      response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseStatus, byteBuf);
    } else {
      response = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, responseStatus);
    }
    if (keepAlive) {
      // Add keep alive and content length if needed
      response.headers().add(Names.CONNECTION, Values.KEEP_ALIVE);
      if (message == null) response.headers().add(Names.CONTENT_LENGTH, 0);
      else response.headers().add(Names.CONTENT_LENGTH, message.getBytes().length);
    }
    ctx.writeAndFlush(response);
    committed = true;
  }
  @Test
  public void testCompatibleExtensionTogetherSuccess() {
    // initialize
    expect(mainHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("main")))
        .andReturn(mainExtensionMock)
        .anyTimes();
    expect(mainHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("fallback")))
        .andReturn(null)
        .anyTimes();
    replay(mainHandshakerMock);

    expect(fallbackHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("fallback")))
        .andReturn(fallbackExtensionMock)
        .anyTimes();
    expect(fallbackHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("main")))
        .andReturn(null)
        .anyTimes();
    replay(fallbackHandshakerMock);

    expect(mainExtensionMock.rsv()).andReturn(WebSocketExtension.RSV1).anyTimes();
    expect(mainExtensionMock.newReponseData())
        .andReturn(new WebSocketExtensionData("main", Collections.<String, String>emptyMap()))
        .once();
    expect(mainExtensionMock.newExtensionEncoder()).andReturn(new DummyEncoder()).once();
    expect(mainExtensionMock.newExtensionDecoder()).andReturn(new DummyDecoder()).once();
    replay(mainExtensionMock);

    expect(fallbackExtensionMock.rsv()).andReturn(WebSocketExtension.RSV2).anyTimes();
    expect(fallbackExtensionMock.newReponseData())
        .andReturn(new WebSocketExtensionData("fallback", Collections.<String, String>emptyMap()))
        .once();
    expect(fallbackExtensionMock.newExtensionEncoder()).andReturn(new Dummy2Encoder()).once();
    expect(fallbackExtensionMock.newExtensionDecoder()).andReturn(new Dummy2Decoder()).once();
    replay(fallbackExtensionMock);

    // execute
    EmbeddedChannel ch =
        new EmbeddedChannel(
            new WebSocketServerExtensionHandler(mainHandshakerMock, fallbackHandshakerMock));

    HttpRequest req = newUpgradeRequest("main, fallback");
    ch.writeInbound(req);

    HttpResponse res = newUpgradeResponse(null);
    ch.writeOutbound(res);

    HttpResponse res2 = ch.readOutbound();
    List<WebSocketExtensionData> resExts =
        WebSocketExtensionUtil.extractExtensions(
            res2.headers().getAndConvert(HttpHeaderNames.SEC_WEBSOCKET_EXTENSIONS));

    // test
    assertEquals(2, resExts.size());
    assertEquals("main", resExts.get(0).name());
    assertEquals("fallback", resExts.get(1).name());
    assertNotNull(ch.pipeline().get(DummyDecoder.class));
    assertNotNull(ch.pipeline().get(DummyEncoder.class));
    assertNotNull(ch.pipeline().get(Dummy2Decoder.class));
    assertNotNull(ch.pipeline().get(Dummy2Encoder.class));
  }
  private boolean handleResponseAndExit(
      final Channel channel,
      final NettyResponseFuture<?> future,
      AsyncHandler<?> handler,
      HttpRequest httpRequest,
      ProxyServer proxyServer,
      HttpResponse response)
      throws Exception {

    // store the original headers so we can re-send all them to
    // the handler in case of trailing headers
    future.setHttpHeaders(response.headers());

    future.setKeepAlive(
        !HttpHeaders.Values.CLOSE.equalsIgnoreCase(
            response.headers().get(HttpHeaders.Names.CONNECTION)));

    HttpResponseStatus status = new ResponseStatus(future.getURI(), response, config);
    int statusCode = response.getStatus().code();
    Request request = future.getRequest();
    Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm();
    HttpResponseHeaders responseHeaders = new ResponseHeaders(future.getURI(), response.headers());

    return handleResponseFiltersReplayRequestAndExit(channel, future, status, responseHeaders) //
        || handleUnauthorizedAndExit(
            statusCode, realm, request, response, future, proxyServer, channel) //
        || handleContinueAndExit(channel, future, statusCode) //
        || handleProxyAuthenticationRequiredAndExit(
            statusCode, realm, request, response, future, proxyServer)
        || handleConnectOKAndExit(
            statusCode, realm, request, httpRequest, response, future, proxyServer, channel) //
        || handleRedirectAndExit(request, future, response, channel) //
        || handleHanderAndExit(channel, future, handler, status, responseHeaders, response);
  }
  @Test
  public void testNoneExtensionMatchingSuccess() {
    // initialize
    expect(mainHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("unknown")))
        .andReturn(null)
        .anyTimes();
    expect(mainHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("unknown2")))
        .andReturn(null)
        .anyTimes();
    replay(mainHandshakerMock);

    expect(fallbackHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("unknown")))
        .andReturn(null)
        .anyTimes();
    expect(fallbackHandshakerMock.handshakeExtension(webSocketExtensionDataEqual("unknown2")))
        .andReturn(null)
        .anyTimes();
    replay(fallbackHandshakerMock);

    // execute
    EmbeddedChannel ch =
        new EmbeddedChannel(
            new WebSocketServerExtensionHandler(mainHandshakerMock, fallbackHandshakerMock));

    HttpRequest req = newUpgradeRequest("unknown, unknown2");
    ch.writeInbound(req);

    HttpResponse res = newUpgradeResponse(null);
    ch.writeOutbound(res);

    HttpResponse res2 = ch.readOutbound();

    // test
    assertFalse(res2.headers().contains(HttpHeaderNames.SEC_WEBSOCKET_EXTENSIONS));
  }
  @Override
  public void fatalError(String message, String stack) {
    if (log.isDebugEnabled()) {
      log.debug("Sending HTTP error due to script error {}", message);
    }

    StringBuilder msg = new StringBuilder(message);
    if (stack != null) {
      msg.append('\n');
      msg.append(stack);
    }
    ByteBuf data = Unpooled.copiedBuffer(msg, Charsets.UTF8);

    response.setStatus(HttpResponseStatus.INTERNAL_SERVER_ERROR);
    response.headers().add("Content-Type", "text/plain");
    response.headers().add("Content-Length", data.readableBytes());
    calculateKeepAlive(true);
    channel.write(response);

    DefaultHttpContent chunk = new DefaultHttpContent(data);
    channel.write(chunk);

    sendLastChunk();
    channel.flush();
    if (!keepAlive) {
      shutDown();
    }
  }
    public HttpResponse clientToProxyRequest(HttpObject httpObject) {
      if (httpObject instanceof DefaultHttpRequest) {

        DefaultHttpRequest fullreq = (DefaultHttpRequest) httpObject;
        Content c = null;
        // only return if content exist & at least one quality is
        // available
        if ((c = content.get(fullreq.getUri())) != null && c.getQualities().size() > 0) {

          LOGGER.debug("Cached resource found {}", c.getUri());

          HttpResponse response =
              new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.TEMPORARY_REDIRECT);
          Collections.shuffle(c.getQualities());

          String redirectUri =
              UriBuilder.fromPath(
                      "http://" + config.getFrontalHostName() + ":" + config.getFrontalPort())
                  .path("api")
                  .path("content")
                  .path(c.getId())
                  .path(c.getQualities().get(0))
                  .build()
                  .toString();
          response.headers().add("Location", redirectUri);
          LOGGER.debug("Redirecting it to ", redirectUri);
          return response;
        }
      }
      return null;
    }
 @Override
 public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
   logger.debug("================进入客户端InBoundHandler channelRead============");
   // 如果是response
   if (msg instanceof HttpResponse) {
     HttpResponse response = (HttpResponse) msg;
     logger.debug(
         "客户端收到的响应CONTENT_TYPE:" + response.headers().get(HttpHeaders.Names.CONTENT_TYPE));
     if (HttpHeaders.isContentLengthSet(response)) {
       reader = new ByteBufToBytes((int) HttpHeaders.getContentLength(response));
     }
   }
   if (msg instanceof HttpContent) {
     HttpContent httpContent = (HttpContent) msg;
     ByteBuf content = httpContent.content();
     reader.reading(content);
     content.release();
     if (reader.isEnd()) {
       String resultStr = new String(reader.readFull());
       logger.debug("收到的服务端的消息是:" + resultStr);
       ctx.close();
     }
   }
   logger.debug("================出客户端InBoundHandler channelRead============");
 }
Exemple #11
0
  @Override
  public Object encode(ChannelHandlerContext ctx, Object msg) throws Exception {

    List<Object> out = new ArrayList<Object>();
    if (msg instanceof HttpRequest) {

      HttpRequest httpRequest = (HttpRequest) msg;
      SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpRequest);
      int streamID = spdySynStreamFrame.getStreamID();
      out.add(spdySynStreamFrame);
      addContent(out, streamID, httpRequest);

    } else if (msg instanceof HttpResponse) {

      HttpResponse httpResponse = (HttpResponse) msg;
      if (httpResponse.containsHeader(SpdyHttpHeaders.Names.ASSOCIATED_TO_STREAM_ID)) {
        SpdySynStreamFrame spdySynStreamFrame = createSynStreamFrame(httpResponse);
        int streamID = spdySynStreamFrame.getStreamID();
        out.add(spdySynStreamFrame);
        addContent(out, streamID, httpResponse);
      } else {
        SpdySynReplyFrame spdySynReplyFrame = createSynReplyFrame(httpResponse);
        int streamID = spdySynReplyFrame.getStreamID();
        out.add(spdySynReplyFrame);
        addContent(out, streamID, httpResponse);
      }

    } else if (msg instanceof HttpChunk) {

      HttpChunk chunk = (HttpChunk) msg;
      SpdyDataFrame spdyDataFrame = new DefaultSpdyDataFrame(currentStreamID);
      spdyDataFrame.setData(chunk.getContent());
      spdyDataFrame.setLast(chunk.isLast());

      if (chunk instanceof HttpChunkTrailer) {
        HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
        List<Map.Entry<String, String>> trailers = trailer.getHeaders();
        if (trailers.isEmpty()) {
          out.add(spdyDataFrame);
        } else {
          // Create SPDY HEADERS frame out of trailers
          SpdyHeadersFrame spdyHeadersFrame = new DefaultSpdyHeadersFrame(currentStreamID);
          for (Map.Entry<String, String> entry : trailers) {
            spdyHeadersFrame.addHeader(entry.getKey(), entry.getValue());
          }

          // Write HEADERS frame and append Data Frame
          out.add(spdyHeadersFrame);
          out.add(spdyDataFrame);
        }
      } else {
        out.add(spdyDataFrame);
      }
    } else {
      throw new UnsupportedMessageTypeException(msg);
    }

    return out.toArray();
  }
 HttpClientResponseImpl(
     HttpClientRequestImpl request, ClientConnection conn, HttpResponse response) {
   this.statusCode = response.getStatus().code();
   this.statusMessage = response.getStatus().reasonPhrase();
   this.request = request;
   this.conn = conn;
   this.response = response;
 }
 public static HttpResponse createRejection(HttpRequest request, String reason) {
   HttpVersion version = request != null ? request.getProtocolVersion() : HttpVersion.HTTP_1_1;
   HttpResponse response = new DefaultHttpResponse(version, HttpResponseStatus.BAD_REQUEST);
   response.setHeader(HttpHeaders.Names.CONTENT_TYPE, "text/plain; charset=\"utf-8\"");
   ChannelBuffer reasonBuffer = ChannelBuffers.wrappedBuffer(toBytes(reason));
   response.setHeader(
       HttpHeaders.Names.CONTENT_LENGTH, Integer.toString(reasonBuffer.readableBytes()));
   response.setContent(reasonBuffer);
   return response;
 }
Exemple #14
0
  private SpdySynReplyFrame createSynReplyFrame(HttpResponse httpResponse) throws Exception {
    boolean chunked = httpResponse.isChunked();

    // Get the Stream-ID from the headers
    int streamID = SpdyHttpHeaders.getStreamID(httpResponse);
    SpdyHttpHeaders.removeStreamID(httpResponse);

    // The Connection, Keep-Alive, Proxy-Connection, and Transfer-ENcoding
    // headers are not valid and MUST not be sent.
    httpResponse.removeHeader(HttpHeaders.Names.CONNECTION);
    httpResponse.removeHeader("Keep-Alive");
    httpResponse.removeHeader("Proxy-Connection");
    httpResponse.removeHeader(HttpHeaders.Names.TRANSFER_ENCODING);

    SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);

    // Unfold the first line of the response into name/value pairs
    SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, httpResponse.getStatus());
    SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, httpResponse.getProtocolVersion());

    // Transfer the remaining HTTP headers
    for (Map.Entry<String, String> entry : httpResponse.getHeaders()) {
      spdySynReplyFrame.addHeader(entry.getKey(), entry.getValue());
    }

    if (chunked) {
      currentStreamID = streamID;
      spdySynReplyFrame.setLast(false);
    } else {
      spdySynReplyFrame.setLast(httpResponse.getContent().readableBytes() == 0);
    }

    return spdySynReplyFrame;
  }
 /**
  * Verifies that a request returns the right response code once the blob has been deleted.
  *
  * @param httpRequest the {@link FullHttpRequest} to send to the server.
  * @param expectedStatusCode the expected {@link HttpResponseStatus}.
  * @throws ExecutionException
  * @throws InterruptedException
  */
 private void verifyDeleted(FullHttpRequest httpRequest, HttpResponseStatus expectedStatusCode)
     throws ExecutionException, InterruptedException {
   Queue<HttpObject> responseParts = nettyClient.sendRequest(httpRequest, null, null).get();
   HttpResponse response = (HttpResponse) responseParts.poll();
   assertEquals("Unexpected response status", expectedStatusCode, response.getStatus());
   assertTrue(
       "No Date header",
       HttpHeaders.getDateHeader(response, HttpHeaders.Names.DATE, null) != null);
   discardContent(responseParts, 1);
   assertTrue("Channel should be active", HttpHeaders.isKeepAlive(response));
 }
  public static boolean hasContents(HttpResponse response, byte[] expectedContents) {
    if (response.getContent() != null
        && HttpHeaders.getContentLength(response, 0) == expectedContents.length
        && response.getContent().readableBytes() == expectedContents.length) {
      byte[] compareBytes = new byte[expectedContents.length];
      response.getContent().readBytes(compareBytes);
      return Arrays.equals(expectedContents, compareBytes);
    }

    return false;
  }
 @Override
 public HttpResponse call() throws Exception {
   HttpResponse response = null;
   response = new DefaultFullHttpResponse(RtspVersions.RTSP_1_0, RtspResponseStatuses.OK);
   response.headers().add(RtspHeaderNames.SERVER, "RtspServer");
   response.headers().add(RtspHeaderNames.CSEQ, this.request.headers().get(RtspHeaderNames.CSEQ));
   response
       .headers()
       .add(RtspHeaderNames.PUBLIC, "SETUP,PLAY,PAUSE,TEARDOWN,GET_PARAMETER,OPTION");
   return response;
 }
  public void channelRead(final ChannelHandlerContext remoteChannelCtx, final Object msg)
      throws Exception {
    LoggerUtil.debug(
        logger, uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY), "Remote msg", msg);

    remainMsgCount++;

    if (remainMsgCount <= 5) {
      remoteChannelCtx.read();
    }

    HttpObject ho = (HttpObject) msg;

    if (ho instanceof HttpResponse) {
      HttpResponse httpResponse = (HttpResponse) ho;

      LoggerUtil.info(
          forwardRestLogger,
          uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY),
          httpResponse.getStatus(),
          httpResponse.getProtocolVersion());

      httpResponse.headers().set(HttpHeaders.Names.CONNECTION, HttpHeaders.Values.KEEP_ALIVE);
      httpResponse.headers().set("Proxy-Connection", HttpHeaders.Values.KEEP_ALIVE);
    }

    if (uaChannel.isActive()) {
      uaChannel
          .writeAndFlush(ho)
          .addListener(
              new ChannelFutureListener() {
                @Override
                public void operationComplete(ChannelFuture future) throws Exception {
                  LoggerUtil.debug(
                      logger,
                      uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY),
                      "Write to UA finished: " + future.isSuccess());
                  if (future.isSuccess()) {
                    remainMsgCount--;
                    remoteChannelCtx.read();
                    LoggerUtil.debug(
                        logger,
                        uaChannel.attr(ApnProxyConnectionAttribute.ATTRIBUTE_KEY),
                        "Fire read again");
                  } else {
                    remoteChannelCtx.close();
                  }
                }
              });
    } else {
      remoteChannelCtx.close();
    }
  }
  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);
      }
    }
  }
 /**
  * Gets the blob info of the blob with blob ID {@code blobId} and verifies them against what is
  * expected.
  *
  * @param blobId the blob ID of the blob to HEAD.
  * @param expectedHeaders the expected headers in the response.
  * @param usermetadata if non-null, this is expected to come as the body.
  * @throws ExecutionException
  * @throws InterruptedException
  */
 private void getBlobInfoAndVerify(String blobId, HttpHeaders expectedHeaders, byte[] usermetadata)
     throws ExecutionException, InterruptedException {
   FullHttpRequest httpRequest =
       buildRequest(HttpMethod.GET, blobId + "/" + RestUtils.SubResource.BlobInfo, null, null);
   Queue<HttpObject> responseParts = nettyClient.sendRequest(httpRequest, null, null).get();
   HttpResponse response = (HttpResponse) responseParts.poll();
   assertEquals("Unexpected response status", HttpResponseStatus.OK, response.getStatus());
   checkCommonGetHeadHeaders(response.headers());
   verifyBlobProperties(expectedHeaders, response);
   verifyUserMetadata(expectedHeaders, response, usermetadata, responseParts);
   assertTrue("Channel should be active", HttpHeaders.isKeepAlive(response));
 }
  public static Object extractErrorMessage(HttpResponse response) {
    if (response.getContent() == null || HttpHeaders.getContentLength(response, 0) == 0) {
      return "";
    }

    byte[] bytes = new byte[response.getContent().readableBytes()];
    response.getContent().readBytes(bytes);
    try {
      return new String(bytes, "UTF-8");
    } catch (UnsupportedEncodingException e) {
      return "";
    }
  }
  private void checkResponseCode(ChannelHandlerContext ctx, HttpResponse response)
      throws Exception {
    boolean discardBody = false;

    int code = response.getStatus().code();
    if (code == HttpResponseStatus.NOT_FOUND.code()
        || code == HttpResponseStatus.BAD_REQUEST.code()) {
      exceptionCaught(ctx, new HttpException(response.getStatus()));
      discardBody = true;
    }

    setDiscardBody(discardBody);
  }
  private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
    // Generate an error page if response status code is not OK (200).
    if (res.getStatus().getCode() != 200) {
      res.setContent(ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8));
      setContentLength(res, res.getContent().readableBytes());
    }

    // Send the response and close the connection if necessary.
    ChannelFuture f = ctx.getChannel().write(res);
    if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
      f.addListener(ChannelFutureListener.CLOSE);
    }
  }
 @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;
 }
  /**
   * Process server response:
   *
   * <pre>
   * HTTP/1.1 101 WebSocket Protocol Handshake
   * Upgrade: WebSocket
   * Connection: Upgrade
   * Sec-WebSocket-Origin: http://example.com
   * Sec-WebSocket-Location: ws://example.com/demo
   * Sec-WebSocket-Protocol: sample
   *
   * 8jKS'y:G*Co,Wxa-
   * </pre>
   *
   * @param ctx Channel context
   * @param response HTTP response returned from the server for the request sent by
   *     beginOpeningHandshake00().
   * @throws WebSocketHandshakeException
   */
  @Override
  public void performClosingHandshake(ChannelHandlerContext ctx, HttpResponse response)
      throws WebSocketHandshakeException {
    final HttpResponseStatus status = new HttpResponseStatus(101, "WebSocket Protocol Handshake");

    if (!response.getStatus().equals(status)) {
      throw new WebSocketHandshakeException(
          "Invalid handshake response status: " + response.getStatus());
    }

    String upgrade = response.getHeader(Names.UPGRADE);
    if (upgrade == null || !upgrade.equals(Values.WEBSOCKET)) {
      throw new WebSocketHandshakeException(
          "Invalid handshake response upgrade: " + response.getHeader(Names.UPGRADE));
    }

    String connection = response.getHeader(Names.CONNECTION);
    if (connection == null || !connection.equals(Values.UPGRADE)) {
      throw new WebSocketHandshakeException(
          "Invalid handshake response connection: " + response.getHeader(Names.CONNECTION));
    }

    byte[] challenge = response.getContent().array();
    if (!Arrays.equals(challenge, expectedChallengeResponseBytes)) {
      throw new WebSocketHandshakeException("Invalid challenge");
    }

    String protocol = response.getHeader(Names.SEC_WEBSOCKET_PROTOCOL);
    this.setSubProtocolResponse(protocol);

    ctx.getPipeline().replace("decoder", "ws-decoder", new WebSocket00FrameDecoder());

    this.setOpenningHandshakeCompleted(true);
  }
  protected void processHeadRequest(
      ChannelHandlerContext channelHandlerContext, FullHttpRequest fullHttpRequest) {

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

      _logger.trace(
          "Client {}: processing head request {}", channel.remoteAddress(), fullHttpRequest.uri());
    }

    SyncFile syncFile = _getSyncFile(fullHttpRequest);

    if (syncFile == null) {
      _sendError(channelHandlerContext, NOT_FOUND);

      return;
    }

    String lanTokenKey = syncFile.getLanTokenKey();

    if ((lanTokenKey == null) || lanTokenKey.isEmpty()) {
      _sendError(channelHandlerContext, NOT_FOUND);

      return;
    }

    String encryptedToken = null;

    try {
      encryptedToken = LanTokenUtil.createEncryptedToken(lanTokenKey);
    } catch (Exception e) {
      _sendError(channelHandlerContext, NOT_FOUND);

      return;
    }

    HttpResponse httpResponse = new DefaultFullHttpResponse(HTTP_1_1, OK);

    HttpHeaders httpHeaders = httpResponse.headers();

    httpHeaders.set("connectionsCount", _syncTrafficShapingHandler.getConnectionsCount());

    httpHeaders.set("downloadRate", _trafficCounter.lastWrittenBytes());
    httpHeaders.set("encryptedToken", encryptedToken);
    httpHeaders.set("maxConnections", PropsValues.SYNC_LAN_SERVER_MAX_CONNECTIONS);

    channelHandlerContext.writeAndFlush(httpResponse);
  }
 /**
  * Gets the blob with blob ID {@code blobId} and verifies that the headers and content match with
  * what is expected.
  *
  * @param blobId the blob ID of the blob to GET.
  * @param range the {@link ByteRange} for the request.
  * @param expectedHeaders the expected headers in the response.
  * @param expectedContent the expected content of the blob.
  * @throws ExecutionException
  * @throws InterruptedException
  */
 private void getBlobAndVerify(
     String blobId, ByteRange range, HttpHeaders expectedHeaders, ByteBuffer expectedContent)
     throws ExecutionException, InterruptedException, RestServiceException {
   HttpHeaders headers = null;
   if (range != null) {
     headers =
         new DefaultHttpHeaders()
             .add(RestUtils.Headers.RANGE, RestTestUtils.getRangeHeaderString(range));
   }
   FullHttpRequest httpRequest = buildRequest(HttpMethod.GET, blobId, headers, null);
   Queue<HttpObject> responseParts = nettyClient.sendRequest(httpRequest, null, null).get();
   HttpResponse response = (HttpResponse) responseParts.poll();
   assertEquals(
       "Unexpected response status",
       range == null ? HttpResponseStatus.OK : HttpResponseStatus.PARTIAL_CONTENT,
       response.getStatus());
   checkCommonGetHeadHeaders(response.headers());
   assertEquals(
       "Content-Type does not match",
       expectedHeaders.get(RestUtils.Headers.AMBRY_CONTENT_TYPE),
       response.headers().get(HttpHeaders.Names.CONTENT_TYPE));
   assertEquals(
       RestUtils.Headers.BLOB_SIZE + " does not match",
       expectedHeaders.get(RestUtils.Headers.BLOB_SIZE),
       response.headers().get(RestUtils.Headers.BLOB_SIZE));
   assertEquals(
       "Accept-Ranges not set correctly",
       "bytes",
       response.headers().get(RestUtils.Headers.ACCEPT_RANGES));
   byte[] expectedContentArray = expectedContent.array();
   if (range != null) {
     long blobSize = Long.parseLong(expectedHeaders.get(RestUtils.Headers.BLOB_SIZE));
     assertEquals(
         "Content-Range header not set correctly",
         RestUtils.buildContentRangeAndLength(range, blobSize).getFirst(),
         response.headers().get(RestUtils.Headers.CONTENT_RANGE));
     ByteRange resolvedRange = range.toResolvedByteRange(blobSize);
     expectedContentArray =
         Arrays.copyOfRange(
             expectedContentArray,
             (int) resolvedRange.getStartOffset(),
             (int) resolvedRange.getEndOffset() + 1);
   } else {
     assertNull(
         "Content-Range header should not be set",
         response.headers().get(RestUtils.Headers.CONTENT_RANGE));
   }
   if (expectedContentArray.length < FRONTEND_CONFIG.frontendChunkedGetResponseThresholdInBytes) {
     assertEquals(
         "Content-length not as expected",
         expectedContentArray.length,
         HttpHeaders.getContentLength(response));
   }
   byte[] responseContentArray = getContent(responseParts, expectedContentArray.length).array();
   assertArrayEquals(
       "GET content does not match original content", expectedContentArray, responseContentArray);
   assertTrue("Channel should be active", HttpHeaders.isKeepAlive(response));
 }
  /**
   * Sets the Date and Cache headers for the HTTP Response
   *
   * @param response HTTP response
   * @param fileToCache file to extract content type
   */
  private static void setDateAndCacheHeaders(HttpResponse response, File fileToCache) {
    SimpleDateFormat dateFormatter = new SimpleDateFormat(HTTP_DATE_FORMAT, Locale.US);
    dateFormatter.setTimeZone(TimeZone.getTimeZone(HTTP_DATE_GMT_TIMEZONE));

    // Date header
    Calendar time = new GregorianCalendar();
    response.headers().set(DATE, dateFormatter.format(time.getTime()));

    // Add cache headers
    time.add(Calendar.SECOND, HTTP_CACHE_SECONDS);
    response.headers().set(EXPIRES, dateFormatter.format(time.getTime()));
    response.headers().set(CACHE_CONTROL, "private, max-age=" + HTTP_CACHE_SECONDS);
    response
        .headers()
        .set(LAST_MODIFIED, dateFormatter.format(new Date(fileToCache.lastModified())));
  }
  private boolean exitAfterSpecialCases(
      final HttpResponse response, final Channel channel, final NettyResponseFuture<?> future)
      throws Exception {

    HttpRequest httpRequest = future.getNettyRequest().getHttpRequest();
    ProxyServer proxyServer = future.getProxyServer();
    int statusCode = response.getStatus().code();
    Request request = future.getCurrentRequest();
    Realm realm = request.getRealm() != null ? request.getRealm() : config.getRealm();

    if (statusCode == UNAUTHORIZED_401) {
      return exitAfterHandling401(
          channel, future, response, request, statusCode, realm, proxyServer, httpRequest);

    } else if (statusCode == PROXY_AUTHENTICATION_REQUIRED_407) {
      return exitAfterHandling407(
          channel, future, response, request, statusCode, proxyServer, httpRequest);

    } else if (statusCode == CONTINUE_100) {
      return exitAfterHandling100(channel, future, statusCode);

    } else if (REDIRECT_STATUSES.contains(statusCode)) {
      return exitAfterHandlingRedirect(channel, future, response, request, statusCode, realm);

    } else if (httpRequest.getMethod() == HttpMethod.CONNECT && statusCode == OK_200) {
      return exitAfterHandlingConnect(
          channel, future, request, proxyServer, statusCode, httpRequest);
    }
    return false;
  }
 /**
  * Sets the value of response headers after making sure that the response metadata is not already
  * sent.
  *
  * @param headerName The name of the header.
  * @param headerValue The intended value of the header.
  * @throws IllegalArgumentException if any of {@code headerName} or {@code headerValue} is null.
  * @throws IllegalStateException if response metadata has already been written to the channel.
  */
 private void setResponseHeader(String headerName, Object headerValue) {
   if (headerName != null && headerValue != null) {
     long startTime = System.currentTimeMillis();
     if (headerValue instanceof Date) {
       HttpHeaders.setDateHeader(responseMetadata, headerName, (Date) headerValue);
     } else {
       HttpHeaders.setHeader(responseMetadata, headerName, headerValue);
     }
     if (responseMetadataWritten.get()) {
       nettyMetrics.deadResponseAccessError.inc();
       throw new IllegalStateException(
           "Response metadata changed after it has already been written to the channel");
     } else {
       logger.trace(
           "Header {} set to {} for channel {}",
           headerName,
           responseMetadata.headers().get(headerName),
           ctx.channel());
       nettyMetrics.headerSetTimeInMs.update(System.currentTimeMillis() - startTime);
     }
   } else {
     throw new IllegalArgumentException(
         "Header name [" + headerName + "] or header value [" + headerValue + "] null");
   }
 }