예제 #1
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;
  }
예제 #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;
  }
예제 #3
0
  private static FullHttpRequest createHttpRequest(int spdyVersion, SpdyHeaderBlock requestFrame)
      throws Exception {
    // Create the first line of the request from the name/value pairs
    HttpMethod method = SpdyHeaders.getMethod(spdyVersion, requestFrame);
    String url = SpdyHeaders.getUrl(spdyVersion, requestFrame);
    HttpVersion httpVersion = SpdyHeaders.getVersion(spdyVersion, requestFrame);
    SpdyHeaders.removeMethod(spdyVersion, requestFrame);
    SpdyHeaders.removeUrl(spdyVersion, requestFrame);
    SpdyHeaders.removeVersion(spdyVersion, requestFrame);

    FullHttpRequest req = new DefaultFullHttpRequest(httpVersion, method, url);

    // Remove the scheme header
    SpdyHeaders.removeScheme(spdyVersion, requestFrame);

    if (spdyVersion >= 3) {
      // Replace the SPDY host header with the HTTP host header
      String host = SpdyHeaders.getHost(requestFrame);
      SpdyHeaders.removeHost(requestFrame);
      HttpHeaders.setHost(req, host);
    }

    for (Map.Entry<String, String> e : requestFrame.headers().entries()) {
      req.headers().add(e.getKey(), e.getValue());
    }

    // The Connection and Keep-Alive headers are no longer valid
    HttpHeaders.setKeepAlive(req, true);

    // Transfer-Encoding header is not valid
    req.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);

    return req;
  }
예제 #4
0
 private static void assertHeaders(Object msg, int streamId, boolean last, SpdyHeaders headers) {
   assertNotNull(msg);
   assertTrue(msg instanceof SpdyHeadersFrame);
   SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
   assertEquals(spdyHeadersFrame.getStreamId(), streamId);
   assertEquals(spdyHeadersFrame.isLast(), last);
   for (String name : headers.names()) {
     List<String> expectedValues = headers.getAll(name);
     List<String> receivedValues = spdyHeadersFrame.headers().getAll(name);
     assertTrue(receivedValues.containsAll(expectedValues));
     receivedValues.removeAll(expectedValues);
     assertTrue(receivedValues.isEmpty());
     spdyHeadersFrame.headers().remove(name);
   }
   assertTrue(spdyHeadersFrame.headers().isEmpty());
 }
예제 #5
0
  private static FullHttpResponse createHttpResponse(int spdyVersion, SpdyHeaderBlock responseFrame)
      throws Exception {
    // Create the first line of the response from the name/value pairs
    HttpResponseStatus status = SpdyHeaders.getStatus(spdyVersion, responseFrame);
    HttpVersion version = SpdyHeaders.getVersion(spdyVersion, responseFrame);
    SpdyHeaders.removeStatus(spdyVersion, responseFrame);
    SpdyHeaders.removeVersion(spdyVersion, responseFrame);

    FullHttpResponse res = new DefaultFullHttpResponse(version, status);
    for (Map.Entry<String, String> e : responseFrame.headers().entries()) {
      res.headers().add(e.getKey(), e.getValue());
    }

    // The Connection and Keep-Alive headers are no longer valid
    HttpHeaders.setKeepAlive(res, true);

    // Transfer-Encoding header is not valid
    res.headers().remove(HttpHeaders.Names.TRANSFER_ENCODING);
    res.headers().remove(HttpHeaders.Names.TRAILER);

    return res;
  }
예제 #6
0
  private SpdySynStreamFrame createSynStreamFrame(HttpMessage httpMessage) throws Exception {
    boolean chunked = httpMessage.isChunked();

    // Get the Stream-ID, Associated-To-Stream-ID, Priority, URL, and scheme from the headers
    int streamID = SpdyHttpHeaders.getStreamID(httpMessage);
    int associatedToStreamID = SpdyHttpHeaders.getAssociatedToStreamID(httpMessage);
    byte priority = SpdyHttpHeaders.getPriority(httpMessage);
    String URL = SpdyHttpHeaders.getUrl(httpMessage);
    String scheme = SpdyHttpHeaders.getScheme(httpMessage);
    SpdyHttpHeaders.removeStreamID(httpMessage);
    SpdyHttpHeaders.removeAssociatedToStreamID(httpMessage);
    SpdyHttpHeaders.removePriority(httpMessage);
    SpdyHttpHeaders.removeUrl(httpMessage);
    SpdyHttpHeaders.removeScheme(httpMessage);

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

    SpdySynStreamFrame spdySynStreamFrame =
        new DefaultSpdySynStreamFrame(streamID, associatedToStreamID, priority);

    // Unfold the first line of the message into name/value pairs
    if (httpMessage instanceof HttpRequest) {
      HttpRequest httpRequest = (HttpRequest) httpMessage;
      SpdyHeaders.setMethod(spdyVersion, spdySynStreamFrame, httpRequest.getMethod());
      SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, httpRequest.getUri());
      SpdyHeaders.setVersion(spdyVersion, spdySynStreamFrame, httpMessage.getProtocolVersion());
    }
    if (httpMessage instanceof HttpResponse) {
      HttpResponse httpResponse = (HttpResponse) httpMessage;
      SpdyHeaders.setStatus(spdyVersion, spdySynStreamFrame, httpResponse.getStatus());
      SpdyHeaders.setUrl(spdyVersion, spdySynStreamFrame, URL);
      spdySynStreamFrame.setUnidirectional(true);
    }

    // Replace the HTTP host header with the SPDY host header
    if (spdyVersion >= 3) {
      String host = HttpHeaders.getHost(httpMessage);
      httpMessage.removeHeader(HttpHeaders.Names.HOST);
      SpdyHeaders.setHost(spdySynStreamFrame, host);
    }

    // Set the SPDY scheme header
    if (scheme == null) {
      scheme = "https";
    }
    SpdyHeaders.setScheme(spdyVersion, spdySynStreamFrame, scheme);

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

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

    return spdySynStreamFrame;
  }
