Skip to content

Commit b6c2bee

Browse files
committed
Updated client errors and added code to allow the processing of a response body.
1 parent 6eb8e03 commit b6c2bee

File tree

6 files changed

+107
-88
lines changed

6 files changed

+107
-88
lines changed

http/src/http/v2/client/client.cpp

Lines changed: 62 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ namespace network {
4444
std::size_t bytes_read,
4545
std::shared_ptr<response> res);
4646

47+
void read_response_body(const boost::system::error_code &ec,
48+
std::size_t bytes_read,
49+
std::shared_ptr<response> res);
50+
4751
std::future<response> do_request(method method_, request request_, request_options options);
4852

4953
client_options options_;
@@ -83,7 +87,7 @@ namespace network {
8387
if (ec) {
8488
if (endpoint_iterator == tcp::resolver::iterator()) {
8589
response_promise_.set_exception(std::make_exception_ptr(
86-
connection_error(client_error::host_not_found)));
90+
client_exception(client_error::host_not_found)));
8791
return;
8892
}
8993

@@ -142,19 +146,19 @@ namespace network {
142146
}
143147

144148
std::istream is(&response_);
145-
std::string version;
149+
string_type version;
146150
is >> version;
147151
unsigned int status;
148152
is >> status;
149-
std::string message;
153+
string_type message;
150154
std::getline(is, message);
151155

152156
res->set_version(version);
153157
res->set_status(network::http::v2::status::code(status));
154158
res->set_status_message(boost::trim_copy(message));
155159

