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:
eidheim 2019-07-26 09:28:20 +02:00
commit ed46b43fa7
7 changed files with 130 additions and 57 deletions

View file

@ -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:

View file

@ -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);
}

View file

@ -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));

View file

@ -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;

View file

@ -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:

View file

@ -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) {

View file

@ -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)) {