Improved comments on public functions and variables as suggested in https://github.com/openjournals/joss-reviews/issues/1592#issuecomment-514946444
This commit is contained in:
parent
5d89bbcd0f
commit
ed46b43fa7
7 changed files with 130 additions and 57 deletions
|
|
@ -15,6 +15,7 @@ namespace SimpleWeb {
|
|||
int lflf = 0;
|
||||
|
||||
public:
|
||||
/// Match condition for asio::read_until to match both standard and non-standard HTTP header endings.
|
||||
std::pair<asio::buffers_iterator<asio::const_buffers_1>, bool> operator()(asio::buffers_iterator<asio::const_buffers_1> begin, asio::buffers_iterator<asio::const_buffers_1> end) {
|
||||
auto it = begin;
|
||||
for(; it != end; ++it) {
|
||||
|
|
@ -72,7 +73,7 @@ namespace SimpleWeb {
|
|||
std::size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
/// Convenience function to return std::string. The stream buffer is consumed.
|
||||
/// Convenience function to return content as a string. The stream buffer is consumed.
|
||||
std::string string() noexcept {
|
||||
try {
|
||||
std::string str;
|
||||
|
|
@ -188,15 +189,14 @@ namespace SimpleWeb {
|
|||
};
|
||||
|
||||
public:
|
||||
/// Set before calling request
|
||||
/// Set before calling a request function.
|
||||
Config config;
|
||||
|
||||
/// If you have your own asio::io_service, store its pointer here before calling request().
|
||||
/// When using asynchronous requests, running the io_service is up to the programmer.
|
||||
/// If you want to reuse an already created asio::io_service, store its pointer here before calling a request function.
|
||||
std::shared_ptr<io_context> io_service;
|
||||
|
||||
/// Convenience function to perform synchronous request. The io_service is run within this function.
|
||||
/// If reusing the io_service for other tasks, use the asynchronous request functions instead.
|
||||
/// If you reuse the io_service for other tasks, use the asynchronous request functions instead.
|
||||
/// Do not use concurrently with the asynchronous request functions.
|
||||
/// When requesting Server-Sent Events: will throw on error::eof, please use asynchronous request functions instead.
|
||||
std::shared_ptr<Response> request(const std::string &method, const std::string &path = {"/"}, string_view content = {}, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
|
|
@ -226,7 +226,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
|
||||
/// Convenience function to perform synchronous request. The io_service is run within this function.
|
||||
/// If reusing the io_service for other tasks, use the asynchronous request functions instead.
|
||||
/// If you reuse the io_service for other tasks, use the asynchronous request functions instead.
|
||||
/// Do not use concurrently with the asynchronous request functions.
|
||||
/// When requesting Server-Sent Events: will throw on error::eof, please use asynchronous request functions instead.
|
||||
std::shared_ptr<Response> request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
|
|
@ -255,7 +255,7 @@ namespace SimpleWeb {
|
|||
return response;
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Asynchronous request where running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
/// When requesting Server-Sent Events: request_callback might be called more than twice, first call with empty contents on open, and with ec = error::eof on last call
|
||||
void request(const std::string &method, const std::string &path, string_view content, const CaseInsensitiveMultimap &header,
|
||||
|
|
@ -307,7 +307,7 @@ namespace SimpleWeb {
|
|||
connect(session);
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Asynchronous request where running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
/// When requesting Server-Sent Events: request_callback might be called more than twice, first call with empty contents on open, and with ec = error::eof on last call
|
||||
void request(const std::string &method, const std::string &path, string_view content,
|
||||
|
|
@ -315,7 +315,7 @@ namespace SimpleWeb {
|
|||
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback_));
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Asynchronous request where running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
/// When requesting Server-Sent Events: request_callback might be called more than twice, first call with empty contents on open, and with ec = error::eof on last call
|
||||
void request(const std::string &method, const std::string &path,
|
||||
|
|
@ -323,14 +323,14 @@ namespace SimpleWeb {
|
|||
request(method, path, std::string(), CaseInsensitiveMultimap(), std::move(request_callback_));
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Asynchronous request where running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
/// When requesting Server-Sent Events: request_callback might be called more than twice, first call with empty contents on open, and with ec = error::eof on last call
|
||||
void request(const std::string &method, std::function<void(std::shared_ptr<Response>, const error_code &)> &&request_callback_) {
|
||||
request(method, std::string("/"), std::string(), CaseInsensitiveMultimap(), std::move(request_callback_));
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Asynchronous request where running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
/// When requesting Server-Sent Events: request_callback might be called more than twice, first call with empty contents on open, and with ec = error::eof on last call
|
||||
void request(const std::string &method, const std::string &path, std::istream &content, const CaseInsensitiveMultimap &header,
|
||||
|
|
@ -386,7 +386,7 @@ namespace SimpleWeb {
|
|||
connect(session);
|
||||
}
|
||||
|
||||
/// Asynchronous request where setting and/or running Client's io_service is required.
|
||||
/// Asynchronous request where running Client's io_service is required.
|
||||
/// Do not use concurrently with the synchronous request functions.
|
||||
/// When requesting Server-Sent Events: request_callback might be called more than twice, first call with empty contents on open, and with ec = error::eof on last call
|
||||
void request(const std::string &method, const std::string &path, std::istream &content,
|
||||
|
|
@ -394,7 +394,7 @@ namespace SimpleWeb {
|
|||
request(method, path, content, CaseInsensitiveMultimap(), std::move(request_callback_));
|
||||
}
|
||||
|
||||
/// Close connections
|
||||
/// Close connections.
|
||||
void stop() noexcept {
|
||||
LockGuard lock(connections_mutex);
|
||||
for(auto it = connections.begin(); it != connections.end();) {
|
||||
|
|
@ -755,6 +755,11 @@ namespace SimpleWeb {
|
|||
template <>
|
||||
class Client<HTTP> : public ClientBase<HTTP> {
|
||||
public:
|
||||
/**
|
||||
* Constructs a client object.
|
||||
*
|
||||
* @param server_port_path Server resource given by host[:port][/path]
|
||||
*/
|
||||
Client(const std::string &server_port_path) noexcept : ClientBase<HTTP>::ClientBase(server_port_path, 80) {}
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -15,11 +15,20 @@ namespace SimpleWeb {
|
|||
template <>
|
||||
class Client<HTTPS> : public ClientBase<HTTPS> {
|
||||
public:
|
||||
Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &cert_file = std::string(),
|
||||
/**
|
||||
* Constructs a client object.
|
||||
*
|
||||
* @param server_port_path Server resource given by host[:port][/path]
|
||||
* @param verify_certificate Set to true (default) to verify the server's certificate and hostname according to RFC 2818.
|
||||
* @param certification_file If non-empty, sends the given certification file to server. Requires private_key_file.
|
||||
* @param private_key_file If non-empty, specifies the file containing the private key for certification_file. Requires certification_file.
|
||||
* @param verify_file If non-empty, use this certificate authority file to perform verification.
|
||||
*/
|
||||
Client(const std::string &server_port_path, bool verify_certificate = true, const std::string &certification_file = std::string(),
|
||||
const std::string &private_key_file = std::string(), const std::string &verify_file = std::string())
|
||||
: ClientBase<HTTPS>::ClientBase(server_port_path, 443), context(asio::ssl::context::tlsv12) {
|
||||
if(cert_file.size() > 0 && private_key_file.size() > 0) {
|
||||
context.use_certificate_chain_file(cert_file);
|
||||
if(certification_file.size() > 0 && private_key_file.size() > 0) {
|
||||
context.use_certificate_chain_file(certification_file);
|
||||
context.use_private_key_file(private_key_file, asio::ssl::context::pem);
|
||||
}
|
||||
|
||||
|
|
|
|||
32
crypto.hpp
32
crypto.hpp
|
|
@ -27,7 +27,8 @@ namespace SimpleWeb {
|
|||
public:
|
||||
class Base64 {
|
||||
public:
|
||||
static std::string encode(const std::string &ascii) noexcept {
|
||||
/// Returns Base64 encoded string from input string.
|
||||
static std::string encode(const std::string &input) noexcept {
|
||||
std::string base64;
|
||||
|
||||
BIO *bio, *b64;
|
||||
|
|
@ -40,13 +41,13 @@ namespace SimpleWeb {
|
|||
BIO_set_mem_buf(b64, bptr, BIO_CLOSE);
|
||||
|
||||
// Write directly to base64-buffer to avoid copy
|
||||
auto base64_length = static_cast<std::size_t>(round(4 * ceil(static_cast<double>(ascii.size()) / 3.0)));
|
||||
auto base64_length = static_cast<std::size_t>(round(4 * ceil(static_cast<double>(input.size()) / 3.0)));
|
||||
base64.resize(base64_length);
|
||||
bptr->length = 0;
|
||||
bptr->max = base64_length + 1;
|
||||
bptr->data = &base64[0];
|
||||
|
||||
if(BIO_write(b64, &ascii[0], static_cast<int>(ascii.size())) <= 0 || BIO_flush(b64) <= 0)
|
||||
if(BIO_write(b64, &input[0], static_cast<int>(input.size())) <= 0 || BIO_flush(b64) <= 0)
|
||||
base64.clear();
|
||||
|
||||
// To keep &base64[0] through BIO_free_all(b64)
|
||||
|
|
@ -59,6 +60,7 @@ namespace SimpleWeb {
|
|||
return base64;
|
||||
}
|
||||
|
||||
/// Returns Base64 decoded string from base64 input.
|
||||
static std::string decode(const std::string &base64) noexcept {
|
||||
std::string ascii;
|
||||
|
||||
|
|
@ -88,7 +90,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
};
|
||||
|
||||
/// Return hex string from bytes in input string.
|
||||
/// Returns hex string from bytes in input string.
|
||||
static std::string to_hex_string(const std::string &input) noexcept {
|
||||
std::stringstream hex_stream;
|
||||
hex_stream << std::hex << std::internal << std::setfill('0');
|
||||
|
|
@ -97,6 +99,7 @@ namespace SimpleWeb {
|
|||
return hex_stream.str();
|
||||
}
|
||||
|
||||
/// Returns md5 hash value from input string.
|
||||
static std::string md5(const std::string &input, std::size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
|
|
@ -109,6 +112,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns md5 hash value from input stream.
|
||||
static std::string md5(std::istream &stream, std::size_t iterations = 1) noexcept {
|
||||
MD5_CTX context;
|
||||
MD5_Init(&context);
|
||||
|
|
@ -126,6 +130,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns sha1 hash value from input string.
|
||||
static std::string sha1(const std::string &input, std::size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
|
|
@ -138,6 +143,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns sha1 hash value from input stream.
|
||||
static std::string sha1(std::istream &stream, std::size_t iterations = 1) noexcept {
|
||||
SHA_CTX context;
|
||||
SHA1_Init(&context);
|
||||
|
|
@ -155,6 +161,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns sha256 hash value from input string.
|
||||
static std::string sha256(const std::string &input, std::size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
|
|
@ -167,6 +174,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns sha256 hash value from input stream.
|
||||
static std::string sha256(std::istream &stream, std::size_t iterations = 1) noexcept {
|
||||
SHA256_CTX context;
|
||||
SHA256_Init(&context);
|
||||
|
|
@ -184,6 +192,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns sha512 hash value from input string.
|
||||
static std::string sha512(const std::string &input, std::size_t iterations = 1) noexcept {
|
||||
std::string hash;
|
||||
|
||||
|
|
@ -196,6 +205,7 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// Returns sha512 hash value from input stream.
|
||||
static std::string sha512(std::istream &stream, std::size_t iterations = 1) noexcept {
|
||||
SHA512_CTX context;
|
||||
SHA512_Init(&context);
|
||||
|
|
@ -213,7 +223,19 @@ namespace SimpleWeb {
|
|||
return hash;
|
||||
}
|
||||
|
||||
/// key_size is number of bytes of the returned key.
|
||||
/// Returns PBKDF2 hash value from the given password
|
||||
/// Input parameter key_size number of bytes of the returned key.
|
||||
|
||||
/**
|
||||
* Returns PBKDF2 derived key from the given password.
|
||||
*
|
||||
* @param password The password to derive key from.
|
||||
* @param salt The salt to be used in the algorithm.
|
||||
* @param iterations Number of iterations to be used in the algorithm.
|
||||
* @param key_size Number of bytes of the returned key.
|
||||
*
|
||||
* @return The PBKDF2 derived key.
|
||||
*/
|
||||
static std::string pbkdf2(const std::string &password, const std::string &salt, int iterations, int key_size) noexcept {
|
||||
std::string key;
|
||||
key.resize(static_cast<std::size_t>(key_size));
|
||||
|
|
|
|||
|
|
@ -69,7 +69,7 @@
|
|||
THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
|
||||
|
||||
namespace SimpleWeb {
|
||||
/// Defines an annotated interface for mutexes.
|
||||
/// Mutex class that is annotated for Clang Thread Safety Analysis.
|
||||
class CAPABILITY("mutex") Mutex {
|
||||
std::mutex mutex;
|
||||
|
||||
|
|
@ -83,6 +83,7 @@ namespace SimpleWeb {
|
|||
}
|
||||
};
|
||||
|
||||
/// Scoped mutex guard class that is annotated for Clang Thread Safety Analysis.
|
||||
class SCOPED_CAPABILITY LockGuard {
|
||||
Mutex &mutex;
|
||||
bool locked = true;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ namespace SimpleWeb {
|
|||
class Session;
|
||||
|
||||
public:
|
||||
/// Response class where the content of the response is sent to client when the object is about to be destroyed.
|
||||
class Response : public std::enable_shared_from_this<Response>, public std::ostream {
|
||||
friend class ServerBase<socket_type>;
|
||||
friend class Server<socket_type>;
|
||||
|
|
@ -124,7 +125,9 @@ namespace SimpleWeb {
|
|||
return streambuf->size();
|
||||
}
|
||||
|
||||
/// Use this function if you need to recursively send parts of a longer message, or when using server-sent events (SSE).
|
||||
/// Send the content of the response stream to client. The callback is called when the send has completed.
|
||||
///
|
||||
/// Use this function if you need to recursively send parts of a longer message, or when using server-sent events.
|
||||
void send(const std::function<void(const error_code &)> &callback = nullptr) noexcept {
|
||||
session->connection->set_timeout(timeout_content);
|
||||
|
||||
|
|
@ -138,18 +141,18 @@ namespace SimpleWeb {
|
|||
send_from_queue();
|
||||
}
|
||||
|
||||
/// Write directly to stream buffer using std::ostream::write
|
||||
/// Write directly to stream buffer using std::ostream::write.
|
||||
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
|
||||
/// 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
|
||||
/// Convenience function for writing status line, header fields, and content.
|
||||
void write(StatusCode status_code, string_view content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
write_header(header, content.size());
|
||||
|
|
@ -157,7 +160,7 @@ namespace SimpleWeb {
|
|||
*this << content;
|
||||
}
|
||||
|
||||
/// Convenience function for writing status line, header fields, and content
|
||||
/// Convenience function for writing status line, header fields, and content.
|
||||
void write(StatusCode status_code, std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
*this << "HTTP/1.1 " << SimpleWeb::status_code(status_code) << "\r\n";
|
||||
content.seekg(0, std::ios::end);
|
||||
|
|
@ -168,22 +171,22 @@ namespace SimpleWeb {
|
|||
*this << content.rdbuf();
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, header fields, and content
|
||||
/// Convenience function for writing success status line, header fields, and content.
|
||||
void write(string_view content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
write(StatusCode::success_ok, content, header);
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, header fields, and content
|
||||
/// Convenience function for writing success status line, header fields, and content.
|
||||
void write(std::istream &content, const CaseInsensitiveMultimap &header = CaseInsensitiveMultimap()) {
|
||||
write(StatusCode::success_ok, content, header);
|
||||
}
|
||||
|
||||
/// Convenience function for writing success status line, and header fields
|
||||
/// Convenience function for writing success status line, and header fields.
|
||||
void write(const CaseInsensitiveMultimap &header) {
|
||||
write(StatusCode::success_ok, std::string(), header);
|
||||
}
|
||||
|
||||
/// If true, force server to close the connection after the response have been sent.
|
||||
/// If set to true, force server to close the connection after the response have been sent.
|
||||
///
|
||||
/// This is useful when implementing a HTTP/1.0-server sending content
|
||||
/// without specifying the content length.
|
||||
|
|
@ -197,7 +200,7 @@ namespace SimpleWeb {
|
|||
std::size_t size() noexcept {
|
||||
return streambuf.size();
|
||||
}
|
||||
/// Convenience function to return std::string. The stream buffer is consumed.
|
||||
/// Convenience function to return content as std::string. The stream buffer is consumed.
|
||||
std::string string() noexcept {
|
||||
try {
|
||||
std::string str;
|
||||
|
|
@ -233,6 +236,7 @@ namespace SimpleWeb {
|
|||
|
||||
CaseInsensitiveMultimap header;
|
||||
|
||||
/// The result of the resource regular expression match of the request path.
|
||||
regex::smatch path_match;
|
||||
|
||||
std::shared_ptr<asio::ip::tcp::endpoint> remote_endpoint;
|
||||
|
|
@ -363,16 +367,20 @@ namespace SimpleWeb {
|
|||
};
|
||||
|
||||
public:
|
||||
/// Use this container to add resources for specific request paths depending on the given regex and method.
|
||||
/// Warning: do not add or remove resources after start() is called
|
||||
std::map<regex_orderable, std::map<std::string, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)>>> resource;
|
||||
|
||||
/// If the request path does not match a resource regex, this function is called.
|
||||
std::map<std::string, std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Response>, std::shared_ptr<typename ServerBase<socket_type>::Request>)>> default_resource;
|
||||
|
||||
/// Called when an error occurs.
|
||||
std::function<void(std::shared_ptr<typename ServerBase<socket_type>::Request>, const error_code &)> on_error;
|
||||
|
||||
/// Called on upgrade requests.
|
||||
std::function<void(std::unique_ptr<socket_type> &, std::shared_ptr<typename ServerBase<socket_type>::Request>)> on_upgrade;
|
||||
|
||||
/// If you have your own asio::io_service, store its pointer here before running start().
|
||||
/// If you want to reuse an already created asio::io_service, store its pointer here before calling start().
|
||||
std::shared_ptr<io_context> io_service;
|
||||
|
||||
/// If you know the server port in advance, use start() instead.
|
||||
|
|
@ -762,6 +770,7 @@ namespace SimpleWeb {
|
|||
template <>
|
||||
class Server<HTTP> : public ServerBase<HTTP> {
|
||||
public:
|
||||
/// Constructs a server object.
|
||||
Server() noexcept : ServerBase<HTTP>::ServerBase(80) {}
|
||||
|
||||
protected:
|
||||
|
|
|
|||
|
|
@ -20,9 +20,16 @@ namespace SimpleWeb {
|
|||
bool set_session_id_context = false;
|
||||
|
||||
public:
|
||||
Server(const std::string &cert_file, const std::string &private_key_file, const std::string &verify_file = std::string())
|
||||
/**
|
||||
* Constructs a server object.
|
||||
*
|
||||
* @param certification_file If non-empty, sends the given certification file to client.
|
||||
* @param private_key_file Specifies the file containing the private key for certification_file.
|
||||
* @param verify_file If non-empty, use this certificate authority file to perform verification of client's certificate and hostname according to RFC 2818.
|
||||
*/
|
||||
Server(const std::string &certification_file, const std::string &private_key_file, const std::string &verify_file = std::string())
|
||||
: ServerBase<HTTPS>::ServerBase(443), context(asio::ssl::context::tlsv12) {
|
||||
context.use_certificate_chain_file(cert_file);
|
||||
context.use_certificate_chain_file(certification_file);
|
||||
context.use_private_key_file(private_key_file, asio::ssl::context::pem);
|
||||
|
||||
if(verify_file.size() > 0) {
|
||||
|
|
|
|||
64
utility.hpp
64
utility.hpp
|
|
@ -151,7 +151,7 @@ namespace SimpleWeb {
|
|||
|
||||
class HttpHeader {
|
||||
public:
|
||||
/// Parse header fields
|
||||
/// Parse header fields from stream
|
||||
static CaseInsensitiveMultimap parse(std::istream &stream) noexcept {
|
||||
CaseInsensitiveMultimap result;
|
||||
std::string line;
|
||||
|
|
@ -170,36 +170,37 @@ namespace SimpleWeb {
|
|||
public:
|
||||
class SemicolonSeparatedAttributes {
|
||||
public:
|
||||
/// Parse Set-Cookie or Content-Disposition header field value. Attribute values are percent-decoded.
|
||||
static CaseInsensitiveMultimap parse(const std::string &str) {
|
||||
/// Parse Set-Cookie or Content-Disposition from given header field value.
|
||||
/// Attribute values are percent-decoded.
|
||||
static CaseInsensitiveMultimap parse(const std::string &value) {
|
||||
CaseInsensitiveMultimap result;
|
||||
|
||||
std::size_t name_start_pos = std::string::npos;
|
||||
std::size_t name_end_pos = std::string::npos;
|
||||
std::size_t value_start_pos = std::string::npos;
|
||||
for(std::size_t c = 0; c < str.size(); ++c) {
|
||||
for(std::size_t c = 0; c < value.size(); ++c) {
|
||||
if(name_start_pos == std::string::npos) {
|
||||
if(str[c] != ' ' && str[c] != ';')
|
||||
if(value[c] != ' ' && value[c] != ';')
|
||||
name_start_pos = c;
|
||||
}
|
||||
else {
|
||||
if(name_end_pos == std::string::npos) {
|
||||
if(str[c] == ';') {
|
||||
result.emplace(str.substr(name_start_pos, c - name_start_pos), std::string());
|
||||
if(value[c] == ';') {
|
||||
result.emplace(value.substr(name_start_pos, c - name_start_pos), std::string());
|
||||
name_start_pos = std::string::npos;
|
||||
}
|
||||
else if(str[c] == '=')
|
||||
else if(value[c] == '=')
|
||||
name_end_pos = c;
|
||||
}
|
||||
else {
|
||||
if(value_start_pos == std::string::npos) {
|
||||
if(str[c] == '"' && c + 1 < str.size())
|
||||
if(value[c] == '"' && c + 1 < value.size())
|
||||
value_start_pos = c + 1;
|
||||
else
|
||||
value_start_pos = c;
|
||||
}
|
||||
else if(str[c] == '"' || str[c] == ';') {
|
||||
result.emplace(str.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(str.substr(value_start_pos, c - value_start_pos)));
|
||||
else if(value[c] == '"' || value[c] == ';') {
|
||||
result.emplace(value.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(value.substr(value_start_pos, c - value_start_pos)));
|
||||
name_start_pos = std::string::npos;
|
||||
name_end_pos = std::string::npos;
|
||||
value_start_pos = std::string::npos;
|
||||
|
|
@ -209,12 +210,12 @@ namespace SimpleWeb {
|
|||
}
|
||||
if(name_start_pos != std::string::npos) {
|
||||
if(name_end_pos == std::string::npos)
|
||||
result.emplace(str.substr(name_start_pos), std::string());
|
||||
result.emplace(value.substr(name_start_pos), std::string());
|
||||
else if(value_start_pos != std::string::npos) {
|
||||
if(str.back() == '"')
|
||||
result.emplace(str.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(str.substr(value_start_pos, str.size() - 1)));
|
||||
if(value.back() == '"')
|
||||
result.emplace(value.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(value.substr(value_start_pos, value.size() - 1)));
|
||||
else
|
||||
result.emplace(str.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(str.substr(value_start_pos)));
|
||||
result.emplace(value.substr(name_start_pos, name_end_pos - name_start_pos), Percent::decode(value.substr(value_start_pos)));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -222,11 +223,21 @@ namespace SimpleWeb {
|
|||
}
|
||||
};
|
||||
};
|
||||
}; // namespace SimpleWeb
|
||||
};
|
||||
|
||||
class RequestMessage {
|
||||
public:
|
||||
/// Parse request line and header fields
|
||||
/** Parse request line and header fields from a request stream.
|
||||
*
|
||||
* @param[in] stream Stream to parse.
|
||||
* @param[out] method HTTP method.
|
||||
* @param[out] path Path from request URI.
|
||||
* @param[out] query_string Query string from request URI.
|
||||
* @param[out] version HTTP version.
|
||||
* @param[out] header Header fields.
|
||||
*
|
||||
* @return True if stream is parsed successfully, false if not.
|
||||
*/
|
||||
static bool parse(std::istream &stream, std::string &method, std::string &path, std::string &query_string, std::string &version, CaseInsensitiveMultimap &header) noexcept {
|
||||
std::string line;
|
||||
std::size_t method_end;
|
||||
|
|
@ -273,7 +284,15 @@ namespace SimpleWeb {
|
|||
|
||||
class ResponseMessage {
|
||||
public:
|
||||
/// Parse status line and header fields
|
||||
/** Parse status line and header fields from a response stream.
|
||||
*
|
||||
* @param[in] stream Stream to parse.
|
||||
* @param[out] version HTTP version.
|
||||
* @param[out] status_code HTTP status code.
|
||||
* @param[out] header Header fields.
|
||||
*
|
||||
* @return True if stream is parsed successfully, false if not.
|
||||
*/
|
||||
static bool parse(std::istream &stream, std::string &version, std::string &status_code, CaseInsensitiveMultimap &header) noexcept {
|
||||
std::string line;
|
||||
std::size_t version_end;
|
||||
|
|
@ -314,9 +333,9 @@ namespace SimpleWeb {
|
|||
#endif
|
||||
|
||||
namespace SimpleWeb {
|
||||
/// Makes it possible to for instance cancel Asio handlers without stopping asio::io_service
|
||||
/// Makes it possible to for instance cancel Asio handlers without stopping asio::io_service.
|
||||
class ScopeRunner {
|
||||
/// Scope count that is set to -1 if scopes are to be canceled
|
||||
/// Scope count that is set to -1 if scopes are to be canceled.
|
||||
std::atomic<long> count;
|
||||
|
||||
public:
|
||||
|
|
@ -335,7 +354,8 @@ namespace SimpleWeb {
|
|||
|
||||
ScopeRunner() noexcept : count(0) {}
|
||||
|
||||
/// Returns nullptr if scope should be exited, or a shared lock otherwise
|
||||
/// Returns nullptr if scope should be exited, or a shared lock otherwise.
|
||||
/// The shared lock ensures that a potential destructor call is delayed until all locks are released.
|
||||
std::unique_ptr<SharedLock> continue_lock() noexcept {
|
||||
long expected = count;
|
||||
while(expected >= 0 && !count.compare_exchange_weak(expected, expected + 1))
|
||||
|
|
@ -347,7 +367,7 @@ namespace SimpleWeb {
|
|||
return std::unique_ptr<SharedLock>(new SharedLock(count));
|
||||
}
|
||||
|
||||
/// Blocks until all shared locks are released, then prevents future shared locks
|
||||
/// Blocks until all shared locks are released, then prevents future shared locks.
|
||||
void stop() noexcept {
|
||||
long expected = 0;
|
||||
while(!count.compare_exchange_weak(expected, -1)) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue