mirror of https://github.com/PurpleI2P/i2pd.git
I2P: End-to-End encrypted and anonymous Internet
https://i2pd.website/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
180 lines
5.2 KiB
180 lines
5.2 KiB
/* |
|
* Copyright (c) 2013-2024, The PurpleI2P Project |
|
* |
|
* This file is part of Purple i2pd project and licensed under BSD3 |
|
* |
|
* See full license text in LICENSE file at top of project tree |
|
*/ |
|
|
|
#ifndef HTTP_H__ |
|
#define HTTP_H__ |
|
|
|
#include <cstring> |
|
#include <map> |
|
#include <list> |
|
#include <sstream> |
|
#include <string> |
|
#include <string_view> |
|
#include <vector> |
|
|
|
namespace i2p |
|
{ |
|
namespace http |
|
{ |
|
const char CRLF[] = "\r\n"; /**< HTTP line terminator */ |
|
const char HTTP_EOH[] = "\r\n\r\n"; /**< HTTP end-of-headers mark */ |
|
extern const std::vector<std::string> HTTP_METHODS; /**< list of valid HTTP methods */ |
|
extern const std::vector<std::string> HTTP_VERSIONS; /**< list of valid HTTP versions */ |
|
|
|
struct URL |
|
{ |
|
std::string schema; |
|
std::string user; |
|
std::string pass; |
|
std::string host; |
|
unsigned short int port; |
|
std::string path; |
|
bool hasquery; |
|
std::string query; |
|
std::string frag; |
|
bool ipv6; |
|
|
|
URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag(""), ipv6(false) {}; |
|
|
|
/** |
|
* @brief Tries to parse url from string |
|
* @return true on success, false on invalid url |
|
*/ |
|
bool parse (const char *str, std::size_t len = 0); |
|
bool parse (std::string_view url); |
|
|
|
/** |
|
* @brief Parse query part of url to key/value map |
|
* @note Honestly, this should be implemented with std::multimap |
|
*/ |
|
bool parse_query(std::map<std::string, std::string> & params); |
|
|
|
/** |
|
* @brief Serialize URL structure to url |
|
* @note Returns relative url if schema if empty, absolute url otherwise |
|
*/ |
|
std::string to_string (); |
|
|
|
/** |
|
* @brief return true if the host is inside i2p |
|
*/ |
|
bool is_i2p() const; |
|
}; |
|
|
|
struct HTTPMsg |
|
{ |
|
std::map<std::string, std::string> headers; |
|
|
|
void add_header(const char *name, std::string & value, bool replace = false); |
|
void add_header(const char *name, const char *value, bool replace = false); |
|
void del_header(const char *name); |
|
|
|
/** @brief Returns declared message length or -1 if unknown */ |
|
long int content_length() const; |
|
}; |
|
|
|
struct HTTPReq |
|
{ |
|
std::list<std::pair<std::string, std::string> > headers; |
|
std::string version; |
|
std::string method; |
|
std::string uri; |
|
|
|
HTTPReq (): version("HTTP/1.0"), method("GET"), uri("/") {}; |
|
|
|
/** |
|
* @brief Tries to parse HTTP request from string |
|
* @return -1 on error, 0 on incomplete query, >0 on success |
|
* @note Positive return value is a size of header |
|
*/ |
|
int parse(const char *buf, size_t len); |
|
int parse(std::string_view buf); |
|
|
|
/** @brief Serialize HTTP request to string */ |
|
std::string to_string(); |
|
void write(std::ostream & o); |
|
|
|
void AddHeader (const std::string& name, const std::string& value); |
|
void UpdateHeader (const std::string& name, const std::string& value); |
|
void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt |
|
void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); }; |
|
std::string GetHeader (const std::string& name) const; |
|
size_t GetNumHeaders (const std::string& name) const; |
|
size_t GetNumHeaders () const { return headers.size (); }; |
|
}; |
|
|
|
struct HTTPRes : HTTPMsg { |
|
std::string version; |
|
std::string status; |
|
unsigned short int code; |
|
/** |
|
* @brief Simplifies response generation |
|
* |
|
* If this variable is set, on @a to_string() call: |
|
* * Content-Length header will be added if missing, |
|
* * contents of @a body will be included in generated response |
|
*/ |
|
std::string body; |
|
|
|
HTTPRes (): version("HTTP/1.1"), status("OK"), code(200) {} |
|
|
|
/** |
|
* @brief Tries to parse HTTP response from string |
|
* @return -1 on error, 0 on incomplete query, >0 on success |
|
* @note Positive return value is a size of header |
|
*/ |
|
int parse(const char *buf, size_t len); |
|
int parse(const std::string_view buf); |
|
|
|
/** |
|
* @brief Serialize HTTP response to string |
|
* @note If @a version is set to HTTP/1.1, and Date header is missing, |
|
* it will be generated based on current time and added to headers |
|
* @note If @a body is set and Content-Length header is missing, |
|
* this header will be added, based on body's length |
|
*/ |
|
std::string to_string(); |
|
|
|
void write(std::ostream & o); |
|
|
|
/** @brief Checks that response declared as chunked data */ |
|
bool is_chunked() const ; |
|
|
|
/** @brief Checks that response contains compressed data */ |
|
bool is_gzipped(bool includingI2PGzip = true) const; |
|
}; |
|
|
|
/** |
|
* @brief returns HTTP status string by integer code |
|
* @param code HTTP code [100, 599] |
|
* @return Immutable string with status |
|
*/ |
|
const char * HTTPCodeToStatus(int code); |
|
|
|
/** |
|
* @brief Replaces %-encoded characters in string with their values |
|
* @param data Source string |
|
* @param null If set to true - decode also %00 sequence, otherwise - skip |
|
* @return Decoded string |
|
*/ |
|
std::string UrlDecode(std::string_view data, bool null = false); |
|
|
|
/** |
|
* @brief Merge HTTP response content with Transfer-Encoding: chunked |
|
* @param in Input stream |
|
* @param out Output stream |
|
* @return true on success, false otherwise |
|
*/ |
|
bool MergeChunkedResponse (std::istream& in, std::ostream& out); |
|
|
|
std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass); |
|
|
|
} // http |
|
} // i2p |
|
|
|
#endif /* HTTP_H__ */
|
|
|