@@ -635,7 +635,57 @@ void connection<config>::remove_header(std::string const & key)
635
635
}
636
636
}
637
637
638
+ // / Defer HTTP Response until later
639
+ /* *
640
+ * Used in the http handler to defer the HTTP response for this connection
641
+ * until later. Handshake timers will be canceled and the connection will be
642
+ * left open until `send_http_response` or an equivalent is called.
643
+ *
644
+ * Warning: deferred connections won't time out and as a result can tie up
645
+ * resources.
646
+ *
647
+ * @param ec A status code, zero on success, non-zero otherwise
648
+ */
649
+ template <typename config>
650
+ void connection<config>::defer_http_response(lib::error_code & ec) {
651
+ // Cancel handshake timer, otherwise the connection will time out and we'll
652
+ // close the connection before the app has a chance to send a response.
653
+ if (m_handshake_timer) {
654
+ m_handshake_timer->cancel ();
655
+ m_handshake_timer.reset ();
656
+ }
657
+
658
+ // Do something to signal deferral
659
+ m_http_state = session::http_state::deferred;
660
+
661
+ ec = lib::error_code ();
662
+ }
638
663
664
+ // / Send deferred HTTP Response
665
+ /* *
666
+ * Sends an http response to an HTTP connection that was deferred. This will
667
+ * send a complete response including all headers, status line, and body
668
+ * text. The connection will be closed afterwards.
669
+ *
670
+ * @since 0.6.0
671
+ *
672
+ * @param ec A status code, zero on success, non-zero otherwise
673
+ */
674
+ template <typename config>
675
+ void connection<config>::send_http_response(lib::error_code & ec) {
676
+ {
677
+ scoped_lock_type lock (m_connection_state_lock);
678
+ if (m_http_state != session::http_state::deferred) {
679
+ ec = error::make_error_code (error::invalid_state);
680
+ return ;
681
+ }
682
+
683
+ m_http_state = session::http_state::body_written;
684
+ }
685
+
686
+ this ->write_http_response (lib::error_code ());
687
+ ec = lib::error_code ();
688
+ }
639
689
640
690
641
691
@@ -728,7 +778,7 @@ void connection<config>::read_handshake(size_t num_bytes) {
728
778
);
729
779
}
730
780
731
- // All exit paths for this function need to call send_http_response () or submit
781
+ // All exit paths for this function need to call write_http_response () or submit
732
782
// a new read request with this function as the handler.
733
783
template <typename config>
734
784
void connection<config>::handle_read_handshake(lib::error_code const & ec,
@@ -784,7 +834,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
784
834
// All HTTP exceptions will result in this request failing and an error
785
835
// response being returned. No more bytes will be read in this con.
786
836
m_response.set_status (e.m_error_code ,e.m_error_msg );
787
- this ->send_http_response_error (error::make_error_code (error::http_parse_error));
837
+ this ->write_http_response_error (error::make_error_code (error::http_parse_error));
788
838
return ;
789
839
}
790
840
@@ -806,7 +856,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
806
856
if (m_request.ready ()) {
807
857
lib::error_code processor_ec = this ->initialize_processor ();
808
858
if (processor_ec) {
809
- this ->send_http_response_error (processor_ec);
859
+ this ->write_http_response_error (processor_ec);
810
860
return ;
811
861
}
812
862
@@ -823,7 +873,7 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
823
873
// TODO: need more bytes
824
874
m_alog.write (log::alevel::devel," short key3 read" );
825
875
m_response.set_status (http::status_code::internal_server_error);
826
- this ->send_http_response_error (processor::error::make_error_code (processor::error::short_key3));
876
+ this ->write_http_response_error (processor::error::make_error_code (processor::error::short_key3));
827
877
return ;
828
878
}
829
879
}
@@ -847,7 +897,9 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
847
897
848
898
// We have the complete request. Process it.
849
899
lib::error_code handshake_ec = this ->process_handshake_request ();
850
- this ->send_http_response (handshake_ec);
900
+ if (!m_is_http || m_http_state != session::http_state::deferred) {
901
+ this ->write_http_response (handshake_ec);
902
+ }
851
903
} else {
852
904
// read at least 1 more byte
853
905
transport_con_type::async_read_at_least (
@@ -864,26 +916,26 @@ void connection<config>::handle_read_handshake(lib::error_code const & ec,
864
916
}
865
917
}
866
918
867
- // send_http_response requires the request to be fully read and the connection
919
+ // write_http_response requires the request to be fully read and the connection
868
920
// to be in the PROCESS_HTTP_REQUEST state. In some cases we can detect errors
869
921
// before the request is fully read (specifically at a point where we aren't
870
922
// sure if the hybi00 key3 bytes need to be read). This method sets the correct
871
- // state and calls send_http_response
923
+ // state and calls write_http_response
872
924
template <typename config>
873
- void connection<config>::send_http_response_error (lib::error_code const & ec) {
925
+ void connection<config>::write_http_response_error (lib::error_code const & ec) {
874
926
if (m_internal_state != istate::READ_HTTP_REQUEST) {
875
927
m_alog.write (log::alevel::devel,
876
- " send_http_response_error called in invalid state" );
928
+ " write_http_response_error called in invalid state" );
877
929
this ->terminate (error::make_error_code (error::invalid_state));
878
930
return ;
879
931
}
880
932
881
933
m_internal_state = istate::PROCESS_HTTP_REQUEST;
882
934
883
- this ->send_http_response (ec);
935
+ this ->write_http_response (ec);
884
936
}
885
937
886
- // All exit paths for this function need to call send_http_response () or submit
938
+ // All exit paths for this function need to call write_http_response () or submit
887
939
// a new read request with this function as the handler.
888
940
template <typename config>
889
941
void connection<config>::handle_read_frame(lib::error_code const & ec,
@@ -1113,6 +1165,7 @@ lib::error_code connection<config>::process_handshake_request() {
1113
1165
if (m_http_handler) {
1114
1166
m_is_http = true ;
1115
1167
m_http_handler (m_connection_hdl);
1168
+
1116
1169
if (m_state == session::state::closed) {
1117
1170
return error::make_error_code (error::http_connection_ended);
1118
1171
}
@@ -1207,8 +1260,8 @@ lib::error_code connection<config>::process_handshake_request() {
1207
1260
}
1208
1261
1209
1262
template <typename config>
1210
- void connection<config>::send_http_response (lib::error_code const & ec) {
1211
- m_alog.write (log::alevel::devel," connection send_http_response " );
1263
+ void connection<config>::write_http_response (lib::error_code const & ec) {
1264
+ m_alog.write (log::alevel::devel," connection write_http_response " );
1212
1265
1213
1266
if (ec == error::make_error_code (error::http_connection_ended)) {
1214
1267
m_alog.write (log::alevel::http," An HTTP handler took over the connection." );
@@ -1254,16 +1307,16 @@ void connection<config>::send_http_response(lib::error_code const & ec) {
1254
1307
m_handshake_buffer.data (),
1255
1308
m_handshake_buffer.size (),
1256
1309
lib::bind (
1257
- &type::handle_send_http_response ,
1310
+ &type::handle_write_http_response ,
1258
1311
type::get_shared (),
1259
1312
lib::placeholders::_1
1260
1313
)
1261
1314
);
1262
1315
}
1263
1316
1264
1317
template <typename config>
1265
- void connection<config>::handle_send_http_response (lib::error_code const & ec) {
1266
- m_alog.write (log::alevel::devel," handle_send_http_response " );
1318
+ void connection<config>::handle_write_http_response (lib::error_code const & ec) {
1319
+ m_alog.write (log::alevel::devel," handle_write_http_response " );
1267
1320
1268
1321
lib::error_code ecm = ec;
1269
1322
@@ -1279,7 +1332,7 @@ void connection<config>::handle_send_http_response(lib::error_code const & ec) {
1279
1332
// usually by the handshake timer. This is basically expected
1280
1333
// (though hopefully rare) and there is nothing we can do so ignore.
1281
1334
m_alog.write (log::alevel::devel,
1282
- " handle_send_http_response invoked after connection was closed" );
1335
+ " handle_write_http_response invoked after connection was closed" );
1283
1336
return ;
1284
1337
} else {
1285
1338
ecm = error::make_error_code (error::invalid_state);
@@ -1294,7 +1347,7 @@ void connection<config>::handle_send_http_response(lib::error_code const & ec) {
1294
1347
return ;
1295
1348
}
1296
1349
1297
- log_err (log::elevel::rerror," handle_send_http_response " ,ecm);
1350
+ log_err (log::elevel::rerror," handle_write_http_response " ,ecm);
1298
1351
this ->terminate (ecm);
1299
1352
return ;
1300
1353
}
@@ -1608,7 +1661,10 @@ void connection<config>::terminate(lib::error_code const & ec) {
1608
1661
m_local_close_reason = ec.message ();
1609
1662
}
1610
1663
1611
- // TODO: does this need a mutex?
1664
+ // TODO: does any of this need a mutex?
1665
+ if (m_is_http) {
1666
+ m_http_state = session::http_state::closed;
1667
+ }
1612
1668
if (m_state == session::state::connecting) {
1613
1669
m_state = session::state::closed;
1614
1670
tstat = failed;
0 commit comments