/**
   * 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 endOpeningHandshake(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);
    return;
  }
예제 #2
0
  public static void send(HttpResponse response, Channel channel, @Nullable HttpRequest request) {
    ChannelBuffer content = response.getContent();
    setContentLength(
        response, content == ChannelBuffers.EMPTY_BUFFER ? 0 : content.readableBytes());

    boolean keepAlive = request != null && addKeepAliveIfNeed(response, request);
    addCommonHeaders(response);
    send(response, channel, !keepAlive);
  }
  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);
    }
  }
예제 #4
0
 /*
  * 私有函数,服务器发送响应给用户时将被调用调用
  * @param       [ctx]       channelHandler中的上下文
  * @param       [req]       消息请求
  * @param       [res]       消息响应
  */
 private void sendHttpResponse(ChannelHandlerContext ctx, HttpRequest req, HttpResponse res) {
   if (res.getStatus().getCode() != 200) {
     // 将响应信息以UTF_8编码格式写回
     ChannelBuffer content =
         ChannelBuffers.copiedBuffer(res.getStatus().toString(), CharsetUtil.UTF_8);
     int contentLength = res.getContent().readableBytes();
     buildResponse(res, false, null, content, contentLength);
   }
   ChannelFuture f = ctx.getChannel().write(res);
   if (!isKeepAlive(req) || res.getStatus().getCode() != 200) {
     f.addListener(ChannelFutureListener.CLOSE);
   }
 }
  @Override
  public Message toCamelMessage(
      HttpResponse response, Exchange exchange, NettyHttpConfiguration configuration)
      throws Exception {
    LOG.trace("toCamelMessage: {}", response);

    NettyHttpMessage answer = new NettyHttpMessage(null, response);
    answer.setExchange(exchange);
    if (configuration.isMapHeaders()) {
      populateCamelHeaders(response, answer.getHeaders(), exchange, configuration);
    }

    // keep the body as is, and use type converters
    answer.setBody(response.getContent());
    return answer;
  }
예제 #6
0
  private void sendHttpResponse(Channel channel, HttpRequest request, HttpResponse response) {
    if (!channel.isOpen()) {
      return;
    }

    // response的内容已在各Listener中填充
    response.headers().set(Names.CONTENT_LENGTH, response.getContent().readableBytes());
    response.headers().set(Names.SERVER, "NAVI/1.1.4(UNIX)");

    if (!HttpHeaders.isKeepAlive(request)
        || response.getStatus() != HttpResponseStatus.OK
        || ServerConfigure.isChannelClose()) {
      response.headers().set(Names.CONNECTION, "close");
      channel.setAttachment(WRITING);
      ChannelFuture f = channel.write(response);
      f.addListener(ChannelFutureListener.CLOSE);
      f.addListener(
          new ChannelFutureListener() {

            public void operationComplete(ChannelFuture f) throws Exception {
              if (!f.isSuccess()) {
                log.error(f.getCause().getMessage(), f.getCause());
              }
            }
          });
    } else {
      if (request.getProtocolVersion() == HttpVersion.HTTP_1_0) {
        response.headers().add(Names.CONNECTION, "Keep-Alive");
      }
      channel.setAttachment(WRITING);
      ChannelFuture f = channel.write(response);
      f.addListener(ChannelFutureListener.CLOSE_ON_FAILURE);
      f.addListener(
          new ChannelFutureListener() {

            public void operationComplete(ChannelFuture f) throws Exception {
              if (!f.isSuccess()) {
                log.error(f.getCause().getMessage(), f.getCause());
              }
            }
          });
    }
  }
