Commit d93ffbec authored by Arthur de Araújo Farias's avatar Arthur de Araújo Farias

Merge branch 'master' of https://github.com/oktal/pistache

parents 4c81d837 9c670280
......@@ -33,7 +33,7 @@ public:
, min(minor)
{ }
void parse(const std::string& str) {
void parse(const std::string& str) override {
auto p = str.find('.');
std::string major, minor;
if (p != std::string::npos) {
......
......@@ -171,13 +171,15 @@ namespace Async {
struct Core {
Core(State _state, TypeId _id)
: state(_state)
: allocated(false)
, state(_state)
, exc()
, mtx()
, requests()
, id(_id)
{ }
bool allocated;
State state;
std::exception_ptr exc;
......@@ -210,11 +212,18 @@ namespace Async {
}
void *mem = memory();
if (allocated) {
reinterpret_cast<T*>(mem)->~T();
allocated = false;
}
new (mem) T(std::forward<Args>(args)...);
allocated = true;
state = State::Fulfilled;
}
virtual ~Core() { }
virtual ~Core() {}
};
template<typename T>
......@@ -224,14 +233,18 @@ namespace Async {
, storage()
{ }
~CoreT() {
if (allocated) {
reinterpret_cast<T*>(&storage)->~T();
allocated = false;
}
}
template<class Other>
struct Rebind {
typedef CoreT<Other> Type;
};
typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage;
Storage storage;
T& value() {
if (state != State::Fulfilled)
throw Error("Attempted to take the value of a not fulfilled promise");
......@@ -241,9 +254,14 @@ namespace Async {
bool isVoid() const override { return false; }
protected:
void *memory() override {
return &storage;
}
private:
typedef typename std::aligned_storage<sizeof(T), alignof(T)>::type Storage;
Storage storage;
};
template<>
......@@ -254,6 +272,7 @@ namespace Async {
bool isVoid() const override { return true; }
protected:
void *memory() override {
return nullptr;
}
......
......@@ -205,18 +205,21 @@ private:
struct ConnectionEntry {
ConnectionEntry(
Async::Resolver resolve, Async::Rejection reject,
std::shared_ptr<Connection> connection, const struct sockaddr* addr, socklen_t addr_len)
std::shared_ptr<Connection> connection, const struct sockaddr* _addr, socklen_t _addr_len)
: resolve(std::move(resolve))
, reject(std::move(reject))
, connection(connection)
, addr(addr)
, addr_len(addr_len)
{ }
{
addr_len = _addr_len;
memcpy(&addr, _addr, addr_len);
}
const sockaddr *getAddr() { return reinterpret_cast<const sockaddr *>(&addr); }
Async::Resolver resolve;
Async::Rejection reject;
std::weak_ptr<Connection> connection;
const struct sockaddr* addr;
sockaddr_storage addr;
socklen_t addr_len;
};
......
......@@ -20,6 +20,8 @@ namespace Pistache {
namespace Http {
struct Cookie {
friend std::ostream& operator<<(std::ostream& os, const Cookie& cookie);
Cookie(std::string name, std::string value);
std::string name;
......@@ -38,9 +40,12 @@ struct Cookie {
static Cookie fromRaw(const char* str, size_t len);
static Cookie fromString(const std::string& str);
private:
void write(std::ostream& os) const;
};
std::ostream& operator<<(std::ostream& os, const Cookie& cookie);
class CookieJar {
public:
using HashMapCookies = std::unordered_map<std::string, Cookie>; // "value" -> Cookie
......
......@@ -169,8 +169,6 @@ public:
new (&storage) T(std::forward<U>(u));
}
~Entry() = default;
const T& data() const {
return *reinterpret_cast<const T*>(&storage);
}
......@@ -228,8 +226,17 @@ public:
return head == tail;
}
std::unique_ptr<Entry> popSafe() {
return std::unique_ptr<Entry>(pop());
std::unique_ptr<T> popSafe() {
std::unique_ptr<T> object;
std::unique_ptr<Entry> entry(pop());
if (entry)
{
object.reset(new T(std::move(entry->data())));
entry->data().~T();
}
return object;
}
private:
......
......@@ -168,7 +168,7 @@ public:
Optional<T> &operator=(Optional<T> &&other)
noexcept(types::is_nothrow_move_constructible<T>::value)
{
if (other.data()) {
if (!other.isEmpty()) {
move_helper(std::move(other), types::is_move_constructible<T>());
other.none_flag = NoneMarker;
}
......
......@@ -20,9 +20,14 @@
#include <openssl/ssl.h>
#endif /* PISTACHE_USE_SSL */
namespace Pistache {
namespace Http { namespace Private { class ParserBase; } }
namespace Tcp {
class Transport;
......@@ -33,6 +38,7 @@ public:
Peer();
Peer(const Address& addr);
~Peer() {}
Address address() const;
std::string hostname() const;
......@@ -43,22 +49,9 @@ public:
void associateSSL(void *ssl);
void *ssl(void) const;
void putData(std::string name, std::shared_ptr<void> data);
std::shared_ptr<void> getData(std::string name) const;
template<typename T>
std::shared_ptr<T> getData(std::string name) const {
return std::static_pointer_cast<T>(getData(std::move(name)));
}
std::shared_ptr<void> tryGetData(std::string name) const;
template<typename T>
std::shared_ptr<T> tryGetData(std::string name) const {
auto data = tryGetData(std::move(name));
if (data == nullptr) return nullptr;
return std::static_pointer_cast<T>(data);
}
void putData(std::string name, std::shared_ptr<Pistache::Http::Private::ParserBase> data);
std::shared_ptr<Pistache::Http::Private::ParserBase> getData(std::string name) const;
std::shared_ptr<Pistache::Http::Private::ParserBase> tryGetData(std::string name) const;
Async::Promise<ssize_t> send(const Buffer& buffer, int flags = 0);
......@@ -71,7 +64,7 @@ private:
Fd fd_;
std::string hostname_;
std::unordered_map<std::string, std::shared_ptr<void>> data_;
std::unordered_map<std::string, std::shared_ptr<Pistache::Http::Private::ParserBase>> data_;
void *ssl_;
};
......
......@@ -7,6 +7,7 @@
#include <pistache/client.h>
#include <pistache/http.h>
#include <pistache/stream.h>
#include <pistache/net.h>
#include <sys/sendfile.h>
#include <netdb.h>
......@@ -266,36 +267,34 @@ void
Transport::handleRequestsQueue() {
// Let's drain the queue
for (;;) {
auto entry = requestsQueue.popSafe();
if (!entry) break;
auto req = requestsQueue.popSafe();
if (!req) break;
auto &req = entry->data();
asyncSendRequestImpl(req);
asyncSendRequestImpl(*req);
}
}
void
Transport::handleConnectionQueue() {
for (;;) {
auto entry = connectionsQueue.popSafe();
if (!entry) break;
auto data = connectionsQueue.popSafe();
if (!data) break;
auto &data = entry->data();
auto conn = data.connection.lock();
auto conn = data->connection.lock();
if (!conn) {
throw std::runtime_error("Connection error");
}
int res = ::connect(conn->fd, data.addr, data.addr_len);
int res = ::connect(conn->fd, data->getAddr(), data->addr_len);
if (res == -1) {
if (errno == EINPROGRESS) {
reactor()->registerFdOneShot(key(), conn->fd, NotifyOn::Write | NotifyOn::Hangup | NotifyOn::Shutdown);
}
else {
data.reject(Error::system("Failed to connect"));
data->reject(Error::system("Failed to connect"));
continue;
}
}
connections.insert(std::make_pair(conn->fd, std::move(data)));
connections.insert(std::make_pair(conn->fd, std::move(*data)));
}
}
......@@ -360,7 +359,6 @@ void
Connection::connect(const Address& addr)
{
struct addrinfo hints;
struct addrinfo *addrs;
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = addr.family();
hints.ai_socktype = SOCK_STREAM; /* Stream socket */
......@@ -369,11 +367,15 @@ Connection::connect(const Address& addr)
const auto& host = addr.host();
const auto& port = addr.port().toString();
TRY(::getaddrinfo(host.c_str(), port.c_str(), &hints, &addrs));
AddrInfo addressInfo;
TRY(addressInfo.invoke(host.c_str(), port.c_str(), &hints));
const addrinfo *addrs = addressInfo.get_info_ptr();
int sfd = -1;
for (struct addrinfo *addr = addrs; addr; addr = addr->ai_next) {
for (const addrinfo *addr = addrs; addr; addr = addr->ai_next) {
sfd = ::socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sfd < 0) continue;
......@@ -552,13 +554,12 @@ Connection::performImpl(
void
Connection::processRequestQueue() {
for (;;) {
auto entry = requestsQueue.popSafe();
if (!entry) break;
auto req = requestsQueue.popSafe();
if (!req) break;
auto &req = entry->data();
performImpl(
req.request,
req.timeout, std::move(req.resolve), std::move(req.reject), std::move(req.onDone));
req->request,
req->timeout, std::move(req->resolve), std::move(req->reject), std::move(req->onDone));
}
}
......
......@@ -207,6 +207,12 @@ Cookie::write(std::ostream& os) const {
}
std::ostream& operator<<(std::ostream& os, const Cookie& cookie)
{
cookie.write(os);
return os;
}
CookieJar::CookieJar()
: cookies()
{ }
......
......@@ -26,9 +26,9 @@ using namespace std;
namespace Pistache {
namespace Http {
template<typename H, typename Stream, typename... Args>
typename std::enable_if<Header::IsHeader<H>::value, Stream&>::type
writeHeader(Stream& stream, Args&& ...args) {
template<typename H, typename Stream, typename... Args>
typename std::enable_if<Header::IsHeader<H>::value, Stream&>::type
writeHeader(Stream& stream, Args&& ...args) {
H header(std::forward<Args>(args)...);
stream << H::Name << ": ";
......@@ -90,7 +90,7 @@ namespace {
std::ostream os(&buf);
for (const auto& cookie: cookies) {
OUT(os << "Set-Cookie: ");
OUT(cookie.write(os));
OUT(os << cookie);
OUT(os << crlf);
}
......@@ -822,7 +822,7 @@ Timeout::onTimeout(uint64_t numWakeup) {
Private::Parser<Http::Request>&
Handler::getParser(const std::shared_ptr<Tcp::Peer>& peer) const {
return *peer->getData<Private::Parser<Http::Request>>(ParserData);
return static_cast<Private::Parser<Http::Request>&>(*peer->getData(ParserData));
}
......
......@@ -346,11 +346,11 @@ Host::parse(const std::string& data) {
unsigned long s_pos = data.find('[');
if (pos != std::string::npos && s_pos != std::string::npos) {
//IPv6 address
host_ = data.substr(s_pos, pos+1);
host_ = data.substr(s_pos, pos + 1);
try {
in6_addr addr6;
char buff6[INET6_ADDRSTRLEN+1];
memcpy(buff6, host_.c_str(), INET6_ADDRSTRLEN);
char buff6[INET6_ADDRSTRLEN + 1] = {0, };
std::copy(&host_[0], &host_[0] + host_.size(), buff6);
inet_pton(AF_INET6, buff6, &(addr6.s6_addr16));
} catch (std::runtime_error) {
throw std::invalid_argument("Invalid IPv6 address");
......@@ -369,8 +369,8 @@ Host::parse(const std::string& data) {
}
try {
in_addr addr;
char buff[INET_ADDRSTRLEN+1];
memcpy(buff, host_.c_str(), INET_ADDRSTRLEN);
char buff[INET_ADDRSTRLEN + 1] = {0, };
std::copy(&host_[0], &host_[0] + host_.size(), buff);
inet_pton(AF_INET, buff, &(addr));
} catch (std::runtime_error) {
throw std::invalid_argument("Invalid IPv4 address");
......
......@@ -238,9 +238,7 @@ Address::init(const std::string& addr) {
family_ = AF_INET6;
try {
in6_addr addr6;
char buff6[INET6_ADDRSTRLEN+1];
memcpy(buff6, host_.c_str(), INET6_ADDRSTRLEN);
inet_pton(AF_INET6, buff6, &(addr6.s6_addr16));
inet_pton(AF_INET6, host_.c_str(), &(addr6.s6_addr16));
} catch (std::runtime_error) {
throw std::invalid_argument("Invalid IPv6 address");
}
......@@ -257,9 +255,7 @@ Address::init(const std::string& addr) {
}
try {
in_addr addr;
char buff[INET_ADDRSTRLEN+1];
memcpy(buff, host_.c_str(), INET_ADDRSTRLEN);
inet_pton(AF_INET, buff, &(addr));
inet_pton(AF_INET, host_.c_str(), &(addr));
} catch (std::runtime_error) {
throw std::invalid_argument("Invalid IPv4 address");
}
......
......@@ -68,7 +68,7 @@ Peer::fd() const {
}
void
Peer::putData(std::string name, std::shared_ptr<void> data) {
Peer::putData(std::string name, std::shared_ptr<Pistache::Http::Private::ParserBase> data) {
auto it = data_.find(name);
if (it != std::end(data_)) {
throw std::runtime_error("The data already exists");
......@@ -77,7 +77,7 @@ Peer::putData(std::string name, std::shared_ptr<void> data) {
data_.insert(std::make_pair(std::move(name), std::move(data)));
}
std::shared_ptr<void>
std::shared_ptr<Pistache::Http::Private::ParserBase>
Peer::getData(std::string name) const {
auto data = tryGetData(std::move(name));
if (data == nullptr) {
......@@ -87,7 +87,7 @@ Peer::getData(std::string name) const {
return data;
}
std::shared_ptr<void>
std::shared_ptr<Pistache::Http::Private::ParserBase>
Peer::tryGetData(std::string(name)) const {
auto it = data_.find(name);
if (it == std::end(data_)) return nullptr;
......
......@@ -270,8 +270,12 @@ Transport::asyncWriteImpl(Fd fd)
}
if (bytesWritten < 0) {
if (errno == EAGAIN || errno == EWOULDBLOCK) {
auto bufferHolder = buffer.detach(totalWritten);
// pop_front kills buffer - so we cannot continue loop or use buffer after this point
wq.pop_front();
wq.push_front(WriteEntry(std::move(deferred), buffer.detach(totalWritten), flags));
wq.push_front(WriteEntry(std::move(deferred), bufferHolder, flags));
reactor()->modifyFd(key(), fd, NotifyOn::Read | NotifyOn::Write, Polling::Mode::Edge);
}
else {
......@@ -354,16 +358,15 @@ void
Transport::handleWriteQueue() {
// Let's drain the queue
for (;;) {
auto entry = writesQueue.popSafe();
if (!entry) break;
auto write = writesQueue.popSafe();
if (!write) break;
auto &write = entry->data();
auto fd = write.peerFd;
auto fd = write->peerFd;
if (!isPeerFd(fd)) continue;
{
Guard guard(toWriteLock);
toWrite[fd].push_back(std::move(write));
toWrite[fd].push_back(std::move(*write));
}
reactor()->modifyFd(key(), fd, NotifyOn::Read | NotifyOn::Write, Polling::Mode::Edge);
......@@ -373,22 +376,20 @@ Transport::handleWriteQueue() {
void
Transport::handleTimerQueue() {
for (;;) {
auto entry = timersQueue.popSafe();
if (!entry) break;
auto timer = timersQueue.popSafe();
if (!timer) break;
auto &timer = entry->data();
armTimerMsImpl(std::move(timer));
armTimerMsImpl(std::move(*timer));
}
}
void
Transport::handlePeerQueue() {
for (;;) {
auto entry = peersQueue.popSafe();
if (!entry) break;
auto data = peersQueue.popSafe();
if (!data) break;
const auto &data = entry->data();
handlePeer(data.peer);
handlePeer(data->peer);
}
}
......
......@@ -97,7 +97,7 @@ TEST(cookie_test, write_test) {
c1.domain = Some(std::string("example.com"));
std::ostringstream oss;
c1.write(oss);
oss << c1;
ASSERT_EQ(oss.str(), "lang=fr-FR; Path=/; Domain=example.com");
......@@ -110,13 +110,13 @@ TEST(cookie_test, write_test) {
c2.expires = Some(FullDate(expires));
oss.str("");
c2.write(oss);
oss << c2;
Cookie c3("lang", "en-US");
c3.secure = true;
c3.ext.insert(std::make_pair("Scope", "Private"));
oss.str("");
c3.write(oss);
oss << c3;
ASSERT_EQ(oss.str(), "lang=en-US; Secure; Scope=Private");
}
......
......@@ -21,7 +21,7 @@ static size_t write_cb(void *contents, size_t size, size_t nmemb, void *userp)
struct HelloHandler : public Http::Handler {
HTTP_PROTOTYPE(HelloHandler)
void onRequest(const Http::Request&, Http::ResponseWriter writer) {
void onRequest(const Http::Request&, Http::ResponseWriter writer) override {
writer.send(Http::Code::Ok, "Hello, World!");
}
};
......
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