Line data Source code
1 : #ifndef THINGER_HTTP_CLIENT_RESPONSE_HPP
2 : #define THINGER_HTTP_CLIENT_RESPONSE_HPP
3 :
4 : #include "../common/http_response.hpp"
5 : #include <boost/system/error_code.hpp>
6 : #include <cassert>
7 : #include <memory>
8 : #include <nlohmann/json.hpp>
9 :
10 : namespace thinger::http {
11 :
12 : class client_response {
13 : private:
14 : std::shared_ptr<http_response> response_;
15 : boost::system::error_code error_;
16 :
17 : public:
18 : // Constructors
19 : client_response() = default;
20 :
21 767 : client_response(const boost::system::error_code& ec,
22 : std::shared_ptr<http_response> res)
23 767 : : response_(std::move(res)), error_(ec) {}
24 :
25 : // Status checks
26 708 : bool ok() const {
27 1382 : return !error_ && response_ && static_cast<int>(response_->get_status()) >= 200 &&
28 1382 : static_cast<int>(response_->get_status()) < 300;
29 : }
30 :
31 : bool success() const { return ok(); }
32 :
33 : operator bool() const { return !error_ && response_; }
34 :
35 : bool has_error() const { return error_ || !response_; }
36 :
37 : bool has_network_error() const { return error_.value() != 0; }
38 :
39 0 : bool has_http_error() const {
40 0 : return !error_ && response_ && static_cast<int>(response_->get_status()) >= 400;
41 : }
42 :
43 : // Content access
44 46 : const std::string& body() const {
45 46 : static const std::string empty;
46 46 : return response_ ? response_->get_content() : empty;
47 : }
48 :
49 : std::string_view text() const { return body(); }
50 :
51 193 : nlohmann::json json() const {
52 193 : if (!response_ || response_->get_content().empty()) {
53 0 : return nlohmann::json();
54 : }
55 193 : auto j = nlohmann::json::parse(response_->get_content(), nullptr, false);
56 193 : if (j.is_discarded()) {
57 0 : return nlohmann::json();
58 : }
59 193 : return j;
60 193 : }
61 :
62 : // Status info
63 164 : int status() const {
64 164 : return response_ ? static_cast<int>(response_->get_status()) : 0;
65 : }
66 :
67 : int status_code() const { return status(); }
68 :
69 15 : bool is_redirect() const {
70 15 : return response_ && response_->is_redirect_response();
71 : }
72 :
73 7 : bool is_client_error() const {
74 7 : return response_ && status() >= 400 && status() < 500;
75 : }
76 :
77 7 : bool is_server_error() const {
78 7 : return response_ && status() >= 500;
79 : }
80 :
81 : // Headers
82 37 : std::string header(const std::string& key) const {
83 37 : return response_ && response_->has_header(key) ?
84 111 : response_->get_header(key) : "";
85 : }
86 :
87 6 : bool has_header(const std::string& key) const {
88 6 : return response_ && response_->has_header(key);
89 : }
90 :
91 : // Error info
92 0 : std::string error() const {
93 0 : if (error_) {
94 0 : return error_.message();
95 0 : } else if (!response_) {
96 0 : return "No response received";
97 0 : } else if (has_http_error()) {
98 0 : return "HTTP error " + std::to_string(status());
99 : }
100 0 : return "";
101 : }
102 :
103 : std::string error_message() const { return error(); }
104 :
105 : const boost::system::error_code& error_code() const { return error_; }
106 :
107 : // Advanced access
108 : const http_response* operator->() const { return response_.get(); }
109 :
110 : const http_response& operator*() const {
111 : assert(response_ && "Dereferencing empty client_response");
112 : return *response_;
113 : }
114 :
115 : std::shared_ptr<http_response> get() const { return response_; }
116 :
117 : // Content type helpers
118 8 : std::string content_type() const {
119 16 : return header("Content-Type");
120 : }
121 :
122 : size_t content_length() const {
123 : if (!response_) return 0;
124 : return response_->get_content_size();
125 : }
126 :
127 : bool is_json() const {
128 : auto ct = content_type();
129 : return ct.find("application/json") != std::string::npos;
130 : }
131 :
132 : bool is_html() const {
133 : auto ct = content_type();
134 : return ct.find("text/html") != std::string::npos;
135 : }
136 :
137 : bool is_text() const {
138 : auto ct = content_type();
139 : return ct.find("text/") == 0;
140 : }
141 : };
142 :
143 : } // namespace thinger::http
144 :
145 : #endif // THINGER_HTTP_CLIENT_RESPONSE_HPP
|