If there are no local credentials for a locked profile, show sign in button
[chromium-blink-merge.git] / net / tools / quic / quic_spdy_server_stream.cc
blobc47fc0c12890cdbebcff029ff0a61e81563e9e95
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 void QuicSpdyServerStream::OnStreamHeadersComplete(bool fin, size_t frame_len) {
32 QuicDataStream::OnStreamHeadersComplete(fin, frame_len);
33 if (!ParseRequestHeaders(decompressed_headers().data(),
34 decompressed_headers().length())) {
35 // Headers were invalid.
36 SendErrorResponse();
38 MarkHeadersConsumed(decompressed_headers().length());
41 void QuicSpdyServerStream::OnDataAvailable() {
42 while (HasBytesToRead()) {
43 struct iovec iov;
44 if (GetReadableRegions(&iov, 1) == 0) {
45 // No more data to read.
46 break;
48 DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " << id();
49 body_.append(static_cast<char*>(iov.iov_base), iov.iov_len);
51 if (content_length_ >= 0 &&
52 static_cast<int>(body_.size()) > content_length_) {
53 SendErrorResponse();
54 return;
56 MarkConsumed(iov.iov_len);
58 if (!sequencer()->IsClosed()) {
59 sequencer()->SetUnblocked();
60 return;
63 // If the sequencer is closed, then the all the body, including the fin,
64 // has been consumed.
65 OnFinRead();
67 if (write_side_closed() || fin_buffered()) {
68 return;
71 if (request_headers_.empty()) {
72 SendErrorResponse();
73 return;
76 if (content_length_ > 0 &&
77 content_length_ != static_cast<int>(body_.size())) {
78 SendErrorResponse();
79 return;
82 SendResponse();
85 bool QuicSpdyServerStream::ParseRequestHeaders(const char* data,
86 uint32 data_len) {
87 DCHECK(headers_decompressed());
88 SpdyFramer framer(HTTP2);
89 size_t len = framer.ParseHeaderBlockInBuffer(data,
90 data_len,
91 &request_headers_);
92 DCHECK_LE(len, data_len);
93 if (len == 0 || request_headers_.empty()) {
94 return false; // Headers were invalid.
97 if (data_len > len) {
98 body_.append(data + len, data_len - len);
100 if (ContainsKey(request_headers_, "content-length") &&
101 !StringToInt(request_headers_["content-length"], &content_length_)) {
102 return false; // Invalid content-length.
104 return true;
107 void QuicSpdyServerStream::SendResponse() {
108 if (!ContainsKey(request_headers_, GetHostKey()) ||
109 !ContainsKey(request_headers_, ":path")) {
110 SendErrorResponse();
111 return;
114 // Find response in cache. If not found, send error response.
115 const QuicInMemoryCache::Response* response =
116 QuicInMemoryCache::GetInstance()->GetResponse(
117 request_headers_[GetHostKey()], request_headers_[":path"]);
118 if (response == nullptr) {
119 SendErrorResponse();
120 return;
123 if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) {
124 DVLOG(1) << "Special response: closing connection.";
125 CloseConnection(QUIC_NO_ERROR);
126 return;
129 if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) {
130 DVLOG(1) << "Special response: ignoring request.";
131 return;
134 DVLOG(1) << "Sending response for stream " << id();
135 if (version() > QUIC_VERSION_24) {
136 SendHeadersAndBody(
137 SpdyUtils::ConvertSpdy3ResponseHeadersToSpdy4(response->headers()),
138 response->body());
139 return;
142 SendHeadersAndBody(response->headers(), response->body());
145 void QuicSpdyServerStream::SendErrorResponse() {
146 DVLOG(1) << "Sending error response for stream " << id();
147 SpdyHeaderBlock headers;
148 if (version() <= QUIC_VERSION_24) {
149 headers[":version"] = "HTTP/1.1";
150 headers[":status"] = "500 Server Error";
151 } else {
152 headers[":status"] = "500";
154 headers["content-length"] = "3";
155 SendHeadersAndBody(headers, "bad");
158 void QuicSpdyServerStream::SendHeadersAndBody(
159 const SpdyHeaderBlock& response_headers,
160 StringPiece body) {
161 // We only support SPDY and HTTP, and neither handles bidirectional streaming.
162 if (!read_side_closed()) {
163 CloseReadSide();
166 WriteHeaders(response_headers, body.empty(), nullptr);
168 if (!body.empty()) {
169 WriteOrBufferData(body, true, nullptr);
173 const string QuicSpdyServerStream::GetHostKey() {
174 // SPDY/4 uses ":authority" instead of ":host".
175 return version() > QUIC_VERSION_24 ? ":authority" : ":host";
178 } // namespace tools
179 } // namespace net