Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(679)

Side by Side Diff: net/server/http_connection.cc

Issue 296053012: Replace StreamListenSocket with StreamSocket in HttpServer. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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/server/http_connection.h" 5 #include "net/server/http_connection.h"
6 6
7 #include <queue>
8
9 #include "base/bind.h"
10 #include "base/location.h"
11 #include "base/message_loop/message_loop_proxy.h"
12 #include "net/base/net_errors.h"
7 #include "net/server/http_server.h" 13 #include "net/server/http_server.h"
8 #include "net/server/http_server_response_info.h" 14 #include "net/server/http_server_response_info.h"
9 #include "net/server/web_socket.h" 15 #include "net/server/web_socket.h"
10 #include "net/socket/stream_listen_socket.h" 16 #include "net/socket/stream_socket.h"
11 17
12 namespace net { 18 namespace net {
13 19
14 int HttpConnection::last_id_ = 0; 20 namespace {
21
22 const size_t kInitialReadBufSize = 1024;
23 const size_t kMinimumReadBufSize = 128;
24 const int kCapacityIncreaseFactor = 2;
25
26 const size_t kPendingDataLimit = 1 * 1024 * 1024; // 1 Mbytes.
27
28 } // namespace
29
30 HttpConnection::ReadIOBuffer::ReadIOBuffer()
31 : base_(new GrowableIOBuffer()) {
32 SetCapacity(kInitialReadBufSize);
33 }
34
35 HttpConnection::ReadIOBuffer::~ReadIOBuffer() {
36 data_ = NULL; // base_ owns data_.
37 }
38
39 IOBuffer* HttpConnection::ReadIOBuffer::GetUnusedIOBuffer() const {
40 return base_.get();
41 }
42
43 size_t HttpConnection::ReadIOBuffer::GetUnusedCapacity() const {
44 return static_cast<size_t>(base_->RemainingCapacity());
45 }
46
47 size_t HttpConnection::ReadIOBuffer::GetCapacity() const {
48 return static_cast<size_t>(base_->capacity());
49 }
50
51 void HttpConnection::ReadIOBuffer::SetCapacity(size_t capacity) {
52 base_->SetCapacity(static_cast<int>(capacity));
53 data_ = base_->StartOfBuffer();
54 }
55
56 size_t HttpConnection::ReadIOBuffer::GetUnconsumedSize() const {
57 DCHECK_GE(base_->data(), data_);
58 return static_cast<size_t>(base_->data() - data_);
59 }
60
61 void HttpConnection::ReadIOBuffer::DidRead(size_t bytes) {
62 DCHECK_LE(bytes, GetUnusedCapacity());
63 base_->set_offset(base_->offset() + bytes);
64 }
65
66 void HttpConnection::ReadIOBuffer::DidConsume(size_t bytes) {
67 DCHECK_LE(bytes, GetUnconsumedSize());
68 if (bytes < GetUnconsumedSize()) {
69 data_ += bytes;
70 return;
71 }
72 // No need to keep consumed data because no data will be moved.
73 // If capacity is too big, reduce it.
74 if (base_->capacity() > static_cast<int>(kMinimumReadBufSize)
75 && base_->capacity() > base_->offset() * kCapacityIncreaseFactor) {
76 SetCapacity(base_->capacity() / kCapacityIncreaseFactor);
77 }
78 base_->set_offset(0);
79 }
80
81 // IOBuffer of pending data which has a queue of pending data. Each pending data
82 // is stored in std::string. data() is the data of first std::string stored.
83 class HttpConnection::PendingWriteIOBuffer : public IOBuffer {
84 public:
85 PendingWriteIOBuffer();
86
87 // Whether or not pending data exists.
88 bool IsEmpty() const;
89
90 // Appends new pending data. Changes data() if this is the first pending data.
91 void Append(const std::string& data);
92 // Consumes data and changes data() accordingly.
93 void DidConsume(size_t size);
94
95 // Gets size of data to write this time. It is NOT total data size.
96 size_t GetSizeToWrite() const;
97
98 size_t total_size() const { return total_size_; }
99
100 private:
101 virtual ~PendingWriteIOBuffer();
102
103 std::queue<std::string> pending_data_;
104 size_t total_size_;
105
106 DISALLOW_COPY_AND_ASSIGN(PendingWriteIOBuffer);
107 };
108
109 HttpConnection::PendingWriteIOBuffer::PendingWriteIOBuffer()
110 : total_size_(0) {
111 }
112
113 HttpConnection::PendingWriteIOBuffer::~PendingWriteIOBuffer() {
114 }
115
116 bool HttpConnection::PendingWriteIOBuffer::IsEmpty() const {
117 return pending_data_.empty();
118 }
119
120 void HttpConnection::PendingWriteIOBuffer::Append(const std::string& data) {
121 if (data.empty()) {
122 return;
123 }
124
125 pending_data_.push(data);
mmenke 2014/05/23 19:20:58 Can't we just take IOBuffers instead, to avoid thi
byungchul 2014/05/28 01:19:35 To construct IOBuffer from std::string in any poin
Ryan Sleevi 2014/05/28 01:36:26 Copy-on-write is forbidden behaviour in C++11, and
byungchul 2014/05/30 00:19:02 Now, HttpServer uses this buffer directly. Buildin
126 total_size_ += data.size();
127
128 // If new data is the first pending data, updates data_.
129 if (pending_data_.size() == 1) {
130 data_ = const_cast<char*>(pending_data_.front().data());
131 }
132 }
133
134 void HttpConnection::PendingWriteIOBuffer::DidConsume(size_t size) {
135 DCHECK_LE(size, total_size_);
136 DCHECK_LE(size, GetSizeToWrite());
137 if (size == 0) {
138 return;
139 }
140
141 if (size < GetSizeToWrite()) {
142 data_ += size;
143 } else { // size == GetSizeToWrite(). Updates data_ to next pending data.
144 pending_data_.pop();
145 data_ = IsEmpty() ? NULL : const_cast<char*>(pending_data_.front().data());
146 }
147 total_size_ -= size;
148 }
149
150 size_t HttpConnection::PendingWriteIOBuffer::GetSizeToWrite() const {
151 if (IsEmpty()) {
152 DCHECK_EQ(total_size_, 0U);
153 return 0;
154 }
155 DCHECK_GE(data_, pending_data_.front().data());
156 size_t consumed = static_cast<size_t>(data_ - pending_data_.front().data());
157 DCHECK_GT(pending_data_.front().size(), consumed);
mmenke 2014/05/23 19:20:58 This class may be may effort than it's worth, as-i
mmenke 2014/05/23 19:20:58 Actually...Why don't we do something simpler, like
byungchul 2014/05/28 01:19:35 Any one needs to store date to write anyway. My im
Ryan Sleevi 2014/05/28 01:36:26 Normally, in net/ code, we leave buffering up to t
byungchul 2014/05/28 05:01:33 While keeping current HttpServer apis, I will try
byungchul 2014/05/30 00:19:02 Done.
158 return pending_data_.front().size() - consumed;
159 }
160
161 HttpConnection::HttpConnection(int id,
162 scoped_ptr<StreamSocket> socket,
163 Delegate* delegate)
164 : id_(id),
165 socket_(socket.Pass()),
166 delegate_(delegate),
167 read_buf_(new ReadIOBuffer()),
168 pending_write_buf_(new PendingWriteIOBuffer()) {
169 DoReadLoop(OK);
170 }
171
172 HttpConnection::~HttpConnection() {
173 }
174
175 void HttpConnection::DoReadLoop(int rv) {
mmenke 2014/05/23 19:20:58 Taking in an "rv" that's always OK seems a little
byungchul 2014/05/30 00:19:02 Done and moved to HttpServer.
176 while (rv == OK) {
177 if (read_buf_->GetUnusedCapacity() == 0) {
178 if (read_buf_->GetCapacity() > kPendingDataLimit) {
179 LOG(ERROR) << "Too large read data is pending: capacity="
180 << read_buf_->GetCapacity()
181 << ", consumed="
182 << read_buf_->GetCapacity() - read_buf_->GetUnconsumedSize();
183 Close();
184 return;
185 }
186 read_buf_->SetCapacity(read_buf_->GetCapacity() * kMinimumReadBufSize);
187 }
188 rv = socket_->Read(read_buf_->GetUnusedIOBuffer(),
189 read_buf_->GetUnusedCapacity(),
190 base::Bind(&HttpConnection::OnReadCompleted,
191 AsWeakPtr()));
mmenke 2014/05/23 19:20:58 We don't need weak pointers here - we own the sock
byungchul 2014/05/30 00:19:02 Replaced with connection id in http server.
192 if (rv == ERR_IO_PENDING) {
193 break;
194 }
195 rv = DidRead(rv);
196 }
197 }
198
199 void HttpConnection::OnReadCompleted(int rv) {
200 if (DidRead(rv) == OK) {
201 DoReadLoop(OK);
202 }
203 }
204
205 int HttpConnection::DidRead(int rv) {
206 if (rv <= 0) {
207 Close();
208 return rv == 0 ? ERR_CONNECTION_CLOSED : rv;
209 }
210
211 read_buf_->DidRead(static_cast<size_t>(rv));
212 delegate_->DidRead(this);
213 return OK;
214 }
15 215
16 void HttpConnection::Send(const std::string& data) { 216 void HttpConnection::Send(const std::string& data) {
17 if (!socket_.get()) 217 if (pending_write_buf_->total_size() + data.size() > kPendingDataLimit) {
pfeldman 2014/05/26 09:21:31 Before we go further, could you elaborate on this
mmenke 2014/05/27 14:32:08 It's buffering 100 MB payloads in RAM? That just
byungchul 2014/05/30 00:19:02 Increased websocket buffer to 100Mb in cast of dev
18 return; 218 LOG(ERROR) << "Too large write data is pending: size="
19 socket_->Send(data); 219 << pending_write_buf_->total_size() + data.size();
220 Close();
221 return;
222 }
223 bool writing_in_progress = !pending_write_buf_->IsEmpty();
224 pending_write_buf_->Append(data);
225 if (!writing_in_progress) {
226 DoWriteLoop(OK);
227 }
20 } 228 }
21 229
22 void HttpConnection::Send(const char* bytes, int len) { 230 void HttpConnection::Send(const char* bytes, int len) {
23 if (!socket_.get()) 231 Send(std::string(bytes, len));
mmenke 2014/05/23 19:20:58 This copy really shouldn't be needed.
byungchul 2014/05/30 00:19:02 This is used only by net/server/web_socket.cc. One
24 return;
25 socket_->Send(bytes, len);
26 } 232 }
27 233
28 void HttpConnection::Send(const HttpServerResponseInfo& response) { 234 void HttpConnection::Send(const HttpServerResponseInfo& response) {
29 Send(response.Serialize()); 235 Send(response.Serialize());
30 } 236 }
31 237
32 HttpConnection::HttpConnection(HttpServer* server, 238 void HttpConnection::DoWriteLoop(int rv) {
mmenke 2014/05/23 19:20:58 Again, rv is always "OK", so doesn't seem like it
byungchul 2014/05/30 00:19:02 Done.
33 scoped_ptr<StreamListenSocket> sock) 239 while (rv == OK && pending_write_buf_->GetSizeToWrite() > 0) {
34 : server_(server), 240 rv = socket_->Write(pending_write_buf_.get(),
35 socket_(sock.Pass()) { 241 pending_write_buf_->GetSizeToWrite(),
36 id_ = last_id_++; 242 base::Bind(&HttpConnection::OnWriteCompleted,
37 } 243 AsWeakPtr()));
mmenke 2014/05/23 19:20:58 WeakPtr not needed.
byungchul 2014/05/30 00:19:02 Done.
38 244 if (rv == ERR_IO_PENDING || rv == OK) {
39 HttpConnection::~HttpConnection() { 245 break;
40 server_->delegate_->OnClose(id_); 246 }
41 } 247 rv = DidWrite(rv);
42 248 }
43 void HttpConnection::Shift(int num_bytes) { 249 }
44 recv_data_ = recv_data_.substr(num_bytes); 250
251 void HttpConnection::OnWriteCompleted(int rv) {
252 if (DidWrite(rv) == OK) {
253 DoWriteLoop(OK);
254 }
255 }
256
257 int HttpConnection::DidWrite(int rv) {
258 if (rv < 0) {
259 Close();
260 return rv;
261 }
262
263 pending_write_buf_->DidConsume(rv);
264 return OK;
265 }
266
267 void HttpConnection::Close() {
mmenke 2014/05/23 19:20:58 This function can end up being called twice: Once
byungchul 2014/05/28 01:19:35 That's why I use a weak ptr.
Ryan Sleevi 2014/05/28 01:36:26 I don't really think that's an ideal solution. No
byungchul 2014/05/30 00:19:02 HttpServer handles it and/so never calls Close() t
268 // DidClose() may delete this object. Call it in next run loop to make sure
269 // any DidRead()/DidWrite() callbacks in the stack return.
270 base::MessageLoopProxy::current()->PostTask(
271 FROM_HERE,
272 base::Bind(&HttpConnection::CloseInNextRunLoop, AsWeakPtr()));
mmenke 2014/05/23 19:20:58 So we always call back Delegate::DidClose asynchro
byungchul 2014/05/28 01:19:35 They are different. DidClose() could be called for
273 }
274
275 void HttpConnection::CloseInNextRunLoop() {
mmenke 2014/05/23 19:20:58 I think this and Close() are misnamed. Close() sh
byungchul 2014/05/30 00:19:02 Not necessary. Removed.
276 socket_->Disconnect();
277 delegate_->DidClose(this);
278 }
279
280 void HttpConnection::UpgradeToWebSocket(const HttpServerRequestInfo& request,
281 size_t* pos) {
282 DCHECK(!web_socket_);
283 web_socket_.reset(WebSocket::CreateWebSocket(this, request, pos));
45 } 284 }
46 285
47 } // namespace net 286 } // namespace net
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698