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_session.h"
11 #include "net/spdy/spdy_protocol.h"
12 #include "net/tools/quic/quic_in_memory_cache.h"
13 #include "net/tools/quic/spdy_utils.h"
15 using base::StringPiece
;
16 using base::StringToInt
;
22 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id
,
24 : QuicDataStream(id
, session
),
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.
36 if (request_headers_
.empty()) {
37 if (!ParseRequestHeaders(data
, data_len
)) {
38 // Headers were invalid.
43 body_
.append(data
, data_len
);
45 DCHECK(!request_headers_
.empty());
46 if (content_length_
>= 0 &&
47 static_cast<int>(body_
.size()) > content_length_
) {
51 DVLOG(1) << "Processed " << data_len
<< " bytes for stream " << id();
55 void QuicSpdyServerStream::OnFinRead() {
56 ReliableQuicStream::OnFinRead();
57 if (write_side_closed() || fin_buffered()) {
61 if (request_headers_
.empty()) {
66 if (content_length_
> 0 &&
67 content_length_
!= static_cast<int>(body_
.size())) {
75 bool QuicSpdyServerStream::ParseRequestHeaders(const char* data
,
77 DCHECK(headers_decompressed());
78 SpdyFramer
framer(SPDY3
);
79 size_t len
= framer
.ParseHeaderBlockInBuffer(data
,
82 DCHECK_LE(len
, data_len
);
83 if (len
== 0 || request_headers_
.empty()) {
84 return false; // Headers were invalid.
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.
97 void QuicSpdyServerStream::SendResponse() {
98 if (!ContainsKey(request_headers_
, ":host") ||
99 !ContainsKey(request_headers_
, ":path")) {
104 // Find response in cache. If not found, send error response.
105 const QuicInMemoryCache::Response
* response
=
106 QuicInMemoryCache::GetInstance()->GetResponse(
107 request_headers_
[":host"],
108 request_headers_
[":path"]);
109 if (response
== nullptr) {
114 if (response
->response_type() == QuicInMemoryCache::CLOSE_CONNECTION
) {
115 DVLOG(1) << "Special response: closing connection.";
116 CloseConnection(QUIC_NO_ERROR
);
120 if (response
->response_type() == QuicInMemoryCache::IGNORE_REQUEST
) {
121 DVLOG(1) << "Special response: ignoring request.";
125 DVLOG(1) << "Sending response for stream " << id();
126 SendHeadersAndBody(response
->headers(), response
->body());
129 void QuicSpdyServerStream::SendErrorResponse() {
130 DVLOG(1) << "Sending error response for stream " << id();
131 SpdyHeaderBlock headers
;
132 headers
[":version"] = "HTTP/1.1";
133 headers
[":status"] = "500 Server Error";
134 headers
["content-length"] = "3";
135 SendHeadersAndBody(headers
, "bad");
138 void QuicSpdyServerStream::SendHeadersAndBody(
139 const SpdyHeaderBlock
& response_headers
,
141 // We only support SPDY and HTTP, and neither handles bidirectional streaming.
142 if (!read_side_closed()) {
146 WriteHeaders(response_headers
, body
.empty(), nullptr);
149 WriteOrBufferData(body
, true, nullptr);