Commit 6d35e560 authored by octal's avatar octal

Added remaining methods to the http client. Also removed main.cc file and...

Added remaining methods to the http client. Also removed main.cc file and created an examples/ folder
parent 28317f82
...@@ -19,8 +19,7 @@ install(FILES ${HEADER_FILES} DESTINATION include/rest) ...@@ -19,8 +19,7 @@ install(FILES ${HEADER_FILES} DESTINATION include/rest)
add_subdirectory (src) add_subdirectory (src)
include_directories (src) include_directories (src)
add_executable(server main.cc) add_subdirectory (examples)
target_link_libraries(server net)
ADD_SUBDIRECTORY (googletest-release-1.7.0) ADD_SUBDIRECTORY (googletest-release-1.7.0)
enable_testing() enable_testing()
......
add_executable(http_server http_server.cc)
target_link_libraries(http_server net)
add_executable(http_client http_client.cc)
target_link_libraries(http_client net)
add_executable(rest_server rest_server.cc)
target_link_libraries(rest_server net)
/*
Mathieu Stefani, 07 février 2016
* Http client example
*/
#include "net.h"
#include "http.h"
#include "client.h"
#include <atomic>
using namespace Net;
int main() {
Net::Http::Client client("http://supnetwork.org:9080");
auto opts = Net::Http::Client::options()
.threads(1)
.maxConnections(20);
using namespace Net::Http;
constexpr size_t Requests = 1000;
std::atomic<int> responsesReceived(0);
client.init(opts);
for (int i = 0; i < Requests; ++i) {
client.get(client
.request("/ping")
.cookie(Cookie("FOO", "bar")))
.then([&](const Http::Response& response) {
responsesReceived.fetch_add(1);
//std::cout << "code = " << response.code() << std::endl;
// std::cout << "body = " << response.body() << std::endl;
}, Async::NoExcept);
}
std::cout << "Sent " << Requests << " requests" << std::endl;
for (;;) {
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Received " << responsesReceived.load() << " responses" << std::endl;
}
client.shutdown();
}
This diff is collapsed.
/*
Mathieu Stefani, 07 février 2016
Example of a REST endpoint with routing
*/
#include "http.h"
#include "router.h"
#include "endpoint.h"
#include <algorithm>
using namespace std;
using namespace Net;
void printCookies(const Net::Http::Request& req) {
auto cookies = req.cookies();
std::cout << "Cookies: [" << std::endl;
const std::string indent(4, ' ');
for (const auto& c: cookies) {
std::cout << indent << c.name << " = " << c.value << std::endl;
}
std::cout << "]" << std::endl;
}
namespace Generic {
void handleReady(const Rest::Request&, Http::ResponseWriter response) {
response.send(Http::Code::Ok, "1");
}
}
class StatsEndpoint {
public:
StatsEndpoint(Net::Address addr)
: httpEndpoint(std::make_shared<Net::Http::Endpoint>(addr))
{ }
void init(size_t thr = 2) {
auto opts = Net::Http::Endpoint::options()
.threads(thr)
.flags(Net::Tcp::Options::InstallSignalHandler);
httpEndpoint->init(opts);
setupRoutes();
}
void start() {
httpEndpoint->setHandler(router.handler());
httpEndpoint->serve();
}
void shutdown() {
httpEndpoint->shutdown();
}
private:
void setupRoutes() {
using namespace Net::Rest;
Routes::Post(router, "/record/:name/:value?", Routes::bind(&StatsEndpoint::doRecordMetric, this));
Routes::Get(router, "/value/:name", Routes::bind(&StatsEndpoint::doGetMetric, this));
Routes::Get(router, "/ready", Routes::bind(&Generic::handleReady));
Routes::Get(router, "/auth", Routes::bind(&StatsEndpoint::doAuth, this));
}
void doRecordMetric(const Rest::Request& request, Net::Http::ResponseWriter response) {
auto name = request.param(":name").as<std::string>();
auto it = std::find_if(metrics.begin(), metrics.end(), [&](const Metric& metric) {
return metric.name() == name;
});
int val = 1;
if (request.hasParam(":value")) {
auto value = request.param(":value");
val = value.as<int>();
}
if (it == std::end(metrics)) {
metrics.push_back(Metric(std::move(name), val));
response.send(Http::Code::Created, std::to_string(val));
}
else {
auto &metric = *it;
metric.incr(val);
response.send(Http::Code::Ok, std::to_string(metric.value()));
}
}
void doGetMetric(const Rest::Request& request, Net::Http::ResponseWriter response) {
auto name = request.param(":name").as<std::string>();
auto it = std::find_if(metrics.begin(), metrics.end(), [&](const Metric& metric) {
return metric.name() == name;
});
if (it == std::end(metrics)) {
response.send(Http::Code::Not_Found, "Metric does not exist");
} else {
const auto& metric = *it;
response.send(Http::Code::Ok, std::to_string(metric.value()));
}
}
void doAuth(const Rest::Request& request, Net::Http::ResponseWriter response) {
printCookies(request);
response.cookies()
.add(Http::Cookie("lang", "en-US"));
response.send(Http::Code::Ok);
}
class Metric {
public:
Metric(std::string name, int initialValue = 1)
: name_(std::move(name))
, value_(initialValue)
{ }
int incr(int n = 1) {
int old = value_;
value_ += n;
return old;
}
int value() const {
return value_;
}
std::string name() const {
return name_;
}
private:
std::string name_;
int value_;
};
std::vector<Metric> metrics;
std::shared_ptr<Net::Http::Endpoint> httpEndpoint;
Rest::Router router;
};
int main(int argc, char *argv[]) {
Net::Port port(9080);
int thr = 2;
if (argc >= 2) {
port = std::stol(argv[1]);
if (argc == 3)
thr = std::stol(argv[2]);
}
Net::Address addr(Net::Ipv4::any(), port);
cout << "Cores = " << hardware_concurrency() << endl;
cout << "Using " << thr << " threads" << endl;
StatsEndpoint stats(addr);
stats.init(thr);
stats.start();
stats.shutdown();
}
...@@ -245,6 +245,15 @@ public: ...@@ -245,6 +245,15 @@ public:
Async::Promise<Response> get( Async::Promise<Response> get(
const Http::Request& request, const Http::Request& request,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0)); std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
Async::Promise<Response> post(
const Http::Request& req,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
Async::Promise<Response> put(
const Http::Request& req,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
Async::Promise<Response> del(
const Http::Request& req,
std::chrono::milliseconds timeout = std::chrono::milliseconds(0));
void shutdown(); void shutdown();
...@@ -260,6 +269,11 @@ private: ...@@ -260,6 +269,11 @@ private:
std::atomic<uint64_t> ioIndex; std::atomic<uint64_t> ioIndex;
Queue<Connection::RequestData> requestsQueue; Queue<Connection::RequestData> requestsQueue;
Async::Promise<Response> doRequest(
const Http::Request& req,
Http::Method method,
std::chrono::milliseconds timeout);
void processRequestQueue(); void processRequestQueue();
}; };
......
...@@ -526,12 +526,6 @@ private: ...@@ -526,12 +526,6 @@ private:
, transport_(nullptr) , transport_(nullptr)
{ } { }
ResponseWriter(Tcp::Transport* transport)
: Response()
, buf_(DefaultStreamSize)
, transport_(transport)
{ }
ResponseWriter(Tcp::Transport* transport, Request request, Handler* handler) ResponseWriter(Tcp::Transport* transport, Request request, Handler* handler)
: Response(request.version()) : Response(request.version())
, buf_(DefaultStreamSize) , buf_(DefaultStreamSize)
......
...@@ -59,7 +59,7 @@ private: ...@@ -59,7 +59,7 @@ private:
class Request; class Request;
struct Route { struct Route {
typedef std::function<void (const Request&, Net::Http::Response)> Handler; typedef std::function<void (const Request&, Net::Http::ResponseWriter)> Handler;
Route(std::string resource, Http::Method method, Handler handler) Route(std::string resource, Http::Method method, Handler handler)
: resource_(std::move(resource)) : resource_(std::move(resource))
...@@ -223,7 +223,7 @@ namespace Routes { ...@@ -223,7 +223,7 @@ namespace Routes {
#define CALL_MEMBER_FN(obj, pmf) ((obj)->*(pmf)) #define CALL_MEMBER_FN(obj, pmf) ((obj)->*(pmf))
return [=](const Rest::Request& request, Http::Response response) { return [=](const Rest::Request& request, Http::ResponseWriter response) {
CALL_MEMBER_FN(obj, func)(request, std::move(response)); CALL_MEMBER_FN(obj, func)(request, std::move(response));
}; };
...@@ -234,7 +234,7 @@ namespace Routes { ...@@ -234,7 +234,7 @@ namespace Routes {
Route::Handler bind(Result (*func)(Args...)) { Route::Handler bind(Result (*func)(Args...)) {
details::static_checks<Args...>(); details::static_checks<Args...>();
return [=](const Rest::Request& request, Http::Response response) { return [=](const Rest::Request& request, Http::ResponseWriter response) {
func(request, std::move(response)); func(request, std::move(response));
}; };
} }
......
...@@ -15,6 +15,8 @@ namespace Net { ...@@ -15,6 +15,8 @@ namespace Net {
namespace Http { namespace Http {
static constexpr const char* UA = "pistache/0.1";
namespace { namespace {
#define OUT(...) \ #define OUT(...) \
do { \ do { \
...@@ -69,7 +71,7 @@ namespace { ...@@ -69,7 +71,7 @@ namespace {
if (!writeCookies(request.cookies(), buf)) return false; if (!writeCookies(request.cookies(), buf)) return false;
if (!writeHeaders(request.headers(), buf)) return false; if (!writeHeaders(request.headers(), buf)) return false;
if (!writeHeader<Header::UserAgent>(os, "restpp/0.1")) return false; if (!writeHeader<Header::UserAgent>(os, UA)) return false;
if (!writeHeader<Header::Host>(os, std::move(host))) return false; if (!writeHeader<Header::Host>(os, std::move(host))) return false;
OUT(os << crlf); OUT(os << crlf);
...@@ -553,11 +555,37 @@ Client::request(std::string val) { ...@@ -553,11 +555,37 @@ Client::request(std::string val) {
Async::Promise<Http::Response> Async::Promise<Http::Response>
Client::get(const Http::Request& request, std::chrono::milliseconds timeout) Client::get(const Http::Request& request, std::chrono::milliseconds timeout)
{
return doRequest(request, Http::Method::Get, timeout);
}
Async::Promise<Http::Response>
Client::post(const Http::Request& request, std::chrono::milliseconds timeout)
{
return doRequest(request, Http::Method::Post, timeout);
}
Async::Promise<Http::Response>
Client::put(const Http::Request& request, std::chrono::milliseconds timeout)
{
return doRequest(request, Http::Method::Put, timeout);
}
Async::Promise<Http::Response>
Client::del(const Http::Request& request, std::chrono::milliseconds timeout)
{
return doRequest(request, Http::Method::Delete, timeout);
}
Async::Promise<Response>
Client::doRequest(
const Http::Request& request,
Http::Method method,
std::chrono::milliseconds timeout)
{ {
unsafe { unsafe {
auto &req = const_cast<Http::Request &>(request); auto &req = const_cast<Http::Request &>(request);
req.method_ = Http::Method::Get; req.method_ = method;
req.headers_.remove<Header::UserAgent>(); req.headers_.remove<Header::UserAgent>();
} }
......
...@@ -809,7 +809,7 @@ void ...@@ -809,7 +809,7 @@ void
Timeout::onTimeout(uint64_t numWakeup) { Timeout::onTimeout(uint64_t numWakeup) {
if (!peer.lock()) return; if (!peer.lock()) return;
ResponseWriter response(transport); ResponseWriter response(transport, request, handler);
response.associatePeer(peer); response.associatePeer(peer);
handler->onTimeout(request, std::move(response)); handler->onTimeout(request, std::move(response));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment