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 "net/server/http_server.h" | 7 #include "base/logging.h" |
8 #include "net/server/http_server_response_info.h" | |
9 #include "net/server/web_socket.h" | 8 #include "net/server/web_socket.h" |
10 #include "net/socket/stream_listen_socket.h" | 9 #include "net/socket/stream_socket.h" |
11 | 10 |
12 namespace net { | 11 namespace net { |
13 | 12 |
14 int HttpConnection::last_id_ = 0; | 13 HttpConnection::ReadIOBuffer::ReadIOBuffer() |
15 | 14 : base_(new GrowableIOBuffer()), |
16 void HttpConnection::Send(const std::string& data) { | 15 max_buffer_size_(kDefaultMaxBufferSize) { |
17 if (!socket_.get()) | 16 SetCapacity(kInitialBufSize); |
18 return; | |
19 socket_->Send(data); | |
20 } | 17 } |
21 | 18 |
22 void HttpConnection::Send(const char* bytes, int len) { | 19 HttpConnection::ReadIOBuffer::~ReadIOBuffer() { |
23 if (!socket_.get()) | 20 data_ = NULL; // base_ owns data_. |
24 return; | |
25 socket_->Send(bytes, len); | |
26 } | 21 } |
27 | 22 |
28 void HttpConnection::Send(const HttpServerResponseInfo& response) { | 23 int HttpConnection::ReadIOBuffer::GetCapacity() const { |
29 Send(response.Serialize()); | 24 return base_->capacity(); |
30 } | 25 } |
31 | 26 |
32 HttpConnection::HttpConnection(HttpServer* server, | 27 void HttpConnection::ReadIOBuffer::SetCapacity(int capacity) { |
33 scoped_ptr<StreamListenSocket> sock) | 28 DCHECK_LE(GetSize(), capacity); |
34 : server_(server), | 29 base_->SetCapacity(capacity); |
35 socket_(sock.Pass()) { | 30 data_ = base_->data(); |
36 id_ = last_id_++; | 31 } |
| 32 |
| 33 bool HttpConnection::ReadIOBuffer::IncreaseCapacity() { |
| 34 if (GetCapacity() >= max_buffer_size_) { |
| 35 LOG(ERROR) << "Too large read data is pending: capacity=" << GetCapacity() |
| 36 << ", max_buffer_size=" << max_buffer_size_ |
| 37 << ", read=" << GetSize(); |
| 38 return false; |
| 39 } |
| 40 |
| 41 int new_capacity = GetCapacity() * kCapacityIncreaseFactor; |
| 42 if (new_capacity > max_buffer_size_) |
| 43 new_capacity = max_buffer_size_; |
| 44 SetCapacity(new_capacity); |
| 45 return true; |
| 46 } |
| 47 |
| 48 char* HttpConnection::ReadIOBuffer::StartOfBuffer() const { |
| 49 return base_->StartOfBuffer(); |
| 50 } |
| 51 |
| 52 int HttpConnection::ReadIOBuffer::GetSize() const { |
| 53 return base_->offset(); |
| 54 } |
| 55 |
| 56 void HttpConnection::ReadIOBuffer::DidRead(int bytes) { |
| 57 DCHECK_GE(RemainingCapacity(), bytes); |
| 58 base_->set_offset(base_->offset() + bytes); |
| 59 data_ = base_->data(); |
| 60 } |
| 61 |
| 62 int HttpConnection::ReadIOBuffer::RemainingCapacity() const { |
| 63 return base_->RemainingCapacity(); |
| 64 } |
| 65 |
| 66 void HttpConnection::ReadIOBuffer::DidConsume(int bytes) { |
| 67 int previous_size = GetSize(); |
| 68 int unconsumed_size = previous_size - bytes; |
| 69 DCHECK_LE(0, unconsumed_size); |
| 70 if (unconsumed_size > 0) { |
| 71 // Move unconsumed data to the start of buffer. |
| 72 memmove(StartOfBuffer(), StartOfBuffer() + bytes, unconsumed_size); |
| 73 } |
| 74 base_->set_offset(unconsumed_size); |
| 75 data_ = base_->data(); |
| 76 |
| 77 // If capacity is too big, reduce it. |
| 78 if (GetCapacity() > kMinimumBufSize && |
| 79 GetCapacity() > previous_size * kCapacityIncreaseFactor) { |
| 80 int new_capacity = GetCapacity() / kCapacityIncreaseFactor; |
| 81 if (new_capacity < kMinimumBufSize) |
| 82 new_capacity = kMinimumBufSize; |
| 83 // realloc() within GrowableIOBuffer::SetCapacity() could move data even |
| 84 // when size is reduced. If unconsumed_size == 0, i.e. no data exists in |
| 85 // the buffer, free internal buffer first to guarantee no data move. |
| 86 if (!unconsumed_size) |
| 87 base_->SetCapacity(0); |
| 88 SetCapacity(new_capacity); |
| 89 } |
| 90 } |
| 91 |
| 92 HttpConnection::QueuedWriteIOBuffer::QueuedWriteIOBuffer() |
| 93 : total_size_(0), |
| 94 max_buffer_size_(kDefaultMaxBufferSize) { |
| 95 } |
| 96 |
| 97 HttpConnection::QueuedWriteIOBuffer::~QueuedWriteIOBuffer() { |
| 98 data_ = NULL; // pending_data_ owns data_. |
| 99 } |
| 100 |
| 101 bool HttpConnection::QueuedWriteIOBuffer::IsEmpty() const { |
| 102 return pending_data_.empty(); |
| 103 } |
| 104 |
| 105 bool HttpConnection::QueuedWriteIOBuffer::Append(const std::string& data) { |
| 106 if (data.empty()) |
| 107 return true; |
| 108 |
| 109 if (total_size_ + static_cast<int>(data.size()) > max_buffer_size_) { |
| 110 LOG(ERROR) << "Too large write data is pending: size=" |
| 111 << total_size_ + data.size() |
| 112 << ", max_buffer_size=" << max_buffer_size_; |
| 113 return false; |
| 114 } |
| 115 |
| 116 pending_data_.push(data); |
| 117 total_size_ += data.size(); |
| 118 |
| 119 // If new data is the first pending data, updates data_. |
| 120 if (pending_data_.size() == 1) |
| 121 data_ = const_cast<char*>(pending_data_.front().data()); |
| 122 return true; |
| 123 } |
| 124 |
| 125 void HttpConnection::QueuedWriteIOBuffer::DidConsume(int size) { |
| 126 DCHECK_GE(total_size_, size); |
| 127 DCHECK_GE(GetSizeToWrite(), size); |
| 128 if (size == 0) |
| 129 return; |
| 130 |
| 131 if (size < GetSizeToWrite()) { |
| 132 data_ += size; |
| 133 } else { // size == GetSizeToWrite(). Updates data_ to next pending data. |
| 134 pending_data_.pop(); |
| 135 data_ = IsEmpty() ? NULL : const_cast<char*>(pending_data_.front().data()); |
| 136 } |
| 137 total_size_ -= size; |
| 138 } |
| 139 |
| 140 int HttpConnection::QueuedWriteIOBuffer::GetSizeToWrite() const { |
| 141 if (IsEmpty()) { |
| 142 DCHECK_EQ(0, total_size_); |
| 143 return 0; |
| 144 } |
| 145 DCHECK_GE(data_, pending_data_.front().data()); |
| 146 int consumed = static_cast<int>(data_ - pending_data_.front().data()); |
| 147 DCHECK_GT(static_cast<int>(pending_data_.front().size()), consumed); |
| 148 return pending_data_.front().size() - consumed; |
| 149 } |
| 150 |
| 151 HttpConnection::HttpConnection(int id, scoped_ptr<StreamSocket> socket) |
| 152 : id_(id), |
| 153 socket_(socket.Pass()), |
| 154 read_buf_(new ReadIOBuffer()), |
| 155 write_buf_(new QueuedWriteIOBuffer()) { |
37 } | 156 } |
38 | 157 |
39 HttpConnection::~HttpConnection() { | 158 HttpConnection::~HttpConnection() { |
40 server_->delegate_->OnClose(id_); | |
41 } | 159 } |
42 | 160 |
43 void HttpConnection::Shift(int num_bytes) { | 161 void HttpConnection::SetWebSocket(scoped_ptr<WebSocket> web_socket) { |
44 recv_data_ = recv_data_.substr(num_bytes); | 162 DCHECK(!web_socket_); |
| 163 web_socket_ = web_socket.Pass(); |
45 } | 164 } |
46 | 165 |
47 } // namespace net | 166 } // namespace net |
OLD | NEW |