15
15
#include " ManapiHttpRequest.hpp"
16
16
#include " ManapiHttpResponse.hpp"
17
17
#include " ../include/ManapiDefaultErrors.hpp"
18
+ #include " crypto/ManapiCryptoUtils.hpp"
18
19
19
20
static const std::set<std::string> methods = {" POST" , " GET" , " HEAD" , " OPTIONS" , " TRACE" , " PUT" , " DELETE" , " PATCH" , " CONNECT" };
20
21
@@ -432,6 +433,57 @@ manapi::future<> manapi::net::http::internal::send_response_formdata(uq_handle_d
432
433
co_return ;
433
434
}
434
435
436
+ bool http_v1_1_is_chunked_data (manapi::net::http::internal::uq_handle_data_t &cdata, manapi::net::http::response *resp) {
437
+ if (cdata->conn ->version == manapi::net::http::versions::HTTP_v1_1
438
+ && !resp->headers ().contains (manapi::net::http::HEADER.CONTENT_LENGTH )) {
439
+ return true ;
440
+ }
441
+ return false ;
442
+ }
443
+
444
+ manapi::future<> send_http_v1_1_chunked_data (manapi::net::http::internal::uq_handle_data_t &cdata, ssize_t rhs, const void *buffer, std::size_t size, bool &finish) {
445
+ if (rhs < 0 )
446
+ THROW_MANAPIHTTP_EXCEPTION2 (manapi::ERR_INVALID_ARGUMENT, " The callback returned an invalid length" );
447
+
448
+ std::string_view const msg = {" 0\r\n\r\n " };
449
+
450
+ if (rhs) {
451
+ char header[20 ];
452
+
453
+ auto res = std::to_chars (header, header + sizeof (header), rhs, 16 );
454
+
455
+ if (res.ec != std::errc ())
456
+ THROW_MANAPIHTTP_EXCEPTION (manapi::ERR_INTERNAL, " to_chars failed: {}" , std::make_error_code (res.ec ).message ());
457
+
458
+ auto len = static_cast <ssize_t >(res.ptr - header);
459
+
460
+ if (len + 2 > sizeof (header) - 1 )
461
+ /* TODO: think */
462
+ goto err;
463
+
464
+ memcpy (header + len, static_cast <const char *>(" \r\n " ), 2 );
465
+ len += 2 ;
466
+
467
+ if (co_await cdata->worker ->fwrite (cdata->conn , header, len, false ) <= 0 )
468
+ goto err;
469
+
470
+ if (co_await cdata->worker ->fwrite (cdata->conn , buffer, rhs, false ) <= 0 )
471
+ goto err;
472
+
473
+ if (co_await cdata->worker ->fwrite (cdata->conn , msg.data () + 1 , 2 , false ) <= 0 )
474
+ goto err;
475
+ }
476
+
477
+ if (finish) {
478
+ if (co_await cdata->worker ->fwrite (cdata->conn , msg.data (),
479
+ static_cast <ssize_t >(msg.size ()), rhs == 0 ) <= 0 )
480
+ goto err;
481
+ }
482
+ co_return ;
483
+ err:
484
+ THROW_MANAPIHTTP_EXCEPTION2 (manapi::ERR_ABORTED, " write(...) failed" );
485
+ }
486
+
435
487
void manapi::net::http::internal::send_response_sync_cb (uq_handle_data_t cdata, std::unique_ptr<response> res, response_features_t features) {
436
488
if (features.compressor_for_file || features.compressor_for_string ) {
437
489
THROW_MANAPIHTTP_EXCEPTION2 (ERR_FAILED_PRECONDITION, " Compression isn't supported" );
@@ -441,6 +493,10 @@ void manapi::net::http::internal::send_response_sync_cb(uq_handle_data_t cdata,
441
493
THROW_MANAPIHTTP_EXCEPTION2 (ERR_FAILED_PRECONDITION, " Replacers isn't supported" );
442
494
}
443
495
496
+
497
+ if (http_v1_1_is_chunked_data (cdata, res.get ()))
498
+ res->header (http::HEADER.TRANSFER_ENCODING , " chunked" );
499
+
444
500
auto task = mask_response (cdata.get (), res.get (), false );
445
501
manapi::async::run<ssize_t > ( std::move (task),
446
502
[res = std::move (res), cdata = std::move (cdata)] (std::exception_ptr err, ssize_t *result) mutable
@@ -454,25 +510,35 @@ void manapi::net::http::internal::send_response_sync_cb(uq_handle_data_t cdata,
454
510
auto cb_sync = std::make_unique<http::response::resp_callback_sync>(std::move (res->callback_sync ()));
455
511
manapi::async::run ([res = std::move (res), cb_sync = std::move (cb_sync), cdata = std::move (cdata)] () mutable
456
512
-> manapi::future<> {
457
- auto buffer = manapi::async::current ()->memory_fabric ().buffer (res->config ()->buffer_size );
513
+ auto buffer = manapi::async::current ()->memory_fabric ().buffer (
514
+ std::max (res->config ()->buffer_size , 64L ));
458
515
459
516
bool finish = false ;
460
517
std::size_t cursor = 0 ;
461
518
462
- while (!finish) {
463
- auto rhs = cb_sync->operator ()(buffer.data () + cursor, buffer.size () - cursor, finish);
464
- if (rhs < 0 ) {
465
- THROW_MANAPIHTTP_EXCEPTION2 (ERR_INVALID_ARGUMENT, " The callback returned an invalid length" );
519
+
520
+ if (http_v1_1_is_chunked_data (cdata, res.get ())) {
521
+ while (!finish) {
522
+ auto rhs = cb_sync->operator ()(buffer.data (), buffer.size (), finish);
523
+ co_await send_http_v1_1_chunked_data (cdata, rhs, buffer.data (), buffer.size (), finish);
466
524
}
467
- rhs = co_await cdata->worker ->write (cdata->conn , buffer.data () + cursor, rhs, finish);
525
+ }
526
+ else {
527
+ while (!finish) {
528
+ auto rhs = cb_sync->operator ()(buffer.data () + cursor, buffer.size () - cursor, finish);
529
+ if (rhs < 0 ) {
530
+ THROW_MANAPIHTTP_EXCEPTION2 (ERR_INVALID_ARGUMENT, " The callback returned an invalid length" );
531
+ }
532
+ rhs = co_await cdata->worker ->write (cdata->conn , buffer.data () + cursor, rhs, finish);
468
533
469
- if (rhs <= 0 )
470
- co_return ;
534
+ if (rhs <= 0 )
535
+ co_return ;
471
536
472
- cursor += rhs;
537
+ cursor += rhs;
473
538
474
- if (buffer.size () == cursor)
475
- cursor = 0 ;
539
+ if (buffer.size () == cursor)
540
+ cursor = 0 ;
541
+ }
476
542
}
477
543
});
478
544
}
@@ -488,6 +554,9 @@ void manapi::net::http::internal::send_response_stream_cb(uq_handle_data_t cdata
488
554
THROW_MANAPIHTTP_EXCEPTION2 (ERR_FAILED_PRECONDITION, " Replacers isn't supported" );
489
555
}
490
556
557
+ if (http_v1_1_is_chunked_data (cdata, res.get ()))
558
+ res->header (http::HEADER.TRANSFER_ENCODING , " chunked" );
559
+
491
560
auto task = mask_response (cdata.get (), res.get (), false );
492
561
manapi::async::run<ssize_t > (std::move (task),
493
562
[res = std::move (res), cdata = std::move (cdata)] (std::exception_ptr err, ssize_t *result) mutable
@@ -498,13 +567,24 @@ void manapi::net::http::internal::send_response_stream_cb(uq_handle_data_t cdata
498
567
}
499
568
500
569
if (result && *result >= 0 ) {
501
- auto reserved = res->config ()->buffer_size ;
502
570
auto cb_async = std::make_unique<http::response::resp_stream>(std::move (res->callback_stream ()));
503
- manapi::async::run ([res = std::move (res), reserved, cb_async = std::move (cb_async), cdata = std::move (cdata)] () mutable
571
+ manapi::async::run ([res = std::move (res), cb_async = std::move (cb_async), cdata = std::move (cdata)] () mutable
504
572
-> manapi::future<> {
505
- co_await cb_async->operator ()([&cdata] (const void *buffer, ssize_t size, bool fin) -> manapi::future<ssize_t > {
506
- co_return co_await cdata->worker ->fwrite (cdata->conn , buffer, size, fin);
507
- });
573
+ if (http_v1_1_is_chunked_data (cdata, res.get ())) {
574
+ co_await cb_async->operator ()([&cdata]
575
+ (const void *buffer, ssize_t size, bool fin)
576
+ -> manapi::future<ssize_t > {
577
+ co_await send_http_v1_1_chunked_data (cdata, size, buffer, size, fin);
578
+ co_return size;
579
+ });
580
+ }
581
+ else {
582
+ co_await cb_async->operator ()([&cdata]
583
+ (const void *buffer, ssize_t size, bool fin)
584
+ -> manapi::future<ssize_t > {
585
+ co_return co_await cdata->worker ->fwrite (cdata->conn , buffer, size, fin);
586
+ });
587
+ }
508
588
cdata->cb ->call (true );
509
589
});
510
590
}
@@ -521,6 +601,9 @@ void manapi::net::http::internal::send_response_async_cb(uq_handle_data_t cdata,
521
601
THROW_MANAPIHTTP_EXCEPTION2 (ERR_FAILED_PRECONDITION, " Replacers isn't supported" );
522
602
}
523
603
604
+ if (http_v1_1_is_chunked_data (cdata, res.get ()))
605
+ res->header (http::HEADER.TRANSFER_ENCODING , " chunked" );
606
+
524
607
auto task = mask_response (cdata.get (), res.get (), false );
525
608
manapi::async::run<ssize_t > (std::move (task),
526
609
[res = std::move (res), cdata = std::move (cdata)] (std::exception_ptr err, ssize_t *result) mutable
@@ -534,24 +617,33 @@ void manapi::net::http::internal::send_response_async_cb(uq_handle_data_t cdata,
534
617
auto cb_async = std::make_unique<http::response::resp_callback_async>(std::move (res->callback_async ()));
535
618
manapi::async::run ([res = std::move (res), cb_async = std::move (cb_async), cdata = std::move (cdata)] () mutable
536
619
-> manapi::future<> {
537
- auto buffer = manapi::async::current ()->memory_fabric ().buffer (res->config ()->buffer_size );
620
+ auto buffer = manapi::async::current ()->memory_fabric ().buffer (
621
+ std::max (res->config ()->buffer_size , 64L ));
538
622
539
- std::size_t cursor = 0 ;
540
623
bool finish = false ;
541
624
542
- while (!finish) {
543
- auto rhs = co_await cb_async->operator ()(buffer.data () + cursor, buffer.size () - cursor, finish);
544
- if (rhs < 0 )
545
- THROW_MANAPIHTTP_EXCEPTION2 (ERR_INVALID_ARGUMENT, " The callback returned an invalid length" );
625
+ if (http_v1_1_is_chunked_data (cdata, res.get ())) {
626
+ while (!finish) {
627
+ auto rhs = co_await cb_async->operator ()(buffer.data (), buffer.size (), finish);
628
+ co_await send_http_v1_1_chunked_data (cdata, rhs, buffer.data (), buffer.size (), finish);
629
+ }
630
+ }
631
+ else {
632
+ std::size_t cursor = 0 ;
633
+ while (!finish) {
634
+ auto rhs = co_await cb_async->operator ()(buffer.data () + cursor, buffer.size () - cursor, finish);
635
+ if (rhs < 0 )
636
+ THROW_MANAPIHTTP_EXCEPTION2 (ERR_INVALID_ARGUMENT, " The callback returned an invalid length" );
546
637
547
- rhs = co_await cdata->worker ->write (cdata->conn , buffer.data () + cursor, rhs, finish);
548
- if (rhs <= 0 )
549
- co_return ;
638
+ rhs = co_await cdata->worker ->write (cdata->conn , buffer.data () + cursor, rhs, finish);
639
+ if (rhs <= 0 )
640
+ co_return ;
550
641
551
- cursor += rhs;
642
+ cursor += rhs;
552
643
553
- if (cursor == buffer.size ())
554
- cursor = 0 ;
644
+ if (cursor == buffer.size ())
645
+ cursor = 0 ;
646
+ }
555
647
}
556
648
});
557
649
}
0 commit comments