예제 #7
0
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {

      Channel ch = e.getChannel();
      ClientConnection conn = connectionMap.get(ch);
      Object msg = e.getMessage();
      if (msg instanceof HttpResponse) {
        HttpResponse response = (HttpResponse) msg;

        conn.handleResponse(response);
        ChannelBuffer content = response.getContent();
        if (content.readable()) {
          conn.handleResponseChunk(new Buffer(content));
        }
        if (!response.isChunked()) {
          conn.handleResponseEnd();
        }
      } else if (msg instanceof HttpChunk) {
        HttpChunk chunk = (HttpChunk) msg;
        if (chunk.getContent().readable()) {
          Buffer buff = new Buffer(chunk.getContent());
          conn.handleResponseChunk(buff);
        }
        if (chunk.isLast()) {
          if (chunk instanceof HttpChunkTrailer) {
            HttpChunkTrailer trailer = (HttpChunkTrailer) chunk;
            conn.handleResponseEnd(trailer);
          } else {
            conn.handleResponseEnd();
          }
        }
      } else if (msg instanceof WebSocketFrame) {
        WebSocketFrame frame = (WebSocketFrame) msg;
        conn.handleWsFrame(frame);
      } else {
        throw new IllegalStateException("Invalid object " + e.getMessage());
      }
    }
  public void writeResponse(byte[] responseValue) {

    this.responseContent = ChannelBuffers.dynamicBuffer(responseValue.length);
    this.responseContent.writeBytes(responseValue);

    // 1. Create the Response object
    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);

    // 2. Set the right headers
    response.setHeader(CONTENT_TYPE, "binary");
    response.setHeader(CONTENT_TRANSFER_ENCODING, "binary");

    // 3. Copy the data into the payload
    response.setContent(responseContent);
    response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());

    if (logger.isDebugEnabled()) {
      logger.debug("Response = " + response);
    }

    // Write the response to the Netty Channel
    this.getRequestMessageEvent.getChannel().write(response);
  }
  @Override
  public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
    Channel ch = ctx.getChannel();
    if (!handshaker.isHandshakeComplete()) {
      handshaker.finishHandshake(ch, (HttpResponse) e.getMessage());

      handler.onConnect();

      return;
    }

    if (e.getMessage() instanceof HttpResponse) {
      HttpResponse response = (HttpResponse) e.getMessage();
      String message =
          "Unexpected HttpResponse (status="
              + response.getStatus()
              + ", content="
              + response.getContent().toString(CharsetUtil.UTF_8)
              + ')';
      log.error(String.format("Web socket client: %s", message));

      throw new Exception(message);
    }

    WebSocketFrame frame = (WebSocketFrame) e.getMessage();
    if (frame instanceof TextWebSocketFrame) {
      TextWebSocketFrame textFrame = (TextWebSocketFrame) frame;
      try {
        handler.onReceive(MAPPER.parseObject(textFrame.getText()));
      } catch (Exception e1) {
        log.error("Error while decoding JSON websocket message", e1);
      }
    } else if (frame instanceof PongWebSocketFrame) {
    } else if (frame instanceof CloseWebSocketFrame) {
      ch.close();
    }
  }
예제 #10
0
    @Override
    public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
      if (!readingChunks) {
        HttpResponse response = (HttpResponse) e.getMessage();

        StringBuilder sb = new StringBuilder();
        if (LOG.isDebugEnabled()) {
          sb.append("STATUS: ")
              .append(response.getStatus())
              .append(", VERSION: ")
              .append(response.getProtocolVersion())
              .append(", HEADER: ");
        }
        if (!response.getHeaderNames().isEmpty()) {
          for (String name : response.getHeaderNames()) {
            for (String value : response.getHeaders(name)) {
              if (LOG.isDebugEnabled()) {
                sb.append(name + " = " + value);
              }
              if (this.length == -1 && name.equals("Content-Length")) {
                this.length = Long.valueOf(value);
              }
            }
          }
        }
        if (LOG.isDebugEnabled()) {
          LOG.debug(sb.toString());
        }

        if (response.getStatus() == HttpResponseStatus.NO_CONTENT) {
          LOG.info("There are no data corresponding to the request");
          return;
        }

        this.raf = new RandomAccessFile(file, "rw");
        this.fc = raf.getChannel();

        if (response.isChunked()) {
          readingChunks = true;
        } else {
          ChannelBuffer content = response.getContent();
          if (content.readable()) {
            fc.write(content.toByteBuffer());
          }
        }
      } else {
        HttpChunk chunk = (HttpChunk) e.getMessage();
        if (chunk.isLast()) {
          readingChunks = false;
          long fileLength = fc.position();
          fc.close();
          raf.close();
          if (fileLength == length) {
            LOG.info("Data fetch is done (total received bytes: " + fileLength + ")");
          } else {
            LOG.info(
                "Data fetch is done, but cannot get all data "
                    + "(received/total: "
                    + fileLength
                    + "/"
                    + length
                    + ")");
          }
        } else {
          fc.write(chunk.getContent().toByteBuffer());
        }
      }
    }
