예제 #1
0
  @Override
  public void send(final FileChannel channel) throws Exception {
    long len = channel.size();

    DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);
    if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
      headers.remove(HttpHeaderNames.TRANSFER_ENCODING);
      headers.set(HttpHeaderNames.CONTENT_LENGTH, len);
    }

    if (keepAlive) {
      headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }

    // dump headers
    rsp.headers().set(headers);
    ChannelHandlerContext ctx = this.ctx;
    ctx.attr(NettyRequest.NEED_FLUSH).set(false);
    ctx.channel()
        .eventLoop()
        .execute(
            () -> {
              // send headers
              ctx.write(rsp);
              ctx.write(new DefaultFileRegion(channel, 0, len));
              keepAlive(ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT));
            });

    committed = true;
  }
예제 #2
0
  private void send(final ByteBuf buffer) throws Exception {
    DefaultFullHttpResponse rsp = new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, status, buffer);

    if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
      headers
          .remove(HttpHeaderNames.TRANSFER_ENCODING)
          .set(HttpHeaderNames.CONTENT_LENGTH, buffer.readableBytes());
    }

    if (keepAlive) {
      headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
    }

    // dump headers
    rsp.headers().set(headers);

    Attribute<Boolean> async = ctx.attr(NettyRequest.ASYNC);
    boolean isAsync = async != null && async.get() == Boolean.TRUE;
    if (isAsync) {
      // we need flush, from async
      keepAlive(ctx.writeAndFlush(rsp));
    } else {
      keepAlive(ctx.write(rsp));
    }

    committed = true;
  }
예제 #3
0
 /**
  * Verifies User metadata headers from output, to that sent in during input
  *
  * @param expectedHeaders the expected headers in the response.
  * @param response the {@link HttpResponse} which contains the headers of the response.
  * @param usermetadata if non-null, this is expected to come as the body.
  * @param content the content accompanying the response.
  */
 private void verifyUserMetadata(
     HttpHeaders expectedHeaders,
     HttpResponse response,
     byte[] usermetadata,
     Queue<HttpObject> content) {
   if (usermetadata == null) {
     assertEquals("Content-Length is not 0", 0, HttpHeaders.getContentLength(response));
     for (Map.Entry<String, String> header : expectedHeaders) {
       String key = header.getKey();
       if (key.startsWith(RestUtils.Headers.USER_META_DATA_HEADER_PREFIX)) {
         assertEquals(
             "Value for " + key + " does not match in user metadata",
             header.getValue(),
             HttpHeaders.getHeader(response, key));
       }
     }
     for (Map.Entry<String, String> header : response.headers()) {
       String key = header.getKey();
       if (key.startsWith(RestUtils.Headers.USER_META_DATA_HEADER_PREFIX)) {
         assertTrue(
             "Key " + key + " does not exist in expected headers", expectedHeaders.contains(key));
       }
     }
     discardContent(content, 1);
   } else {
     assertEquals(
         "Content-Length is not as expected",
         usermetadata.length,
         HttpHeaders.getContentLength(response));
     byte[] receivedMetadata = getContent(content, HttpHeaders.getContentLength(response)).array();
     assertArrayEquals("User metadata does not match original", usermetadata, receivedMetadata);
   }
 }
예제 #4
0
 /**
  * Verifies blob properties from output, to that sent in during input
  *
  * @param expectedHeaders the expected headers in the response.
  * @param response the {@link HttpResponse} that contains the headers.
  */
 private void verifyBlobProperties(HttpHeaders expectedHeaders, HttpResponse response) {
   assertEquals(
       "Blob size does not match",
       Long.parseLong(expectedHeaders.get(RestUtils.Headers.BLOB_SIZE)),
       Long.parseLong(HttpHeaders.getHeader(response, RestUtils.Headers.BLOB_SIZE)));
   assertEquals(
       RestUtils.Headers.SERVICE_ID + " does not match",
       expectedHeaders.get(RestUtils.Headers.SERVICE_ID),
       HttpHeaders.getHeader(response, RestUtils.Headers.SERVICE_ID));
   assertEquals(
       RestUtils.Headers.PRIVATE + " does not match",
       expectedHeaders.get(RestUtils.Headers.PRIVATE),
       HttpHeaders.getHeader(response, RestUtils.Headers.PRIVATE));
   assertEquals(
       RestUtils.Headers.AMBRY_CONTENT_TYPE + " does not match",
       expectedHeaders.get(RestUtils.Headers.AMBRY_CONTENT_TYPE),
       HttpHeaders.getHeader(response, RestUtils.Headers.AMBRY_CONTENT_TYPE));
   assertTrue(
       "No " + RestUtils.Headers.CREATION_TIME,
       HttpHeaders.getHeader(response, RestUtils.Headers.CREATION_TIME, null) != null);
   if (Long.parseLong(expectedHeaders.get(RestUtils.Headers.TTL)) != Utils.Infinite_Time) {
     assertEquals(
         RestUtils.Headers.TTL + " does not match",
         expectedHeaders.get(RestUtils.Headers.TTL),
         HttpHeaders.getHeader(response, RestUtils.Headers.TTL));
   }
   if (expectedHeaders.contains(RestUtils.Headers.OWNER_ID)) {
     assertEquals(
         RestUtils.Headers.OWNER_ID + " does not match",
         expectedHeaders.get(RestUtils.Headers.OWNER_ID),
         HttpHeaders.getHeader(response, RestUtils.Headers.OWNER_ID));
   }
 }
