• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2012 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifdef UNSAFE_BUFFERS_BUILD
6 // TODO(crbug.com/40284755): Remove this and spanify to fix the errors.
7 #pragma allow_unsafe_buffers
8 #endif
9 
10 #include "net/server/http_connection.h"
11 
12 #include <utility>
13 
14 #include "base/logging.h"
15 #include "net/server/web_socket.h"
16 #include "net/socket/stream_socket.h"
17 
18 namespace net {
19 
ReadIOBuffer()20 HttpConnection::ReadIOBuffer::ReadIOBuffer()
21     : base_(base::MakeRefCounted<GrowableIOBuffer>()) {
22   SetCapacity(kInitialBufSize);
23 }
24 
~ReadIOBuffer()25 HttpConnection::ReadIOBuffer::~ReadIOBuffer() {
26   data_ = nullptr;  // Avoid dangling ptr when `base_` is destroyed.
27 }
28 
GetCapacity() const29 int HttpConnection::ReadIOBuffer::GetCapacity() const {
30   return base_->capacity();
31 }
32 
SetCapacity(int capacity)33 void HttpConnection::ReadIOBuffer::SetCapacity(int capacity) {
34   DCHECK_LE(GetSize(), capacity);
35   data_ = nullptr;
36   base_->SetCapacity(capacity);
37   data_ = base_->data();
38 }
39 
IncreaseCapacity()40 bool HttpConnection::ReadIOBuffer::IncreaseCapacity() {
41   if (GetCapacity() >= max_buffer_size_) {
42     LOG(ERROR) << "Too large read data is pending: capacity=" << GetCapacity()
43                << ", max_buffer_size=" << max_buffer_size_
44                << ", read=" << GetSize();
45     return false;
46   }
47 
48   int new_capacity = GetCapacity() * kCapacityIncreaseFactor;
49   if (new_capacity > max_buffer_size_)
50     new_capacity = max_buffer_size_;
51   SetCapacity(new_capacity);
52   return true;
53 }
54 
StartOfBuffer() const55 char* HttpConnection::ReadIOBuffer::StartOfBuffer() const {
56   return base::as_writable_chars(base_->everything()).data();
57 }
58 
GetSize() const59 int HttpConnection::ReadIOBuffer::GetSize() const {
60   return base_->offset();
61 }
62 
DidRead(int bytes)63 void HttpConnection::ReadIOBuffer::DidRead(int bytes) {
64   DCHECK_GE(RemainingCapacity(), bytes);
65   base_->set_offset(base_->offset() + bytes);
66   data_ = base_->data();
67 }
68 
RemainingCapacity() const69 int HttpConnection::ReadIOBuffer::RemainingCapacity() const {
70   return base_->RemainingCapacity();
71 }
72 
DidConsume(int bytes)73 void HttpConnection::ReadIOBuffer::DidConsume(int bytes) {
74   int previous_size = GetSize();
75   int unconsumed_size = previous_size - bytes;
76   DCHECK_LE(0, unconsumed_size);
77   if (unconsumed_size > 0) {
78     // Move unconsumed data to the start of buffer.
79     memmove(StartOfBuffer(), StartOfBuffer() + bytes, unconsumed_size);
80   }
81   base_->set_offset(unconsumed_size);
82   data_ = base_->data();
83 
84   // If capacity is too big, reduce it.
85   if (GetCapacity() > kMinimumBufSize &&
86       GetCapacity() > previous_size * kCapacityIncreaseFactor) {
87     int new_capacity = GetCapacity() / kCapacityIncreaseFactor;
88     if (new_capacity < kMinimumBufSize)
89       new_capacity = kMinimumBufSize;
90     // this avoids the pointer to dangle until `SetCapacity` gets called.
91     data_ = nullptr;
92     // realloc() within GrowableIOBuffer::SetCapacity() could move data even
93     // when size is reduced. If unconsumed_size == 0, i.e. no data exists in
94     // the buffer, free internal buffer first to guarantee no data move.
95     if (!unconsumed_size)
96       base_->SetCapacity(0);
97     SetCapacity(new_capacity);
98   }
99 }
100 
101 HttpConnection::QueuedWriteIOBuffer::QueuedWriteIOBuffer() = default;
102 
~QueuedWriteIOBuffer()103 HttpConnection::QueuedWriteIOBuffer::~QueuedWriteIOBuffer() {
104   data_ = nullptr;  // pending_data_ owns data_.
105 }
106 
IsEmpty() const107 bool HttpConnection::QueuedWriteIOBuffer::IsEmpty() const {
108   return pending_data_.empty();
109 }
110 
Append(const std::string & data)111 bool HttpConnection::QueuedWriteIOBuffer::Append(const std::string& data) {
112   if (data.empty())
113     return true;
114 
115   if (total_size_ + static_cast<int>(data.size()) > max_buffer_size_) {
116     LOG(ERROR) << "Too large write data is pending: size="
117                << total_size_ + data.size()
118                << ", max_buffer_size=" << max_buffer_size_;
119     return false;
120   }
121 
122   pending_data_.push(std::make_unique<std::string>(data));
123   total_size_ += data.size();
124 
125   // If new data is the first pending data, updates data_.
126   if (pending_data_.size() == 1)
127     data_ = const_cast<char*>(pending_data_.front()->data());
128   return true;
129 }
130 
DidConsume(int size)131 void HttpConnection::QueuedWriteIOBuffer::DidConsume(int size) {
132   DCHECK_GE(total_size_, size);
133   DCHECK_GE(GetSizeToWrite(), size);
134   if (size == 0)
135     return;
136 
137   if (size < GetSizeToWrite()) {
138     data_ += size;
139   } else {  // size == GetSizeToWrite(). Updates data_ to next pending data.
140     data_ = nullptr;
141     pending_data_.pop();
142     data_ =
143         IsEmpty() ? nullptr : const_cast<char*>(pending_data_.front()->data());
144   }
145   total_size_ -= size;
146 }
147 
GetSizeToWrite() const148 int HttpConnection::QueuedWriteIOBuffer::GetSizeToWrite() const {
149   if (IsEmpty()) {
150     DCHECK_EQ(0, total_size_);
151     return 0;
152   }
153   DCHECK_GE(data_, pending_data_.front()->data());
154   int consumed = static_cast<int>(data_ - pending_data_.front()->data());
155   DCHECK_GT(static_cast<int>(pending_data_.front()->size()), consumed);
156   return pending_data_.front()->size() - consumed;
157 }
158 
HttpConnection(int id,std::unique_ptr<StreamSocket> socket)159 HttpConnection::HttpConnection(int id, std::unique_ptr<StreamSocket> socket)
160     : id_(id),
161       socket_(std::move(socket)),
162       read_buf_(base::MakeRefCounted<ReadIOBuffer>()),
163       write_buf_(base::MakeRefCounted<QueuedWriteIOBuffer>()) {}
164 
165 HttpConnection::~HttpConnection() = default;
166 
SetWebSocket(std::unique_ptr<WebSocket> web_socket)167 void HttpConnection::SetWebSocket(std::unique_ptr<WebSocket> web_socket) {
168   DCHECK(!web_socket_);
169   web_socket_ = std::move(web_socket);
170 }
171 
172 }  // namespace net
173