예제 #11
0
  /**
   * Sends nested multipart response. Outer multipart wraps all the keys requested. Each key has a
   * separate multipart for the versioned values.
   */
  @Override
  public void sendResponse(StoreStats performanceStats, boolean isFromLocalZone, long startTimeInMs)
      throws Exception {

    // multiPartKeys is the outer multipart
    MimeMultipart multiPartKeys = new MimeMultipart();
    ByteArrayOutputStream keysOutputStream = new ByteArrayOutputStream();

    for (Entry<ByteArray, List<Versioned<byte[]>>> entry : versionedResponses.entrySet()) {
      ByteArray key = entry.getKey();
      String contentLocationKey =
          "/" + this.storeName + "/" + new String(Base64.encodeBase64(key.get()));

      // Create the individual body part - for each key requested
      MimeBodyPart keyBody = new MimeBodyPart();
      try {
        // Add the right headers
        keyBody.addHeader(CONTENT_TYPE, "application/octet-stream");
        keyBody.addHeader(CONTENT_TRANSFER_ENCODING, "binary");
        keyBody.addHeader(CONTENT_LOCATION, contentLocationKey);
      } catch (MessagingException me) {
        logger.error("Exception while constructing key body headers", me);
        keysOutputStream.close();
        throw me;
      }
      // multiPartValues is the inner multipart
      MimeMultipart multiPartValues = new MimeMultipart();
      for (Versioned<byte[]> versionedValue : entry.getValue()) {

        byte[] responseValue = versionedValue.getValue();

        VectorClock vectorClock = (VectorClock) versionedValue.getVersion();
        String eTag = RestUtils.getSerializedVectorClock(vectorClock);

        // Create the individual body part - for each versioned value of
        // a key
        MimeBodyPart valueBody = new MimeBodyPart();
        try {
          // Add the right headers
          valueBody.addHeader(CONTENT_TYPE, "application/octet-stream");
          valueBody.addHeader(CONTENT_TRANSFER_ENCODING, "binary");
          valueBody.addHeader(RestMessageHeaders.X_VOLD_VECTOR_CLOCK, eTag);
          valueBody.setContent(responseValue, "application/octet-stream");

          multiPartValues.addBodyPart(valueBody);
        } catch (MessagingException me) {
          logger.error("Exception while constructing value body part", me);
          keysOutputStream.close();
          throw me;
        }
      }
      try {
        // Add the inner multipart as the content of the outer body part
        keyBody.setContent(multiPartValues);
        multiPartKeys.addBodyPart(keyBody);
      } catch (MessagingException me) {
        logger.error("Exception while constructing key body part", me);
        keysOutputStream.close();
        throw me;
      }
    }
    try {
      multiPartKeys.writeTo(keysOutputStream);
    } catch (Exception e) {
      logger.error("Exception while writing mutipart to output stream", e);
      throw e;
    }

    ChannelBuffer responseContent = ChannelBuffers.dynamicBuffer();
    responseContent.writeBytes(keysOutputStream.toByteArray());

    // Create the Response object
    HttpResponse response = new DefaultHttpResponse(HTTP_1_1, OK);

    // Set the right headers
    response.setHeader(CONTENT_TYPE, "multipart/binary");
    response.setHeader(CONTENT_TRANSFER_ENCODING, "binary");

    // Copy the data into the payload
    response.setContent(responseContent);
    response.setHeader(CONTENT_LENGTH, response.getContent().readableBytes());

    // Write the response to the Netty Channel
    this.messageEvent.getChannel().write(response);

    if (performanceStats != null && isFromLocalZone) {
      recordStats(performanceStats, startTimeInMs, Tracked.GET_ALL);
    }

    keysOutputStream.close();
  }