From 0cb4539c9af7e28e7a42a9f5a0d39d50f5746bed Mon Sep 17 00:00:00 2001 From: JustinAJ Date: Wed, 25 Nov 2015 14:33:06 -0500 Subject: [PATCH] Added unfinished HTTP server. Added additional single-element span() to Readable_String. --- Jupiter/HTTP_Server.cpp | 841 ++++++++++++++++++++++++++++++++++ Jupiter/Readable_String.h | 1 + Jupiter/Readable_String_Imp.h | 8 + Release/Jupiter.lib | Bin 294078 -> 302612 bytes 4 files changed, 850 insertions(+) create mode 100644 Jupiter/HTTP_Server.cpp diff --git a/Jupiter/HTTP_Server.cpp b/Jupiter/HTTP_Server.cpp new file mode 100644 index 0000000..647327d --- /dev/null +++ b/Jupiter/HTTP_Server.cpp @@ -0,0 +1,841 @@ +/** + * Copyright (C) 2015 Justin James. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Written by Justin James + */ + +#include +#include +#include "String.h" +#include "CString.h" +#include "Reference_String.h" +#include "TCPSocket.h" +#include "ArrayList.h" +#include "HTTP.h" +#include "HTTP_Server.h" + +using namespace Jupiter::literals; + +static const Jupiter::ReferenceString HTTP_REQUEST_ENDING = "\r\n\r\n"_jrs; + +// HTTPCommand + +enum HTTPCommand +{ + GET, + HEAD, + UNKNOWN, + NONE_SPECIFIED +}; + +// HTTPVersion + +enum HTTPVersion +{ + HTTP_1_0, + HTTP_1_1, + HTTP_Unsupported +}; + +// HTTP::Server::Content + +Jupiter::HTTP::Server::Content::Content(const Jupiter::ReadableString &in_name, Jupiter::HTTP::Server::HTTPFunction in_function) : name(in_name) +{ + Jupiter::HTTP::Server::Content::function = in_function; + Jupiter::HTTP::Server::Content::name_checksum = Jupiter::HTTP::Server::Content::name.calcChecksum(); // switch to calcChecksumi to make case-insensitive +} + +Jupiter::ReadableString *Jupiter::HTTP::Server::Content::execute(const Jupiter::ReadableString ¶meters) +{ + return Jupiter::HTTP::Server::Content::function(parameters); +} + +// HTTP::Server::Directory + +Jupiter::HTTP::Server::Directory::Directory(const Jupiter::ReadableString &in_name) : name(in_name) +{ + name_checksum = Jupiter::HTTP::Server::Directory::name.calcChecksumi(); +} + +Jupiter::HTTP::Server::Directory::~Directory() +{ + Jupiter::HTTP::Server::Directory::directories.emptyAndDelete(); + Jupiter::HTTP::Server::Directory::content.emptyAndDelete(); +} + +// host/dir/content +// .hook(host, "dir/content") + +void Jupiter::HTTP::Server::Directory::hook(const Jupiter::ReadableString &in_name, Content *in_content) +{ + Jupiter::ReferenceString in_name_ref = in_name; + in_name_ref.shiftRight(in_name_ref.span('/')); + + size_t index = in_name_ref.find('/'); + if (index == Jupiter::INVALID_INDEX) // Hook content + Jupiter::HTTP::Server::Directory::content.add(in_content); + else + { + Jupiter::ReferenceString dir_name(in_name_ref.ptr(), index); + in_name_ref.shiftRight(dir_name.size()); + Jupiter::HTTP::Server::Directory *directory; + unsigned int dir_name_checksum = dir_name.calcChecksum(); + index = Jupiter::HTTP::Server::Directory::directories.size(); + while (index != 0) + { + directory = Jupiter::HTTP::Server::Directory::directories.get(--index); + if (directory->name_checksum == dir_name_checksum && directory->name.equals(dir_name)) + return directory->hook(dir_name, in_content); + } + + // create directories + directory = new Jupiter::HTTP::Server::Directory(dir_name); + Jupiter::HTTP::Server::Directory::directories.add(directory); + + directory_add_loop: + index = in_name_ref.find('/'); + if (index != Jupiter::INVALID_INDEX) + { + // add directory + directory->directories.add(new Jupiter::HTTP::Server::Directory(in_name_ref.substring(0U, index))); + directory = directory->directories.get(directories.size() - 1); + goto directory_add_loop; + } + // add content + directory->content.add(in_content); + } +} + +bool Jupiter::HTTP::Server::Directory::remove(const Jupiter::ReadableString &in_name) +{ + return false; +} + +bool Jupiter::HTTP::Server::Directory::has(const Jupiter::ReadableString &in_name) +{ + return false; +} + +Jupiter::HTTP::Server::Content *Jupiter::HTTP::Server::Directory::find(const Jupiter::ReadableString &in_name) +{ + Jupiter::ReferenceString in_name_ref = in_name; + in_name_ref.shiftRight(in_name_ref.span("/"_jrs)); + + size_t index = in_name_ref.find('/'); + if (index == Jupiter::INVALID_INDEX) // Search content + { + unsigned int content_name_checksum = in_name_ref.calcChecksum(); + index = Jupiter::HTTP::Server::Directory::content.size(); + Jupiter::HTTP::Server::Content *content_itr; + while (index != 0) + { + content_itr = Jupiter::HTTP::Server::Directory::content.get(--index); + if (content_itr->name_checksum == content_name_checksum && content_itr->name.equals(in_name_ref)) + return content_itr; + } + return nullptr; // No such content + } + + Jupiter::ReferenceString dir_name(in_name_ref.ptr(), index); + in_name_ref.shiftRight(dir_name.size()); + Jupiter::HTTP::Server::Directory *directory; + unsigned int dir_name_checksum = dir_name.calcChecksum(); + index = Jupiter::HTTP::Server::Directory::directories.size(); + while (index != 0) + { + directory = Jupiter::HTTP::Server::Directory::directories.get(--index); + if (directory->name_checksum == dir_name_checksum && directory->name.equals(dir_name)) + return directory->find(in_name_ref); + } + + return nullptr; // No such directory +} + +Jupiter::ReadableString *Jupiter::HTTP::Server::Directory::execute(const Jupiter::ReadableString &in_name, const Jupiter::ReadableString ¶meters) +{ + Jupiter::HTTP::Server::Content *content = Jupiter::HTTP::Server::Directory::find(in_name); + if (content == nullptr) + return nullptr; + return content->execute(parameters); +} + +// HTTP::Server::Host + +Jupiter::HTTP::Server::Host::Host(const Jupiter::ReadableString &in_name) : Directory(in_name) +{ + name_checksum = Jupiter::HTTP::Server::Host::name.calcChecksumi(); +} + +// HTTPSession struct + +struct HTTPSession +{ + Jupiter::Socket sock; + Jupiter::String request; + bool keep_alive = false; + Jupiter::HTTP::Server::Host *host = nullptr; + HTTPVersion version = HTTPVersion::HTTP_1_0; + std::chrono::steady_clock::time_point last_active = std::chrono::steady_clock::now(); + HTTPSession(Jupiter::Socket &&in_sock); + ~HTTPSession(); +}; + +HTTPSession::HTTPSession(Jupiter::Socket &&in_sock) : sock(std::move(in_sock)) +{ +} + +HTTPSession::~HTTPSession() +{ + HTTPSession::sock.closeSocket(); +} + +// Server::Data struct + +struct Jupiter::HTTP::Server::Data +{ + /** Data */ + Jupiter::ArrayList hosts; + Jupiter::ArrayList ports; + Jupiter::ArrayList sessions; + std::chrono::milliseconds session_timeout = std::chrono::milliseconds(30000); // TODO: Config variable + std::chrono::milliseconds keep_alive_session_timeout = std::chrono::milliseconds(30000); // TODO: Config variable + size_t max_request_size = 1024; // TODO: Config variable + bool permit_keept_alive = true; // TODO: Config variable + + /** Foward functions */ + void hook(const Jupiter::ReadableString &host, const Jupiter::ReadableString &path, Content *in_content); + bool remove(const Jupiter::ReadableString &hostname); + bool remove(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name); + bool has(const Jupiter::ReadableString &hostname); + bool has(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name); + Jupiter::HTTP::Server::Host *find_host(const Jupiter::ReadableString &name); + Content *find(const Jupiter::ReadableString &name); + Content *find(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name); + Jupiter::ReadableString *execute(const Jupiter::ReadableString &name, const Jupiter::ReadableString ¶meters); + Jupiter::ReadableString *execute(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name, const Jupiter::ReadableString ¶meters); + + int process_request(HTTPSession &session); + + /** Constructors */ + Data(); + Data(const Data &source) = delete; + Data(Data &&source) = delete; + + /** Destructor */ + ~Data(); +}; + +// Data constructor + +Jupiter::HTTP::Server::Data::Data() +{ + // hosts[0] is always the "global" namespace. + Jupiter::HTTP::Server::Data::hosts.add(new Jupiter::HTTP::Server::Host(Jupiter::HTTP::Server::global_namespace)); +} + +// Data destructor + +Jupiter::HTTP::Server::Data::~Data() +{ + Jupiter::HTTP::Server::Data::hosts.emptyAndDelete(); + Jupiter::HTTP::Server::Data::sessions.emptyAndDelete(); + Jupiter::HTTP::Server::Data::ports.emptyAndDelete(); +} + +// Data functions + +void Jupiter::HTTP::Server::Data::hook(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &in_path, Content *in_content) +{ + Jupiter::ReferenceString path = in_path; + Jupiter::ReferenceString dir_name; + Jupiter::HTTP::Server::Host *host = Jupiter::HTTP::Server::Data::find_host(hostname); + Jupiter::HTTP::Server::Directory *dir; + + if (host == nullptr) + { + host = new Jupiter::HTTP::Server::Host(hostname); + Jupiter::HTTP::Server::Data::hosts.add(host); + // OPTIMIZE: create directory tree and return. + } + + dir = host; + + path.shiftRight(path.span('/')); + if (path.isEmpty()) + host->content.add(in_content); + + if (path.isNotEmpty()) + { + dir_name = path.getToken(0, '/'); + + size_t index = dir->directories.size(); + Jupiter::HTTP::Server::Directory *t_dir; + + dir_search_loop: + if (index != 0) + { + t_dir = dir->directories.get(--index); + if (t_dir->name.equalsi(dir_name) == false) + goto dir_search_loop; + dir = t_dir; + } + else // directory doesn't exist + { + t_dir = new Jupiter::HTTP::Server::Directory(dir_name); + dir->directories.add(t_dir); + dir = t_dir; + // OPTIMIZE: create directory tree and return. + } + // end dir_search_loop + + path.shiftRight(dir_name.size()); + path.shiftRight(path.span('/')); + } + dir->hook(path, in_content); + //dir->content.add(in_content); + + // path is empty -- insert content into dir +} + +bool Jupiter::HTTP::Server::Data::remove(const Jupiter::ReadableString &hostname) +{ + unsigned int name_checksum = hostname.calcChecksumi(); + size_t index = Jupiter::HTTP::Server::Data::hosts.size(); + Jupiter::HTTP::Server::Host *host; + while (index != 0) + { + host = Jupiter::HTTP::Server::Data::hosts.get(--index); + if (name_checksum == host->name_checksum && host->name.equalsi(hostname)) + { + delete Jupiter::HTTP::Server::Data::hosts.remove(index); + return true; + } + } + return false; +} + +// name: path/to/resource OR path/ +bool Jupiter::HTTP::Server::Data::remove(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name) +{ + /*unsigned int name_checksum = hostname.calcChecksumi(); + size_t index = Jupiter::HTTP::Server::Data::hosts.size(); + Jupiter::HTTP::Server::Host *host; + while (index != 0) + { + host = Jupiter::HTTP::Server::Data::hosts.get(--index); + if (name_checksum == host->name_checksum && host->name.equalsi(hostname)) + { + name_checksum = name.calcChecksum(); // switch to equalsi to make case-insensitive + index = host->functions.size(); + Jupiter::HTTP::Server::Content *content; + while (index != 0) + { + content = host->functions.get(--index); + if (name_checksum == content->name_checksum && content->name.equals(name)) // switch to equalsi to make case-insensitive + { + delete host->functions.remove(index); + return true; + } + } + return false; + } + }*/ + return false; +} + +bool Jupiter::HTTP::Server::Data::has(const Jupiter::ReadableString &hostname) +{ + unsigned int name_checksum = hostname.calcChecksumi(); + size_t index = Jupiter::HTTP::Server::Data::hosts.size(); + Jupiter::HTTP::Server::Host *host; + while (index != 0) + { + host = Jupiter::HTTP::Server::Data::hosts.get(--index); + if (name_checksum == host->name_checksum && host->name.equalsi(hostname)) + return true; + } + return false; +} + +bool Jupiter::HTTP::Server::Data::has(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name) +{ + unsigned int name_checksum = hostname.calcChecksumi(); + size_t index = Jupiter::HTTP::Server::Data::hosts.size(); + Jupiter::HTTP::Server::Host *host; + while (index != 0) + { + host = Jupiter::HTTP::Server::Data::hosts.get(--index); + if (name_checksum == host->name_checksum && host->name.equalsi(hostname)) + { + name_checksum = name.calcChecksum(); // switch to equalsi to make case-insensitive + index = host->content.size(); + Jupiter::HTTP::Server::Content *content; + while (index != 0) + { + content = host->content.get(--index); + if (name_checksum == content->name_checksum && content->name.equals(name)) // switch to equalsi to make case-insensitive + return true; + } + return false; + } + } + return false; +} + +Jupiter::HTTP::Server::Host *Jupiter::HTTP::Server::Data::find_host(const Jupiter::ReadableString &name) +{ + unsigned int name_checksum = name.calcChecksumi(); + size_t index = Jupiter::HTTP::Server::Data::hosts.size(); + Jupiter::HTTP::Server::Host *host; + while (index != 0) + { + host = Jupiter::HTTP::Server::Data::hosts.get(--index); + if (name_checksum == host->name_checksum && host->name.equalsi(name)) + return host; + } + return nullptr; +} + +Jupiter::HTTP::Server::Content *Jupiter::HTTP::Server::Data::find(const Jupiter::ReadableString &name) +{ + return Jupiter::HTTP::Server::Data::hosts.get(0)->find(name); +} + +Jupiter::HTTP::Server::Content *Jupiter::HTTP::Server::Data::find(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name) +{ + Jupiter::HTTP::Server::Host *host = Jupiter::HTTP::Server::Data::find_host(hostname); + if (host == nullptr) + return nullptr; + + return host->find(name); +} + +Jupiter::ReadableString *Jupiter::HTTP::Server::Data::execute(const Jupiter::ReadableString &name, const Jupiter::ReadableString ¶meters) +{ + Jupiter::HTTP::Server::Content *content = Jupiter::HTTP::Server::Data::find(name); + if (content == nullptr) + return nullptr; + return content->execute(parameters); +} + +Jupiter::ReadableString *Jupiter::HTTP::Server::Data::execute(const Jupiter::ReadableString &hostname, const Jupiter::ReadableString &name, const Jupiter::ReadableString ¶meters) +{ + Jupiter::HTTP::Server::Content *content = Jupiter::HTTP::Server::Data::find(hostname, name); + if (content == nullptr) + return nullptr; + return content->execute(parameters); +} + +char *html_time() +{ + time_t rawtime = time(0); + char *rtime = new char[64]; + strftime(rtime, 64, "%a, %d %b %Y %H:%M:%S GMT", gmtime(&rawtime)); + return rtime; +} + +int Jupiter::HTTP::Server::Data::process_request(HTTPSession &session) +{ + Jupiter::ReadableString::TokenizeResult lines = Jupiter::ReferenceString::tokenize(session.request, STRING_LITERAL_AS_REFERENCE(ENDL)); + HTTPCommand command = HTTPCommand::NONE_SPECIFIED; + Content *content = nullptr; + Jupiter::ReferenceString content_parameters; + Jupiter::ReferenceString first_token; + size_t index = 0; + size_t span; + + auto get_line_offset = [&session, &lines](size_t index) + { + size_t offset = 0; + while (index != 0) + offset += lines.tokens[--index].size() + 2; + return offset; + }; + + while (index != lines.token_count) + { + Jupiter::ReferenceString &line = lines.tokens[index++]; + + // trim front-end spaces. + span = line.span(" "_jrs); + if (span != 0) + line.shiftRight(span); + + if (line.isEmpty()) // end of http request + { + Jupiter::String result(256); + switch (command) + { + case HTTPCommand::GET: + case HTTPCommand::HEAD: + if (content != nullptr) + { + /* + HTTP/1.1 200 OK + Date: Mon, 05 Oct 2015 01:50:08 GMT + Server: Apache/2.4.7 (Ubuntu) + Last-Modified: Tue, 18 Aug 2015 03:53:28 GMT + ETag: "0-51d8ddc61160f" + Accept-Ranges: bytes + Content-Length: 0 + Connection: close + Content-Type: text/html + */ + Jupiter::ReadableString *content_result = content->execute(content_parameters); + + switch (session.version) + { + default: + case HTTPVersion::HTTP_1_0: + result = "HTTP/1.0 200 OK"_jrs ENDL; + break; + case HTTPVersion::HTTP_1_1: + result = "HTTP/1.1 200 OK"_jrs ENDL; + break; + } + + char *time_header = html_time(); + result += "Date: "_jrs ENDL; + result += time_header; + delete[] time_header; + + result += "Server: " JUPITER_VERSION ENDL; + + result += Jupiter::StringS::Format("Content-Length: %u" ENDL, content_result->size()); + + switch (session.version) + { + default: + case HTTPVersion::HTTP_1_0: + result += "Connection: close"_jrs ENDL; + break; + case HTTPVersion::HTTP_1_1: + result += "Connection: keep-alive"_jrs ENDL; + break; + } + + result += "Content-Type: "_jrs; + if (content->type == nullptr) + result += Jupiter::HTTP::Content::Type::Text::PLAIN; + else + result += *content->type; + if (content->charset != nullptr) + { + result += "; charset="_jrs; + result += *content->charset; + } + result += ENDL; + + if (content->language != nullptr) + { + result += "Content-Language"_jrs; + result += *content->language; + } + + result += ENDL ENDL; + if (command == HTTPCommand::GET) + result += *content_result; + + delete content_result; + + session.sock.send(result); + } + else + { + // 404 + /* + HTTP/1.1 404 Not Found + Date: Mon, 05 Oct 2015 01:46:01 GMT + Server: Apache/2.4.7 (Ubuntu) + Content-Length: 281 + Connection: close + Content-Type: text/html; charset=iso-8859-1 + */ + + } + break; + default: + break; + } + + if (session.keep_alive == false) // not keep-alive -- will be destroyed on return + break; + if (index == lines.token_count) // end of packet + session.request.erase(); + else // end of request -- another request is following + session.request.shiftRight(get_line_offset(index)); + + if (session.request.find(HTTP_REQUEST_ENDING) != Jupiter::INVALID_INDEX) // there's another full request already received + return Jupiter::HTTP::Server::Data::process_request(session); + break; + } + + // Not empty + first_token = line.getToken(0, ' '); + + if (first_token.get(first_token.size() - 1) == ':') // header field + { + first_token.truncate(1); // trim trailing ':' + if (first_token.equalsi("HOST"_jrs)) + session.host = Jupiter::HTTP::Server::Data::find_host(line.getWord(1, " ")); + else if (first_token.equalsi("CONNECTION"_jrs)) + { + Jupiter::ReferenceString connection_type = line.getWord(1, " "); + if (connection_type.equalsi("keep-alive"_jrs)) + session.keep_alive = true; + } + } + else // command + { + if (first_token.equals("GET"_jrs)) + { + command = HTTPCommand::GET; + + content_parameters = line.getWord(1, " "); + span = content_parameters.find('?'); // repurposing 'span' + if (span == Jupiter::INVALID_INDEX) + { + content = Jupiter::HTTP::Server::Data::find(content_parameters); + content_parameters.erase(); + } + else + { + content = Jupiter::HTTP::Server::Data::find(content_parameters.substring(0U, span)); + content_parameters.shiftRight(span + 1); + // decode content_parameters here + } + + Jupiter::ReferenceString protocol_str = line.getWord(2, " "); + if (protocol_str.equalsi("http/1.0"_jrs)) + session.version = HTTPVersion::HTTP_1_0; + else if (protocol_str.equalsi("http/1.1"_jrs)) + { + session.version = HTTPVersion::HTTP_1_1; + session.keep_alive = true; + } + } + else if (first_token.equals("HEAD"_jrs)) + { + command = HTTPCommand::HEAD; + + content_parameters = line.getWord(1, " "); + span = content_parameters.find('?'); // repurposing 'span' + if (span == Jupiter::INVALID_INDEX) + { + content = Jupiter::HTTP::Server::Data::find(content_parameters); + content_parameters.erase(); + } + else + { + content = Jupiter::HTTP::Server::Data::find(content_parameters.substring(0U, span)); + content_parameters.shiftRight(span + 1); + } + + Jupiter::ReferenceString protocol_str = line.getWord(2, " "); + if (protocol_str.equalsi("http/1.0"_jrs)) + session.version = HTTPVersion::HTTP_1_0; + else if (protocol_str.equalsi("http/1.1"_jrs)) + { + session.version = HTTPVersion::HTTP_1_1; + session.keep_alive = true; + } + } + else + command = HTTPCommand::UNKNOWN; + } + } + return 0; +} + +/** HTTP::Server */ + +// Server constructors + +Jupiter::HTTP::Server::Server() +{ + Jupiter::HTTP::Server::data_ = new Jupiter::HTTP::Server::Data(); +} + +Jupiter::HTTP::Server::Server(Jupiter::HTTP::Server &&source) +{ + Jupiter::HTTP::Server::data_ = source.data_; + source.data_ = new Jupiter::HTTP::Server::Data(); +} + +Jupiter::HTTP::Server::~Server() +{ + delete Jupiter::HTTP::Server::data_; +} + +// Server functions + +void Jupiter::HTTP::Server::hook(const Jupiter::ReadableString &host, const Jupiter::ReadableString &name, Content *content) +{ + return Jupiter::HTTP::Server::data_->hook(host, name, content); +} + +bool Jupiter::HTTP::Server::remove(const Jupiter::ReadableString &host) +{ + return Jupiter::HTTP::Server::data_->remove(host); +} + +bool Jupiter::HTTP::Server::remove(const Jupiter::ReadableString &host, const Jupiter::ReadableString &name) +{ + return Jupiter::HTTP::Server::data_->remove(host, name); +} + +bool Jupiter::HTTP::Server::has(const Jupiter::ReadableString &host) +{ + return Jupiter::HTTP::Server::data_->has(host); +} + +bool Jupiter::HTTP::Server::has(const Jupiter::ReadableString &host, const Jupiter::ReadableString &name) +{ + return Jupiter::HTTP::Server::data_->has(host, name); +} + +Jupiter::HTTP::Server::Content *Jupiter::HTTP::Server::find(const Jupiter::ReadableString &name) +{ + return Jupiter::HTTP::Server::data_->find(name); +} + +Jupiter::HTTP::Server::Content *Jupiter::HTTP::Server::find(const Jupiter::ReadableString &host, const Jupiter::ReadableString &name) +{ + return Jupiter::HTTP::Server::data_->find(host, name); +} + +Jupiter::ReadableString *Jupiter::HTTP::Server::execute(const Jupiter::ReadableString &name, const Jupiter::ReadableString ¶meters) +{ + return Jupiter::HTTP::Server::data_->execute(name, parameters); +} + +Jupiter::ReadableString *Jupiter::HTTP::Server::execute(const Jupiter::ReadableString &host, const Jupiter::ReadableString &name, const Jupiter::ReadableString ¶meters) +{ + return Jupiter::HTTP::Server::data_->execute(host, name, parameters); +} + +bool Jupiter::HTTP::Server::bind(const Jupiter::ReadableString &hostname, uint16_t port) +{ + Jupiter::TCPSocket *socket = new Jupiter::TCPSocket(); + if (socket->bind(Jupiter::CStringS(hostname).c_str(), port, true)) + { + socket->setBlocking(false); + Jupiter::HTTP::Server::data_->ports.add(socket); + return true; + } + delete socket; + return false; +} + +bool Jupiter::HTTP::Server::tls_bind(const Jupiter::ReadableString &hostname, uint16_t port) +{ + Jupiter::SecureTCPSocket *socket = new Jupiter::SecureTCPSocket(); + if (socket->bind(Jupiter::CStringS(hostname).c_str(), port, true)) + { + Jupiter::HTTP::Server::data_->ports.add(socket); + return true; + } + delete socket; + return false; +} + +int Jupiter::HTTP::Server::think() +{ + Jupiter::Socket *socket; + HTTPSession *session; + + // Process existing clients + size_t index = Jupiter::HTTP::Server::data_->sessions.size(); + while (index != 0) + { + session = Jupiter::HTTP::Server::data_->sessions.get(--index); + std::chrono::steady_clock::now(); + if ((std::chrono::steady_clock::now() > session->last_active + Jupiter::HTTP::Server::data_->keep_alive_session_timeout) + || (session->keep_alive == false && std::chrono::steady_clock::now() > session->last_active + Jupiter::HTTP::Server::data_->session_timeout)) + delete Jupiter::HTTP::Server::data_->sessions.remove(index); + else if (session->sock.recv() > 0) + { + const Jupiter::ReadableString &sock_buffer = session->sock.getBuffer(); + if (session->request.size() + sock_buffer.size() <= Jupiter::HTTP::Server::data_->max_request_size) // accept + { + session->request += sock_buffer; + if (session->request.find(HTTP_REQUEST_ENDING) != Jupiter::INVALID_INDEX) // completed request + { + session->last_active = std::chrono::steady_clock::now(); + Jupiter::HTTP::Server::data_->process_request(*session); + if (session->keep_alive == false) // remove completed session + delete Jupiter::HTTP::Server::data_->sessions.remove(index); + } + else if (session->request.size() == Jupiter::HTTP::Server::data_->max_request_size) // reject (full buffer) + delete Jupiter::HTTP::Server::data_->sessions.remove(index); + } + else // reject + delete Jupiter::HTTP::Server::data_->sessions.remove(index); + } + else if (session->sock.getLastError() != 10035) + delete Jupiter::HTTP::Server::data_->sessions.remove(index); + } + + // Process incoming clients + index = Jupiter::HTTP::Server::data_->ports.size(); + while (index != 0) + { + socket = Jupiter::HTTP::Server::data_->ports.get(--index); + socket = socket->accept(); + if (socket != nullptr) + { + socket->setBlocking(false); + session = new HTTPSession(std::move(*socket)); + if (session->sock.recv()) // data received + { + const Jupiter::ReadableString &sock_buffer = session->sock.getBuffer(); + if (sock_buffer.size() < Jupiter::HTTP::Server::data_->max_request_size) // accept + { + session->request = session->sock.getBuffer(); + if (sock_buffer.find(HTTP_REQUEST_ENDING) != Jupiter::INVALID_INDEX) // completed request + { + Jupiter::HTTP::Server::data_->process_request(*session); + if (session->keep_alive) // session will live for 30 seconds. + Jupiter::HTTP::Server::data_->sessions.add(session); + else // session completed + delete session; + } + else // store for more processing + Jupiter::HTTP::Server::data_->sessions.add(session); + } + else if (sock_buffer.size() == Jupiter::HTTP::Server::data_->max_request_size) + { + if (sock_buffer.find(HTTP_REQUEST_ENDING) == Jupiter::INVALID_INDEX) // reject (too large) + delete session; + else // accept (max size, completed request) + { + session->request = session->sock.getBuffer(); + Jupiter::HTTP::Server::data_->process_request(*session); + if (session->keep_alive) // session will live for 30 seconds. + Jupiter::HTTP::Server::data_->sessions.add(session); + else // session completed + delete session; + } + } + else // reject (too large) + delete session; + } + } + } + return 0; +} + +const Jupiter::ReadableString &Jupiter::HTTP::Server::global_namespace = Jupiter::ReferenceString::empty; +const Jupiter::ReadableString &Jupiter::HTTP::Server::server_string = "Jupiter"_jrs; \ No newline at end of file diff --git a/Jupiter/Readable_String.h b/Jupiter/Readable_String.h index 08a6ede..669d01b 100644 --- a/Jupiter/Readable_String.h +++ b/Jupiter/Readable_String.h @@ -116,6 +116,7 @@ namespace Jupiter */ size_t span(const Readable_String &in) const; size_t span(const T *str) const; + size_t span(const T &in) const; /** * @brief Compares another string against the String. diff --git a/Jupiter/Readable_String_Imp.h b/Jupiter/Readable_String_Imp.h index a48e232..6d94896 100644 --- a/Jupiter/Readable_String_Imp.h +++ b/Jupiter/Readable_String_Imp.h @@ -180,6 +180,14 @@ template size_t Jupiter::Readable_String::span(const T *in) const return index; } +template size_t Jupiter::Readable_String::span(const T &in) const +{ + size_t index = 0; + while (index != this->size() && this->get(index) == in) + ++index; + return index; +} + // compare() template int Jupiter::Readable_String::compare(const Jupiter::Readable_String &in) const diff --git a/Release/Jupiter.lib b/Release/Jupiter.lib index 84378916453c03c2732eb49b54ffebc0232e609f..f94723ceda1d4ae94c59772d969615bfd92b2fb3 100644 GIT binary patch literal 302612 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

|pi*xZIO=7gr-&#CNx@a{Q57J-(*3Pt*W>}&( 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 K&!A)W=l=l}g3bs4 delta 41471 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