Rework the client error handling
This commit is contained in:
@@ -31,8 +31,8 @@ int main() {
|
||||
// Print the response content data.
|
||||
std::cout << r->content() << std::endl;
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
+14
-14
@@ -73,8 +73,8 @@ TEST(ClientTest, Get_RequestFunc) {
|
||||
|
||||
AssertGet(r);
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,8 +88,8 @@ TEST(ClientTest, Get_Shortcut) {
|
||||
|
||||
AssertGet(r);
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,8 +110,8 @@ TEST(ClientTest, Get_SSL) {
|
||||
|
||||
AssertGet(r);
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
#endif // WEBCC_ENABLE_SSL
|
||||
@@ -131,8 +131,8 @@ TEST(ClientTest, Compression_Gzip) {
|
||||
|
||||
EXPECT_EQ(true, json["gzipped"].asBool());
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,8 @@ TEST(ClientTest, Compression_Deflate) {
|
||||
|
||||
EXPECT_EQ(true, json["deflated"].asBool());
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -201,8 +201,8 @@ TEST(ClientTest, KeepAlive) {
|
||||
|
||||
EXPECT_TRUE(iequals(r->GetHeader("Connection"), "Keep-alive"));
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -226,8 +226,8 @@ TEST(ClientTest, GetImageJpeg) {
|
||||
|
||||
// TODO: Verify the response is a valid JPEG image.
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,8 +58,8 @@ int main() {
|
||||
|
||||
#endif // WEBCC_ENABLE_SSL
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << "Exception: " << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -58,8 +58,8 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
std::cout << r->status() << std::endl;
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << "Exception: " << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
@@ -55,7 +55,7 @@ int main(int argc, char* argv[]) {
|
||||
server.Run();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -67,8 +67,8 @@ void ListEvents(webcc::ClientSession& session) {
|
||||
|
||||
PRINT_JSON_STRING(r->content());
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,8 +81,8 @@ void ListUserFollowers(webcc::ClientSession& session, const std::string& user) {
|
||||
|
||||
PRINT_JSON_STRING(r->content());
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,8 +100,8 @@ void ListAuthUserFollowers(webcc::ClientSession& session,
|
||||
|
||||
PRINT_JSON_STRING(r->content());
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +124,8 @@ void CreateAuthorization(webcc::ClientSession& session,
|
||||
|
||||
std::cout << r->content() << std::endl;
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cout << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cout << error << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,8 +74,8 @@ public:
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -97,8 +97,8 @@ public:
|
||||
|
||||
return !id->empty();
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -122,8 +122,8 @@ public:
|
||||
|
||||
return JsonStringToBook(r->content(), book);
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -143,8 +143,8 @@ public:
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -159,8 +159,8 @@ public:
|
||||
|
||||
return true;
|
||||
|
||||
} catch (const webcc::Exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
} catch (const webcc::Error& error) {
|
||||
std::cerr << error << std::endl;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,7 +238,7 @@ int main(int argc, char* argv[]) {
|
||||
server.Run();
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
std::cerr << "Exception: " << e.what() << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
+56
-60
@@ -12,43 +12,30 @@ Client::Client()
|
||||
buffer_size_(kBufferSize),
|
||||
timeout_(kMaxReadSeconds),
|
||||
closed_(false),
|
||||
timer_canceled_(false),
|
||||
timed_out_(false),
|
||||
error_(kNoError) {
|
||||
timer_canceled_(false) {
|
||||
}
|
||||
|
||||
bool Client::Request(RequestPtr request, bool connect) {
|
||||
io_context_.restart();
|
||||
|
||||
response_.reset(new Response{});
|
||||
response_parser_.Init(response_.get());
|
||||
|
||||
closed_ = false;
|
||||
timer_canceled_ = false;
|
||||
timed_out_ = false;
|
||||
error_ = kNoError;
|
||||
|
||||
if (buffer_.size() != buffer_size_) {
|
||||
LOG_VERB("Resize buffer: %u -> %u.", buffer_.size(), buffer_size_);
|
||||
buffer_.resize(buffer_size_);
|
||||
}
|
||||
Error Client::Request(RequestPtr request, bool connect) {
|
||||
Restart();
|
||||
|
||||
if (connect) {
|
||||
// No existing socket connection was specified, create a new one.
|
||||
if ((error_ = Connect(request)) != kNoError) {
|
||||
return false;
|
||||
Connect(request);
|
||||
|
||||
if (error_) {
|
||||
return error_;
|
||||
}
|
||||
}
|
||||
|
||||
if ((error_ = WriteReqeust(request)) != kNoError) {
|
||||
return false;
|
||||
WriteReqeust(request);
|
||||
|
||||
if (error_) {
|
||||
return error_;
|
||||
}
|
||||
|
||||
if ((error_ = ReadResponse()) != kNoError) {
|
||||
return false;
|
||||
}
|
||||
ReadResponse();
|
||||
|
||||
return true;
|
||||
return error_;
|
||||
}
|
||||
|
||||
void Client::Close() {
|
||||
@@ -68,22 +55,38 @@ void Client::Close() {
|
||||
}
|
||||
}
|
||||
|
||||
Error Client::Connect(RequestPtr request) {
|
||||
if (request->url().scheme() == "https") {
|
||||
#if WEBCC_ENABLE_SSL
|
||||
socket_.reset(new SslSocket{ io_context_, ssl_verify_ });
|
||||
return DoConnect(request, "443");
|
||||
#else
|
||||
LOG_ERRO("SSL/HTTPS support is not enabled.");
|
||||
return kSchemaError;
|
||||
#endif // WEBCC_ENABLE_SSL
|
||||
} else {
|
||||
socket_.reset(new Socket{ io_context_ });
|
||||
return DoConnect(request, "80");
|
||||
void Client::Restart() {
|
||||
io_context_.restart();
|
||||
|
||||
response_.reset(new Response{});
|
||||
response_parser_.Init(response_.get());
|
||||
|
||||
closed_ = false;
|
||||
timer_canceled_ = false;
|
||||
error_ = Error{};
|
||||
|
||||
if (buffer_.size() != buffer_size_) {
|
||||
LOG_VERB("Resize buffer: %u -> %u.", buffer_.size(), buffer_size_);
|
||||
buffer_.resize(buffer_size_);
|
||||
}
|
||||
}
|
||||
|
||||
Error Client::DoConnect(RequestPtr request, const std::string& default_port) {
|
||||
void Client::Connect(RequestPtr request) {
|
||||
if (request->url().scheme() == "https") {
|
||||
#if WEBCC_ENABLE_SSL
|
||||
socket_.reset(new SslSocket{ io_context_, ssl_verify_ });
|
||||
DoConnect(request, "443");
|
||||
#else
|
||||
LOG_ERRO("SSL/HTTPS support is not enabled.");
|
||||
return kSyntaxError;
|
||||
#endif // WEBCC_ENABLE_SSL
|
||||
} else {
|
||||
socket_.reset(new Socket{ io_context_ });
|
||||
DoConnect(request, "80");
|
||||
}
|
||||
}
|
||||
|
||||
void Client::DoConnect(RequestPtr request, const std::string& default_port) {
|
||||
tcp::resolver resolver(io_context_);
|
||||
|
||||
std::string port = request->port(default_port);
|
||||
@@ -94,7 +97,7 @@ Error Client::DoConnect(RequestPtr request, const std::string& default_port) {
|
||||
if (ec) {
|
||||
LOG_ERRO("Host resolve error (%s): %s, %s.", ec.message().c_str(),
|
||||
request->host().c_str(), port.c_str());
|
||||
return kHostResolveError;
|
||||
error_.Set(Error::kResolveError, "Host resolve error");
|
||||
}
|
||||
|
||||
LOG_VERB("Connect to server...");
|
||||
@@ -106,15 +109,14 @@ Error Client::DoConnect(RequestPtr request, const std::string& default_port) {
|
||||
if (ec) {
|
||||
LOG_ERRO("Socket connect error (%s).", ec.message().c_str());
|
||||
Close();
|
||||
return kEndpointConnectError;
|
||||
// TODO: Handshake error
|
||||
error_.Set(Error::kConnectError, "Endpoint connect error");
|
||||
}
|
||||
|
||||
LOG_VERB("Socket connected.");
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
Error Client::WriteReqeust(RequestPtr request) {
|
||||
void Client::WriteReqeust(RequestPtr request) {
|
||||
LOG_VERB("HTTP request:\n%s", request->Dump(4, "> ").c_str());
|
||||
|
||||
// NOTE:
|
||||
@@ -130,35 +132,29 @@ Error Client::WriteReqeust(RequestPtr request) {
|
||||
if (ec) {
|
||||
LOG_ERRO("Socket write error (%s).", ec.message().c_str());
|
||||
Close();
|
||||
return kSocketWriteError;
|
||||
error_.Set(Error::kSocketWriteError, "Socket write error");
|
||||
}
|
||||
|
||||
LOG_INFO("Request sent.");
|
||||
|
||||
return kNoError;
|
||||
}
|
||||
|
||||
Error Client::ReadResponse() {
|
||||
void Client::ReadResponse() {
|
||||
LOG_VERB("Read response (timeout: %ds)...", timeout_);
|
||||
|
||||
timer_.expires_after(std::chrono::seconds(timeout_));
|
||||
|
||||
DoWaitTimer();
|
||||
DoReadResponse();
|
||||
|
||||
Error error = kNoError;
|
||||
DoReadResponse(&error);
|
||||
|
||||
if (error == kNoError) {
|
||||
if (!error_) {
|
||||
LOG_VERB("HTTP response:\n%s", response_->Dump(4, "> ").c_str());
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
void Client::DoReadResponse(Error* error) {
|
||||
void Client::DoReadResponse() {
|
||||
boost::system::error_code ec = boost::asio::error::would_block;
|
||||
|
||||
auto handler = [this, &ec, error](boost::system::error_code inner_ec,
|
||||
auto handler = [this, &ec](boost::system::error_code inner_ec,
|
||||
std::size_t length) {
|
||||
ec = inner_ec;
|
||||
|
||||
@@ -170,7 +166,7 @@ void Client::DoReadResponse(Error* error) {
|
||||
// TODO: Is it necessary to check `length == 0`?
|
||||
if (ec || length == 0) {
|
||||
Close();
|
||||
*error = kSocketReadError;
|
||||
error_.Set(Error::kSocketReadError, "Socket read error");
|
||||
LOG_ERRO("Socket read error (%s).", ec.message().c_str());
|
||||
return;
|
||||
}
|
||||
@@ -180,7 +176,7 @@ void Client::DoReadResponse(Error* error) {
|
||||
// Parse the response piece just read.
|
||||
if (!response_parser_.Parse(buffer_.data(), length)) {
|
||||
Close();
|
||||
*error = kHttpError;
|
||||
error_.Set(Error::kParseError, "HTTP parse error");
|
||||
LOG_ERRO("Failed to parse HTTP response.");
|
||||
return;
|
||||
}
|
||||
@@ -203,7 +199,7 @@ void Client::DoReadResponse(Error* error) {
|
||||
}
|
||||
|
||||
if (!closed_) {
|
||||
DoReadResponse(error);
|
||||
DoReadResponse();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -238,7 +234,7 @@ void Client::OnTimer(boost::system::error_code ec) {
|
||||
// The deadline has passed. The socket is closed so that any outstanding
|
||||
// asynchronous operations are canceled.
|
||||
LOG_WARN("HTTP client timed out.");
|
||||
timed_out_ = true;
|
||||
error_.set_timeout(true);
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
+9
-15
@@ -29,7 +29,7 @@ class Client {
|
||||
public:
|
||||
Client();
|
||||
|
||||
virtual ~Client() = default;
|
||||
~Client() = default;
|
||||
|
||||
Client(const Client&) = delete;
|
||||
Client& operator=(const Client&) = delete;
|
||||
@@ -52,7 +52,7 @@ public:
|
||||
}
|
||||
|
||||
// Connect to server, send request, wait until response is received.
|
||||
bool Request(RequestPtr request, bool connect = true);
|
||||
Error Request(RequestPtr request, bool connect = true);
|
||||
|
||||
// Close the socket.
|
||||
void Close();
|
||||
@@ -61,20 +61,18 @@ public:
|
||||
|
||||
bool closed() const { return closed_; }
|
||||
|
||||
bool timed_out() const { return timed_out_; }
|
||||
|
||||
Error error() const { return error_; }
|
||||
|
||||
private:
|
||||
Error Connect(RequestPtr request);
|
||||
void Restart();
|
||||
|
||||
Error DoConnect(RequestPtr request, const std::string& default_port);
|
||||
void Connect(RequestPtr request);
|
||||
|
||||
Error WriteReqeust(RequestPtr request);
|
||||
void DoConnect(RequestPtr request, const std::string& default_port);
|
||||
|
||||
Error ReadResponse();
|
||||
void WriteReqeust(RequestPtr request);
|
||||
|
||||
void DoReadResponse(Error* error);
|
||||
void ReadResponse();
|
||||
|
||||
void DoReadResponse();
|
||||
|
||||
void DoWaitTimer();
|
||||
void OnTimer(boost::system::error_code ec);
|
||||
@@ -113,10 +111,6 @@ private:
|
||||
// Deadline timer canceled.
|
||||
bool timer_canceled_;
|
||||
|
||||
// Timeout occurred.
|
||||
bool timed_out_;
|
||||
|
||||
// Error code.
|
||||
Error error_;
|
||||
};
|
||||
|
||||
|
||||
@@ -143,11 +143,11 @@ void ClientSession::InitHeaders() {
|
||||
// content coding.
|
||||
//
|
||||
// A note about "deflate":
|
||||
// (https://www.zlib.net/zlib_faq.html#faq39)
|
||||
// "gzip" is the gzip format, and "deflate" is the zlib format. They should
|
||||
// probably have called the second one "zlib" instead to avoid confusion with
|
||||
// the raw deflate compressed data format.
|
||||
// Simply put, "deflate" is not recommended for HTTP 1.1 encoding.
|
||||
// (https://www.zlib.net/zlib_faq.html#faq39)
|
||||
|
||||
#if WEBCC_ENABLE_GZIP
|
||||
headers_.Set(kAcceptEncoding, "gzip, deflate");
|
||||
@@ -161,7 +161,7 @@ void ClientSession::InitHeaders() {
|
||||
}
|
||||
|
||||
ResponsePtr ClientSession::Send(RequestPtr request) {
|
||||
const ClientPool::Key key{request->url()};
|
||||
const ClientPool::Key key{ request->url() };
|
||||
|
||||
// Reuse a pooled connection.
|
||||
bool reuse = false;
|
||||
@@ -179,22 +179,22 @@ ResponsePtr ClientSession::Send(RequestPtr request) {
|
||||
client->set_buffer_size(buffer_size_);
|
||||
client->set_timeout(timeout_);
|
||||
|
||||
bool ok = client->Request(request, !reuse);
|
||||
Error error = client->Request(request, !reuse);
|
||||
|
||||
if (!ok) {
|
||||
if (reuse && client->error() == kSocketWriteError) {
|
||||
if (error) {
|
||||
if (reuse && error.code() == Error::kSocketWriteError) {
|
||||
LOG_WARN("Cannot send request with the reused connection. "
|
||||
"The server must have closed it, reconnect and try again.");
|
||||
ok = client->Request(request, true);
|
||||
error = client->Request(request, true);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ok) {
|
||||
if (reuse) {
|
||||
if (error) {
|
||||
// Remove the failed connection from pool.
|
||||
if (reuse) {
|
||||
pool_.Remove(key);
|
||||
}
|
||||
throw Exception(client->error(), "", client->timed_out());
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Update connection pool.
|
||||
|
||||
+1
-1
@@ -204,7 +204,7 @@ FormPart::FormPart(const std::string& name, const Path& path,
|
||||
const std::string& media_type)
|
||||
: name_(name), media_type_(media_type) {
|
||||
if (!ReadFile(path, &data_)) {
|
||||
throw Exception(kFileIOError, "Cannot read the file.");
|
||||
throw Error{ Error::kFileError, "Cannot read the file." };
|
||||
}
|
||||
|
||||
// Determine file name from file path.
|
||||
|
||||
+7
-32
@@ -1,9 +1,8 @@
|
||||
#include "webcc/globals.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "webcc/version.h"
|
||||
|
||||
namespace webcc {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
@@ -47,37 +46,13 @@ std::string FromExtension(const std::string& extension,
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
const char* DescribeError(Error error) {
|
||||
switch (error) {
|
||||
case kSchemaError:
|
||||
return "Schema error";
|
||||
case kHostResolveError:
|
||||
return "Host resolve error";
|
||||
case kEndpointConnectError:
|
||||
return "Endpoint connect error";
|
||||
case kHandshakeError:
|
||||
return "Handshake error";
|
||||
case kSocketReadError:
|
||||
return "Socket read error";
|
||||
case kSocketWriteError:
|
||||
return "Socket write error";
|
||||
case kHttpError:
|
||||
return "HTTP error";
|
||||
case kFileIOError:
|
||||
return "File IO error";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
Exception::Exception(Error error, const std::string& details, bool timeout)
|
||||
: error_(error), msg_(DescribeError(error)), timeout_(timeout) {
|
||||
if (!details.empty()) {
|
||||
msg_ += " (" + details + ")";
|
||||
}
|
||||
if (timeout) {
|
||||
msg_ += " (timeout)";
|
||||
std::ostream& operator<<(std::ostream& os, const Error& error) {
|
||||
os << std::to_string(static_cast<int>(error.code()));
|
||||
os << ": " << error.message();
|
||||
if (error.timeout()) {
|
||||
os << " (timeout)";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
+31
-37
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <cassert>
|
||||
#include <exception>
|
||||
#include <iosfwd>
|
||||
#include <string>
|
||||
|
||||
#include "webcc/config.h"
|
||||
@@ -149,56 +150,49 @@ enum class ContentEncoding {
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// Client side error codes.
|
||||
enum Error {
|
||||
kNoError = 0, // i.e., OK
|
||||
|
||||
kSchemaError, // TODO
|
||||
|
||||
kHostResolveError,
|
||||
kEndpointConnectError,
|
||||
kHandshakeError, // HTTPS handshake
|
||||
// Error (or exception) for the client.
|
||||
class Error {
|
||||
public:
|
||||
enum Code {
|
||||
kOK = 0,
|
||||
kSyntaxError,
|
||||
kResolveError,
|
||||
kConnectError,
|
||||
kHandshakeError,
|
||||
kSocketReadError,
|
||||
kSocketWriteError,
|
||||
kParseError,
|
||||
kFileError,
|
||||
};
|
||||
|
||||
// HTTP error.
|
||||
// E.g., failed to parse HTTP response (invalid content length, etc.).
|
||||
kHttpError,
|
||||
|
||||
// File read/write error.
|
||||
kFileIOError,
|
||||
};
|
||||
|
||||
// Return a descriptive message for the given error code.
|
||||
const char* DescribeError(Error error);
|
||||
|
||||
class Exception : public std::exception {
|
||||
public:
|
||||
explicit Exception(Error error, const std::string& details = "",
|
||||
bool timeout = false);
|
||||
|
||||
Error error() const {
|
||||
return error_;
|
||||
Error(Code code = kOK, const std::string& message = "")
|
||||
: code_(code), message_(message), timeout_(false) {
|
||||
}
|
||||
|
||||
// Note that `noexcept` is required by GCC.
|
||||
const char* what() const WEBCC_NOEXCEPT override{
|
||||
return msg_.c_str();
|
||||
Code code() const { return code_; }
|
||||
|
||||
const std::string& message() const { return message_; }
|
||||
|
||||
void Set(Code code, const std::string& message) {
|
||||
code_ = code;
|
||||
message_ = message;
|
||||
}
|
||||
|
||||
bool timeout() const {
|
||||
return timeout_;
|
||||
}
|
||||
bool timeout() const { return timeout_; }
|
||||
|
||||
void set_timeout(bool timeout) { timeout_ = timeout; }
|
||||
|
||||
operator bool() const { return code_ != kOK; }
|
||||
|
||||
private:
|
||||
Error error_;
|
||||
|
||||
std::string msg_;
|
||||
|
||||
// If the error was caused by timeout or not.
|
||||
Code code_;
|
||||
std::string message_;
|
||||
bool timeout_;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Error& error);
|
||||
|
||||
} // namespace webcc
|
||||
|
||||
#endif // WEBCC_GLOBALS_H_
|
||||
|
||||
+1
-1
@@ -81,7 +81,7 @@ void Request::CreateStartLine() {
|
||||
}
|
||||
|
||||
if (url_.host().empty()) {
|
||||
throw Exception(kSchemaError, "Invalid request: host is missing.");
|
||||
throw Error{ Error::kSyntaxError, "Host is missing" };
|
||||
}
|
||||
|
||||
std::string target = "/" + url_.path();
|
||||
|
||||
@@ -25,7 +25,7 @@ bool RestServiceManager::AddService(RestServicePtr service,
|
||||
item.url_regex.assign(url, flags);
|
||||
service_items_.push_back(std::move(item));
|
||||
return true;
|
||||
} catch (std::regex_error& e) {
|
||||
} catch (const std::regex_error& e) {
|
||||
LOG_ERRO("URL is not a valid regular expression: %s", e.what());
|
||||
return false;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user