SPDY: refactor SpdyHttpDecoder to allow subclasses to access messageMap
This commit is contained in:
parent
a00f9f0b70
commit
79648026ff
@ -45,7 +45,7 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
|
|
||||||
private final int spdyVersion;
|
private final int spdyVersion;
|
||||||
private final int maxContentLength;
|
private final int maxContentLength;
|
||||||
private final Map<Integer, HttpMessage> messageMap = new HashMap<Integer, HttpMessage>();
|
private final Map<Integer, HttpMessage> messageMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new instance for the SPDY/2 protocol
|
* Creates a new instance for the SPDY/2 protocol
|
||||||
@ -68,6 +68,19 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
* a {@link TooLongFrameException} will be raised.
|
* a {@link TooLongFrameException} will be raised.
|
||||||
*/
|
*/
|
||||||
public SpdyHttpDecoder(int version, int maxContentLength) {
|
public SpdyHttpDecoder(int version, int maxContentLength) {
|
||||||
|
this(version, maxContentLength, new HashMap<Integer, HttpMessage>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new instance with the specified parameters.
|
||||||
|
*
|
||||||
|
* @param version the protocol version
|
||||||
|
* @param maxContentLength the maximum length of the message content.
|
||||||
|
* If the length of the message content exceeds this value,
|
||||||
|
* a {@link TooLongFrameException} will be raised.
|
||||||
|
* @param messageMap the {@link Map} used to hold partially received messages.
|
||||||
|
*/
|
||||||
|
protected SpdyHttpDecoder(int version, int maxContentLength, Map<Integer, HttpMessage> messageMap) {
|
||||||
if (version < SPDY_MIN_VERSION || version > SPDY_MAX_VERSION) {
|
if (version < SPDY_MIN_VERSION || version > SPDY_MAX_VERSION) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"unsupported version: " + version);
|
"unsupported version: " + version);
|
||||||
@ -78,6 +91,19 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
}
|
}
|
||||||
spdyVersion = version;
|
spdyVersion = version;
|
||||||
this.maxContentLength = maxContentLength;
|
this.maxContentLength = maxContentLength;
|
||||||
|
this.messageMap = messageMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpMessage putMessage(int streamId, HttpMessage message) {
|
||||||
|
return messageMap.put(streamId, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpMessage getMessage(int streamId) {
|
||||||
|
return messageMap.get(streamId);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected HttpMessage removeMessage(int streamId) {
|
||||||
|
return messageMap.remove(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -88,17 +114,17 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
|
|
||||||
// HTTP requests/responses are mapped one-to-one to SPDY streams.
|
// HTTP requests/responses are mapped one-to-one to SPDY streams.
|
||||||
SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
|
SpdySynStreamFrame spdySynStreamFrame = (SpdySynStreamFrame) msg;
|
||||||
int streamID = spdySynStreamFrame.getStreamId();
|
int streamId = spdySynStreamFrame.getStreamId();
|
||||||
|
|
||||||
if (isServerId(streamID)) {
|
if (isServerId(streamId)) {
|
||||||
// SYN_STREAM frames initiated by the server are pushed resources
|
// SYN_STREAM frames initiated by the server are pushed resources
|
||||||
int associatedToStreamID = spdySynStreamFrame.getAssociatedToStreamId();
|
int associatedToStreamId = spdySynStreamFrame.getAssociatedToStreamId();
|
||||||
|
|
||||||
// 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);
|
||||||
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +134,7 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
// it must reply with a RST_STREAM with error code PROTOCOL_ERROR
|
// it must reply with a RST_STREAM with error code PROTOCOL_ERROR
|
||||||
if (URL == null) {
|
if (URL == null) {
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame =
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
new DefaultSpdyRstStreamFrame(streamID, SpdyStreamStatus.PROTOCOL_ERROR);
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,8 +142,8 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynStreamFrame);
|
HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynStreamFrame);
|
||||||
|
|
||||||
// Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
|
// Set the Stream-ID, Associated-To-Stream-ID, Priority, and URL as headers
|
||||||
SpdyHttpHeaders.setStreamId(httpResponse, streamID);
|
SpdyHttpHeaders.setStreamId(httpResponse, streamId);
|
||||||
SpdyHttpHeaders.setAssociatedToStreamId(httpResponse, associatedToStreamID);
|
SpdyHttpHeaders.setAssociatedToStreamId(httpResponse, associatedToStreamId);
|
||||||
SpdyHttpHeaders.setPriority(httpResponse, spdySynStreamFrame.getPriority());
|
SpdyHttpHeaders.setPriority(httpResponse, spdySynStreamFrame.getPriority());
|
||||||
SpdyHttpHeaders.setUrl(httpResponse, URL);
|
SpdyHttpHeaders.setUrl(httpResponse, URL);
|
||||||
|
|
||||||
@ -126,11 +152,11 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
return httpResponse;
|
return httpResponse;
|
||||||
} else {
|
} else {
|
||||||
// Response body will follow in a series of Data Frames
|
// Response body will follow in a series of Data Frames
|
||||||
messageMap.put(streamID, httpResponse);
|
putMessage(streamId, httpResponse);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame =
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
new DefaultSpdyRstStreamFrame(streamID, SpdyStreamStatus.PROTOCOL_ERROR);
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -139,19 +165,19 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
HttpRequest httpRequest = createHttpRequest(spdyVersion, spdySynStreamFrame);
|
HttpRequest httpRequest = createHttpRequest(spdyVersion, spdySynStreamFrame);
|
||||||
|
|
||||||
// Set the Stream-ID as a header
|
// Set the Stream-ID as a header
|
||||||
SpdyHttpHeaders.setStreamId(httpRequest, streamID);
|
SpdyHttpHeaders.setStreamId(httpRequest, streamId);
|
||||||
|
|
||||||
if (spdySynStreamFrame.isLast()) {
|
if (spdySynStreamFrame.isLast()) {
|
||||||
return httpRequest;
|
return httpRequest;
|
||||||
} else {
|
} else {
|
||||||
// Request body will follow in a series of Data Frames
|
// Request body will follow in a series of Data Frames
|
||||||
messageMap.put(streamID, httpRequest);
|
putMessage(streamId, httpRequest);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// If a client sends a SYN_STREAM without all of the method, url (host and path),
|
// If a client sends a SYN_STREAM without all of the method, url (host and path),
|
||||||
// scheme, and version headers the server must reply with a HTTP 400 BAD REQUEST reply.
|
// 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
|
// Also sends HTTP 400 BAD REQUEST reply if header name/value pairs are invalid
|
||||||
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamID);
|
SpdySynReplyFrame spdySynReplyFrame = new DefaultSpdySynReplyFrame(streamId);
|
||||||
spdySynReplyFrame.setLast(true);
|
spdySynReplyFrame.setLast(true);
|
||||||
SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, HttpResponseStatus.BAD_REQUEST);
|
SpdyHeaders.setStatus(spdyVersion, spdySynReplyFrame, HttpResponseStatus.BAD_REQUEST);
|
||||||
SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, HttpVersion.HTTP_1_0);
|
SpdyHeaders.setVersion(spdyVersion, spdySynReplyFrame, HttpVersion.HTTP_1_0);
|
||||||
@ -162,37 +188,36 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
} else if (msg instanceof SpdySynReplyFrame) {
|
} else if (msg instanceof SpdySynReplyFrame) {
|
||||||
|
|
||||||
SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg;
|
SpdySynReplyFrame spdySynReplyFrame = (SpdySynReplyFrame) msg;
|
||||||
int streamID = spdySynReplyFrame.getStreamId();
|
int streamId = spdySynReplyFrame.getStreamId();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynReplyFrame);
|
HttpResponse httpResponse = createHttpResponse(spdyVersion, spdySynReplyFrame);
|
||||||
|
|
||||||
// Set the Stream-ID as a header
|
// Set the Stream-ID as a header
|
||||||
SpdyHttpHeaders.setStreamId(httpResponse, streamID);
|
SpdyHttpHeaders.setStreamId(httpResponse, streamId);
|
||||||
|
|
||||||
if (spdySynReplyFrame.isLast()) {
|
if (spdySynReplyFrame.isLast()) {
|
||||||
HttpHeaders.setContentLength(httpResponse, 0);
|
HttpHeaders.setContentLength(httpResponse, 0);
|
||||||
return httpResponse;
|
return httpResponse;
|
||||||
} else {
|
} else {
|
||||||
// Response body will follow in a series of Data Frames
|
// Response body will follow in a series of Data Frames
|
||||||
messageMap.put(streamID, httpResponse);
|
putMessage(streamId, httpResponse);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
// If a client receives a SYN_REPLY without valid status and version headers
|
// If a client receives a SYN_REPLY without valid status and version headers
|
||||||
// the client must reply with a RST_STREAM frame indicating a PROTOCOL_ERROR
|
// the client must reply with a RST_STREAM frame indicating a PROTOCOL_ERROR
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame =
|
SpdyRstStreamFrame spdyRstStreamFrame =
|
||||||
new DefaultSpdyRstStreamFrame(streamID, SpdyStreamStatus.PROTOCOL_ERROR);
|
new DefaultSpdyRstStreamFrame(streamId, SpdyStreamStatus.PROTOCOL_ERROR);
|
||||||
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
Channels.write(ctx, Channels.future(channel), spdyRstStreamFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (msg instanceof SpdyHeadersFrame) {
|
} else if (msg instanceof SpdyHeadersFrame) {
|
||||||
|
|
||||||
SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
|
SpdyHeadersFrame spdyHeadersFrame = (SpdyHeadersFrame) msg;
|
||||||
Integer streamID = spdyHeadersFrame.getStreamId();
|
Integer streamId = spdyHeadersFrame.getStreamId();
|
||||||
HttpMessage httpMessage = messageMap.get(streamID);
|
HttpMessage httpMessage = getMessage(streamId);
|
||||||
|
|
||||||
// If message is not in map discard HEADERS frame.
|
// If message is not in map discard HEADERS frame.
|
||||||
// SpdySessionHandler should prevent this from happening.
|
|
||||||
if (httpMessage == null) {
|
if (httpMessage == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@ -201,21 +226,25 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
httpMessage.addHeader(e.getKey(), e.getValue());
|
httpMessage.addHeader(e.getKey(), e.getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (spdyHeadersFrame.isLast()) {
|
||||||
|
removeMessage(streamId);
|
||||||
|
return httpMessage;
|
||||||
|
}
|
||||||
|
|
||||||
} else if (msg instanceof SpdyDataFrame) {
|
} else if (msg instanceof SpdyDataFrame) {
|
||||||
|
|
||||||
SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
|
SpdyDataFrame spdyDataFrame = (SpdyDataFrame) msg;
|
||||||
Integer streamID = spdyDataFrame.getStreamId();
|
Integer streamId = spdyDataFrame.getStreamId();
|
||||||
HttpMessage httpMessage = messageMap.get(streamID);
|
HttpMessage httpMessage = getMessage(streamId);
|
||||||
|
|
||||||
// If message is not in map discard Data Frame.
|
// If message is not in map discard Data Frame.
|
||||||
// SpdySessionHandler should prevent this from happening.
|
|
||||||
if (httpMessage == null) {
|
if (httpMessage == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
ChannelBuffer content = httpMessage.getContent();
|
ChannelBuffer content = httpMessage.getContent();
|
||||||
if (content.readableBytes() > maxContentLength - spdyDataFrame.getData().readableBytes()) {
|
if (content.readableBytes() > maxContentLength - spdyDataFrame.getData().readableBytes()) {
|
||||||
messageMap.remove(streamID);
|
removeMessage(streamId);
|
||||||
throw new TooLongFrameException(
|
throw new TooLongFrameException(
|
||||||
"HTTP content length exceeded " + maxContentLength + " bytes.");
|
"HTTP content length exceeded " + maxContentLength + " bytes.");
|
||||||
}
|
}
|
||||||
@ -230,15 +259,15 @@ public class SpdyHttpDecoder extends OneToOneDecoder {
|
|||||||
|
|
||||||
if (spdyDataFrame.isLast()) {
|
if (spdyDataFrame.isLast()) {
|
||||||
HttpHeaders.setContentLength(httpMessage, content.readableBytes());
|
HttpHeaders.setContentLength(httpMessage, content.readableBytes());
|
||||||
messageMap.remove(streamID);
|
removeMessage(streamId);
|
||||||
return httpMessage;
|
return httpMessage;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (msg instanceof SpdyRstStreamFrame) {
|
} else if (msg instanceof SpdyRstStreamFrame) {
|
||||||
|
|
||||||
SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg;
|
SpdyRstStreamFrame spdyRstStreamFrame = (SpdyRstStreamFrame) msg;
|
||||||
Integer streamID = spdyRstStreamFrame.getStreamId();
|
Integer streamId = spdyRstStreamFrame.getStreamId();
|
||||||
messageMap.remove(streamID);
|
removeMessage(streamId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
Loading…
Reference in New Issue
Block a user