Skip to content

Commit bcf175d

Browse files
committedAug 21, 2017
- Fixed problem with connections not being released once all data is read (closes jgaa#24)
- Refactored a few tests to avoid error-indicators in kdevelop - Added more fine-graded time outs
1 parent dfce221 commit bcf175d

26 files changed

+316
-167
lines changed
 

‎externals/rapidjson

‎include/restc-cpp/DataReaderStream.h

+1-3
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ class DataReaderStream : public DataReader {
5555
--getc_bytes_;
5656
}
5757

58-
void SetEof() {
59-
eof_ = true;
60-
}
58+
void SetEof();
6159

6260
char GetCurrentCh() const {
6361
assert(curr_ != nullptr);

‎include/restc-cpp/IoTimer.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ class IoTimer : public std::enable_shared_from_this<IoTimer>
113113
[weak_connection, timerName]() {
114114
if (auto connection = weak_connection.lock()) {
115115
if (connection->GetSocket().GetSocket().is_open()) {
116-
RESTC_CPP_LOG_WARN
116+
RESTC_CPP_LOG_TRACE
117117
<< "Timer " << timerName << ": "
118118
<< *connection
119119
<< " timed out.";
120-
connection->GetSocket().GetSocket().close();
120+
connection->GetSocket().Close(Socket::Reason::TIME_OUT);
121121
}
122122
}
123123
}));

‎include/restc-cpp/IteratorFromJsonSerializer.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,8 @@ class IteratorFromJsonSerializer
172172
state_ = State::DONE;
173173
break;
174174
} else {
175-
throw ParseException("Unexpected character in input stream");
175+
static const std::string err_msg{"IteratorFromJsonSerializer: Unexpected character in input stream: "};
176+
throw ParseException(err_msg + std::string(1, ch));
176177
}
177178
}
178179
}

