 Chromium Code Reviews
 Chromium Code Reviews Issue 296053012:
  Replace StreamListenSocket with StreamSocket in HttpServer.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master
    
  
    Issue 296053012:
  Replace StreamListenSocket with StreamSocket in HttpServer.  (Closed) 
  Base URL: https://chromium.googlesource.com/chromium/src.git@master| OLD | NEW | 
|---|---|
| 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 | 
| OLD | NEW |