SPDY: add support for pushed resources in SpdyHttpDecoder
Motivation: The SPDY/3.1 spec does not adequate describe how to push resources from the server. This was solidified in the HTTP/2 drafts by dividing the push into two frames, a PushPromise containing the request, followed by a Headers frame containing the response. Modifications: This commit modifies the SpdyHttpDecoder to support pushed resources that are divided into multiple frames. The decoder will accept a pushed SpdySynStreamFrame containing the request headers, followed by a SpdyHeadersFrame containing the response headers. Result: The SpdyHttpDecoder will create an HttpRequest object followed by an HttpResponse object when receiving pushed resources.
This commit is contained in:
parent
28c388e525
commit
3868645d7d
@ -137,7 +137,7 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
|||||||
int associatedToStreamId = spdySynStreamFrame.associatedStreamId();
|
int associatedToStreamId = spdySynStreamFrame.associatedStreamId();
|
||||||
|
|
||||||
// If a client receives a SYN_STREAM with an Associated-To-Stream-ID of 0
|
// 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
|
// it must reply with a RST_STREAM with error code INVALID_STREAM.
|
||||||
if (associatedToStreamId == 0) {
|
if (associatedToStreamId == 0) {
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame =
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INVALID_STREAM);
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INVALID_STREAM);
|
||||||
@ -145,12 +145,10 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CharSequence URL = spdySynStreamFrame.headers().get(PATH);
|
// If a client receives a SYN_STREAM with isLast set,
|
||||||
spdySynStreamFrame.headers().remove(PATH);
|
// reply with a RST_STREAM with error code PROTOCOL_ERROR
|
||||||
|
// (we only support pushed resources divided into two header blocks).
|
||||||
// If a client receives a SYN_STREAM without a 'url' header
|
if (spdySynStreamFrame.isLast()) {
|
||||||
// it must reply with a RST_STREAM with error code PROTOCOL_ERROR
|
|
||||||
if (URL == null) {
|
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame =
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
ctx.writeAndFlush(spdyRstStreamFrame);
|
ctx.writeAndFlush(spdyRstStreamFrame);
|
||||||
@ -167,22 +165,15 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
FullHttpResponse httpResponseWithEntity =
|
FullHttpRequest httpRequestWithEntity = createHttpRequest(spdyVersion, spdySynStreamFrame);
|
||||||
createHttpResponse(ctx, spdySynStreamFrame, validateHeaders);
|
|
||||||
|
|
||||||
// Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
|
// Set the Stream-ID, Associated-To-Stream-ID, iand Priority as headers
|
||||||
httpResponseWithEntity.headers().setInt(Names.STREAM_ID, streamId);
|
httpRequestWithEntity.headers().setInt(Names.STREAM_ID, streamId);
|
||||||
httpResponseWithEntity.headers().setInt(Names.ASSOCIATED_TO_STREAM_ID, associatedToStreamId);
|
httpRequestWithEntity.headers().setInt(Names.ASSOCIATED_TO_STREAM_ID, associatedToStreamId);
|
||||||
httpResponseWithEntity.headers().setByte(Names.PRIORITY, spdySynStreamFrame.priority());
|
httpRequestWithEntity.headers().setByte(Names.PRIORITY, spdySynStreamFrame.priority());
|
||||||
httpResponseWithEntity.headers().set(Names.URL, URL);
|
|
||||||
|
out.add(httpRequestWithEntity);
|
||||||
|
|
||||||
if (spdySynStreamFrame.isLast()) {
|
|
||||||
HttpHeaderUtil.setContentLength(httpResponseWithEntity, 0);
|
|
||||||
out.add(httpResponseWithEntity);
|
|
||||||
} else {
|
|
||||||
// Response body will follow in a series of Data Frames
|
|
||||||
putMessage(streamId, httpResponseWithEntity);
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame =
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
@ -269,8 +260,40 @@ public class SpdyHttpDecoder extends MessageToMessageDecoder<SpdyFrame> {
|
|||||||
int streamId = spdyHeadersFrame.streamId();
|
int streamId = spdyHeadersFrame.streamId();
|
||||||
FullHttpMessage fullHttpMessage = getMessage(streamId);
|
FullHttpMessage fullHttpMessage = getMessage(streamId);
|
||||||
|
|
||||||
// If message is not in map discard HEADERS frame.
|
|
||||||
if (fullHttpMessage == null) {
|
if (fullHttpMessage == null) {
|
||||||
|
// HEADERS frames may initiate a pushed response
|
||||||
|
if (SpdyCodecUtil.isServerId(streamId)) {
|
||||||
|
|
||||||
|
// If a client receives a HEADERS with a truncated header block,
|
||||||
|
// reply with a RST_STREAM frame with error code INTERNAL_ERROR.
|
||||||
|
if (spdyHeadersFrame.isTruncated()) {
|
||||||
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.INTERNAL_ERROR);
|
||||||
|
ctx.writeAndFlush(spdyRstStreamFrame);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
fullHttpMessage = createHttpResponse(ctx, spdyHeadersFrame, validateHeaders);
|
||||||
|
|
||||||
|
// Set the Stream-ID as a header
|
||||||
|
fullHttpMessage.headers().setInt(Names.STREAM_ID, streamId);
|
||||||
|
|
||||||
|
if (spdyHeadersFrame.isLast()) {
|
||||||
|
HttpHeaderUtil.setContentLength(fullHttpMessage, 0);
|
||||||
|
out.add(fullHttpMessage);
|
||||||
|
} else {
|
||||||
|
// Response body will follow in a series of Data Frames
|
||||||
|
putMessage(streamId, fullHttpMessage);
|
||||||
|
}
|
||||||
|
} 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.writeAndFlush(spdyRstStreamFrame);
|
||||||
|
}
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user