‎include/restc-cpp/RapidJsonReader.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@ class RapidJsonReader {
6868
//! \return The begin writer pointer.
6969
Ch* PutBegin() {
7070
assert(false);
71-
return nullptr;
71+
return nullptr;
7272
}
7373

7474
//! Write a character.
@@ -86,7 +86,7 @@ class RapidJsonReader {
8686
//! \return Number of characters written.
8787
size_t PutEnd(Ch* begin) {
8888
assert(false);
89-
return 0;
89+
return 0;
9090
}
9191

9292
private:

‎include/restc-cpp/RequestBuilder.h

+20-4
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,21 @@
1616
#include "rapidjson/writer.h"
1717
#include "rapidjson/stringbuffer.h"
1818

19+
// If enabled, 'localhost' is mapped to the content of the
20+
// environment variable RESTC_CPP_TEST_DOCKER_ADDRESS
21+
1922
namespace restc_cpp {
2023

24+
#ifdef RESTC_CPP_ENABLE_URL_TEST_MAPPING
25+
# ifndef RESTC_CPP_TEST_HELPER_H_
26+
# error "Include "restc-cpp/test_helper.h" first"
27+
# endif
28+
# define MAP_URL_FOR_TESTING(url) url = GetDockerUrl(url);
29+
#else
30+
# define MAP_URL_FOR_TESTING(url)
31+
#endif
32+
33+
2134
/*! Convenience class for building requests */
2235
class RequestBuilder
2336
{
@@ -30,6 +43,7 @@ class RequestBuilder
3043
RequestBuilder& Get(std::string url) {
3144
assert(url_.empty());
3245
url_ = std::move(url);
46+
MAP_URL_FOR_TESTING(url_);
3347
type_ = Request::Type::GET;
3448
return *this;
3549
}
@@ -38,6 +52,7 @@ class RequestBuilder
3852
RequestBuilder& Post(std::string url) {
3953
assert(url_.empty());
4054
url_ = std::move(url);
55+
MAP_URL_FOR_TESTING(url_);
4156
type_ = Request::Type::POST;
4257
return *this;
4358
}
@@ -46,6 +61,7 @@ class RequestBuilder
4661
RequestBuilder& Put(std::string url) {
4762
assert(url_.empty());
4863
url_ = std::move(url);
64+
MAP_URL_FOR_TESTING(url_);
4965
type_ = Request::Type::PUT;
5066
return *this;
5167
}
@@ -54,6 +70,7 @@ class RequestBuilder
5470
RequestBuilder& Delete(std::string url) {
5571
assert(url_.empty());
5672
url_ = std::move(url);
73+
MAP_URL_FOR_TESTING(url_);
5774
type_ = Request::Type::DELETE;
5875
return *this;
5976
}
@@ -76,7 +93,7 @@ class RequestBuilder
7693
headers_->insert({std::move(name), std::move(value)});
7794
return *this;
7895
}
79-
96+
8097
RequestBuilder& AddHeaders(const Request::headers_t& headers) {
8198
if (!headers_) {
8299
headers_ = Request::headers_t();
@@ -87,15 +104,15 @@ class RequestBuilder
87104
}
88105
return *this;
89106
}
90-
107+
91108
RequestBuilder& AddHeaders(
92109
boost::optional<Request::headers_t> headers) {
93110
if (headers) {
94111
return AddHeaders(*headers);
95112
}
96113
return *this;
97114
}
98-
115+
99116

100117
/*! Add a request argument
101118
*
@@ -295,6 +312,5 @@ class RequestBuilder
295312

296313
} // restc_cpp
297314

298-
299315
#endif // RESTC_CPP_REQUEST_BUILDER_H_
300316

‎include/restc-cpp/Socket.h

+30-1
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,21 @@
88

99
#include <vector>
1010

11+
#include <boost/system/error_code.hpp>
12+
13+
#include "restc-cpp/typename.h"
14+
#include "error.h"
15+
1116
namespace restc_cpp {
1217

1318
class Socket
1419
{
1520
public:
21+
enum class Reason {
22+
DONE,
23+
TIME_OUT
24+
};
25+
1626
virtual ~Socket() = default;
1727

1828
virtual boost::asio::ip::tcp::socket& GetSocket() = 0;
@@ -36,7 +46,7 @@ class Socket
3646

3747
virtual void AsyncShutdown(boost::asio::yield_context& yield) = 0;
3848

39-
virtual void Close() = 0;
49+
virtual void Close(Reason reoson = Reason::DONE) = 0;
4050

4151
virtual bool IsOpen() const noexcept = 0;
4252

@@ -49,6 +59,25 @@ class Socket
4959
};
5060

5161

62+
class ExceptionWrapper {
63+
protected:
64+
template <typename Tret, typename Tfn>
65+
Tret WrapException(Tfn fn) {
66+
try {
67+
return fn();
68+
} catch (const boost::system::system_error& ex) {
69+
if (ex.code().value() == boost::system::errc::operation_canceled) {
70+
if (reason_ == Socket::Reason::TIME_OUT) {
71+
throw RequestTimeOutException();
72+
}
73+
}
74+
throw;
75+
}
76+
}
77+
78+
boost::optional<Socket::Reason> reason_;
79+
};
80+
5281
} // restc_cpp
5382

5483

‎include/restc-cpp/error.h

+6
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ struct ObjectExpiredException : public RestcCppException
149149
: RestcCppException(cause) {}
150150
};
151151

152+
struct RequestTimeOutException : public RestcCppException
153+
{
154+
RequestTimeOutException()
155+
: RestcCppException("Request Timed Out") {}
156+
};
157+
152158
} // namespace
153159
#endif // RESTC_CPP_ERROR_H_
154160

‎include/restc-cpp/test_helper.h

+11-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,22 @@
11
#pragma once
22

3+
#define RESTC_CPP_TEST_HELPER_H_
4+
35
#include <cstdlib>
46
#include <boost/algorithm/string.hpp>
57

8+
69
namespace restc_cpp {
710
namespace {
811

9-
#define STARTCASE(name) { CASE(#name)
10-
#define ENDCASE },
12+
#define STARTCASE(name) { CASE(#name) { \
13+
RESTC_CPP_LOG_DEBUG << "================================"; \
14+
RESTC_CPP_LOG_INFO << "Test case: " << #name; \
15+
RESTC_CPP_LOG_DEBUG << "================================";
16+
17+
#define ENDCASE \
18+
RESTC_CPP_LOG_DEBUG << "============== ENDCASE ============="; \
19+
}},
1120

1221
template<typename T1, typename T2>
1322
bool compare(const T1& left, const T2& right) {

‎src/ChunkedReaderImpl.cpp

+30-16
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
#include <assert.h>
2+
#include <locale.h>
3+
#include <ios>
24

35
#include "restc-cpp/restc-cpp.h"
46
#include "restc-cpp/DataReader.h"
@@ -23,24 +25,35 @@ class ChunkedReaderImpl : public DataReader {
2325
return stream_->IsEof();
2426
}
2527

26-
void Log(const boost::asio::const_buffers_1 buffers, const char *tag) {
27-
size_t seg = 0;
28+
string ToPrintable(boost::string_ref buf) const {
29+
ostringstream out;
30+
locale loc;
31+
auto pos = 0;
32+
out << endl;
2833

29-
// At the time of the implementation, there are never multiple buffers.
30-
// However, if this change in the future, this logging will still be correct.
31-
// It may save some time if other propbels occur.
32-
for(const auto buffer : buffers) {
34+
for(const auto ch : buf) {
35+
if (!(++pos % 80)) {
36+
out << endl;
37+
}
38+
if (std::isprint(ch, loc)) {
39+
out << ch;
40+
} else {
41+
out << '.';
42+
}
43+
}
3344

34-
boost::string_ref sr {
35-
boost::asio::buffer_cast<const char *>(buffer),
36-
boost::asio::buffer_size(buffer)
37-
};
45+
return out.str();
46+
}
3847

39-
RESTC_CPP_LOG_TRACE << tag << ' ' << seg << "# "
40-
<< boost::asio::buffer_size(buffer) << " bytes: " << sr;
48+
void Log(const boost::asio::const_buffers_1 buffers, const char *tag) {
49+
const auto buf_len = boost::asio::buffer_size(*buffers.begin());
4150

42-
++seg;
43-
}
51+
// At the time of the implementation, there are never multiple buffers.
52+
RESTC_CPP_LOG_TRACE << tag << ' ' << "# " << buf_len
53+
<< " bytes: "
54+
<< ToPrintable({
55+
boost::asio::buffer_cast<const char *>(*buffers.begin()),
56+
buf_len});
4457
}
4558

4659
boost::asio::const_buffers_1 ReadSome() override {
@@ -54,6 +67,9 @@ class ChunkedReaderImpl : public DataReader {
5467
if (chunk_len_ == 0) {
5568
RESTC_CPP_LOG_TRACE << "ChunkedReaderImpl::ReadSome(): Need new chunk.";
5669
chunk_len_ = GetNextChunkLen();
70+
RESTC_CPP_LOG_TRACE << "ChunkedReaderImpl::ReadSome(): "
71+
<< "Next chunk is " << chunk_len_ << " bytes ("
72+
<< hex << chunk_len_ << " hex)";
5773
if (chunk_len_ == 0) {
5874
// Read the trailer
5975
RESTC_CPP_LOG_TRACE << "ChunkedReaderImpl::ReadSome(): End of chunked stream - reading headers";
@@ -130,8 +146,6 @@ class ChunkedReaderImpl : public DataReader {
130146
throw ParseException("Missing LF in first chunk line");
131147
}
132148

133-
RESTC_CPP_LOG_TRACE << "ChunkedReaderImpl::GetNextChunkLen(): " << chunk_len;
134-
135149
return chunk_len;
136150
}
137151

‎src/DataReaderStream.cpp

+15-4
Original file line numberDiff line numberDiff line change
@@ -22,24 +22,30 @@ void DataReaderStream::Fetch() {
2222
RESTC_CPP_LOG_TRACE << "DataReaderStream::Fetch: Fetched buffer with "
2323
<< boost::asio::buffer_size(buf) << " bytes.";
2424

25-
curr_ = boost::asio::buffer_cast<const char *>(buf);
26-
end_ = curr_ + boost::asio::buffer_size(buf);
27-
eof_ = curr_ == end_;
28-
if (eof_) {
25+
const auto bytes = boost::asio::buffer_size(buf);
26+
if (bytes == 0) {
2927
RESTC_CPP_LOG_TRACE << "DataReaderStream::Fetch: EOF";
3028
throw ProtocolException("Fetch(): EOF");
3129
}
30+
curr_ = boost::asio::buffer_cast<const char *>(buf);
31+
end_ = curr_ + boost::asio::buffer_size(buf);
3232
}
3333
}
3434

3535
boost::asio::const_buffers_1
3636
DataReaderStream::ReadSome() {
3737
Fetch();
38+
3839
boost::asio::const_buffers_1 rval = {curr_,
3940
static_cast<size_t>(end_ - curr_)};
4041
curr_ = end_;
4142
RESTC_CPP_LOG_TRACE << "DataReaderStream::ReadSome: Returning buffer with "
4243
<< boost::asio::buffer_size(rval) << " bytes.";
44+
45+
if (source_->IsEof()) {
46+
SetEof();
47+
}
48+
4349
return rval;
4450
}
4551

@@ -218,4 +224,9 @@ std::string DataReaderStream::GetHeaderValue() {
218224
}
219225

220226

227+
void DataReaderStream::SetEof() {
228+
RESTC_CPP_LOG_TRACE << "Reached EOF";
229+
eof_ = true;
230+
}
231+
221232
} // namespace

0 commit comments

Comments
 (0)
Please sign in to comment.