#pragma once #include #include #include #include #include "crow/json.h" #include "crow/http_request.h" #include "crow/ci_map.h" #include "crow/socket_adaptors.h" #include "crow/logging.h" #include "crow/mime_types.h" #if !defined(_WIN32) #include #endif namespace crow { template class Connection; struct response { template friend class crow::Connection; int code{200}; std::string body; json::wvalue json_value; // `headers' stores HTTP headers. ci_map headers; void set_header(std::string key, std::string value) { headers.erase(key); headers.emplace(std::move(key), std::move(value)); } void add_header(std::string key, std::string value) { headers.emplace(std::move(key), std::move(value)); } const std::string& get_header_value(const std::string& key) { return crow::get_header_value(headers, key); } response() {} explicit response(int code) : code(code) {} response(std::string body) : body(std::move(body)) {} response(json::wvalue&& json_value) : json_value(std::move(json_value)) { json_mode(); } response(int code, std::string body) : code(code), body(std::move(body)) {} response(const json::wvalue& json_value) : body(json::dump(json_value)) { json_mode(); } response(int code, const json::wvalue& json_value) : code(code), body(json::dump(json_value)) { json_mode(); } response(response&& r) { *this = std::move(r); } response& operator = (const response& r) = delete; response& operator = (response&& r) noexcept { body = std::move(r.body); json_value = std::move(r.json_value); code = r.code; headers = std::move(r.headers); completed_ = r.completed_; return *this; } bool is_completed() const noexcept { return completed_; } void clear() { body.clear(); json_value.clear(); code = 200; headers.clear(); completed_ = false; } void redirect(const std::string& location) { code = 301; set_header("Location", location); } void write(const std::string& body_part) { body += body_part; } void end() { if (!completed_) { completed_ = true; if (complete_request_handler_) { complete_request_handler_(); } } } void end(const std::string& body_part) { body += body_part; end(); } bool is_alive() { return is_alive_helper_ && is_alive_helper_(); } /* adding static file support here * middlware must call res.set_static_file_info(filename) * you must add route starting with /your/restricted/path/ */ #if !defined(_WIN32) struct static_file_info{ std::string path = ""; struct stat statbuf; int statResult; }; static_file_info file_info; void set_static_file_info(std::string path){ file_info.path = path; file_info.statResult = stat(file_info.path.c_str(), &file_info.statbuf); if (file_info.statResult == 0) { std::size_t last_dot = path.find_last_of("."); std::string extension = path.substr(last_dot+1); std::string mimeType = ""; code = 200; this->add_header("Content-length", std::to_string(file_info.statbuf.st_size)); if (extension != ""){ mimeType = mime_types[extension]; if (mimeType != "") this-> add_header("Content-Type", mimeType); else this-> add_header("content-Type", "text/plain"); } } else { code = 404; this->end(); } } template void do_write_sendfile(Adaptor adaptor) { if (file_info.statResult == 0) { std::ifstream is(file_info.path.c_str(), std::ios::in | std::ios::binary); char buf[16384]; while (is.read(buf, sizeof(buf)).gcount() > 0) { std::vector buffers; buffers.push_back(boost::asio::buffer(buf)); boost::asio::write(adaptor->socket(), buffers, [this](std::error_code ec, std::size_t) { if (!ec) { //CROW_LOG_DEBUG << "sending file, no error"; return false; } else { CROW_LOG_ERROR << ec << " - happened while sending file"; this->end(); return true; } }); } } } #endif /* static file support end */ private: bool completed_{}; std::function complete_request_handler_; std::function is_alive_helper_; //In case of a JSON object, set the Content-Type header void json_mode() { set_header("Content-Type", "application/json"); } }; }