File: HTTP.h

package info (click to toggle)
i2pd 2.58.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 3,612 kB
  • sloc: cpp: 59,663; makefile: 224; sh: 138
file content (178 lines) | stat: -rw-r--r-- 5,149 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
* Copyright (c) 2013-2025, 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
{
	constexpr std::string_view CRLF = "\r\n";         /**< HTTP line terminator */
	constexpr std::string_view HTTP_EOH = "\r\n\r\n"; /**< HTTP end-of-headers mark */

	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, const 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 (std::string_view name) const;
		size_t GetNumHeaders (std::string_view 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
	 */
	std::string_view 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__ */