diff --git a/bin/rest-cpp b/bin/rest-cpp index 580ce93..fcf3411 100755 --- a/bin/rest-cpp +++ b/bin/rest-cpp @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/python2 import sys, os, string, re diff --git a/src/rest/exceptions.h b/src/rest/exceptions.h index d0b9c6a..0e94852 100644 --- a/src/rest/exceptions.h +++ b/src/rest/exceptions.h @@ -1,9 +1,10 @@ #ifndef REST_CPP_EXCEPTIONS_H #define REST_CPP_EXCEPTIONS_H #define CREATE(NAME, PARENT, MESSAGE) class NAME : public PARENT { public: virtual const char* what() const throw() { return (MESSAGE); } virtual int code() {return 401; }}; -#define ERROR(NAME, CODE, MESSAGE) class NAME : public Error { public: virtual const char* what() const throw() { return (MESSAGE); } virtual int code() { return (CODE); } }; +#define ERROR(NAME, CODE) class NAME : public Error { public: virtual const char* what() const throw() { return STATUS::messages.at((CODE)).c_str(); } virtual int code() { return (int)(CODE); } }; #include +#include "http.h" namespace REST { @@ -20,10 +21,10 @@ namespace REST { namespace HTTP { CREATE(Error, Exception, "Unknown HTTP protocol error"); - ERROR(NotAuthorized, 401, "Not Authorized"); - ERROR(NotFound, 404, "Not Found"); - ERROR(MethodNotAllowed, 405, "Method Not Allowed"); - ERROR(NotImplemented, 501, "Not Implemented"); + ERROR(NotAuthorized, STATUS::Code::Unauthorized); + ERROR(NotFound, STATUS::Code::NotFound); + ERROR(MethodNotAllowed, STATUS::Code::MethodNotAllowed); + ERROR(NotImplemented, STATUS::Code::NotImplemented); } } diff --git a/src/rest/http.h b/src/rest/http.h new file mode 100644 index 0000000..1cebf93 --- /dev/null +++ b/src/rest/http.h @@ -0,0 +1,149 @@ +#ifndef REST_CPP_HTTP_H +#define REST_CPP_HTTP_H + +#include +#include + +namespace REST { +namespace HTTP { +namespace STATUS { + enum Code { + Continue=100, + SwitchingProtocols=101, + Processing=102, + OK=200, + Created=201, + Accepted=202, + NonAuthoritativeInformation=203, + NoContent=204, + ResetContent=205, + PartialContent=206, + MultiStatus=207, + AlreadyReported=208, + IMUsed=226, + MultipleChoices=300, + MovedPermanently=301, + Found=302, + SeeOther=303, + NotModified=304, + UseProxy=305, + TemporaryRedirect=307, + PermanentRedirect=308, + BadRequest=400, + Unauthorized=401, + PaymentRequired=402, + Forbidden=403, + NotFound=404, + MethodNotAllowed=405, + NotAcceptable=406, + ProxyAuthenticationRequired=407, + RequestTimeout=408, + Conflict=409, + Gone=410, + LengthRequired=411, + PreconditionFailed=412, + RequestEntityTooLarge=413, + RequestURITooLong=414, + UnsupportedMediaType=415, + RequestedRangeNotSatisfiable=416, + ExpectationFailed=417, + ImATeapot=418, + EnhanceYourCalm=420, + UnprocessableEntity=422, + Locked=423, + FailedDependency=424, + UpgradeRequired=426, + PreconditionRequired=428, + TooManyRequests=429, + RequestHeaderFieldsTooLarge=431, + NoResponse=444, + RetryWith=449, + ClientClosedRequest=499, + InternalServerError=500, + NotImplemented=501, + BadGateway=502, + ServiceUnavailable=503, + GatewayTimeout=504, + HTTPVersionNotSupported=505, + VariantAlsoNegotiates=506, + InsufficientStorage=507, + LoopDetected=508, + BandwidthLimitExceeded=509, + NotExtended=510, + NetworkAuthenticationRequired=511, + NetworkReadTimeoutError=598, + NetworkConnectTimeoutError=599 + }; + + const static std::map messages { + {(Code) 100, "Continue"}, + {(Code) 101, "Switching Protocols"}, + {(Code) 102, "Processing (WebDAV)"}, + {(Code) 200, "OK"}, + {(Code) 201, "Created"}, + {(Code) 202, "Accepted"}, + {(Code) 203, "Non-Authoritative Information"}, + {(Code) 204, "No Content"}, + {(Code) 205, "Reset Content"}, + {(Code) 206, "Partial Content"}, + {(Code) 207, "Multi-Status (WebDAV)"}, + {(Code) 208, "Already Reported (WebDAV)"}, + {(Code) 226, "IM Used"}, + {(Code) 300, "Multiple Choices"}, + {(Code) 301, "Moved Permanently"}, + {(Code) 302, "Found"}, + {(Code) 303, "See Other"}, + {(Code) 304, "Not Modified"}, + {(Code) 305, "Use Proxy"}, + {(Code) 307, "Temporary Redirect"}, + {(Code) 308, "Permanent Redirect (experiemental)"}, + {(Code) 400, "Bad Request"}, + {(Code) 401, "Unauthorized"}, + {(Code) 402, "Payment Required"}, + {(Code) 403, "Forbidden"}, + {(Code) 404, "Not Found"}, + {(Code) 405, "Method Not Allowed"}, + {(Code) 406, "Not Acceptable"}, + {(Code) 407, "Proxy Authentication Required"}, + {(Code) 408, "Request Timeout"}, + {(Code) 409, "Conflict"}, + {(Code) 410, "Gone"}, + {(Code) 411, "Length Required"}, + {(Code) 412, "Precondition Failed"}, + {(Code) 413, "Request Entity Too Large"}, + {(Code) 414, "Request-URI Too Long"}, + {(Code) 415, "Unsupported Media Type"}, + {(Code) 416, "Requested Range Not Satisfiable"}, + {(Code) 417, "Expectation Failed"}, + {(Code) 418, "I'm a teapot (RFC 2324)"}, + {(Code) 420, "Enhance Your Calm (Twitter)"}, + {(Code) 422, "Unprocessable Entity (WebDAV)"}, + {(Code) 423, "Locked (WebDAV)"}, + {(Code) 424, "Failed Dependency (WebDAV)"}, + {(Code) 426, "Upgrade Required"}, + {(Code) 428, "Precondition Required"}, + {(Code) 429, "Too Many Requests"}, + {(Code) 431, "Request Header Fields Too Large"}, + {(Code) 444, "No Response (Nginx)"}, + {(Code) 449, "Retry With (Microsoft)"}, + {(Code) 499, "Client Closed Request (Nginx)"}, + {(Code) 500, "Internal Server Error"}, + {(Code) 501, "Not Implemented"}, + {(Code) 502, "Bad Gateway"}, + {(Code) 503, "Service Unavailable"}, + {(Code) 504, "Gateway Timeout"}, + {(Code) 505, "HTTP Version Not Supported"}, + {(Code) 506, "Variant Also Negotiates (Experimental)"}, + {(Code) 507, "Insufficient Storage (WebDAV)"}, + {(Code) 508, "Loop Detected (WebDAV)"}, + {(Code) 509, "Bandwidth Limit Exceeded (Apache)"}, + {(Code) 510, "Not Extended"}, + {(Code) 511, "Network Authentication Required"}, + {(Code) 598, "Network read timeout error"}, + {(Code) 599, "Network connect timeout error"} + }; +} +} +} + +#endif diff --git a/src/rest/response.cpp b/src/rest/response.cpp index 3593185..65b1141 100644 --- a/src/rest/response.cpp +++ b/src/rest/response.cpp @@ -10,7 +10,7 @@ Response::Response(Request::shared request) { } Response::Response(Request::shared request, HTTP::Error &error) : Response(request) { - status = error.code(); + status = (HTTP::STATUS::Code) error.code(); status_message = error.what(); use_json(); data["error"]["code"] = status; @@ -52,6 +52,11 @@ size_t Response::send(Json::FastWriter &json_writer) { return bytes_sent; } +void Response::set_status(HTTP::STATUS::Code code) { + status = code; + status_message = HTTP::STATUS::messages.at(code); +} + Response::~Response() { } diff --git a/src/rest/response.h b/src/rest/response.h index 4954d6c..c1b0d2d 100644 --- a/src/rest/response.h +++ b/src/rest/response.h @@ -4,6 +4,7 @@ #include "exceptions.h" #include "request.h" #include "json/json.h" +#include "http.h" #include #include @@ -25,16 +26,13 @@ class Response { typedef std::unique_ptr unique; ~Response(); - - int status = 200; - std::string status_message = "OK"; std::string raw; std::map< std::string, std::string > headers; void use_json(); Json::Value data; - + void set_status(HTTP::STATUS::Code); private: Response(Request::shared request); @@ -42,6 +40,8 @@ class Response { size_t send(Json::FastWriter &json_writer); std::chrono::high_resolution_clock::time_point start_time; + HTTP::STATUS::Code status = HTTP::STATUS::Code::OK; + std::string status_message = HTTP::STATUS::messages.at(status); int handle; bool is_json = false; diff --git a/src/rest/router.cpp b/src/rest/router.cpp index dc351c5..a495d3d 100644 --- a/src/rest/router.cpp +++ b/src/rest/router.cpp @@ -16,34 +16,6 @@ namespace REST { delete root; } - bool Router::Node::Less::operator()(const Node* a, const Node* b) const { - if (a->path[0] == '*') - return false; - if (b->path[0] == '*') - return true; - - if (a->path[0] == ':') - if (b->path[0] != ':') - return false; - if (b->path[0] == ':') - if (a->path[0] != ':') - return true; - - return a->path < b->path; - } - - bool Router::Node::Unifiable::operator()(const Node* a, const Node* b) const { - if (a == nullptr || b == nullptr) - return false; - - if (!b->path.empty() && (b->path[0] == '*' || b->path[0] == ':')) - return false; - if (!a->path.empty() && (a->path[0] == '*' || a->path[0] == ':')) - return true; - - return a->path == b->path; - } - void Router::print() { std::cout << "Available routes:\n"; root->print(1); diff --git a/src/rest/router.h b/src/rest/router.h index df2e296..2f866c2 100644 --- a/src/rest/router.h +++ b/src/rest/router.h @@ -66,11 +66,35 @@ class Router { public: static struct Less { - bool operator()(const Node* a, const Node* b) const; + bool operator()(const Node* a, const Node* b) const { + if (a->path[0] == '*') + return false; + if (b->path[0] == '*') + return true; + + if (a->path[0] == ':') + if (b->path[0] != ':') + return false; + if (b->path[0] == ':') + if (a->path[0] != ':') + return true; + + return a->path < b->path; + } } less; static struct Unifiable { - bool operator()(const Node* a, const Node* b) const; + bool operator()(const Node* a, const Node* b) const { + if (a == nullptr || b == nullptr) + return false; + + if (!b->path.empty() && (b->path[0] == '*' || b->path[0] == ':')) + return false; + if (!a->path.empty() && (a->path[0] == '*' || a->path[0] == ':')) + return true; + + return a->path == b->path; + } } unifiable; static struct Equal {