예제 #5
0
 private void keepAlive(final ChannelFuture future) {
   if (headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
     if (!keepAlive) {
       future.addListener(CLOSE);
     }
   } else {
     // content len is not set, just close the connection regardless keep alive or not.
     future.addListener(CLOSE);
   }
 }
예제 #6
0
  private FullHttpRequest convertToHttpRequest(Invocation invocation) {
    requireNonNull(invocation, "invocation");
    final ServiceInvocationContext ctx = invocation.invocationContext();
    final FullHttpRequest request;
    final Object content = invocation.content();

    if (content instanceof FullHttpRequest) {
      request = (FullHttpRequest) content;
    } else if (content instanceof ByteBuf) {
      request =
          new DefaultFullHttpRequest(
              HttpVersion.HTTP_1_1, HttpMethod.POST, ctx.path(), (ByteBuf) content);
    } else {
      throw new IllegalStateException(
          "content is not a ByteBuf or FullHttpRequest: " + content.getClass().getName());
    }

    HttpHeaders headers = request.headers();

    headers.set(HttpHeaderNames.HOST, ctx.host());
    headers.set(ExtensionHeaderNames.SCHEME.text(), sessionProtocol.uriText());
    headers.set(HttpHeaderNames.USER_AGENT, ARMERIA_USER_AGENT);
    headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);

    ByteBuf contentBuf = request.content();
    if (contentBuf != null && contentBuf.isReadable()) {
      headers.set(HttpHeaderNames.CONTENT_LENGTH, contentBuf.readableBytes());
    }

    invocation.options().get(ClientOption.HTTP_HEADERS).ifPresent(headers::add);
    if (ctx.scheme().serializationFormat() != SerializationFormat.NONE) {
      // we allow a user can set content type and accept headers
      String mimeType = ctx.scheme().serializationFormat().mimeType();
      if (!headers.contains(HttpHeaderNames.CONTENT_TYPE)) {
        headers.set(HttpHeaderNames.CONTENT_TYPE, mimeType);
      }
      if (!headers.contains(HttpHeaderNames.ACCEPT)) {
        headers.set(HttpHeaderNames.ACCEPT, mimeType);
      }
    }

    return request;
  }
예제 #7
0
  /**
   * Returns the content length of the specified web socket message. If the specified message is not
   * a web socket message, {@code -1} is returned.
   */
  private static int getWebSocketContentLength(HttpMessage message) {
    // WebSockset messages have constant content-lengths.
    HttpHeaders h = message.headers();
    if (message instanceof HttpRequest) {
      HttpRequest req = (HttpRequest) message;
      if (HttpMethod.GET.equals(req.getMethod())
          && h.contains(Names.SEC_WEBSOCKET_KEY1)
          && h.contains(Names.SEC_WEBSOCKET_KEY2)) {
        return 8;
      }
    } else if (message instanceof HttpResponse) {
      HttpResponse res = (HttpResponse) message;
      if (res.getStatus().code() == 101
          && h.contains(Names.SEC_WEBSOCKET_ORIGIN)
          && h.contains(Names.SEC_WEBSOCKET_LOCATION)) {
        return 16;
      }
    }

    // Not a web socket message
    return -1;
  }
예제 #8
0
  @Override
  public void send(final InputStream stream) throws Exception {
    byte[] chunk = new byte[bufferSize];
    int count = ByteStreams.read(stream, chunk, 0, bufferSize);
    if (count <= 0) {
      return;
    }
    ByteBuf buffer = Unpooled.wrappedBuffer(chunk, 0, count);
    if (count < bufferSize) {
      send(buffer);
    } else {
      DefaultHttpResponse rsp = new DefaultHttpResponse(HttpVersion.HTTP_1_1, status);

      if (!headers.contains(HttpHeaderNames.CONTENT_LENGTH)) {
        headers.set(HttpHeaderNames.TRANSFER_ENCODING, HttpHeaderValues.CHUNKED);
      } else {
        if (keepAlive) {
          headers.set(HttpHeaderNames.CONNECTION, HttpHeaderValues.KEEP_ALIVE);
        }
      }

      // dump headers
      rsp.headers().set(headers);
      ChannelHandlerContext ctx = this.ctx;
      ctx.attr(NettyRequest.NEED_FLUSH).set(false);

      // add chunker
      ChannelPipeline pipeline = ctx.pipeline();
      if (pipeline.get("chunker") == null) {
        pipeline.addAfter("encoder", "chunker", new ChunkedWriteHandler());
      }

      // group all write
      ctx.channel()
          .eventLoop()
          .execute(
              () -> {
                // send headers
                ctx.write(rsp);
                // send head chunk
                ctx.write(buffer);
                // send tail
                ctx.write(new ChunkedStream(stream, bufferSize));
                keepAlive(ctx.writeAndFlush(LastHttpContent.EMPTY_LAST_CONTENT));
              });
    }

    committed = true;
  }
