| 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/memory/singleton.h" | |
| 8 #include "net/quic/quic_session.h" | |
| 9 #include "net/spdy/spdy_framer.h" | |
| 10 #include "net/tools/quic/quic_in_memory_cache.h" | |
| 11 #include "net/tools/quic/spdy_utils.h" | |
| 12 | |
| 13 using base::StringPiece; | |
| 14 using std::string; | |
| 15 | |
| 16 namespace net { | |
| 17 namespace tools { | |
| 18 | |
| 19 static const size_t kHeaderBufInitialSize = 4096; | |
| 20 | |
| 21 QuicSpdyServerStream::QuicSpdyServerStream(QuicStreamId id, | |
| 22 QuicSession* session) | |
| 23 : QuicDataStream(id, session), | |
| 24 read_buf_(new GrowableIOBuffer()), | |
| 25 request_headers_received_(false) { | |
| 26 } | |
| 27 | |
| 28 QuicSpdyServerStream::~QuicSpdyServerStream() { | |
| 29 } | |
| 30 | |
| 31 uint32 QuicSpdyServerStream::ProcessData(const char* data, uint32 data_len) { | |
| 32 uint32 total_bytes_processed = 0; | |
| 33 | |
| 34 // Are we still reading the request headers. | |
| 35 if (!request_headers_received_) { | |
| 36 // Grow the read buffer if necessary. | |
| 37 if (read_buf_->RemainingCapacity() < (int)data_len) { | |
| 38 read_buf_->SetCapacity(read_buf_->capacity() + kHeaderBufInitialSize); | |
| 39 } | |
| 40 memcpy(read_buf_->data(), data, data_len); | |
| 41 read_buf_->set_offset(read_buf_->offset() + data_len); | |
| 42 ParseRequestHeaders(); | |
| 43 } else { | |
| 44 body_.append(data + total_bytes_processed, | |
| 45 data_len - total_bytes_processed); | |
| 46 } | |
| 47 return data_len; | |
| 48 } | |
| 49 | |
| 50 void QuicSpdyServerStream::OnFinRead() { | |
| 51 ReliableQuicStream::OnFinRead(); | |
| 52 if (write_side_closed() || fin_buffered()) { | |
| 53 return; | |
| 54 } | |
| 55 | |
| 56 if (!request_headers_received_) { | |
| 57 SendErrorResponse(); // We're not done reading headers. | |
| 58 } else if ((headers_.content_length_status() == | |
| 59 BalsaHeadersEnums::VALID_CONTENT_LENGTH) && | |
| 60 body_.size() != headers_.content_length()) { | |
| 61 SendErrorResponse(); // Invalid content length | |
| 62 } else { | |
| 63 SendResponse(); | |
| 64 } | |
| 65 } | |
| 66 | |
| 67 void QuicSpdyServerStream::ParseRequestHeaders() { | |
| 68 size_t read_buf_len = static_cast<size_t>(read_buf_->offset()); | |
| 69 SpdyFramer framer(SPDY3); | |
| 70 SpdyHeaderBlock headers; | |
| 71 char* data = read_buf_->StartOfBuffer(); | |
| 72 size_t len = framer.ParseHeaderBlockInBuffer(data, read_buf_->offset(), | |
| 73 &headers); | |
| 74 if (len == 0) { | |
| 75 return; | |
| 76 } | |
| 77 | |
| 78 if (!SpdyUtils::FillBalsaRequestHeaders(headers, &headers_)) { | |
| 79 SendErrorResponse(); | |
| 80 return; | |
| 81 } | |
| 82 | |
| 83 size_t delta = read_buf_len - len; | |
| 84 if (delta > 0) { | |
| 85 body_.append(data + len, delta); | |
| 86 } | |
| 87 | |
| 88 request_headers_received_ = true; | |
| 89 } | |
| 90 | |
| 91 void QuicSpdyServerStream::SendResponse() { | |
| 92 // Find response in cache. If not found, send error response. | |
| 93 const QuicInMemoryCache::Response* response = | |
| 94 QuicInMemoryCache::GetInstance()->GetResponse(headers_); | |
| 95 if (response == nullptr) { | |
| 96 SendErrorResponse(); | |
| 97 return; | |
| 98 } | |
| 99 | |
| 100 if (response->response_type() == QuicInMemoryCache::CLOSE_CONNECTION) { | |
| 101 DVLOG(1) << "Special response: closing connection."; | |
| 102 CloseConnection(QUIC_NO_ERROR); | |
| 103 return; | |
| 104 } | |
| 105 | |
| 106 if (response->response_type() == QuicInMemoryCache::IGNORE_REQUEST) { | |
| 107 DVLOG(1) << "Special response: ignoring request."; | |
| 108 return; | |
| 109 } | |
| 110 | |
| 111 DVLOG(1) << "Sending response for stream " << id(); | |
| 112 SendHeadersAndBody(response->headers(), response->body()); | |
| 113 } | |
| 114 | |
| 115 void QuicSpdyServerStream::SendErrorResponse() { | |
| 116 DVLOG(1) << "Sending error response for stream " << id(); | |
| 117 BalsaHeaders headers; | |
| 118 headers.SetResponseFirstlineFromStringPieces( | |
| 119 "HTTP/1.1", "500", "Server Error"); | |
| 120 headers.ReplaceOrAppendHeader("content-length", "3"); | |
| 121 SendHeadersAndBody(headers, "bad"); | |
| 122 } | |
| 123 | |
| 124 void QuicSpdyServerStream::SendHeadersAndBody( | |
| 125 const BalsaHeaders& response_headers, | |
| 126 StringPiece body) { | |
| 127 // We only support SPDY and HTTP, and neither handles bidirectional streaming. | |
| 128 if (!read_side_closed()) { | |
| 129 CloseReadSide(); | |
| 130 } | |
| 131 | |
| 132 SpdyHeaderBlock header_block = | |
| 133 SpdyUtils::ResponseHeadersToSpdyHeaders(response_headers); | |
| 134 | |
| 135 WriteHeaders(header_block, body.empty(), nullptr); | |
| 136 | |
| 137 if (!body.empty()) { | |
| 138 WriteOrBufferData(body, true, nullptr); | |
| 139 } | |
| 140 } | |
| 141 | |
| 142 } // namespace tools | |
| 143 } // namespace net | |
| OLD | NEW |