| Index: net/tools/quic/quic_spdy_server_stream.cc
|
| diff --git a/net/tools/quic/quic_spdy_server_stream.cc b/net/tools/quic/quic_spdy_server_stream.cc
|
| index 5937d6d6253a50e3024fb81d20e5f3fa1f06309e..7a0563d87d64f480dad16cf0e52ab9200ea56e53 100644
|
| --- a/net/tools/quic/quic_spdy_server_stream.cc
|
| +++ b/net/tools/quic/quic_spdy_server_stream.cc
|
| @@ -4,7 +4,7 @@
|
|
|
| #include "net/tools/quic/quic_spdy_server_stream.h"
|
|
|
| -#include "base/memory/singleton.h"
|
| +#include "base/strings/string_number_conversions.h"
|
| #include "net/quic/quic_session.h"
|
| #include "net/spdy/spdy_framer.h"
|
| #include "net/tools/quic/quic_in_memory_cache.h"
|
| @@ -12,39 +12,41 @@
|
| #include "url/gurl.h"
|
|
|
| using base::StringPiece;
|
| +using base::StringToInt;
|
| using std::string;
|
|
|
| namespace net {
|
| namespace tools {
|
|
|
| -static const size_t kHeaderBufInitialSize = 4096;
|
| -
|
| QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
|
| QuicSession* session)
|
| : QuicDataStream(id, session),
|
| - read_buf_(new GrowableIOBuffer()),
|
| - request_headers_received_(false) {
|
| + content_length_(-1) {
|
| }
|
|
|
| QuicSpdyServerStream::~QuicSpdyServerStream() {
|
| }
|
|
|
| uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
|
| - uint32 total_bytes_processed = 0;
|
| -
|
| - // Are we still reading the request headers.
|
| - if (!request_headers_received_) {
|
| - // Grow the read buffer if necessary.
|
| - if (read_buf_->RemainingCapacity() < (int)data_len) {
|
| - read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize);
|
| + if (!headers_decompressed()) {
|
| + // Let the headers data accumulate in the underlying QuicDataStream.
|
| + return 0;
|
| + }
|
| + if (request_headers_.empty()) {
|
| + if (!ParseRequestHeaders(data, data_len)) {
|
| + // Headers were invalid.
|
| + SendErrorResponse();
|
| + return 0;
|
| }
|
| - memcpy(read_buf_->data(), data, data_len);
|
| - read_buf_->set_offset(read_buf_->offset() + data_len);
|
| - ParseRequestHeaders();
|
| } else {
|
| - body_.append(data + total_bytes_processed,
|
| - data_len - total_bytes_processed);
|
| + body_.append(data, data_len);
|
| }
|
| + DCHECK(!request_headers_.empty());
|
| + if (content_length_ > 0 && static_cast<int>(body_.size()) > content_length_) {
|
| + SendErrorResponse();
|
| + return 0;
|
| + }
|
| + DVLOG(1) << "Processed " << data_len << " bytes for stream " << id();
|
| return data_len;
|
| }
|
|
|
| @@ -54,52 +56,54 @@ void QuicSpdyServerStream::OnFinRead() {
|
| return;
|
| }
|
|
|
| - if (!request_headers_received_) {
|
| - SendErrorResponse(); // We're not done reading headers.
|
| - } else if ((headers_.content_length_status() ==
|
| - BalsaHeadersEnums::VALID_CONTENT_LENGTH) &&
|
| - body_.size() != headers_.content_length()) {
|
| - SendErrorResponse(); // Invalid content length
|
| - } else {
|
| - SendResponse();
|
| - }
|
| -}
|
| -
|
| -void QuicSpdyServerStream::ParseRequestHeaders() {
|
| - size_t read_buf_len = static_cast<size_t>(read_buf_->offset());
|
| - SpdyFramer framer(SPDY3);
|
| - SpdyHeaderBlock headers;
|
| - char* data = read_buf_->StartOfBuffer();
|
| - size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(),
|
| - &headers);
|
| - if (len == 0) {
|
| + if (request_headers_.empty()) {
|
| + SendErrorResponse();
|
| return;
|
| }
|
|
|
| - if (!SpdyUtils::FillBalsaRequestHeaders(headers, &headers_)) {
|
| + if (content_length_ > 0 &&
|
| + content_length_ != static_cast<int>(body_.size())) {
|
| SendErrorResponse();
|
| return;
|
| }
|
|
|
| - size_t delta = read_buf_len - len;
|
| - if (delta > 0) {
|
| - body_.append(data + len, delta);
|
| + SendResponse();
|
| +}
|
| +
|
| +bool QuicSpdyServerStream::ParseRequestHeaders(const char* data,
|
| + uint32 data_len) {
|
| + DCHECK(headers_decompressed());
|
| + SpdyFramer framer(SPDY3);
|
| + size_t len = framer.ParseHeaderBlockInBuffer(data,
|
| + data_len,
|
| + &request_headers_);
|
| + DCHECK_LE(len, data_len);
|
| + if (len == 0 || request_headers_.empty()) {
|
| + return false; // Headers were invalid.
|
| }
|
|
|
| - request_headers_received_ = true;
|
| + if (data_len > len) {
|
| + body_.append(data + len, data_len - len);
|
| + }
|
| + if (ContainsKey(request_headers_, "content-length") &&
|
| + !StringToInt(request_headers_["content-length"], &content_length_)) {
|
| + return false; // Invalid content-length.
|
| + }
|
| + return true;
|
| }
|
|
|
| void QuicSpdyServerStream::SendResponse() {
|
| - // Find response in cache. If not found, send error response.
|
| - GURL url(headers_.request_uri().as_string());
|
| - if (!url.is_valid()) {
|
| + if (!ContainsKey(request_headers_, ":host") ||
|
| + !ContainsKey(request_headers_, ":path")) {
|
| SendErrorResponse();
|
| return;
|
| }
|
| +
|
| + // Find response in cache. If not found, send error response.
|
| const QuicInMemoryCache::Response* response =
|
| QuicInMemoryCache::GetInstance()->GetResponse(
|
| - url.host(),
|
| - url.PathForRequest());
|
| + request_headers_[":host"],
|
| + request_headers_[":path"]);
|
| if (response == nullptr) {
|
| SendErrorResponse();
|
| return;
|
| @@ -122,25 +126,22 @@ void QuicSpdyServerStream::SendResponse() {
|
|
|
| void QuicSpdyServerStream::SendErrorResponse() {
|
| DVLOG(1) << "Sending error response for stream " << id();
|
| - BalsaHeaders headers;
|
| - headers.SetResponseFirstlineFromStringPieces(
|
| - "HTTP/1.1", "500", "Server Error");
|
| - headers.ReplaceOrAppendHeader("content-length", "3");
|
| + SpdyHeaderBlock headers;
|
| + headers[":version"] = "HTTP/1.1";
|
| + headers[":status"] = "500 Server Error";
|
| + headers["content-length"] = "3";
|
| SendHeadersAndBody(headers, "bad");
|
| }
|
|
|
| void QuicSpdyServerStream::SendHeadersAndBody(
|
| - const BalsaHeaders& response_headers,
|
| + const SpdyHeaderBlock& response_headers,
|
| StringPiece body) {
|
| // We only support SPDY and HTTP, and neither handles bidirectional streaming.
|
| if (!read_side_closed()) {
|
| CloseReadSide();
|
| }
|
|
|
| - SpdyHeaderBlock header_block =
|
| - SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers);
|
| -
|
| - WriteHeaders(header_block, body.empty(), nullptr);
|
| + WriteHeaders(response_headers, body.empty(), nullptr);
|
|
|
| if (!body.empty()) {
|
| WriteOrBufferData(body, true, nullptr);
|
|
|