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 |