| OLD | NEW |
| (Empty) |
| 1 // Copyright 2014 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/quic/quic_spdy_server_stream.h" | |
| 6 | |
| 7 #include "base/memory/singleton.h" | |
| 8 #include "base/strings/string_number_conversions.h" | |
| 9 #include "net/quic/quic_in_memory_cache.h" | |
| 10 #include "net/quic/quic_session.h" | |
| 11 #include "net/quic/spdy_utils.h" | |
| 12 #include "net/spdy/spdy_framer.h" | |
| 13 #include "net/spdy/spdy_header_block.h" | |
| 14 #include "net/spdy/spdy_http_utils.h" | |
| 15 | |
| 16 using base::StringPiece; | |
| 17 using std::string; | |
| 18 | |
| 19 namespace net { | |
| 20 | |
| 21 static const size_t kHeaderBufInitialSize = 4096; | |
| 22 | |
| 23 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id, | |
| 24 QuicSession* session) | |
| 25 : QuicDataStream(id, session), | |
| 26 read_buf_(new GrowableIOBuffer()), | |
| 27 request_headers_received_(false) { | |
| 28 read_buf_->SetCapacity(kHeaderBufInitialSize); | |
| 29 } | |
| 30 | |
| 31 QuicSpdyServerStream::~QuicSpdyServerStream() { | |
| 32 } | |
| 33 | |
| 34 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) { | |
| 35 if (data_len > INT_MAX) { | |
| 36 LOG(DFATAL) << "Data length too long: " << data_len; | |
| 37 return 0; | |
| 38 } | |
| 39 // Are we still reading the request headers. | |
| 40 if (!request_headers_received_) { | |
| 41 // Grow the read buffer if necessary. | |
| 42 while (read_buf_->RemainingCapacity() < static_cast<int>(data_len)) { | |
| 43 read_buf_->SetCapacity(read_buf_->capacity() * 2); | |
| 44 } | |
| 45 memcpy(read_buf_->data(), data, data_len); | |
| 46 read_buf_->set_offset(read_buf_->offset() + data_len); | |
| 47 // Try parsing the request headers. This will set request_headers_received_ | |
| 48 // if successful; if not, it will be tried again with more data. | |
| 49 ParseRequestHeaders(); | |
| 50 } else { | |
| 51 body_.append(data, data_len); | |
| 52 } | |
| 53 return data_len; | |
| 54 } | |
| 55 | |
| 56 void QuicSpdyServerStream::OnFinRead() { | |
| 57 ReliableQuicStream::OnFinRead(); | |
| 58 if (write_side_closed() || fin_buffered()) { | |
| 59 return; | |
| 60 } | |
| 61 | |
| 62 if (!request_headers_received_) { | |
| 63 SendErrorResponse(); // We're not done reading headers. | |
| 64 return; | |
| 65 } | |
| 66 | |
| 67 SpdyHeaderBlock::const_iterator it = headers_.find("content-length"); | |
| 68 size_t content_length; | |
| 69 if (it != headers_.end() && | |
| 70 (!base::StringToSizeT(it->second, &content_length) || | |
| 71 body_.size() != content_length)) { | |
| 72 SendErrorResponse(); // Invalid content length | |
| 73 return; | |
| 74 } | |
| 75 | |
| 76 SendResponse(); | |
| 77 } | |
| 78 | |
| 79 // Try parsing the request headers. If successful, sets | |
| 80 // request_headers_received_. If not successful, it can just be tried again once | |
| 81 // there's more data. | |
| 82 void QuicSpdyServerStream::ParseRequestHeaders() { | |
| 83 SpdyFramer framer((kDefaultSpdyMajorVersion)); | |
| 84 const char* data = read_buf_->StartOfBuffer(); | |
| 85 size_t read_buf_len = static_cast<size_t>(read_buf_->offset()); | |
| 86 size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_len, &headers_); | |
| 87 if (len == 0) { | |
| 88 // Not enough data yet, presumably. (If we still don't succeed by the end of | |
| 89 // the stream, then we'll error in OnFinRead().) | |
| 90 return; | |
| 91 } | |
| 92 | |
| 93 // Headers received and parsed: extract the request URL. | |
| 94 request_url_ = GetUrlFromHeaderBlock(headers_, | |
| 95 kDefaultSpdyMajorVersion, | |
| 96 false); | |
| 97 if (!request_url_.is_valid()) { | |
| 98 SendErrorResponse(); | |
| 99 return; | |
| 100 } | |
| 101 | |
| 102 // Add any data past the headers to the request body. | |
| 103 size_t delta = read_buf_len - len; | |
| 104 if (delta > 0) { | |
| 105 body_.append(data + len, delta); | |
| 106 } | |
| 107 | |
| 108 request_headers_received_ = true; | |
| 109 } | |
| 110 | |
| 111 void QuicSpdyServerStream::SendResponse() { | |
| 112 // Find response in cache. If not found, send error response. | |
| 113 const QuicInMemoryCache::Response* response = | |
| 114 QuicInMemoryCache::GetInstance()->GetResponse(request_url_); | |
| 115 if (response == nullptr) { | |
| 116 SendErrorResponse(); | |
| 117 return; | |
| 118 } | |
| 119 | |
| 120 if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) { | |
| 121 DVLOG(1) << "Special response: closing connection."; | |
| 122 CloseConnection(QUIC_NO_ERROR); | |
| 123 return; | |
| 124 } | |
| 125 | |
| 126 if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) { | |
| 127 DVLOG(1) << "Special response: ignoring request."; | |
| 128 return; | |
| 129 } | |
| 130 | |
| 131 DVLOG(1) << "Sending response for stream " << id(); | |
| 132 SendHeadersAndBody(response->headers(), response->body()); | |
| 133 } | |
| 134 | |
| 135 void QuicSpdyServerStream::SendErrorResponse() { | |
| 136 DVLOG(1) << "Sending error response for stream " << id(); | |
| 137 scoped_refptr<HttpResponseHeaders> headers | |
| 138 = new HttpResponseHeaders(string("HTTP/1.1 500 Server Error") + '\0' + | |
| 139 "content-length: 3" + '\0' + '\0'); | |
| 140 SendHeadersAndBody(*headers.get(), "bad"); | |
| 141 } | |
| 142 | |
| 143 void QuicSpdyServerStream::SendHeadersAndBody( | |
| 144 const HttpResponseHeaders& response_headers, | |
| 145 StringPiece body) { | |
| 146 // We only support SPDY and HTTP, and neither handles bidirectional streaming. | |
| 147 if (!read_side_closed()) { | |
| 148 CloseReadSide(); | |
| 149 } | |
| 150 | |
| 151 SpdyHeaderBlock header_block; | |
| 152 CreateSpdyHeadersFromHttpResponse(response_headers, | |
| 153 kDefaultSpdyMajorVersion, | |
| 154 &header_block); | |
| 155 | |
| 156 WriteHeaders(header_block, body.empty(), nullptr); | |
| 157 | |
| 158 if (!body.empty()) { | |
| 159 WriteOrBufferData(body, true, nullptr); | |
| 160 } | |
| 161 } | |
| 162 | |
| 163 } // namespace net | |
| OLD | NEW |