Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(114)

Side by Side Diff: net/tools/quic/quic_simple_server_stream.cc

Issue 1777083002: Make QuicSimpleServerStream supports multipart response body (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@quicsmaller
Patch Set: Rebased Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « net/tools/quic/quic_simple_server_stream.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/tools/quic/quic_simple_server_stream.h" 5 #include "net/tools/quic/quic_simple_server_stream.h"
6 6
7 #include "base/logging.h" 7 #include "base/logging.h"
8 #include "base/stl_util.h" 8 #include "base/stl_util.h"
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_piece.h" 10 #include "base/strings/string_piece.h"
11 #include "base/strings/string_split.h" 11 #include "base/strings/string_split.h"
12 #include "net/quic/quic_bug_tracker.h" 12 #include "net/quic/quic_bug_tracker.h"
13 #include "net/quic/quic_flags.h" 13 #include "net/quic/quic_flags.h"
14 #include "net/quic/quic_spdy_stream.h" 14 #include "net/quic/quic_spdy_stream.h"
15 #include "net/quic/spdy_utils.h" 15 #include "net/quic/spdy_utils.h"
16 #include "net/spdy/spdy_protocol.h" 16 #include "net/spdy/spdy_protocol.h"
17 #include "net/tools/quic/quic_in_memory_cache.h" 17 #include "net/tools/quic/quic_in_memory_cache.h"
18 #include "net/tools/quic/quic_simple_server_session.h" 18 #include "net/tools/quic/quic_simple_server_session.h"
19 19
20 using base::StringPiece; 20 using base::StringPiece;
21 using base::StringToInt; 21 using base::StringToInt;
22 using std::string; 22 using std::string;
23 23
24 namespace net { 24 namespace net {
25 25
26 QuicSimpleServerStream::QuicSimpleServerStream(QuicStreamId id, 26 QuicSimpleServerStream::QuicSimpleServerStream(QuicStreamId id,
27 QuicSpdySession* session) 27 QuicSpdySession* session)
28 : QuicSpdyStream(id, session), content_length_(-1) {} 28 : QuicSpdyStream(id, session),
29 next_state_(INIT),
30 content_length_(-1),
31 body_chunks_consumed_(0) {}
29 32
30 QuicSimpleServerStream::~QuicSimpleServerStream() {} 33 QuicSimpleServerStream::~QuicSimpleServerStream() {}
31 34
32 void QuicSimpleServerStream::OnInitialHeadersComplete(bool fin, 35 void QuicSimpleServerStream::OnInitialHeadersComplete(bool fin,
33 size_t frame_len) { 36 size_t frame_len) {
34 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len); 37 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len);
35 if (!SpdyUtils::ParseHeaders(decompressed_headers().data(), 38 if (!SpdyUtils::ParseHeaders(decompressed_headers().data(),
36 decompressed_headers().length(), 39 decompressed_headers().length(),
37 &content_length_, &request_headers_)) { 40 &content_length_, &request_headers_)) {
38 DVLOG(1) << "Invalid headers"; 41 DVLOG(1) << "Invalid headers";
39 SendErrorResponse(); 42 SendErrorResponse();
40 } 43 }
44
45 const QuicInMemoryCache::Response* response =
46 QuicInMemoryCache::GetInstance()->GetResponse(
47 request_headers_[":authority"], request_headers_[":path"]);
48 if (response != nullptr) {
49 response_.set_response_type(response->response_type());
50 }
51
41 MarkHeadersConsumed(decompressed_headers().length()); 52 MarkHeadersConsumed(decompressed_headers().length());
42 } 53 }
43 54
44 void QuicSimpleServerStream::OnTrailingHeadersComplete(bool fin, 55 void QuicSimpleServerStream::OnTrailingHeadersComplete(bool fin,
45 size_t frame_len) { 56 size_t frame_len) {
46 QUIC_BUG << "Server does not support receiving Trailers."; 57 QUIC_BUG << "Server does not support receiving Trailers.";
47 SendErrorResponse(); 58 SendErrorResponse();
48 } 59 }
49 60
50 void QuicSimpleServerStream::OnDataAvailable() { 61 void QuicSimpleServerStream::OnDataAvailable() {
(...skipping 10 matching lines...) Expand all
61 static_cast<int>(body_.size()) > content_length_) { 72 static_cast<int>(body_.size()) > content_length_) {
62 DVLOG(1) << "Body size (" << body_.size() << ") > content length (" 73 DVLOG(1) << "Body size (" << body_.size() << ") > content length ("
63 << content_length_ << ")."; 74 << content_length_ << ").";
64 SendErrorResponse(); 75 SendErrorResponse();
65 return; 76 return;
66 } 77 }
67 MarkConsumed(iov.iov_len); 78 MarkConsumed(iov.iov_len);
68 } 79 }
69 if (!sequencer()->IsClosed()) { 80 if (!sequencer()->IsClosed()) {
70 sequencer()->SetUnblocked(); 81 sequencer()->SetUnblocked();
82 if (response_.response_type() == QuicInMemoryCache::BIDIRECTIONAL) {
83 // This will continue send multipart body or trailers.
84 if (next_state_ != NONE)
85 DoLoop();
86 }
71 return; 87 return;
72 } 88 }
73 89
74 // If the sequencer is closed, then all the body, including the fin, has been 90 // If the sequencer is closed, then all the body, including the fin, has been
75 // consumed. 91 // consumed.
76 OnFinRead(); 92 OnFinRead();
77 93
78 if (write_side_closed() || fin_buffered()) { 94 if (write_side_closed() || fin_buffered()) {
79 return; 95 return;
80 } 96 }
81 97
82 if (request_headers_.empty()) { 98 if (request_headers_.empty()) {
83 DVLOG(1) << "Request headers empty."; 99 DVLOG(1) << "Request headers empty.";
84 SendErrorResponse(); 100 SendErrorResponse();
85 return; 101 return;
86 } 102 }
87 103
88 if (content_length_ > 0 && 104 if (content_length_ > 0 &&
89 content_length_ != static_cast<int>(body_.size())) { 105 content_length_ != static_cast<int>(body_.size())) {
90 DVLOG(1) << "Content length (" << content_length_ << ") != body size (" 106 DVLOG(1) << "Content length (" << content_length_ << ") != body size ("
91 << body_.size() << ")."; 107 << body_.size() << ").";
92 SendErrorResponse(); 108 SendErrorResponse();
93 return; 109 return;
94 } 110 }
95 111
96 SendResponse(); 112 if (next_state_ != NONE)
113 DoLoop();
97 } 114 }
98 115
99 void QuicSimpleServerStream::PushResponse( 116 void QuicSimpleServerStream::PushResponse(
100 SpdyHeaderBlock push_request_headers) { 117 SpdyHeaderBlock push_request_headers) {
101 if (id() % 2 != 0) { 118 if (id() % 2 != 0) {
102 QUIC_BUG << "Client initiated stream shouldn't be used as promised stream."; 119 QUIC_BUG << "Client initiated stream shouldn't be used as promised stream.";
103 return; 120 return;
104 } 121 }
105 // Change the stream state to emulate a client request. 122 // Change the stream state to emulate a client request.
106 request_headers_ = push_request_headers; 123 request_headers_ = push_request_headers;
107 content_length_ = 0; 124 content_length_ = 0;
108 DVLOG(1) << "Stream " << id() << ": Ready to receive server push response."; 125 DVLOG(1) << "Stream " << id() << ": Ready to receive server push response.";
109 126
110 // Set as if stream decompresed the headers and received fin. 127 // Set as if stream decompresed the headers and received fin.
111 QuicSpdyStream::OnInitialHeadersComplete(/*fin=*/true, 0); 128 QuicSpdyStream::OnInitialHeadersComplete(/*fin=*/true, 0);
112 } 129 }
113 130
114 void QuicSimpleServerStream::SendResponse() { 131 void QuicSimpleServerStream::SendNotFoundResponse() {
132 DVLOG(1) << "Sending not found response for stream " << id();
133
134 SpdyHeaderBlock response_headers;
135 response_headers[":status"] = "404";
136 response_headers["content-length"] =
137 base::IntToString(strlen(kNotFoundResponseBody));
138 response_.set_response_type(QuicInMemoryCache::REGULAR_RESPONSE);
139 response_.set_headers(response_headers);
140 response_.set_body(kNotFoundResponseBody);
141
142 next_state_ = SEND_HEADERS;
143 DoLoop();
144 }
145
146 void QuicSimpleServerStream::SendErrorResponse() {
147 DVLOG(1) << "Sending error response for stream " << id();
148
149 SpdyHeaderBlock response_headers;
150 response_headers[":status"] = "500";
151 response_headers["content-length"] =
152 base::UintToString(strlen(kErrorResponseBody));
153 response_.set_response_type(QuicInMemoryCache::REGULAR_RESPONSE);
154 response_.set_headers(response_headers);
155 response_.set_body(kErrorResponseBody);
156
157 next_state_ = SEND_HEADERS;
158 DoLoop();
159 }
160
161 void QuicSimpleServerStream::DoLoop() {
162 DCHECK_NE(NONE, next_state_);
163 do {
164 State state = next_state_;
165 next_state_ = NONE;
166 switch (state) {
167 case INIT:
168 Init();
169 break;
170 case SEND_HEADERS:
171 SendHeaders();
172 break;
173 case SEND_BODY:
174 SendBody();
175 break;
176 case SEND_TRAILERS:
177 SendTrailers();
178 break;
179 default:
180 NOTREACHED();
181 }
182 } while (next_state_ != NONE &&
183 (sequencer()->IsClosed() ||
184 response_.response_type() != QuicInMemoryCache::BIDIRECTIONAL));
185 }
186
187 void QuicSimpleServerStream::Init() {
115 if (!ContainsKey(request_headers_, ":authority") || 188 if (!ContainsKey(request_headers_, ":authority") ||
116 !ContainsKey(request_headers_, ":path")) { 189 !ContainsKey(request_headers_, ":path")) {
117 DVLOG(1) << "Request headers do not contain :authority or :path."; 190 DVLOG(1) << "Request headers do not contain :authority or :path.";
118 SendErrorResponse(); 191 SendErrorResponse();
119 return; 192 return;
120 } 193 }
121 194
122 // Find response in cache. If not found, send error response. 195 // Find response in cache. If not found, send error response.
123 const QuicInMemoryCache::Response* response = 196 const QuicInMemoryCache::Response* response =
124 QuicInMemoryCache::GetInstance()->GetResponse( 197 QuicInMemoryCache::GetInstance()->GetResponse(
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after
179 << id(); 252 << id();
180 253
181 if (!resources.empty()) { 254 if (!resources.empty()) {
182 QuicSimpleServerSession* session = 255 QuicSimpleServerSession* session =
183 static_cast<QuicSimpleServerSession*>(spdy_session()); 256 static_cast<QuicSimpleServerSession*>(spdy_session());
184 session->PromisePushResources(request_url, resources, id(), 257 session->PromisePushResources(request_url, resources, id(),
185 request_headers_); 258 request_headers_);
186 } 259 }
187 260
188 DVLOG(1) << "Sending response for stream " << id(); 261 DVLOG(1) << "Sending response for stream " << id();
189 SendHeadersAndBodyAndTrailers(response->headers(), response->body(), 262 response_.set_response_type(response->response_type());
190 response->trailers()); 263 response_.set_headers(response->headers());
264 response_.set_body(response->body());
265 response_.set_trailers(response->trailers());
266 response_.SetBodyChunks(response->body_chunks());
267 next_state_ = SEND_HEADERS;
191 } 268 }
192 269
193 void QuicSimpleServerStream::SendNotFoundResponse() { 270 void QuicSimpleServerStream::SendHeaders() {
194 DVLOG(1) << "Sending not found response for stream " << id(); 271 // Stop reading if this response is not bidirectional.
195 SpdyHeaderBlock headers; 272 if (response_.response_type() != QuicInMemoryCache::BIDIRECTIONAL) {
196 headers[":status"] = "404"; 273 if (!reading_stopped()) {
197 headers["content-length"] = base::IntToString(strlen(kNotFoundResponseBody)); 274 StopReading();
198 SendHeadersAndBody(headers, kNotFoundResponseBody); 275 }
199 }
200
201 void QuicSimpleServerStream::SendErrorResponse() {
202 DVLOG(1) << "Sending error response for stream " << id();
203 SpdyHeaderBlock headers;
204 headers[":status"] = "500";
205 headers["content-length"] = base::UintToString(strlen(kErrorResponseBody));
206 SendHeadersAndBody(headers, kErrorResponseBody);
207 }
208
209 void QuicSimpleServerStream::SendHeadersAndBody(
210 const SpdyHeaderBlock& response_headers,
211 StringPiece body) {
212 SendHeadersAndBodyAndTrailers(response_headers, body, SpdyHeaderBlock());
213 }
214
215 void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers(
216 const SpdyHeaderBlock& response_headers,
217 StringPiece body,
218 const SpdyHeaderBlock& response_trailers) {
219 // This server only supports SPDY and HTTP, and neither handles bidirectional
220 // streaming.
221 if (!reading_stopped()) {
222 StopReading();
223 } 276 }
224
225 // Send the headers, with a FIN if there's nothing else to send. 277 // Send the headers, with a FIN if there's nothing else to send.
226 bool send_fin = (body.empty() && response_trailers.empty()); 278 bool send_fin =
279 (response_.body().empty() && response_.body_chunks().empty() &&
280 response_.trailers().empty());
227 DVLOG(1) << "Writing headers (fin = " << send_fin 281 DVLOG(1) << "Writing headers (fin = " << send_fin
228 << ") : " << response_headers.DebugString(); 282 << ") : " << response_.headers().DebugString();
229 WriteHeaders(response_headers, send_fin, nullptr); 283 WriteHeaders(response_.headers(), send_fin, nullptr);
230 if (send_fin) { 284 if (send_fin) {
231 // Nothing else to send. 285 // Nothing else to send.
232 return; 286 return;
233 } 287 }
288 next_state_ = SEND_BODY;
289 }
234 290
235 // Send the body, with a FIN if there's nothing else to send. 291 void QuicSimpleServerStream::SendBody() {
236 send_fin = response_trailers.empty(); 292 if (response_.response_type() == QuicInMemoryCache::BIDIRECTIONAL) {
237 DVLOG(1) << "Writing body (fin = " << send_fin 293 if (response_.body_chunks().size() > body_chunks_consumed_) {
238 << ") with size: " << body.size(); 294 WriteOrBufferData(
239 WriteOrBufferData(body, send_fin, nullptr); 295 response_.body_chunks().at(body_chunks_consumed_),
240 if (send_fin) { 296 response_.trailers().empty() &&
241 // Nothing else to send. 297 body_chunks_consumed_ + 1 == response_.body_chunks().size(),
242 return; 298 nullptr);
299 body_chunks_consumed_++;
300 next_state_ = SEND_BODY;
301 } else if (response_.body_chunks().size() == body_chunks_consumed_) {
302 if (response_.trailers().empty())
303 return;
304 next_state_ = SEND_TRAILERS;
305 }
306 } else {
307 // Send the body, with a FIN if there's nothing else to send.
308 bool send_fin = response_.trailers().empty();
309 DVLOG(1) << "Writing body (fin = " << send_fin
310 << ") with size: " << response_.body().size();
311 WriteOrBufferData(response_.body(), send_fin, nullptr);
312 if (send_fin) {
313 // Nothing else to send.
314 return;
315 }
316 next_state_ = SEND_TRAILERS;
243 } 317 }
318 }
244 319
320 void QuicSimpleServerStream::SendTrailers() {
245 // Send the trailers. A FIN is always sent with trailers. 321 // Send the trailers. A FIN is always sent with trailers.
246 DVLOG(1) << "Writing trailers (fin = true): " 322 DVLOG(1) << "Writing trailers (fin = true): "
247 << response_trailers.DebugString(); 323 << response_.trailers().DebugString();
248 WriteTrailers(response_trailers, nullptr); 324 WriteTrailers(response_.trailers(), nullptr);
325 next_state_ = NONE;
249 } 326 }
250 327
251 const char* const QuicSimpleServerStream::kErrorResponseBody = "bad"; 328 const char* const QuicSimpleServerStream::kErrorResponseBody = "bad";
252 const char* const QuicSimpleServerStream::kNotFoundResponseBody = 329 const char* const QuicSimpleServerStream::kNotFoundResponseBody =
253 "file not found"; 330 "file not found";
254 331
255 } // namespace net 332 } // namespace net
OLDNEW
« no previous file with comments | « net/tools/quic/quic_simple_server_stream.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698