156160
connection_->async_read_until(response_,
157-
"\r\n",
161+
"\r\n\r\n",
158162
strand_.wrap(
159163
[=] (const boost::system::error_code &ec,
160164
std::size_t bytes_read) {
@@ -173,23 +177,65 @@ namespace network {
173177

174178
// fill headers
175179
std::istream is(&response_);
176-
std::string header;
177-
while ((header != "\r") && std::getline(is, header)) {
180+
string_type header;
181+
while (std::getline(is, header) && (header != "\r")) {
178182
std::vector<string_type> kvp;
179183
boost::split(kvp, header, boost::is_any_of(":"));
180184
res->add_header(kvp[0], boost::trim_copy(kvp[1]));
181185
}
182186

183-
connection_->async_read_until(response_,
184-
"\r\n\r\n",
185-
strand_.wrap(
186-
[=] (const boost::system::error_code &ec,
187-
std::size_t bytes_read) {
188-
// um...
189-
response_promise_.set_value(*res);
190-
}));
187+
connection_->async_read(response_,
188+
strand_.wrap(
189+
[=] (const boost::system::error_code &ec,
190+
std::size_t bytes_read) {
191+
read_response_body(ec, bytes_read, res);
192+
}));
193+
}
194+
195+
namespace {
196+
std::istream &getline_with_newline(std::istream &is, std::string &line) {
197+
line.clear();
198+
199+
std::istream::sentry se(is, true);
200+
std::streambuf *sb = is.rdbuf();
201+
202+
while (true) {
203+
int c = sb->sbumpc();
204+
switch (c) {
205+
case EOF:
206+
if (line.empty()) {
207+
is.setstate(std::ios::eofbit);
208+
}
209+
return is;
210+
default:
211+
line += static_cast<char>(c);
212+
}
213+
}
214+
}
215+
} // namespace
216+
217+
void client::impl::read_response_body(const boost::system::error_code &ec,
218+
std::size_t bytes_read,
219+
std::shared_ptr<response> res) {
220+
if (bytes_read == 0) {
221+
response_promise_.set_value(*res);
222+
return;
191223
}
192224

225+
std::istream is(&response_);
226+
string_type line;
227+
while (!getline_with_newline(is, line).eof()) {
228+
res->append_body(line);
229+
}
230+
231+
connection_->async_read(response_,
232+
strand_.wrap(
233+
[=] (const boost::system::error_code &ec,
234+
std::size_t bytes_read) {
235+
read_response_body(ec, bytes_read, res);
236+
}));
237+
}
238+
193239
std::future<response> client::impl::do_request(method met,
194240
request req,
195241
request_options options) {
@@ -199,7 +245,8 @@ namespace network {
199245
std::ostream request_stream(&request_);
200246
request_stream << req;
201247
if (!request_stream) {
202-
// set error
248+
response_promise_.set_exception(std::make_exception_ptr(
249+
client_exception(client_error::invalid_request)));
203250
}
204251

205252
// HTTP 1.1

http/src/http/v2/client/client_errors.cpp

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ namespace network {
3737
switch (client_error(ev)) {
3838
case client_error::invalid_url:
3939
return "Requires HTTP or HTTPS URL.";
40-
case client_error::resolver_error:
41-
return "Unable to resolve host";
40+
case client_error::invalid_request:
41+
return "Invalid HTTP request.";
42+
case client_error::host_not_found:
43+
return "Unable to resolve host.";
44+
case client_error::invalid_response:
45+
return "Invalid HTTP response.";
4246
default:
4347
break;
4448
}
@@ -63,21 +67,12 @@ namespace network {
6367

6468
}
6569

66-
resolver_error::resolver_error()
67-
: std::system_error(make_error_code(client_error::resolver_error)) {
68-
69-
}
70-
71-
resolver_error::~resolver_error() {
72-
73-
}
74-
75-
connection_error::connection_error(client_error error)
70+
client_exception::client_exception(client_error error)
7671
: std::system_error(make_error_code(error)) {
7772

7873
}
7974

80-
connection_error::~connection_error() {
75+
client_exception::~client_exception() {
8176

8277
}
8378

http/src/network/http/v2/client/client_errors.hpp

Lines changed: 9 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ namespace network {
2020
namespace v2 {
2121
/**
2222
* \ingroup http_client
23-
* \enum client_error network/http/v2/client/client_errors.hpp
23+
* \enum client_error network/http/v2/client/client_errors.hpp network/http/v2/client.hpp
2424
* \brief An enumeration of all types of client error.
2525
*/
2626
enum class client_error {
2727
// url
2828
invalid_url,
2929

30-
// resolution
31-
resolver_error,
30+
// request
31+
invalid_request,
3232

3333
// connection
3434
host_not_found,
@@ -49,7 +49,7 @@ namespace network {
4949

5050
/**
5151
* \ingroup http_client
52-
* \class invalid_url network/http/v2/client/client_errors.hpp
52+
* \class invalid_url network/http/v2/client/client_errors.hpp network/http/v2/client.hpp
5353
* \brief An exception thrown if the URL provides is invalid.
5454
*/
5555
class invalid_url : public std::system_error {
@@ -70,67 +70,25 @@ namespace network {
7070

7171
/**
7272
* \ingroup http_client
73-
* \class resolver_error network/http/v2/client/client_errors.hpp
74-
* \brief An exception thrown when there is a resolver error.
73+
* \class client_exception network/http/v2/client/client_errors.hpp network/http/v2/client.hpp
74+
* \brief An exception thrown when there is a client error.
7575
*/
76-
class resolver_error : std::system_error {
76+
class client_exception : public std::system_error {
7777

7878
public:
7979

8080
/**
8181
* \brief Constructor.
8282
*/
83-
explicit resolver_error();
83+
explicit client_exception(client_error error);
8484

8585
/**
8686
* \brief Destructor.
8787
*/
88-
virtual ~resolver_error() noexcept;
88+
virtual ~client_exception() noexcept;
8989

9090
};
9191

92-
/**
93-
* \ingroup http_client
94-
* \class connection_error network/http/v2/client/client_errors.hpp
95-
* \brief An exception thrown when there is a connection error.
96-
*/
97-
class connection_error : public std::system_error {
98-
99-
public:
100-
101-
/**
102-
* \brief Constructor.
103-
* \param The client_error code.
104-
*/
105-
explicit connection_error(client_error error);
106-
107-
/**
108-
* \brief Destructor.
109-
*/
110-
virtual ~connection_error() noexcept;
111-
112-
};
113-
114-
/**
115-
* \ingroup http_client
116-
* \class response_error network/http/v2/client/client_errors.hpp
117-
*/
118-
class response_error : public std::system_error {
119-
120-
public:
121-
122-
/**
123-
* \brief Constructor.
124-
* \param The client_error code.
125-
*/
126-
explicit response_error(client_error error);
127-
128-
/**
129-
* \brief Destructor.
130-
*/
131-
virtual ~response_error() noexcept;
132-
133-
};
13492
} // namespace v2
13593
} // namespace http
13694
} // namespace network

http/src/network/http/v2/client/connection/async_connection.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,8 @@ namespace network {
7777
const std::string &delim,
7878
read_callback callback) = 0;
7979

80+
virtual void async_read(boost::asio::streambuf &command_streambuf,
81+
read_callback callback) = 0;
8082

8183
/**
8284
* \brief Cancels an operation on a connection.

http/src/network/http/v2/client/connection/normal_connection.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#define NETWORK_HTTP_V2_CLIENT_CONNECTION_NORMAL_CONNECTION_INC
88

99
#include <boost/asio/write.hpp>
10+
#include <boost/asio/read.hpp>
1011
#include <boost/asio/read_until.hpp>
1112
#include <boost/asio/ip/tcp.hpp>
1213
#include <boost/asio/io_service.hpp>
@@ -50,6 +51,12 @@ namespace network {
5051
boost::asio::async_read_until(*socket_, command_streambuf, delim, callback);
5152
}
5253

54+
virtual void async_read(boost::asio::streambuf &command_streambuf,
55+
read_callback callback) {
56+
boost::asio::async_read(*socket_, command_streambuf,
57+
boost::asio::transfer_at_least(1), callback);
58+
}
59+
5360
virtual void cancel() {
5461
socket_->cancel();
5562
}

http/src/network/http/v2/client/response.hpp

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,8 @@ namespace network {
6767
: version_(other.version_)
6868
, status_(other.status_)
6969
, status_message_(other.status_message_)
70-
, headers_(other.headers_) {
70+
, headers_(other.headers_)
71+
, body_(other.body_) {
7172

7273
}
7374

@@ -79,7 +80,8 @@ namespace network {
7980
: version_(std::move(other.version_))
8081
, status_(std::move(other.status_))
8182
, status_message_(std::move(other.status_message_))
82-
, headers_(std::move(other.headers_)) {
83+
, headers_(std::move(other.headers_))
84+
, body_(std::move(other.body_)) {
8385

8486
}
8587

@@ -102,13 +104,14 @@ namespace network {
102104
swap(status_, other.status_);
103105
swap(status_message_, other.status_message_);
104106
swap(headers_, other.headers_);
107+
swap(body_, other.body_);
105108
}
106109

107110
/**
108111
* \brief Sets the HTTP version.
109112
* \param version The HTTP version (1.0 or 1.1).
110113
*/
111-
void set_version(const string_type &version) {
114+
void set_version(string_type version) {
112115
version_ = version;
113116
}
114117

@@ -140,7 +143,7 @@ namespace network {
140143
* \brief Sets the HTTP response status message.
141144
* \param status The HTTP response status message.
142145
*/
143-
void set_status_message(const string_type &status_message) {
146+
void set_status_message(string_type status_message) {
144147
status_message_ = status_message;
145148
}
146149

@@ -163,19 +166,26 @@ namespace network {
163166
return boost::make_iterator_range(std::begin(headers_), std::end(headers_));
164167
}
165168

166-
std::future<string_type> read_body(std::size_t length) const;
169+
void append_body(const char *body, std::size_t length) {
170+
body_.reserve(body_.size() + length);
171+
body_.append(body);
172+
}
173+
174+
void append_body(string_type body) {
175+
body_.append(body);
176+
}
167177

168-
// add_header
169-
// set_body
170-
// append_body
171-
// get_body
178+
string_type body() const {
179+
return body_;
180+
}
172181

173182
private:
174183

175184
string_type version_;
176185
network::http::v2::status::code status_;
177186
string_type status_message_;
178187
headers_type headers_;
188+
string_type body_;
179189

180190
};
181191

0 commit comments

Comments
 (0)