From 313bc233d0c34aa2fcfcded2c3a48f2eb7267c99 Mon Sep 17 00:00:00 2001 From: eidheim Date: Mon, 11 Aug 2014 10:04:36 +0200 Subject: [PATCH] renamed example files --- http_examples.cpp | 151 +++++++++++++++++++++++++++++++++++++++++++++ https_examples.cpp | 149 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 300 insertions(+) create mode 100644 http_examples.cpp create mode 100644 https_examples.cpp diff --git a/http_examples.cpp b/http_examples.cpp new file mode 100644 index 0000000..26e3370 --- /dev/null +++ b/http_examples.cpp @@ -0,0 +1,151 @@ +#include "server_http.hpp" +#include "client_http.hpp" + +//Added for the json-example +#include +#include + +//Added for the default_resource example +#include + +using namespace std; +using namespace SimpleWeb; +//Added for the json-example: +using namespace boost::property_tree; + +//TODO Client: support Chunked transfer encoding +//TODO Client + +int main() { + //HTTP-server at port 8080 using 4 threads + Server server(8080, 4); + + //Add resources using regular expression for path, a method-string, and an anonymous function + //POST-example for the path /string, responds the posted string + // If C++14: use 'auto' instead of 'shared_ptr::Request>' + server.resource["^/string/?$"]["POST"]=[](ostream& response, shared_ptr::Request> request) { + //Retrieve string from istream (*request.content) + stringstream ss; + request->content >> ss.rdbuf(); + string content=ss.str(); + + response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + }; + + //POST-example for the path /json, responds firstName+" "+lastName from the posted json + //Responds with an appropriate error message if the posted json is not valid, or if firstName or lastName is missing + //Example posted json: + //{ + // "firstName": "John", + // "lastName": "Smith", + // "age": 25 + //} + server.resource["^/json/?$"]["POST"]=[](ostream& response, shared_ptr::Request> request) { + try { + ptree pt; + read_json(request->content, pt); + + string name=pt.get("firstName")+" "+pt.get("lastName"); + + response << "HTTP/1.1 200 OK\r\nContent-Length: " << name.length() << "\r\n\r\n" << name; + } + catch(exception& e) { + response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << strlen(e.what()) << "\r\n\r\n" << e.what(); + } + }; + + //GET-example for the path /info + //Responds with request-information + server.resource["^/info/?$"]["GET"]=[](ostream& response, shared_ptr::Request> request) { + stringstream content_stream; + content_stream << "

Request:

"; + content_stream << request->method << " " << request->path << " HTTP/" << request->http_version << "
"; + for(auto& header: request->header) { + content_stream << header.first << ": " << header.second << "
"; + } + + //find length of content_stream (length received using content_stream.tellp()) + content_stream.seekp(0, ios::end); + + response << "HTTP/1.1 200 OK\r\nContent-Length: " << content_stream.tellp() << "\r\n\r\n" << content_stream.rdbuf(); + }; + + //GET-example for the path /match/[number], responds with the matched string in path (number) + //For instance a request GET /match/123 will receive: 123 + server.resource["^/match/([0-9]+)/?$"]["GET"]=[](ostream& response, shared_ptr::Request> request) { + string number=request->path_match[1]; + response << "HTTP/1.1 200 OK\r\nContent-Length: " << number.length() << "\r\n\r\n" << number; + }; + + //Default GET-example. If no other matches, this anonymous function will be called. + //Will respond with content in the web/-directory, and its subdirectories. + //Default file: index.html + //Can for instance be used to retrieve an HTML 5 client that uses REST-resources on this server + server.default_resource["^/?(.*)$"]["GET"]=[](ostream& response, shared_ptr::Request> request) { + string filename="web/"; + + string path=request->path_match[1]; + + //Remove all but the last '.' (so we can't leave the web-directory) + size_t last_pos=path.rfind("."); + size_t current_pos=0; + size_t pos; + while((pos=path.find('.', current_pos))!=string::npos && pos!=last_pos) { + current_pos=pos; + path.erase(pos, 1); + last_pos--; + } + + filename+=path; + ifstream ifs; + //A simple platform-independent file-or-directory check do not exist, but this works in most of the cases: + if(filename.find('.')==string::npos) { + if(filename[filename.length()-1]!='/') + filename+='/'; + filename+="index.html"; + } + ifs.open(filename, ifstream::in); + + if(ifs) { + ifs.seekg(0, ios::end); + size_t length=ifs.tellg(); + + ifs.seekg(0, ios::beg); + + //The file-content is copied to the response-stream. Should not be used for very large files. + response << "HTTP/1.1 200 OK\r\nContent-Length: " << length << "\r\n\r\n" << ifs.rdbuf(); + + ifs.close(); + } + else { + string content="Could not open file "+filename; + response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + } + }; + + thread server_thread([&server](){ + //Start WS-server + server.start(); + }); + + //Wait for server to start so that the client can connect + this_thread::sleep_for(chrono::seconds(1)); + + //Client examples + Client client("localhost:8080"); + auto r1=client.request("GET", "/match/123"); + cout << r1->content.rdbuf() << endl; + + string json="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}"; + stringstream ss(json); + auto r2=client.request("POST", "/string", ss); + cout << r2->content.rdbuf() << endl; + + ss.str(json); + auto r3=client.request("POST", "/json", ss); + cout << r3->content.rdbuf() << endl; + + server_thread.join(); + + return 0; +} \ No newline at end of file diff --git a/https_examples.cpp b/https_examples.cpp new file mode 100644 index 0000000..c3b405d --- /dev/null +++ b/https_examples.cpp @@ -0,0 +1,149 @@ +#include "server_https.hpp" +#include "client_https.hpp" + +//Added for the json-example +#include +#include + +//Added for the default_resource example +#include + +using namespace std; +using namespace SimpleWeb; +//Added for the json-example: +using namespace boost::property_tree; + +int main() { + //HTTPS-server at port 8080 using 4 threads + Server server(8080, 4, "server.crt", "server.key"); + + //Add resources using regular expression for path, a method-string, and an anonymous function + //POST-example for the path /string, responds the posted string + // If C++14: use 'auto' instead of 'shared_ptr::Request>' + server.resource["^/string/?$"]["POST"]=[](ostream& response, shared_ptr::Request> request) { + //Retrieve string from istream (*request.content) + stringstream ss; + request->content >> ss.rdbuf(); + string content=ss.str(); + + response << "HTTP/1.1 200 OK\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + }; + + //POST-example for the path /json, responds firstName+" "+lastName from the posted json + //Responds with an appropriate error message if the posted json is not valid, or if firstName or lastName is missing + //Example posted json: + //{ + // "firstName": "John", + // "lastName": "Smith", + // "age": 25 + //} + server.resource["^/json/?$"]["POST"]=[](ostream& response, shared_ptr::Request> request) { + try { + ptree pt; + read_json(request->content, pt); + + string name=pt.get("firstName")+" "+pt.get("lastName"); + + response << "HTTP/1.1 200 OK\r\nContent-Length: " << name.length() << "\r\n\r\n" << name; + } + catch(exception& e) { + response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << strlen(e.what()) << "\r\n\r\n" << e.what(); + } + }; + + //GET-example for the path /info + //Responds with request-information + server.resource["^/info/?$"]["GET"]=[](ostream& response, shared_ptr::Request> request) { + stringstream content_stream; + content_stream << "

