| 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 <list> | 7 #include <list> |
| 8 #include <utility> | 8 #include <utility> |
| 9 | 9 |
| 10 #include "base/logging.h" | |
| 11 #include "base/stl_util.h" | 10 #include "base/stl_util.h" |
| 12 #include "net/quic/core/quic_flags.h" | 11 #include "net/quic/core/quic_flags.h" |
| 13 #include "net/quic/core/quic_spdy_stream.h" | 12 #include "net/quic/core/quic_spdy_stream.h" |
| 14 #include "net/quic/core/spdy_utils.h" | 13 #include "net/quic/core/spdy_utils.h" |
| 15 #include "net/quic/platform/api/quic_bug_tracker.h" | 14 #include "net/quic/platform/api/quic_bug_tracker.h" |
| 15 #include "net/quic/platform/api/quic_logging.h" |
| 16 #include "net/quic/platform/api/quic_text_utils.h" | 16 #include "net/quic/platform/api/quic_text_utils.h" |
| 17 #include "net/spdy/spdy_protocol.h" | 17 #include "net/spdy/spdy_protocol.h" |
| 18 #include "net/tools/quic/quic_http_response_cache.h" | 18 #include "net/tools/quic/quic_http_response_cache.h" |
| 19 #include "net/tools/quic/quic_simple_server_session.h" | 19 #include "net/tools/quic/quic_simple_server_session.h" |
| 20 | 20 |
| 21 using base::StringPiece; | 21 using base::StringPiece; |
| 22 using std::string; | 22 using std::string; |
| 23 | 23 |
| 24 namespace net { | 24 namespace net { |
| 25 | 25 |
| 26 QuicSimpleServerStream::QuicSimpleServerStream( | 26 QuicSimpleServerStream::QuicSimpleServerStream( |
| 27 QuicStreamId id, | 27 QuicStreamId id, |
| 28 QuicSpdySession* session, | 28 QuicSpdySession* session, |
| 29 QuicHttpResponseCache* response_cache) | 29 QuicHttpResponseCache* response_cache) |
| 30 : QuicSpdyServerStreamBase(id, session), | 30 : QuicSpdyServerStreamBase(id, session), |
| 31 content_length_(-1), | 31 content_length_(-1), |
| 32 response_cache_(response_cache) {} | 32 response_cache_(response_cache) {} |
| 33 | 33 |
| 34 QuicSimpleServerStream::~QuicSimpleServerStream() {} | 34 QuicSimpleServerStream::~QuicSimpleServerStream() {} |
| 35 | 35 |
| 36 void QuicSimpleServerStream::OnInitialHeadersComplete( | 36 void QuicSimpleServerStream::OnInitialHeadersComplete( |
| 37 bool fin, | 37 bool fin, |
| 38 size_t frame_len, | 38 size_t frame_len, |
| 39 const QuicHeaderList& header_list) { | 39 const QuicHeaderList& header_list) { |
| 40 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list); | 40 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len, header_list); |
| 41 if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length_, | 41 if (!SpdyUtils::CopyAndValidateHeaders(header_list, &content_length_, |
| 42 &request_headers_)) { | 42 &request_headers_)) { |
| 43 DVLOG(1) << "Invalid headers"; | 43 QUIC_DVLOG(1) << "Invalid headers"; |
| 44 SendErrorResponse(); | 44 SendErrorResponse(); |
| 45 } | 45 } |
| 46 ConsumeHeaderList(); | 46 ConsumeHeaderList(); |
| 47 } | 47 } |
| 48 | 48 |
| 49 void QuicSimpleServerStream::OnTrailingHeadersComplete( | 49 void QuicSimpleServerStream::OnTrailingHeadersComplete( |
| 50 bool fin, | 50 bool fin, |
| 51 size_t frame_len, | 51 size_t frame_len, |
| 52 const QuicHeaderList& header_list) { | 52 const QuicHeaderList& header_list) { |
| 53 QUIC_BUG << "Server does not support receiving Trailers."; | 53 QUIC_BUG << "Server does not support receiving Trailers."; |
| 54 SendErrorResponse(); | 54 SendErrorResponse(); |
| 55 } | 55 } |
| 56 | 56 |
| 57 void QuicSimpleServerStream::OnDataAvailable() { | 57 void QuicSimpleServerStream::OnDataAvailable() { |
| 58 while (HasBytesToRead()) { | 58 while (HasBytesToRead()) { |
| 59 struct iovec iov; | 59 struct iovec iov; |
| 60 if (GetReadableRegions(&iov, 1) == 0) { | 60 if (GetReadableRegions(&iov, 1) == 0) { |
| 61 // No more data to read. | 61 // No more data to read. |
| 62 break; | 62 break; |
| 63 } | 63 } |
| 64 DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " << id(); | 64 QUIC_DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " |
| 65 << id(); |
| 65 body_.append(static_cast<char*>(iov.iov_base), iov.iov_len); | 66 body_.append(static_cast<char*>(iov.iov_base), iov.iov_len); |
| 66 | 67 |
| 67 if (content_length_ >= 0 && | 68 if (content_length_ >= 0 && |
| 68 body_.size() > static_cast<uint64_t>(content_length_)) { | 69 body_.size() > static_cast<uint64_t>(content_length_)) { |
| 69 DVLOG(1) << "Body size (" << body_.size() << ") > content length (" | 70 QUIC_DVLOG(1) << "Body size (" << body_.size() << ") > content length (" |
| 70 << content_length_ << ")."; | 71 << content_length_ << ")."; |
| 71 SendErrorResponse(); | 72 SendErrorResponse(); |
| 72 return; | 73 return; |
| 73 } | 74 } |
| 74 MarkConsumed(iov.iov_len); | 75 MarkConsumed(iov.iov_len); |
| 75 } | 76 } |
| 76 if (!sequencer()->IsClosed()) { | 77 if (!sequencer()->IsClosed()) { |
| 77 sequencer()->SetUnblocked(); | 78 sequencer()->SetUnblocked(); |
| 78 return; | 79 return; |
| 79 } | 80 } |
| 80 | 81 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 91 | 92 |
| 92 void QuicSimpleServerStream::PushResponse( | 93 void QuicSimpleServerStream::PushResponse( |
| 93 SpdyHeaderBlock push_request_headers) { | 94 SpdyHeaderBlock push_request_headers) { |
| 94 if (id() % 2 != 0) { | 95 if (id() % 2 != 0) { |
| 95 QUIC_BUG << "Client initiated stream shouldn't be used as promised stream."; | 96 QUIC_BUG << "Client initiated stream shouldn't be used as promised stream."; |
| 96 return; | 97 return; |
| 97 } | 98 } |
| 98 // Change the stream state to emulate a client request. | 99 // Change the stream state to emulate a client request. |
| 99 request_headers_ = std::move(push_request_headers); | 100 request_headers_ = std::move(push_request_headers); |
| 100 content_length_ = 0; | 101 content_length_ = 0; |
| 101 DVLOG(1) << "Stream " << id() << ": Ready to receive server push response."; | 102 QUIC_DVLOG(1) << "Stream " << id() |
| 103 << ": Ready to receive server push response."; |
| 102 | 104 |
| 103 // Set as if stream decompresed the headers and received fin. | 105 // Set as if stream decompresed the headers and received fin. |
| 104 QuicSpdyStream::OnInitialHeadersComplete(/*fin=*/true, 0, QuicHeaderList()); | 106 QuicSpdyStream::OnInitialHeadersComplete(/*fin=*/true, 0, QuicHeaderList()); |
| 105 } | 107 } |
| 106 | 108 |
| 107 void QuicSimpleServerStream::SendResponse() { | 109 void QuicSimpleServerStream::SendResponse() { |
| 108 if (request_headers_.empty()) { | 110 if (request_headers_.empty()) { |
| 109 DVLOG(1) << "Request headers empty."; | 111 QUIC_DVLOG(1) << "Request headers empty."; |
| 110 SendErrorResponse(); | 112 SendErrorResponse(); |
| 111 return; | 113 return; |
| 112 } | 114 } |
| 113 | 115 |
| 114 if (content_length_ > 0 && | 116 if (content_length_ > 0 && |
| 115 static_cast<uint64_t>(content_length_) != body_.size()) { | 117 static_cast<uint64_t>(content_length_) != body_.size()) { |
| 116 DVLOG(1) << "Content length (" << content_length_ << ") != body size (" | 118 QUIC_DVLOG(1) << "Content length (" << content_length_ << ") != body size (" |
| 117 << body_.size() << ")."; | 119 << body_.size() << ")."; |
| 118 SendErrorResponse(); | 120 SendErrorResponse(); |
| 119 return; | 121 return; |
| 120 } | 122 } |
| 121 | 123 |
| 122 if (!base::ContainsKey(request_headers_, ":authority") || | 124 if (!base::ContainsKey(request_headers_, ":authority") || |
| 123 !base::ContainsKey(request_headers_, ":path")) { | 125 !base::ContainsKey(request_headers_, ":path")) { |
| 124 DVLOG(1) << "Request headers do not contain :authority or :path."; | 126 QUIC_DVLOG(1) << "Request headers do not contain :authority or :path."; |
| 125 SendErrorResponse(); | 127 SendErrorResponse(); |
| 126 return; | 128 return; |
| 127 } | 129 } |
| 128 | 130 |
| 129 // Find response in cache. If not found, send error response. | 131 // Find response in cache. If not found, send error response. |
| 130 const QuicHttpResponseCache::Response* response = nullptr; | 132 const QuicHttpResponseCache::Response* response = nullptr; |
| 131 auto authority = request_headers_.find(":authority"); | 133 auto authority = request_headers_.find(":authority"); |
| 132 auto path = request_headers_.find(":path"); | 134 auto path = request_headers_.find(":path"); |
| 133 if (authority != request_headers_.end() && path != request_headers_.end()) { | 135 if (authority != request_headers_.end() && path != request_headers_.end()) { |
| 134 response = response_cache_->GetResponse(authority->second, path->second); | 136 response = response_cache_->GetResponse(authority->second, path->second); |
| 135 } | 137 } |
| 136 if (response == nullptr) { | 138 if (response == nullptr) { |
| 137 DVLOG(1) << "Response not found in cache."; | 139 QUIC_DVLOG(1) << "Response not found in cache."; |
| 138 SendNotFoundResponse(); | 140 SendNotFoundResponse(); |
| 139 return; | 141 return; |
| 140 } | 142 } |
| 141 | 143 |
| 142 if (response->response_type() == QuicHttpResponseCache::CLOSE_CONNECTION) { | 144 if (response->response_type() == QuicHttpResponseCache::CLOSE_CONNECTION) { |
| 143 DVLOG(1) << "Special response: closing connection."; | 145 QUIC_DVLOG(1) << "Special response: closing connection."; |
| 144 CloseConnectionWithDetails(QUIC_NO_ERROR, "Toy server forcing close"); | 146 CloseConnectionWithDetails(QUIC_NO_ERROR, "Toy server forcing close"); |
| 145 return; | 147 return; |
| 146 } | 148 } |
| 147 | 149 |
| 148 if (response->response_type() == QuicHttpResponseCache::IGNORE_REQUEST) { | 150 if (response->response_type() == QuicHttpResponseCache::IGNORE_REQUEST) { |
| 149 DVLOG(1) << "Special response: ignoring request."; | 151 QUIC_DVLOG(1) << "Special response: ignoring request."; |
| 150 return; | 152 return; |
| 151 } | 153 } |
| 152 | 154 |
| 153 // Examing response status, if it was not pure integer as typical h2 response | 155 // Examing response status, if it was not pure integer as typical h2 response |
| 154 // status, send error response. | 156 // status, send error response. |
| 155 string request_url = request_headers_[":authority"].as_string() + | 157 string request_url = request_headers_[":authority"].as_string() + |
| 156 request_headers_[":path"].as_string(); | 158 request_headers_[":path"].as_string(); |
| 157 int response_code; | 159 int response_code; |
| 158 const SpdyHeaderBlock& response_headers = response->headers(); | 160 const SpdyHeaderBlock& response_headers = response->headers(); |
| 159 if (!ParseHeaderStatusCode(response_headers, &response_code)) { | 161 if (!ParseHeaderStatusCode(response_headers, &response_code)) { |
| 160 auto status = response_headers.find(":status"); | 162 auto status = response_headers.find(":status"); |
| 161 if (status == response_headers.end()) { | 163 if (status == response_headers.end()) { |
| 162 LOG(WARNING) << ":status not present in response from cache for request " | 164 QUIC_LOG(WARNING) |
| 163 << request_url; | 165 << ":status not present in response from cache for request " |
| 166 << request_url; |
| 164 } else { | 167 } else { |
| 165 LOG(WARNING) << "Illegal (non-integer) response :status from cache: " | 168 QUIC_LOG(WARNING) << "Illegal (non-integer) response :status from cache: " |
| 166 << status->second << " for request " << request_url; | 169 << status->second << " for request " << request_url; |
| 167 } | 170 } |
| 168 SendErrorResponse(); | 171 SendErrorResponse(); |
| 169 return; | 172 return; |
| 170 } | 173 } |
| 171 | 174 |
| 172 if (id() % 2 == 0) { | 175 if (id() % 2 == 0) { |
| 173 // A server initiated stream is only used for a server push response, | 176 // A server initiated stream is only used for a server push response, |
| 174 // and only 200 and 30X response codes are supported for server push. | 177 // and only 200 and 30X response codes are supported for server push. |
| 175 // This behavior mirrors the HTTP/2 implementation. | 178 // This behavior mirrors the HTTP/2 implementation. |
| 176 bool is_redirection = response_code / 100 == 3; | 179 bool is_redirection = response_code / 100 == 3; |
| 177 if (response_code != 200 && !is_redirection) { | 180 if (response_code != 200 && !is_redirection) { |
| 178 LOG(WARNING) << "Response to server push request " << request_url | 181 QUIC_LOG(WARNING) << "Response to server push request " << request_url |
| 179 << " result in response code " << response_code; | 182 << " result in response code " << response_code; |
| 180 Reset(QUIC_STREAM_CANCELLED); | 183 Reset(QUIC_STREAM_CANCELLED); |
| 181 return; | 184 return; |
| 182 } | 185 } |
| 183 } | 186 } |
| 184 std::list<QuicHttpResponseCache::ServerPushInfo> resources = | 187 std::list<QuicHttpResponseCache::ServerPushInfo> resources = |
| 185 response_cache_->GetServerPushResources(request_url); | 188 response_cache_->GetServerPushResources(request_url); |
| 186 DVLOG(1) << "Found " << resources.size() << " push resources for stream " | 189 QUIC_DVLOG(1) << "Found " << resources.size() << " push resources for stream " |
| 187 << id(); | 190 << id(); |
| 188 | 191 |
| 189 if (!resources.empty()) { | 192 if (!resources.empty()) { |
| 190 QuicSimpleServerSession* session = | 193 QuicSimpleServerSession* session = |
| 191 static_cast<QuicSimpleServerSession*>(spdy_session()); | 194 static_cast<QuicSimpleServerSession*>(spdy_session()); |
| 192 session->PromisePushResources(request_url, resources, id(), | 195 session->PromisePushResources(request_url, resources, id(), |
| 193 request_headers_); | 196 request_headers_); |
| 194 } | 197 } |
| 195 | 198 |
| 196 DVLOG(1) << "Sending response for stream " << id(); | 199 QUIC_DVLOG(1) << "Sending response for stream " << id(); |
| 197 SendHeadersAndBodyAndTrailers(response->headers().Clone(), response->body(), | 200 SendHeadersAndBodyAndTrailers(response->headers().Clone(), response->body(), |
| 198 response->trailers().Clone()); | 201 response->trailers().Clone()); |
| 199 } | 202 } |
| 200 | 203 |
| 201 void QuicSimpleServerStream::SendNotFoundResponse() { | 204 void QuicSimpleServerStream::SendNotFoundResponse() { |
| 202 DVLOG(1) << "Sending not found response for stream " << id(); | 205 QUIC_DVLOG(1) << "Sending not found response for stream " << id(); |
| 203 SpdyHeaderBlock headers; | 206 SpdyHeaderBlock headers; |
| 204 headers[":status"] = "404"; | 207 headers[":status"] = "404"; |
| 205 headers["content-length"] = | 208 headers["content-length"] = |
| 206 QuicTextUtils::Uint64ToString(strlen(kNotFoundResponseBody)); | 209 QuicTextUtils::Uint64ToString(strlen(kNotFoundResponseBody)); |
| 207 SendHeadersAndBody(std::move(headers), kNotFoundResponseBody); | 210 SendHeadersAndBody(std::move(headers), kNotFoundResponseBody); |
| 208 } | 211 } |
| 209 | 212 |
| 210 void QuicSimpleServerStream::SendErrorResponse() { | 213 void QuicSimpleServerStream::SendErrorResponse() { |
| 211 DVLOG(1) << "Sending error response for stream " << id(); | 214 QUIC_DVLOG(1) << "Sending error response for stream " << id(); |
| 212 SpdyHeaderBlock headers; | 215 SpdyHeaderBlock headers; |
| 213 headers[":status"] = "500"; | 216 headers[":status"] = "500"; |
| 214 headers["content-length"] = | 217 headers["content-length"] = |
| 215 QuicTextUtils::Uint64ToString(strlen(kErrorResponseBody)); | 218 QuicTextUtils::Uint64ToString(strlen(kErrorResponseBody)); |
| 216 SendHeadersAndBody(std::move(headers), kErrorResponseBody); | 219 SendHeadersAndBody(std::move(headers), kErrorResponseBody); |
| 217 } | 220 } |
| 218 | 221 |
| 219 void QuicSimpleServerStream::SendHeadersAndBody( | 222 void QuicSimpleServerStream::SendHeadersAndBody( |
| 220 SpdyHeaderBlock response_headers, | 223 SpdyHeaderBlock response_headers, |
| 221 StringPiece body) { | 224 StringPiece body) { |
| 222 SendHeadersAndBodyAndTrailers(std::move(response_headers), body, | 225 SendHeadersAndBodyAndTrailers(std::move(response_headers), body, |
| 223 SpdyHeaderBlock()); | 226 SpdyHeaderBlock()); |
| 224 } | 227 } |
| 225 | 228 |
| 226 void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers( | 229 void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers( |
| 227 SpdyHeaderBlock response_headers, | 230 SpdyHeaderBlock response_headers, |
| 228 StringPiece body, | 231 StringPiece body, |
| 229 SpdyHeaderBlock response_trailers) { | 232 SpdyHeaderBlock response_trailers) { |
| 230 if (!allow_bidirectional_data() && !reading_stopped()) { | 233 if (!allow_bidirectional_data() && !reading_stopped()) { |
| 231 StopReading(); | 234 StopReading(); |
| 232 } | 235 } |
| 233 | 236 |
| 234 // Send the headers, with a FIN if there's nothing else to send. | 237 // Send the headers, with a FIN if there's nothing else to send. |
| 235 bool send_fin = (body.empty() && response_trailers.empty()); | 238 bool send_fin = (body.empty() && response_trailers.empty()); |
| 236 DVLOG(1) << "Writing headers (fin = " << send_fin | 239 QUIC_DLOG(INFO) << "Writing headers (fin = " << send_fin |
| 237 << ") : " << response_headers.DebugString(); | 240 << ") : " << response_headers.DebugString(); |
| 238 WriteHeaders(std::move(response_headers), send_fin, nullptr); | 241 WriteHeaders(std::move(response_headers), send_fin, nullptr); |
| 239 if (send_fin) { | 242 if (send_fin) { |
| 240 // Nothing else to send. | 243 // Nothing else to send. |
| 241 return; | 244 return; |
| 242 } | 245 } |
| 243 | 246 |
| 244 // Send the body, with a FIN if there's no trailers to send. | 247 // Send the body, with a FIN if there's no trailers to send. |
| 245 send_fin = response_trailers.empty(); | 248 send_fin = response_trailers.empty(); |
| 246 DVLOG(1) << "Writing body (fin = " << send_fin | 249 QUIC_DLOG(INFO) << "Writing body (fin = " << send_fin |
| 247 << ") with size: " << body.size(); | 250 << ") with size: " << body.size(); |
| 248 if (!body.empty() || send_fin) { | 251 if (!body.empty() || send_fin) { |
| 249 WriteOrBufferData(body, send_fin, nullptr); | 252 WriteOrBufferData(body, send_fin, nullptr); |
| 250 } | 253 } |
| 251 if (send_fin) { | 254 if (send_fin) { |
| 252 // Nothing else to send. | 255 // Nothing else to send. |
| 253 return; | 256 return; |
| 254 } | 257 } |
| 255 | 258 |
| 256 // Send the trailers. A FIN is always sent with trailers. | 259 // Send the trailers. A FIN is always sent with trailers. |
| 257 DVLOG(1) << "Writing trailers (fin = true): " | 260 QUIC_DLOG(INFO) << "Writing trailers (fin = true): " |
| 258 << response_trailers.DebugString(); | 261 << response_trailers.DebugString(); |
| 259 WriteTrailers(std::move(response_trailers), nullptr); | 262 WriteTrailers(std::move(response_trailers), nullptr); |
| 260 } | 263 } |
| 261 | 264 |
| 262 const char* const QuicSimpleServerStream::kErrorResponseBody = "bad"; | 265 const char* const QuicSimpleServerStream::kErrorResponseBody = "bad"; |
| 263 const char* const QuicSimpleServerStream::kNotFoundResponseBody = | 266 const char* const QuicSimpleServerStream::kNotFoundResponseBody = |
| 264 "file not found"; | 267 "file not found"; |
| 265 | 268 |
| 266 } // namespace net | 269 } // namespace net |
| OLD | NEW |