@@ -90,29 +90,31 @@ class Connection
9090 throw std::logic_error (" Invalid connection state" );
9191 }
9292
93- size_t offset = 0 ;
94-
95- if (not body_buffer_.empty ())
93+ auto already_read = request_buffer_.size () - offset_body_start_;
94+ if (already_read)
9695 {
97- if (size <= body_buffer_. size () )
96+ if (size <= already_read )
9897 {
99- std::copy (begin (body_buffer_), begin (body_buffer_) + size, buffer);
100- body_buffer_.erase (begin (body_buffer_), begin (body_buffer_) + size);
98+ offset_body_end_ = offset_body_start_ + size;
99+ std::copy (
100+ request_buffer_.begin () + offset_body_start_,
101+ request_buffer_.begin () + offset_body_end_,
102+ buffer
103+ );
101104 disown ();
102105 callable (boost::system::error_code ());
103106 return ;
104107 }
105- else
106- {
107- std::copy (begin (body_buffer_), end (body_buffer_), buffer);
108- size -= body_buffer_.size ();
109- offset += body_buffer_.size ();
110- body_buffer_.clear ();
111- }
108+ std::copy (
109+ request_buffer_.begin () + offset_body_start_, request_buffer_.end (), buffer
110+ );
111+ size -= already_read;
112+ request_buffer_.resize (offset_body_start_);
112113 }
113114
115+ offset_body_end_ = offset_body_start_;
114116 async_read (
115- boost::asio::buffer (buffer + offset , size),
117+ boost::asio::buffer (buffer + already_read , size),
116118 [callable = std::move (callable), this ](const boost::system::error_code& ec, size_t ) mutable
117119 {
118120 disown ();
@@ -138,23 +140,20 @@ class Connection
138140 throw std::logic_error (" Invalid connection state" );
139141 }
140142
141- if (not body_buffer_.empty ())
143+ auto already_read = request_buffer_.size () - offset_body_start_;
144+ if (already_read)
142145 {
143- if (body_size <= body_buffer_.size ())
146+ auto body_start = request_buffer_.data () + offset_body_start_;
147+ if (body_size <= already_read)
144148 {
145- callable ( boost::system::error_code (), body_buffer_. data (), body_size) ;
146- body_buffer_. erase ( begin (body_buffer_ ), begin (body_buffer_) + body_size );
149+ offset_body_end_ = offset_body_start_ + body_size;
150+ callable ( boost::system::error_code ( ), body_start, already_read );
147151 body_size = 0 ;
148152 }
149153 else
150154 {
151- callable (
152- boost::system::error_code (),
153- body_buffer_.data (),
154- body_buffer_.size ()
155- );
156- body_size -= body_buffer_.size ();
157- body_buffer_.clear ();
155+ callable (boost::system::error_code (), body_start, already_read);
156+ body_size -= already_read;
158157 }
159158 }
160159
@@ -165,12 +164,19 @@ class Connection
165164 return ;
166165 }
167166
167+ offset_body_end_ = offset_body_start_;
168168 auto buf_size = std::min (BUFFER_SIZE, body_size);
169169
170- body_buffer_.resize (buf_size);
170+ auto capacity = request_buffer_.capacity () - offset_body_start_;
171+ if (capacity < buf_size)
172+ {
173+ request_buffer_.reserve (offset_body_start_ + buf_size + 1 );
174+ reparse ();
175+ }
171176
177+ request_buffer_.resize (offset_body_start_ + buf_size);
172178 async_read_some (
173- boost::asio::buffer (body_buffer_ ),
179+ boost::asio::buffer (request_buffer_. data () + offset_body_start_, buf_size ),
174180 [body_size,
175181 callable = std::move (callable),
176182 this ](const boost::system::error_code& ec, size_t size) mutable
@@ -185,14 +191,77 @@ class Connection
185191 return ;
186192 }
187193
188- body_buffer_ .resize (size);
194+ request_buffer_ .resize (offset_body_start_ + size);
189195 read (body_size, std::move (callable));
190196 }
191197 );
192198 }
193199
200+ template <typename Callable>
201+ void read_whole (size_t body_size, Callable callable)
202+ {
203+ if (!own ())
204+ {
205+ throw std::logic_error (" Invalid connection state" );
206+ }
207+
208+ auto already_read = request_buffer_.size () - offset_body_start_;
209+ offset_body_end_ = offset_body_start_ + body_size;
210+ if (already_read)
211+ {
212+ if (body_size <= already_read)
213+ {
214+ callable (boost::system::error_code ());
215+ return ;
216+ }
217+ }
218+
219+ if (!body_size)
220+ {
221+ disown ();
222+ callable (boost::system::error_code ());
223+ return ;
224+ }
225+
226+ auto missing = body_size - already_read;
227+
228+ // +1 for an hypothetical \0
229+ auto capacity = offset_body_end_ + 1 ;
230+ if (request_buffer_.capacity () < capacity)
231+ {
232+ request_buffer_.reserve (capacity);
233+ // pointer might have changed, so we need to reconstruct header,
234+ // path, etc.
235+ reparse ();
236+ }
237+
238+ request_buffer_.resize (offset_body_end_);
239+ async_read (
240+ boost::asio::buffer (request_buffer_.data () + offset_body_end_ - missing, missing),
241+ [callable = std::move (callable),
242+ this ](const boost::system::error_code& ec, size_t size) mutable
243+ {
244+ disown ();
245+
246+ if (ec)
247+ {
248+ LOG (connection_detail::conn_logger_, error)
249+ << " Error detected while reading the body" ;
250+ callable (ec);
251+ return ;
252+ }
253+
254+ callable (boost::system::error_code ());
255+ }
256+ );
257+ }
258+
194259 void sendResponse ();
195260 void sendContinue (Callback&& cb);
261+ std::pair<char *, size_t > mutable_body ();
262+
263+ private:
264+ void reparse ();
196265
197266private:
198267 static void release (Connection* connection);
@@ -246,8 +315,9 @@ class Connection
246315 std::atomic_bool is_owned_ = {false };
247316 bool should_be_deleted_ = {false };
248317 std::vector<char > request_buffer_;
249- std::vector<char > body_buffer_;
250318 size_t size_ = 0 ;
319+ size_t offset_body_start_ = 0 ;
320+ size_t offset_body_end_ = 0 ;
251321
252322 std::mutex mutex_;
253323
0 commit comments