예제 #9
0
  private void processHead(ChannelHandlerContext context, FullHttpRequest request) {
    HttpHeaders headers = request.headers();
    FullHttpResponse response = null;

    if (headers.contains(Names.CONTENT_LENGTH)) {

      try {
        File file = getRequestedFile(request.getUri());

        response =
            new DefaultFullHttpResponse(
                HTTP_1_1, request.getDecoderResult().isSuccess() ? OK : BAD_REQUEST);

        HttpHeaders.setContentLength(response, file.length());

      } catch (FileNotFoundException | URISyntaxException e) {
        response = getBadRequest(e.getMessage());
      }
    }

    context.writeAndFlush(response);
  }
예제 #10
0
 private void prepareHeaders() {
   HttpHeaders headers = request.headers();
   headers.remove(TRANSFER_ENCODING);
   if (!headers.contains(HOST)) {
     request.headers().set(HOST, conn.hostHeader());
   }
   if (chunked) {
     HttpHeaders.setTransferEncodingChunked(request);
   }
   if (client.getOptions().isTryUseCompression()
       && request.headers().get(ACCEPT_ENCODING) == null) {
     // if compression should be used but nothing is specified by the user support deflate and
     // gzip.
     request.headers().set(ACCEPT_ENCODING, DEFLATE_GZIP);
   }
   if (!client.getOptions().isKeepAlive()
       && client.getOptions().getProtocolVersion() == io.vertx.core.http.HttpVersion.HTTP_1_1) {
     request.headers().set(CONNECTION, CLOSE);
   } else if (client.getOptions().isKeepAlive()
       && client.getOptions().getProtocolVersion() == io.vertx.core.http.HttpVersion.HTTP_1_0) {
     request.headers().set(CONNECTION, KEEP_ALIVE);
   }
 }
예제 #11
0
  @Override
  protected Object encode(ChannelHandlerContext ctx, HttpObject msg) throws Exception {

    if (msg instanceof HttpResponse && ((HttpResponse) msg).getStatus().code() == 100) {
      // 100-continue response must be passed through.
      return msg;
    }

    // handle the case of single complete message without content
    if (msg instanceof FullHttpMessage && !((FullHttpMessage) msg).data().isReadable()) {

      // Remove content encoding
      String acceptEncoding = acceptEncodingQueue.poll();
      if (acceptEncoding == null) {
        throw new IllegalStateException("cannot send more responses than requests");
      }

      return msg;
    }

    if (msg instanceof HttpMessage) {
      assert message == null;

      // check if this message is also of type HttpContent is such case just make a safe copy of the
      // headers
      // as the content will get handled later and this simplify the handling
      if (msg instanceof HttpContent) {
        if (msg instanceof HttpRequest) {
          HttpRequest req = (HttpRequest) msg;
          message = new DefaultHttpRequest(req.getProtocolVersion(), req.getMethod(), req.getUri());
          message.headers().set(req.headers());
        } else if (msg instanceof HttpResponse) {
          HttpResponse res = (HttpResponse) msg;
          message = new DefaultHttpResponse(res.getProtocolVersion(), res.getStatus());
          message.headers().set(res.headers());
        } else {
          return msg;
        }
      } else {
        message = (HttpMessage) msg;
      }

      cleanup();
    }

    if (msg instanceof HttpContent) {
      HttpContent c = (HttpContent) msg;

      if (!encodeStarted) {
        encodeStarted = true;
        HttpMessage message = this.message;
        HttpHeaders headers = message.headers();
        this.message = null;

        // Determine the content encoding.
        String acceptEncoding = acceptEncodingQueue.poll();
        if (acceptEncoding == null) {
          throw new IllegalStateException("cannot send more responses than requests");
        }

        Result result = beginEncode(message, c, acceptEncoding);

        if (result == null) {
          if (c instanceof LastHttpContent) {
            return new Object[] {message, new DefaultLastHttpContent(c.data().retain())};
          } else {
            return new Object[] {message, new DefaultHttpContent(c.data().retain())};
          }
        }

        encoder = result.contentEncoder();

        // Encode the content and remove or replace the existing headers
        // so that the message looks like a decoded message.
        headers.set(HttpHeaders.Names.CONTENT_ENCODING, result.targetContentEncoding());

        Object[] encoded = encodeContent(message, c);

        if (!HttpHeaders.isTransferEncodingChunked(message) && encoded.length == 3) {
          if (headers.contains(HttpHeaders.Names.CONTENT_LENGTH)) {
            long length =
                ((ByteBufHolder) encoded[1]).data().readableBytes()
                    + ((ByteBufHolder) encoded[2]).data().readableBytes();

            headers.set(HttpHeaders.Names.CONTENT_LENGTH, Long.toString(length));
          }
        }
        return encoded;
      }

      if (encoder != null) {
        return encodeContent(null, c);
      }

      c.retain();
      return c;
    }
    return null;
  }