/ libi2pd / HTTP.h
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__ */