You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
92 lines
5.5 KiB
92 lines
5.5 KiB
#ifndef _TOREST_HTTP_HPP_ |
|
#define _TOREST_HTTP_HPP_ |
|
|
|
#include <json.hpp> |
|
#include <unordered_map> |
|
|
|
class http { |
|
public: |
|
/// http codes |
|
enum status { |
|
/*! Standard response for successful HTTP requests. */ ok=200, |
|
/*! The request has been fulfilled, resulting in the creation of a new resource. */ created=201, |
|
/*! The request has been accepted for processing, but the processing has not been completed. */ accepted=202, |
|
/*! The server successfully processed the request and is not returning any content. */ no_content=204, |
|
/*! The server cannot or will not process the request due to an apparent client error */ bad_request=400, |
|
/*! Similar to 403 Forbidden, but specifically for use when authentication is required and has failed or has not yet been provided. */ unauthorized=401, |
|
/*! Reserved for future use. The */ payment_required=402, |
|
/*! the request was a valid request, but the server is refusing to respond to it. */ forbidden=403, |
|
/*! The requested resource could not be found but may be available in the future. */ not_found=404, |
|
/*! Allowed A request method is not supported for the requested resource */ method_not_allowed=405, |
|
/*! The resource identified by the request is only capable of generating response entities which have content characteristics not acceptable according to the accept headers sent in the request. */ not_acceptable=406, |
|
/*! A generic error message, given when an unexpected condition was encountered and no more specific message is suitable. */ internal_server_error=500, |
|
/*! The server either does not recognize the request method, or it lacks the ability to fulfill the request. */ not_implemented=501, |
|
/*! The server was acting as a gateway or proxy and received an invalid response from the upstream server. */ bad_gateway=502, |
|
/*! The server is currently unavailable (because it is overloaded or down for maintenance). Generally, this is a temporary state. */ service_unavailable=503, |
|
/*! Gateway timed out */ gateway_timeout=504, |
|
/*! http-version not supported */ http_version_not_supported=505 |
|
}; |
|
typedef std::pair<status,std::string> code; |
|
typedef std::pair<std::string,std::string> header; |
|
typedef std::unordered_map<std::string,std::string> headers; |
|
|
|
/// creates a http::code object out of a http::status code |
|
static code http_code(status status){switch(status){case accepted:return{status,"Accepted"};case bad_gateway:return{status,"Bad gateway"};case bad_request:return{status,"Bad Request"};case created:return{status,"Created"};case forbidden:return{status,"Forbidden"};case gateway_timeout:return{status,"Gateway Timeout"};case http_version_not_supported:return{status,"HTTP Version Not Supported"};case internal_server_error:return{status,"Internal Server Error"};case method_not_allowed:return{status,"Method Not Allowed"};case not_acceptable:return{status,"Not Acceptable"};case no_content:return{status,"No Content"};case not_found:return{status,"Not Found"};case not_implemented:return{status,"Not Implemented"};case ok:return{status,"OK"};case payment_required:return{status,"Payment Required"};case service_unavailable:return{status,"Service Unavailable"};case unauthorized:return{status,"Unauthorized"};default: return {status,"UNKNOWN"};}} |
|
|
|
class basic_response { |
|
protected: |
|
virtual std::ostream& do_response(std::ostream& os)const=0; |
|
public: |
|
virtual ~basic_response(){} |
|
virtual void add_header(const http::header &header)=0; |
|
virtual void set_status(http::status code)=0; |
|
friend std::ostream& operator<<(std::ostream& os,const http::basic_response &rh){ return rh.do_response(os); } |
|
}; |
|
|
|
class response : public basic_response { |
|
public: |
|
response():status_code(http::http_code(http::ok)){} |
|
void add_header(const http::header &header) override { response_headers.emplace(header); } |
|
void set_status(http::status code) override { status_code=http_code(code); } |
|
void set_body(std::string content) { body=content; } |
|
protected: |
|
std::ostream& do_response(std::ostream &os) const override { |
|
os << "HTTP/1.1" << " " << status_code.first << " " << status_code.second << "\r\n"; |
|
for(auto &header:response_headers) |
|
os << header.first << ": " << header.second << "\r\n"; |
|
if(status_code.first!=http::no_content){ |
|
os << "Content-Length: "; |
|
if(!body.empty()){ |
|
return os << body.size() << "\r\n\r\n" << body; |
|
} else { |
|
auto body_replace=std::to_string(status_code.first) + " " + status_code.second; |
|
return os << body_replace.size() << "\r\n\r\n" << body_replace; |
|
} |
|
} |
|
return os << "\r\n"; |
|
} |
|
protected: |
|
headers response_headers; |
|
std::string body; |
|
code status_code; |
|
}; |
|
|
|
/// A JSON response. The default constructor sets the Content-Type header to |
|
/// application/json, the response defaults to 200 OK. |
|
class json_response : public response { |
|
public: |
|
json_response(){ |
|
add_header({"Content-Type","application/json"}); |
|
set_body({{"code",status_code.first},{"status",status_code.second}}); |
|
} |
|
/// Method updates the http status code. set_statups also updates the body to correspond to the new status. |
|
/// Notice: if you previously set a body, it will be overwritten by the status code JSON representation. |
|
void set_status(http::status code) override { |
|
response::set_status(code); |
|
set_body({{"code",status_code.first},{"status",status_code.second}}); |
|
} |
|
void set_body(nlohmann::json json){ response::set_body(json.dump()); } |
|
}; |
|
};;; |
|
|
|
#endif // _TOREST_HTTP_HPP_
|
|
|