OLD | NEW |
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 Loading... |
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 Loading... |
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 |
OLD | NEW |