HTTP.h
1 /* 2 * Copyright (c) 2013-2026, The PurpleI2P Project 3 * 4 * This file is part of Purple i2pd project and licensed under BSD3 5 * 6 * See full license text in LICENSE file at top of project tree 7 */ 8 9 #ifndef HTTP_H__ 10 #define HTTP_H__ 11 12 #include <cstring> 13 #include <map> 14 #include <list> 15 #include <sstream> 16 #include <string> 17 #include <string_view> 18 #include <vector> 19 20 namespace i2p 21 { 22 namespace http 23 { 24 constexpr std::string_view CRLF = "\r\n"; /**< HTTP line terminator */ 25 constexpr std::string_view HTTP_EOH = "\r\n\r\n"; /**< HTTP end-of-headers mark */ 26 27 struct URL 28 { 29 std::string schema; 30 std::string user; 31 std::string pass; 32 std::string host; 33 unsigned short int port; 34 std::string path; 35 bool hasquery; 36 std::string query; 37 std::string frag; 38 bool ipv6; 39 40 URL(): schema(""), user(""), pass(""), host(""), port(0), path(""), hasquery(false), query(""), frag(""), ipv6(false) {}; 41 42 /** 43 * @brief Tries to parse url from string 44 * @return true on success, false on invalid url 45 */ 46 bool parse (const char *str, std::size_t len = 0); 47 bool parse (std::string_view url); 48 49 /** 50 * @brief Parse query part of url to key/value map 51 * @note Honestly, this should be implemented with std::multimap 52 */ 53 bool parse_query(std::map<std::string, std::string> & params); 54 55 /** 56 * @brief Serialize URL structure to url 57 * @note Returns relative url if schema if empty, absolute url otherwise 58 */ 59 std::string to_string (); 60 61 /** 62 * @brief return true if the host is inside i2p 63 */ 64 bool is_i2p() const; 65 }; 66 67 struct HTTPMsg 68 { 69 std::map<std::string, std::string> headers; 70 71 void add_header(const char *name, const std::string & value, bool replace = false); 72 void add_header(const char *name, const char *value, bool replace = false); 73 void del_header(const char *name); 74 std::string get_header(const std::string& name) const; 75 76 /** @brief Returns declared message length or -1 if unknown */ 77 long int content_length() const; 78 }; 79 80 struct HTTPReq 81 { 82 std::list<std::pair<std::string, std::string> > headers; 83 std::string version; 84 std::string method; 85 std::string uri; 86 87 HTTPReq (): version("HTTP/1.0"), method("GET"), uri("/") {}; 88 89 /** 90 * @brief Tries to parse HTTP request from string 91 * @return -1 on error, 0 on incomplete query, >0 on success 92 * @note Positive return value is a size of header 93 */ 94 int parse(const char *buf, size_t len); 95 int parse(std::string_view buf); 96 97 /** @brief Serialize HTTP request to string */ 98 std::string to_string(); 99 void write(std::ostream & o); 100 101 void AddHeader (const std::string& name, const std::string& value); 102 void UpdateHeader (const std::string& name, const std::string& value); 103 void RemoveHeader (const std::string& name, const std::string& exempt); // remove all headers starting with name, but exempt 104 void RemoveHeader (const std::string& name) { RemoveHeader (name, ""); }; 105 std::string GetHeader (std::string_view name) const; 106 size_t GetNumHeaders (std::string_view name) const; 107 size_t GetNumHeaders () const { return headers.size (); }; 108 }; 109 110 struct HTTPRes : HTTPMsg { 111 std::string version; 112 std::string status; 113 unsigned short int code; 114 /** 115 * @brief Simplifies response generation 116 * 117 * If this variable is set, on @a to_string() call: 118 * * Content-Length header will be added if missing, 119 * * contents of @a body will be included in generated response 120 */ 121 std::string body; 122 123 HTTPRes (): version("HTTP/1.1"), status("OK"), code(200) {} 124 125 /** 126 * @brief Tries to parse HTTP response from string 127 * @return -1 on error, 0 on incomplete query, >0 on success 128 * @note Positive return value is a size of header 129 */ 130 int parse(const char *buf, size_t len); 131 int parse(const std::string_view buf); 132 133 /** 134 * @brief Serialize HTTP response to string 135 * @note If @a version is set to HTTP/1.1, and Date header is missing, 136 * it will be generated based on current time and added to headers 137 * @note If @a body is set and Content-Length header is missing, 138 * this header will be added, based on body's length 139 */ 140 std::string to_string(); 141 142 void write(std::ostream & o); 143 144 /** @brief Checks that response declared as chunked data */ 145 bool is_chunked() const ; 146 147 /** @brief Checks that response contains compressed data */ 148 bool is_gzipped(bool includingI2PGzip = true) const; 149 }; 150 151 /** 152 * @brief returns HTTP status string by integer code 153 * @param code HTTP code [100, 599] 154 * @return Immutable string with status 155 */ 156 std::string_view HTTPCodeToStatus(int code); 157 158 /** 159 * @brief Replaces %-encoded characters in string with their values 160 * @param data Source string 161 * @param null If set to true - decode also %00 sequence, otherwise - skip 162 * @return Decoded string 163 */ 164 std::string UrlDecode(std::string_view url, bool null = false); 165 166 /** 167 * @brief Merge HTTP response content with Transfer-Encoding: chunked 168 * @param in Input stream 169 * @param out Output stream 170 * @return true on success, false otherwise 171 */ 172 bool MergeChunkedResponse (std::istream& in, std::ostream& out); 173 174 std::string CreateBasicAuthorizationString (const std::string& user, const std::string& pass); 175 176 } // http 177 } // i2p 178 179 #endif /* HTTP_H__ */