From 4efdc095bdf478552cd8a0697520ab47dfdd30a5 Mon Sep 17 00:00:00 2001 From: eidheim Date: Thu, 22 Jun 2017 21:46:01 +0200 Subject: [PATCH] Added convenience write functions to Server::response --- http_examples.cpp | 4 ++++ https_examples.cpp | 4 ++++ server_http.hpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++ tests/io_test.cpp | 42 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+) diff --git a/http_examples.cpp b/http_examples.cpp index 64ef3b6..d211661 100644 --- a/http_examples.cpp +++ b/http_examples.cpp @@ -44,6 +44,10 @@ int main() { //string content=ss.str(); *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + + + // Alternatively, use one of the convenience functions, for instance: + // response->write(content); }; //POST-example for the path /json, responds firstName+" "+lastName from the posted json diff --git a/https_examples.cpp b/https_examples.cpp index 69d562b..8719c9a 100644 --- a/https_examples.cpp +++ b/https_examples.cpp @@ -42,6 +42,10 @@ int main() { //string content=ss.str(); *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + + + // Alternatively, use one of the convenience functions, for instance: + // response->write(content); }; //POST-example for the path /json, responds firstName+" "+lastName from the posted json diff --git a/server_http.hpp b/server_http.hpp index 0cbcf89..bfbbb22 100644 --- a/server_http.hpp +++ b/server_http.hpp @@ -57,10 +57,61 @@ namespace SimpleWeb { Response(const std::shared_ptr &socket): std::ostream(&streambuf), socket(socket) {} + template + void write_header(const CaseInsensitiveMultimap &header, size_type size=0) { + bool content_length_written=false; + for(auto &header_field: header) { + if(size && !content_length_written && case_insensitive_equal(header_field.first, "content-length")) + content_length_written=true; + *this << header_field.first << ": " << header_field.second << "\r\n"; + } + if(size && !content_length_written) + *this << "Content-Length: " << size << "\r\n\r\n"; + else + *this << "\r\n"; + } public: size_t size() { return streambuf.size(); } + + void write(const char_type *ptr, std::streamsize n) { + std::ostream::write(ptr, n); + } + + /// Convenience function for writing status line, potential header fields, and empty content + void write(StatusCode status_code=StatusCode::success_ok, const CaseInsensitiveMultimap &header=CaseInsensitiveMultimap()) { + *this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n"; + write_header(header, 0); + } + + /// Convenience function for writing status line, header fields, and content + void write(StatusCode status_code, const std::string &content, const CaseInsensitiveMultimap &header=CaseInsensitiveMultimap()) { + *this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n"; + write_header(header, content.size()); + if(!content.empty()) + *this << content; + } + + /// Convenience function for writing status line, header fields, and content + void write(StatusCode status_code, std::ostream &content, const CaseInsensitiveMultimap &header=CaseInsensitiveMultimap()) { + *this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n"; + content.seekp(0, std::ios::end); + auto size=content.tellp(); + write_header(header, size); + if(size) + *this << content.rdbuf(); + } + + /// Convenience function for writing success status line, header fields, and content + void write(const std::string &content, const CaseInsensitiveMultimap &header=CaseInsensitiveMultimap()) { + write(StatusCode::success_ok, content, header); + } + + /// Convenience function for writing success status line, header fields, and content + void write(std::iostream &content, const CaseInsensitiveMultimap &header=CaseInsensitiveMultimap()) { + write(StatusCode::success_ok, content, header); + } /// If true, force server to close the connection after the response have been sent. /// diff --git a/tests/io_test.cpp b/tests/io_test.cpp index 67491e0..97b10e6 100644 --- a/tests/io_test.cpp +++ b/tests/io_test.cpp @@ -18,6 +18,20 @@ int main() { *response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; }; + server.resource["^/string2$"]["POST"]=[](shared_ptr response, shared_ptr request) { + response->write(request->content.string()); + }; + + server.resource["^/string3$"]["POST"]=[](shared_ptr response, shared_ptr request) { + std::stringstream stream; + stream << request->content.rdbuf(); + response->write(stream); + }; + + server.resource["^/string4$"]["POST"]=[](shared_ptr response, shared_ptr /*request*/) { + response->write(SimpleWeb::StatusCode::client_error_forbidden, {{"Test1", "test2"}, {"tesT3", "test4"}}); + }; + server.resource["^/info$"]["GET"]=[](shared_ptr response, shared_ptr request) { stringstream content_stream; content_stream << request->method << " " << request->path << " " << request->http_version << " "; @@ -51,10 +65,38 @@ int main() { { stringstream output; auto r=client.request("POST", "/string", "A string"); + assert(SimpleWeb::status_code(r->status_code)==SimpleWeb::StatusCode::success_ok); output << r->content.rdbuf(); assert(output.str()=="A string"); } + { + stringstream output; + auto r=client.request("POST", "/string2", "A string"); + assert(SimpleWeb::status_code(r->status_code)==SimpleWeb::StatusCode::success_ok); + output << r->content.rdbuf(); + assert(output.str()=="A string"); + } + + { + stringstream output; + auto r=client.request("POST", "/string3", "A string"); + assert(SimpleWeb::status_code(r->status_code)==SimpleWeb::StatusCode::success_ok); + output << r->content.rdbuf(); + assert(output.str()=="A string"); + } + + { + stringstream output; + auto r=client.request("POST", "/string4", "A string"); + assert(SimpleWeb::status_code(r->status_code)==SimpleWeb::StatusCode::client_error_forbidden); + assert(r->header.size()==2); + assert(r->header.find("test1")->second=="test2"); + assert(r->header.find("tEst3")->second=="test4"); + output << r->content.rdbuf(); + assert(output.str()==""); + } + { stringstream output; stringstream content("A string");