Landing Recent QUIC changes until 06/17/2015 14:59.
[chromium-blink-merge.git] / net / tools / quic / quic_spdy_server_stream.cc
blobd43e65e39a5e8179de581917b6288a0d25bb5ae8
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "net/tools/quic/quic_spdy_server_stream.h"
7 #include "base/logging.h"
8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "net/quic/quic_data_stream.h"
11 #include "net/quic/quic_spdy_session.h"
12 #include "net/quic/spdy_utils.h"
13 #include "net/spdy/spdy_protocol.h"
14 #include "net/tools/quic/quic_in_memory_cache.h"
16 using base::StringPiece;
17 using base::StringToInt;
18 using std::string;
20 namespace net {
21 namespace tools {
23 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id,
24 QuicSpdySession* session)
25 : QuicDataStream(id, session), content_length_(-1) {
28 QuicSpdyServerStream::~QuicSpdyServerStream() {
31 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) {
32 if (!headers_decompressed()) {
33 // Let the headers data accumulate in the underlying QuicDataStream.
34 return 0;
36 if (request_headers_.empty()) {
37 if (!ParseRequestHeaders(data, data_len)) {
38 // Headers were invalid.
39 SendErrorResponse();
40 return 0;
42 } else {
43 body_.append(data, data_len);
45 DCHECK(!request_headers_.empty());
46 if (content_length_ >= 0 &&
47 static_cast<int>(body_.size()) > content_length_) {
48 SendErrorResponse();
49 return 0;
51 DVLOG(1) << "Processed " << data_len << " bytes for stream " << id();
52 return data_len;
55 void QuicSpdyServerStream::OnFinRead() {
56 ReliableQuicStream::OnFinRead();
57 if (write_side_closed() || fin_buffered()) {
58 return;
61 if (request_headers_.empty()) {
62 SendErrorResponse();
63 return;
66 if (content_length_ > 0 &&
67 content_length_ != static_cast<int>(body_.size())) {
68 SendErrorResponse();
69 return;
72 SendResponse();
75 bool QuicSpdyServerStream::ParseRequestHeaders(const char* data,
76 uint32 data_len) {
77 DCHECK(headers_decompressed());
78 SpdyFramer framer(SPDY3);
79 size_t len = framer.ParseHeaderBlockInBuffer(data,
80 data_len,
81 &request_headers_);
82 DCHECK_LE(len, data_len);
83 if (len == 0 || request_headers_.empty()) {
84 return false; // Headers were invalid.
87 if (data_len > len) {
88 body_.append(data + len, data_len - len);
90 if (ContainsKey(request_headers_, "content-length") &&
91 !StringToInt(request_headers_["content-length"], &content_length_)) {
92 return false; // Invalid content-length.
94 return true;
97 void QuicSpdyServerStream::SendResponse() {
98 if (!ContainsKey(request_headers_, GetHostKey()) ||
99 !ContainsKey(request_headers_, ":path")) {
100 SendErrorResponse();
101 return;
104 // Find response in cache. If not found, send error response.
105 const QuicInMemoryCache::Response* response =
106 QuicInMemoryCache::GetInstance()->GetResponse(
107 request_headers_[GetHostKey()], request_headers_[":path"]);
108 if (response == nullptr) {
109 SendErrorResponse();
110 return;
113 if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
114 DVLOG(1) << "Special response: closing connection.";
115 CloseConnection(QUIC_NO_ERROR);
116 return;
119 if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
120 DVLOG(1) << "Special response: ignoring request.";
121 return;
124 DVLOG(1) << "Sending response for stream " << id();
125 if (version() > QUIC_VERSION_24) {
126 SendHeadersAndBody(
127 SpdyUtils::ConvertSpdy3ResponseHeadersToSpdy4(response->headers()),
128 response->body());
129 return;
132 SendHeadersAndBody(response->headers(), response->body());
135 void QuicSpdyServerStream::SendErrorResponse() {
136 DVLOG(1) << "Sending error response for stream " << id();
137 SpdyHeaderBlock headers;
138 if (version() <= QUIC_VERSION_24) {
139 headers[":version"] = "HTTP/1.1";
140 headers[":status"] = "500 Server Error";
141 } else {
142 headers[":status"] = "500";
144 headers["content-length"] = "3";
145 SendHeadersAndBody(headers, "bad");
148 void QuicSpdyServerStream::SendHeadersAndBody(
149 const SpdyHeaderBlock& response_headers,
150 StringPiece body) {
151 // We only support SPDY and HTTP, and neither handles bidirectional streaming.
152 if (!read_side_closed()) {
153 CloseReadSide();
156 WriteHeaders(response_headers, body.empty(), nullptr);
158 if (!body.empty()) {
159 WriteOrBufferData(body, true, nullptr);
163 const string QuicSpdyServerStream::GetHostKey() {
164 // SPDY/4 uses ":authority" instead of ":host".
165 return version() > QUIC_VERSION_24 ? ":authority" : ":host";
168 } // namespace tools
169 } // namespace net