Skip to content

Commit 1cc3acb

Browse files
committed
Fixes #40 : Write headers and status in one packet
This commit removes the additional call to write when an HTTP response is written out from the asynchronous server that causes browsers to choke when the status line does not come with the headers in a single frame.
1 parent 8dc51c1 commit 1cc3acb

File tree

1 file changed

+24
-72
lines changed

1 file changed

+24
-72
lines changed

boost/network/protocol/http/server/async_connection.hpp

+24-72
Original file line numberDiff line numberDiff line change
@@ -140,9 +140,7 @@ namespace boost { namespace network { namespace http {
140140
, handler(handler)
141141
, thread_pool_(thread_pool)
142142
, headers_already_sent(false)
143-
, first_line_already_sent(false)
144143
, headers_in_progress(false)
145-
, first_line_in_progress(false)
146144
, headers_buffer(BOOST_NETWORK_HTTP_SERVER_CONNECTION_HEADER_BUFFER_MAX_SIZE)
147145
{
148146
new_start = read_buffer_.begin();
@@ -167,26 +165,30 @@ namespace boost { namespace network { namespace http {
167165
template <class Range>
168166
void set_headers(Range headers) {
169167
lock_guard lock(headers_mutex);
170-
if (first_line_in_progress || headers_in_progress || headers_already_sent)
168+
if (headers_in_progress || headers_already_sent)
171169
boost::throw_exception(std::logic_error("Headers have already been sent."));
172170

173171
if (error_encountered)
174172
boost::throw_exception(boost::system::system_error(*error_encountered));
175173

176174
typedef constants<Tag> consts;
177-
headers_buffer.consume(headers_buffer.size());
178-
std::ostream stream(&headers_buffer);
179-
if (!boost::empty(headers)) {
180-
typedef typename Range::const_iterator iterator;
181-
typedef typename string<Tag>::type string_type;
182-
boost::transform(headers,
183-
std::ostream_iterator<string_type>(stream),
184-
linearize_header<Tag>());
185-
} else {
175+
{
176+
std::ostream stream(&headers_buffer);
177+
stream
178+
<< consts::http_slash() << 1<< consts::dot() << 1 << consts::space()
179+
<< status << consts::space() << status_message(status)
180+
<< consts::crlf();
181+
if (!boost::empty(headers)) {
182+
typedef typename Range::const_iterator iterator;
183+
typedef typename string<Tag>::type string_type;
184+
boost::transform(headers,
185+
std::ostream_iterator<string_type>(stream),
186+
linearize_header<Tag>());
187+
} else {
188+
stream << consts::crlf();
189+
}
186190
stream << consts::crlf();
187191
}
188-
stream << consts::crlf();
189-
stream.flush();
190192

191193
write_headers_only(
192194
boost::bind(
@@ -307,8 +309,8 @@ namespace boost { namespace network { namespace http {
307309
asio::io_service::strand strand;
308310
Handler & handler;
309311
utils::thread_pool & thread_pool_;
310-
volatile bool headers_already_sent, first_line_already_sent, headers_in_progress, first_line_in_progress;
311-
asio::streambuf headers_buffer, first_line_buffer;
312+
volatile bool headers_already_sent, headers_in_progress;
313+
asio::streambuf headers_buffer;
312314

313315
boost::recursive_mutex headers_mutex;
314316
buffer_type read_buffer_;
@@ -468,23 +470,12 @@ namespace boost { namespace network { namespace http {
468470
}
469471

470472
void client_error() {
471-
status = bad_request;
472-
write_first_line(
473-
strand.wrap(
474-
boost::bind(
475-
&async_connection<Tag,Handler>::client_error_first_line_written
476-
, async_connection<Tag,Handler>::shared_from_this()
477-
, asio::placeholders::error
478-
, asio::placeholders::bytes_transferred)));
479-
}
480-
481-
void client_error_first_line_written(boost::system::error_code const & ec, std::size_t bytes_transferred) {
482473
static char const * bad_request =
483474
"HTTP/1.0 400 Bad Request\r\nConnection: close\r\nContent-Type: text/plain\r\nContent-Length: 12\r\n\r\nBad Request.";
484475

485476
asio::async_write(
486477
socket()
487-
, asio::buffer(bad_request, 115)
478+
, asio::buffer(bad_request, strlen(bad_request))
488479
, strand.wrap(
489480
boost::bind(
490481
&async_connection<Tag,Handler>::client_error_sent
@@ -505,60 +496,21 @@ namespace boost { namespace network { namespace http {
505496

506497
void do_nothing() {}
507498

508-
template <class Callback>
509-
void write_first_line(Callback callback) {
510-
lock_guard lock(headers_mutex);
511-
if (first_line_in_progress) return;
512-
first_line_in_progress = true;
513-
514-
typedef constants<Tag> consts;
515-
first_line_buffer.consume(first_line_buffer.size());
516-
std::ostream first_line_stream(&first_line_buffer);
517-
first_line_stream
518-
<< consts::http_slash() << 1<< consts::dot() << 1 << consts::space()
519-
<< status << consts::space() << status_message(status)
520-
<< consts::crlf()
521-
<< std::flush
522-
;
523-
asio::async_write(
524-
socket()
525-
, first_line_buffer
526-
, callback);
527-
}
528-
529499
void write_headers_only(boost::function<void()> callback) {
530500
if (headers_in_progress) return;
531501
headers_in_progress = true;
532-
533-
write_first_line(
534-
strand.wrap(
502+
asio::async_write(
503+
socket()
504+
, headers_buffer
505+
, strand.wrap(
535506
boost::bind(
536-
&async_connection<Tag,Handler>::handle_first_line_written
507+
&async_connection<Tag,Handler>::handle_write_headers
537508
, async_connection<Tag,Handler>::shared_from_this()
538509
, callback
539510
, asio::placeholders::error
540511
, asio::placeholders::bytes_transferred)));
541512
}
542513

543-
void handle_first_line_written(boost::function<void()> callback, boost::system::error_code const & ec, std::size_t bytes_transferred) {
544-
lock_guard lock(headers_mutex);
545-
if (!ec) {
546-
first_line_already_sent = true;
547-
asio::async_write(
548-
socket()
549-
, headers_buffer
550-
, strand.wrap(
551-
boost::bind(
552-
&async_connection<Tag,Handler>::handle_write_headers
553-
, async_connection<Tag,Handler>::shared_from_this()
554-
, callback
555-
, asio::placeholders::error
556-
, asio::placeholders::bytes_transferred)));
557-
} else {
558-
error_encountered = in_place<boost::system::system_error>(ec);
559-
}
560-
}
561-
562514
void handle_write_headers(boost::function<void()> callback, boost::system::error_code const & ec, std::size_t bytes_transferred) {
563515
lock_guard lock(headers_mutex);
564516
if (!ec) {

0 commit comments

Comments
 (0)