예제 #7
0
  @Override
  protected void decode(
      ChannelHandlerContext ctx, SpdyDataOrControlFrame msg, MessageBuf<Object> out)
      throws Exception {
    if (msg instanceof SpdySynStreamFrame) {

      // HTTP requests/responses are mapped one-to-one to SPDY streams.
      SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
      int streamId = spdySynStreamFrame.getStreamId();

      if (SpdyCodecUtil.isServerId(streamId)) {
        // SYN_STREAM frames initiated by the server are pushed resources
        int associatedToStreamId = spdySynStreamFrame.getAssociatedToStreamId();

        // If a client receives a SYN_STREAM with an Associated-To-Stream-ID of 0
        // it must reply with a RST_STREAM with error code INVALID_STREAM
        if (associatedToStreamId == 0) {
          SpdyRstStreamFrame spdyRstStreamFrame =
              new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INVALID_STREAM);
          ctx.write(spdyRstStreamFrame);
        }

        String URL = SpdyHeaders.getUrl(spdyVersion, spdySynStreamFrame);

        // If a client receives a SYN_STREAM without a 'url' header
        // it must reply with a RST_STREAM with error code PROTOCOL_ERROR
        if (URL == null) {
          SpdyRstStreamFrame spdyRstStreamFrame =
              new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
          ctx.write(spdyRstStreamFrame);
        }

        try {
          FullHttpResponse httpResponseWithEntity =
              createHttpResponse(spdyVersion, spdySynStreamFrame);

          // Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
          SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId);
          SpdyHttpHeaders.setAssociatedToStreamId(httpResponseWithEntity, associatedToStreamId);
          SpdyHttpHeaders.setPriority(httpResponseWithEntity, spdySynStreamFrame.getPriority());
          SpdyHttpHeaders.setUrl(httpResponseWithEntity, URL);

          if (spdySynStreamFrame.isLast()) {
            HttpHeaders.setContentLength(httpResponseWithEntity, 0);
            out.add(httpResponseWithEntity);
          } else {
            // Response body will follow in a series of Data Frames
            putMessage(streamId, httpResponseWithEntity);
          }
        } catch (Exception e) {
          SpdyRstStreamFrame spdyRstStreamFrame =
              new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
          ctx.write(spdyRstStreamFrame);
        }
      } else {
        // SYN_STREAM frames initiated by the client are HTTP requests
        try {
          FullHttpRequest httpRequestWithEntity =
              createHttpRequest(spdyVersion, spdySynStreamFrame);

          // Set the Stream-ID as a header
          SpdyHttpHeaders.setStreamId(httpRequestWithEntity, streamId);

          if (spdySynStreamFrame.isLast()) {
            out.add(httpRequestWithEntity);
          } else {
            // Request body will follow in a series of Data Frames
            putMessage(streamId, httpRequestWithEntity);
          }
        } catch (Exception e) {
          // If a client sends a SYN_STREAM without all of the getMethod, url (host and path),
          // scheme, and version headers the server must reply with a HTTP 400 BAD REQUEST reply.
          // Also sends HTTP 400 BAD REQUEST reply if header name/value pairs are invalid
          SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
          spdySynReplyFrame.setLast(true);
          SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, HttpResponseStatus.BAD_REQUEST);
          SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, HttpVersion.HTTP_1_0);
          ctx.write(spdySynReplyFrame);
        }
      }

    } else if (msg instanceof SpdySynReplyFrame) {

      SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg;
      int streamId = spdySynReplyFrame.getStreamId();

      try {
        FullHttpResponse httpResponseWithEntity =
            createHttpResponse(spdyVersion, spdySynReplyFrame);

        // Set the Stream-ID as a header
        SpdyHttpHeaders.setStreamId(httpResponseWithEntity, streamId);

        if (spdySynReplyFrame.isLast()) {
          HttpHeaders.setContentLength(httpResponseWithEntity, 0);
          out.add(httpResponseWithEntity);
        } else {
          // Response body will follow in a series of Data Frames
          putMessage(streamId, httpResponseWithEntity);
        }
      } catch (Exception e) {
        // If a client receives a SYN_REPLY without valid getStatus and version headers
        // the client must reply with a RST_STREAM frame indicating a PROTOCOL_ERROR
        SpdyRstStreamFrame spdyRstStreamFrame =
            new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
        ctx.write(spdyRstStreamFrame);
      }

    } else if (msg instanceof SpdyHeadersFrame) {

      SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
      int streamId = spdyHeadersFrame.getStreamId();
      FullHttpMessage fullHttpMessage = getMessage(streamId);

      // If message is not in map discard HEADERS frame.
      if (fullHttpMessage == null) {
        return;
      }

      for (Map.Entry<String, String> e : spdyHeadersFrame.headers().entries()) {
        fullHttpMessage.headers().add(e.getKey(), e.getValue());
      }

      if (spdyHeadersFrame.isLast()) {
        HttpHeaders.setContentLength(fullHttpMessage, fullHttpMessage.content().readableBytes());
        removeMessage(streamId);
        out.add(fullHttpMessage);
      }

    } else if (msg instanceof SpdyDataFrame) {

      SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
      int streamId = spdyDataFrame.getStreamId();
      FullHttpMessage fullHttpMessage = getMessage(streamId);

      // If message is not in map discard Data Frame.
      if (fullHttpMessage == null) {
        return;
      }

      ByteBuf content = fullHttpMessage.content();
      if (content.readableBytes() > maxContentLength - spdyDataFrame.content().readableBytes()) {
        removeMessage(streamId);
        throw new TooLongFrameException(
            "HTTP content length exceeded " + maxContentLength + " bytes.");
      }

      ByteBuf spdyDataFrameData = spdyDataFrame.content();
      int spdyDataFrameDataLen = spdyDataFrameData.readableBytes();
      content.writeBytes(spdyDataFrameData, spdyDataFrameData.readerIndex(), spdyDataFrameDataLen);

      if (spdyDataFrame.isLast()) {
        HttpHeaders.setContentLength(fullHttpMessage, content.readableBytes());
        removeMessage(streamId);
        out.add(fullHttpMessage);
      }

    } else if (msg instanceof SpdyRstStreamFrame) {

      SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg;
      int streamId = spdyRstStreamFrame.getStreamId();
      removeMessage(streamId);
    }
  }