Request:

"; + content_stream << request->method << " " << request->path << " HTTP/" << request->http_version << "
"; + for(auto& header: request->header) { + content_stream << header.first << ": " << header.second << "
"; + } + + //find length of content_stream (length received using content_stream.tellp()) + content_stream.seekp(0, ios::end); + + response << "HTTP/1.1 200 OK\r\nContent-Length: " << content_stream.tellp() << "\r\n\r\n" << content_stream.rdbuf(); + }; + + //GET-example for the path /match/[number], responds with the matched string in path (number) + //For instance a request GET /match/123 will receive: 123 + server.resource["^/match/([0-9]+)/?$"]["GET"]=[](ostream& response, shared_ptr::Request> request) { + string number=request->path_match[1]; + response << "HTTP/1.1 200 OK\r\nContent-Length: " << number.length() << "\r\n\r\n" << number; + }; + + //Default GET-example. If no other matches, this anonymous function will be called. + //Will respond with content in the web/-directory, and its subdirectories. + //Default file: index.html + //Can for instance be used to retrieve an HTML 5 client that uses REST-resources on this server + server.default_resource["^/?(.*)$"]["GET"]=[](ostream& response, shared_ptr::Request> request) { + string filename="web/"; + + string path=request->path_match[1]; + + //Remove all but the last '.' (so we can't leave the web-directory) + size_t last_pos=path.rfind("."); + size_t current_pos=0; + size_t pos; + while((pos=path.find('.', current_pos))!=string::npos && pos!=last_pos) { + current_pos=pos; + path.erase(pos, 1); + last_pos--; + } + + filename+=path; + ifstream ifs; + //A simple platform-independent file-or-directory check do not exist, but this works in most of the cases: + if(filename.find('.')==string::npos) { + if(filename[filename.length()-1]!='/') + filename+='/'; + filename+="index.html"; + } + ifs.open(filename, ifstream::in); + + if(ifs) { + ifs.seekg(0, ios::end); + size_t length=ifs.tellg(); + + ifs.seekg(0, ios::beg); + + //The file-content is copied to the response-stream. Should not be used for very large files. + response << "HTTP/1.1 200 OK\r\nContent-Length: " << length << "\r\n\r\n" << ifs.rdbuf(); + + ifs.close(); + } + else { + string content="Could not open file "+filename; + response << "HTTP/1.1 400 Bad Request\r\nContent-Length: " << content.length() << "\r\n\r\n" << content; + } + }; + + thread server_thread([&server](){ + //Start WS-server + server.start(); + }); + + //Wait for server to start so that the client can connect + this_thread::sleep_for(chrono::seconds(1)); + + //Client examples + //Second Client() parameter set to false: no certificate verification + Client client("localhost:8080", false); + auto r1=client.request("GET", "/match/123"); + cout << r1->content.rdbuf() << endl; + + string json="{\"firstName\": \"John\",\"lastName\": \"Smith\",\"age\": 25}"; + stringstream ss(json); + auto r2=client.request("POST", "/string", ss); + cout << r2->content.rdbuf() << endl; + + ss.str(json); + auto r3=client.request("POST", "/json", ss); + cout << r3->content.rdbuf() << endl; + + server_thread.join(); + + return 0; +} \ No newline at end of file