| OLD | NEW |
| (Empty) |
| 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. | |
| 4 | |
| 5 #include "net/tools/quic/quic_spdy_server_stream.h" | |
| 6 | |
| 7 #include "base/logging.h" | |
| 8 #include "base/stl_util.h" | |
| 9 #include "base/strings/string_number_conversions.h" | |
| 10 #include "base/strings/string_piece.h" | |
| 11 #include "base/strings/string_split.h" | |
| 12 #include "net/quic/quic_flags.h" | |
| 13 #include "net/quic/quic_spdy_session.h" | |
| 14 #include "net/quic/quic_spdy_stream.h" | |
| 15 #include "net/quic/spdy_utils.h" | |
| 16 #include "net/spdy/spdy_protocol.h" | |
| 17 #include "net/tools/quic/quic_in_memory_cache.h" | |
| 18 | |
| 19 using base::StringPiece; | |
| 20 using base::StringToInt; | |
| 21 using std::string; | |
| 22 | |
| 23 namespace net { | |
| 24 namespace tools { | |
| 25 | |
| 26 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id, | |
| 27 QuicSpdySession* session) | |
| 28 : QuicSpdyStream(id, session), content_length_(-1) {} | |
| 29 | |
| 30 QuicSpdyServerStream::~QuicSpdyServerStream() { | |
| 31 } | |
| 32 | |
| 33 void QuicSpdyServerStream::OnInitialHeadersComplete(bool fin, | |
| 34 size_t frame_len) { | |
| 35 QuicSpdyStream::OnInitialHeadersComplete(fin, frame_len); | |
| 36 if (!SpdyUtils::ParseHeaders(decompressed_headers().data(), | |
| 37 decompressed_headers().length(), | |
| 38 &content_length_, &request_headers_)) { | |
| 39 DVLOG(1) << "Invalid headers"; | |
| 40 SendErrorResponse(); | |
| 41 } | |
| 42 MarkHeadersConsumed(decompressed_headers().length()); | |
| 43 } | |
| 44 | |
| 45 void QuicSpdyServerStream::OnTrailingHeadersComplete(bool fin, | |
| 46 size_t frame_len) { | |
| 47 LOG(DFATAL) << "Server does not support receiving Trailers."; | |
| 48 SendErrorResponse(); | |
| 49 } | |
| 50 | |
| 51 void QuicSpdyServerStream::OnDataAvailable() { | |
| 52 while (HasBytesToRead()) { | |
| 53 struct iovec iov; | |
| 54 if (GetReadableRegions(&iov, 1) == 0) { | |
| 55 // No more data to read. | |
| 56 break; | |
| 57 } | |
| 58 DVLOG(1) << "Processed " << iov.iov_len << " bytes for stream " << id(); | |
| 59 body_.append(static_cast<char*>(iov.iov_base), iov.iov_len); | |
| 60 | |
| 61 if (content_length_ >= 0 && | |
| 62 static_cast<int>(body_.size()) > content_length_) { | |
| 63 DVLOG(1) << "Body size (" << body_.size() << ") > content length (" | |
| 64 << content_length_ << ")."; | |
| 65 SendErrorResponse(); | |
| 66 return; | |
| 67 } | |
| 68 MarkConsumed(iov.iov_len); | |
| 69 } | |
| 70 if (!sequencer()->IsClosed()) { | |
| 71 sequencer()->SetUnblocked(); | |
| 72 return; | |
| 73 } | |
| 74 | |
| 75 // If the sequencer is closed, then all the body, including the fin, has been | |
| 76 // consumed. | |
| 77 OnFinRead(); | |
| 78 | |
| 79 if (write_side_closed() || fin_buffered()) { | |
| 80 return; | |
| 81 } | |
| 82 | |
| 83 if (request_headers_.empty()) { | |
| 84 DVLOG(1) << "Request headers empty."; | |
| 85 SendErrorResponse(); | |
| 86 return; | |
| 87 } | |
| 88 | |
| 89 if (content_length_ > 0 && | |
| 90 content_length_ != static_cast<int>(body_.size())) { | |
| 91 DVLOG(1) << "Content length (" << content_length_ << ") != body size (" | |
| 92 << body_.size() << ")."; | |
| 93 SendErrorResponse(); | |
| 94 return; | |
| 95 } | |
| 96 | |
| 97 SendResponse(); | |
| 98 } | |
| 99 | |
| 100 void QuicSpdyServerStream::SendResponse() { | |
| 101 if (!ContainsKey(request_headers_, ":authority") || | |
| 102 !ContainsKey(request_headers_, ":path")) { | |
| 103 DVLOG(1) << "Request headers do not contain :authority or :path."; | |
| 104 SendErrorResponse(); | |
| 105 return; | |
| 106 } | |
| 107 | |
| 108 // Find response in cache. If not found, send error response. | |
| 109 const QuicInMemoryCache::Response* response = | |
| 110 QuicInMemoryCache::GetInstance()->GetResponse( | |
| 111 request_headers_[":authority"], request_headers_[":path"]); | |
| 112 if (response == nullptr) { | |
| 113 DVLOG(1) << "Response not found in cache."; | |
| 114 SendErrorResponse(); | |
| 115 return; | |
| 116 } | |
| 117 | |
| 118 if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) { | |
| 119 DVLOG(1) << "Special response: closing connection."; | |
| 120 CloseConnection(QUIC_NO_ERROR); | |
| 121 return; | |
| 122 } | |
| 123 | |
| 124 if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) { | |
| 125 DVLOG(1) << "Special response: ignoring request."; | |
| 126 return; | |
| 127 } | |
| 128 | |
| 129 // Examing response status, if it was not pure integer as typical h2 response | |
| 130 // status, send error response. | |
| 131 string request_url = request_headers_[":scheme"].as_string() + "://" + | |
| 132 request_headers_[":authority"].as_string() + | |
| 133 request_headers_[":path"].as_string(); | |
| 134 int response_code; | |
| 135 SpdyHeaderBlock response_headers = response->headers(); | |
| 136 if (!base::StringToInt(response_headers[":status"], &response_code)) { | |
| 137 DVLOG(1) << "Illegal (non-integer) response :status from cache: " | |
| 138 << response_headers[":status"].as_string() << " for request " | |
| 139 << request_url; | |
| 140 SendErrorResponse(); | |
| 141 return; | |
| 142 } | |
| 143 | |
| 144 if (id() % 2 == 0) { | |
| 145 // A server initiated stream is only used for a server push response, | |
| 146 // and only 200 and 30X response codes are supported for server push. | |
| 147 // This behavior mirrors the HTTP/2 implementation. | |
| 148 bool is_redirection = response_code / 100 == 3; | |
| 149 if (response_code != 200 && !is_redirection) { | |
| 150 LOG(WARNING) << "Response to server push request " << request_url | |
| 151 << " result in response code " << response_code; | |
| 152 Reset(QUIC_STREAM_CANCELLED); | |
| 153 return; | |
| 154 } | |
| 155 } | |
| 156 DVLOG(1) << "Sending response for stream " << id(); | |
| 157 SendHeadersAndBodyAndTrailers(response->headers(), response->body(), | |
| 158 response->trailers()); | |
| 159 } | |
| 160 | |
| 161 void QuicSpdyServerStream::SendErrorResponse() { | |
| 162 DVLOG(1) << "Sending error response for stream " << id(); | |
| 163 SpdyHeaderBlock headers; | |
| 164 headers[":status"] = "500"; | |
| 165 headers["content-length"] = base::UintToString(strlen(kErrorResponseBody)); | |
| 166 SendHeadersAndBody(headers, kErrorResponseBody); | |
| 167 } | |
| 168 | |
| 169 void QuicSpdyServerStream::SendHeadersAndBody( | |
| 170 const SpdyHeaderBlock& response_headers, | |
| 171 StringPiece body) { | |
| 172 SendHeadersAndBodyAndTrailers(response_headers, body, SpdyHeaderBlock()); | |
| 173 } | |
| 174 | |
| 175 void QuicSpdyServerStream::SendHeadersAndBodyAndTrailers( | |
| 176 const SpdyHeaderBlock& response_headers, | |
| 177 StringPiece body, | |
| 178 const SpdyHeaderBlock& response_trailers) { | |
| 179 // This server only supports SPDY and HTTP, and neither handles bidirectional | |
| 180 // streaming. | |
| 181 if (!reading_stopped()) { | |
| 182 StopReading(); | |
| 183 } | |
| 184 | |
| 185 // Send the headers, with a FIN if there's nothing else to send. | |
| 186 bool send_fin = (body.empty() && response_trailers.empty()); | |
| 187 DVLOG(1) << "Writing headers (fin = " << send_fin | |
| 188 << ") : " << response_headers.DebugString(); | |
| 189 WriteHeaders(response_headers, send_fin, nullptr); | |
| 190 if (send_fin) { | |
| 191 // Nothing else to send. | |
| 192 return; | |
| 193 } | |
| 194 | |
| 195 // Send the body, with a FIN if there's nothing else to send. | |
| 196 send_fin = response_trailers.empty(); | |
| 197 DVLOG(1) << "Writing body (fin = " << send_fin | |
| 198 << ") with size: " << body.size(); | |
| 199 WriteOrBufferData(body, send_fin, nullptr); | |
| 200 if (send_fin) { | |
| 201 // Nothing else to send. | |
| 202 return; | |
| 203 } | |
| 204 | |
| 205 // Send the trailers. A FIN is always sent with trailers. | |
| 206 DVLOG(1) << "Writing trailers (fin = true): " | |
| 207 << response_trailers.DebugString(); | |
| 208 WriteTrailers(response_trailers, nullptr); | |
| 209 } | |
| 210 | |
| 211 const char* const QuicSpdyServerStream::kErrorResponseBody = "bad"; | |
| 212 | |
| 213 } // namespace tools | |
| 214 } // namespace net | |
| OLD | NEW |