예제 #8
0
  @SuppressWarnings("deprecation")
  private SpdySynStreamFrame createSynStreamFrame(HttpMessage httpMessage) throws Exception {
    // Get the Stream-ID, Associated-To-Stream-ID, Priority, URL, and scheme from the headers
    final HttpHeaders httpHeaders = httpMessage.headers();
    int streamID = httpHeaders.getInt(Names.STREAM_ID);
    int associatedToStreamId = httpHeaders.getInt(Names.ASSOCIATED_TO_STREAM_ID, 0);
    byte priority = (byte) httpHeaders.getInt(Names.PRIORITY, 0);
    String URL = httpHeaders.get(Names.URL);
    String scheme = httpHeaders.get(Names.SCHEME);
    httpHeaders.remove(Names.STREAM_ID);
    httpHeaders.remove(Names.ASSOCIATED_TO_STREAM_ID);
    httpHeaders.remove(Names.PRIORITY);
    httpHeaders.remove(Names.URL);
    httpHeaders.remove(Names.SCHEME);

    // 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);

    SpdySynStreamFrame spdySynStreamFrame =
        new DefaultSpdySynStreamFrame(streamID, associatedToStreamId, priority);

    // Unfold the first line of the message into name/value pairs
    SpdyHeaders frameHeaders = spdySynStreamFrame.headers();
    if (httpMessage instanceof FullHttpRequest) {
      HttpRequest httpRequest = (HttpRequest) httpMessage;
      frameHeaders.set(METHOD, httpRequest.method());
      frameHeaders.set(PATH, httpRequest.uri());
      frameHeaders.set(VERSION, httpMessage.protocolVersion());
    }
    if (httpMessage instanceof HttpResponse) {
      HttpResponse httpResponse = (HttpResponse) httpMessage;
      frameHeaders.set(STATUS, httpResponse.status());
      frameHeaders.set(PATH, URL);
      frameHeaders.set(VERSION, httpMessage.protocolVersion());
      spdySynStreamFrame.setUnidirectional(true);
    }

    // Replace the HTTP host header with the SPDY host header
    if (spdyVersion >= 3) {
      CharSequence host = httpHeaders.getUnconverted(HttpHeaders.Names.HOST);
      httpHeaders.remove(HttpHeaders.Names.HOST);
      frameHeaders.set(HOST, host);
    }

    // Set the SPDY scheme header
    if (scheme == null) {
      scheme = "https";
    }
    frameHeaders.set(SCHEME, scheme);

    // Transfer the remaining HTTP headers
    for (Map.Entry<String, String> entry : httpHeaders) {
      frameHeaders.add(entry.getKey(), entry.getValue());
    }
    currentStreamId = spdySynStreamFrame.streamId();
    spdySynStreamFrame.setLast(isLast(httpMessage));

    return spdySynStreamFrame;
  }