@@ -545,35 +545,63 @@ namespace http = beast::http;
545
545
namespace json = boost::json;
546
546
using tcp = asio::ip::tcp;
547
547
548
- // Function to handle incoming HTTP requests
549
- void handle_request(http::request<http::string_body> req, http::response<http::string_body>& res) {
548
+ // Function to handle incoming HTTP requests and produce appropriate responses
549
+ void handle_request(
550
+ http::request<http::string_body> req, // Incoming HTTP request
551
+ http::response<http::string_body>& res // Outgoing HTTP response (to be filled in)
552
+ ) {
553
+ // JSON object to hold the response body
550
554
json::object response_json;
555
+
556
+ // Log request information to the console for debugging
551
557
std::cout << "Method: " << req.method() << "...\n";
552
558
std::cout << "Target: " << req.target() << "...\n";
553
559
std::cout << "Body: " << req.body() << "...\n\n";
560
+
561
+ // Route: GET /status — return a simple status message
554
562
if (req.method() == http::verb::get && req.target() == "/status") {
555
563
response_json["status"] = "Server is running!";
556
564
}
565
+
566
+ // Route: POST /greet — expects JSON input and returns a personalized greeting
557
567
else if (req.method() == http::verb::post && req.target() == "/greet") {
558
568
try {
569
+
570
+ // Parse the incoming request body as JSON
559
571
json::value parsed_body = json::parse(req.body());
572
+
573
+ // Extract the "name" field from the JSON object
560
574
std::string name = parsed_body.as_object()["name"].as_string().c_str();
575
+
576
+ // Compose a greeting message
561
577
response_json["message"] = "Hello, " + name + "!";
562
578
}
563
579
catch (...) {
580
+
581
+ // If parsing fails or "name" field is missing, return an error
564
582
response_json["error"] = "Invalid JSON format.";
565
583
}
566
584
}
585
+
586
+ // Handle all other unknown endpoints or unsupported methods
567
587
else {
568
588
response_json["error"] = "Unknown endpoint.";
569
589
}
570
590
591
+ // Set the response status to 200 OK
571
592
res.result(http::status::ok);
593
+
594
+ // Specify the content type as JSON
572
595
res.set(http::field::content_type, "application/json");
596
+
597
+ // Serialize the JSON object and assign it to the response body
573
598
res.body() = json::serialize(response_json);
599
+
600
+ // Finalize the response by preparing content-length and other headers
574
601
res.prepare_payload();
575
602
}
576
603
604
+
577
605
// HTTP Server function
578
606
void run_server(asio::io_context& ioc, unsigned short port) {
579
607
tcp::acceptor acceptor(ioc, tcp::endpoint(tcp::v4(), port));
@@ -623,37 +651,62 @@ namespace http = beast::http;
623
651
namespace json = boost::json;
624
652
using tcp = asio::ip::tcp;
625
653
626
- // Function to send an HTTP request
627
- std::string send_request(const std::string& host, const std::string& port, http::verb method, const std::string& target, const std::string& body = "") {
654
+ // Function to send a basic HTTP request using Boost.Beast (synchronous, plain TCP)
655
+ std::string send_request(
656
+ const std::string& host, // e.g., "api.example.com"
657
+ const std::string& port, // e.g., "80" or "443" (for HTTPS you'd need SSL setup)
658
+ http::verb method, // HTTP method, e.g., http::verb::post or http::verb::get
659
+ const std::string& target, // The path/resource being requested, e.g., "/v1/data"
660
+ const std::string& body = "" // Optional request body (for POST/PUT)
661
+ ) {
628
662
try {
663
+ // Create an I/O context required for all I/O operations
629
664
asio::io_context ioc;
665
+
666
+ // Create a resolver to turn the host name into a TCP endpoint
630
667
tcp::resolver resolver(ioc);
668
+
669
+ // Create the TCP stream for connecting and communicating
631
670
beast::tcp_stream stream(ioc);
632
671
672
+ // Resolve the host and port into a list of endpoints
633
673
auto const results = resolver.resolve(host, port);
634
- stream.connect(results);
635
674
636
- http::request<http::string_body> req{ method, target, 11 };
637
- req.set(http::field::host, host);
638
- req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING);
639
- req.set(http::field::content_type, "application/json");
640
- req.body() = body;
641
- req.prepare_payload();
675
+ // Establish a connection to one of the resolved endpoints
676
+ stream.connect(results);
642
677
643
- if (!body.empty()) req.body() = body;
678
+ // Build the HTTP request message
679
+ http::request<http::string_body> req{ method, target, 11 }; // HTTP/1.1
680
+ req.set(http::field::host, host); // Required: Host header
681
+ req.set(http::field::user_agent, BOOST_BEAST_VERSION_STRING); // Optional: Identifies the client
682
+ req.set(http::field::content_type, "application/json"); // Optional: for JSON bodies
683
+ req.body() = body; // Set the request body (if any)
684
+ req.prepare_payload(); // Sets Content-Length and finalizes headers
644
685
686
+ // Send the HTTP request to the remote host
645
687
http::write(stream, req);
688
+
689
+ // Buffer for receiving data
646
690
beast::flat_buffer buffer;
691
+
692
+ // Container for the HTTP response
647
693
http::response<http::string_body> res;
694
+
695
+ // Receive the response
648
696
http::read(stream, buffer, res);
649
697
698
+ // Return only the response body as a string
650
699
return res.body();
651
700
}
652
701
catch (std::exception& e) {
702
+
703
+ // Return the exception message prefixed with "Client error:"
653
704
return std::string("Client error: ") + e.what();
654
705
}
655
706
}
656
707
708
+
709
+
657
710
int main() {
658
711
std::string host = "127.0.0.1";
659
712
std::string port = "8080";
0 commit comments