userver: userver/http/url.hpp Source File
Loading...
Searching...
No Matches
url.hpp
Go to the documentation of this file.
1#pragma once
2
3/// @file userver/http/url.hpp
4/// @brief URL manipulation functions
5/// @ingroup userver_universal
6
7#include <map>
8#include <optional>
9#include <string>
10#include <string_view>
11#include <unordered_map>
12#include <vector>
13
14#include <userver/utils/impl/internal_tag_fwd.hpp>
15#include <userver/utils/str_icase.hpp>
16
17USERVER_NAMESPACE_BEGIN
18
19namespace http {
20
22 std::string_view scheme;
23 std::string_view host;
24 std::string_view path;
25 std::string_view query;
26 std::string_view fragment;
27};
28
29/// @brief Decode URL
30[[deprecated("Use a more strict http::parser::UrlDecode instead")]] std::string UrlDecode(std::string_view range);
31
32/// @brief Encode as URL
33/// @param input_string String to encode
34/// @returns URL-encoded string where special characters are encoded as %XX sequences
35/// @code
36/// auto encoded = UrlEncode("hello world");
37/// // Returns: "hello%20world"
38/// @endcode
39std::string UrlEncode(std::string_view input_string);
40
41/// @brief Encode a URL path segment (for use in S3 and similar APIs)
42/// @param input_string String to encode
43/// @returns URL-encoded string where special characters are encoded as %XX sequences,
44/// but path-safe characters (-, _, ., ~, $, &, ,, :, =, @) are kept unescaped
45/// @note This is less aggressive than UrlEncode and is suitable for encoding path segments
46/// where you want to preserve readability of certain special characters
47/// @code
48/// auto encoded = UrlEncodePathSegment("file-name_with spaces.txt");
49/// // Returns: "file-name_with%20spaces.txt"
50/// @endcode
51std::string UrlEncodePathSegment(std::string_view input_string);
52
53/// @brief Encode an S3 object key for use in URL path
54/// @param key S3 object key (may contain '/' as part of the key name)
55/// @returns URL-encoded path where each segment is encoded but '/' separators are preserved
56/// @note S3 object keys can contain '/' which should be preserved as path separators,
57/// while other special characters should be encoded
58/// @code
59/// auto encoded = EncodeS3Key("folder/file with spaces.txt");
60/// // Returns: "folder/file%20with%20spaces.txt"
61/// @endcode
62std::string EncodeS3Key(std::string_view key);
63
64using Args = std::unordered_map<std::string, std::string, utils::StrCaseHash>;
65using MultiArgs = std::multimap<std::string, std::string>;
66using PathArgs = std::unordered_map<std::string, std::string>;
67
68/// @brief Make an URL query
69/// @param query_args Map of query parameters
70/// @returns URL query string without leading '?' character
71/// @code
72/// auto query = MakeQuery(http::Args{{"param", "value"}, {"filter", "active"}});
73/// // Returns: "param=value&filter=active"
74/// @endcode
75std::string MakeQuery(const Args& query_args);
76
77/// @brief Make an URL query
78/// @param query_args Multimap of query parameters
79/// @returns URL query string without leading '?' character
80/// @code
81/// http::MultiArgs args = {{"tag", "new"}, {"tag", "featured"}};
82/// auto query = MakeQuery(args);
83/// // Returns: "tag=new&tag=featured"
84/// @endcode
85std::string MakeQuery(const MultiArgs& query_args);
86
87/// @brief Make an URL query
88/// @param query_args Map of query parameters
89/// @returns URL query string without leading '?' character
90/// @code
91/// auto query = MakeQuery(std::unordered_map<std::string, std::string>{{"page", "1"}, {"size", "10"}});
92/// // Returns: "page=1&size=10"
93/// @endcode
94std::string MakeQuery(const std::unordered_map<std::string, std::string>& query_args);
95
96/// @brief Make an URL query
97/// @param query_args Initializer list of query parameters as key-value pairs
98/// @returns URL query string without leading '?' character
99/// @code
100/// auto query = MakeQuery({{"sort", "date"}, {"order", "desc"}});
101/// // Returns: "sort=date&order=desc"
102/// @endcode
103std::string MakeQuery(std::initializer_list<std::pair<std::string_view, std::string_view>> query_args);
104
105/// @brief Make an URL with query arguments
106/// @param path Base URL path
107/// @param query_args Map of query parameters
108/// @returns Complete URL with query string
109/// @code
110/// auto url = MakeUrl("/api/users", http::Args{{"status", "active"}});
111/// // Returns: "/api/users?status=active"
112/// @endcode
113std::string MakeUrl(std::string_view path, const Args& query_args);
114
115/// @brief Make an URL with query arguments
116/// @param path Base URL path
117/// @param query_args Map of query parameters
118/// @returns Complete URL with query string
119/// @code
120/// auto url = MakeUrl("/api/products", std::unordered_map<std::string, std::string>{{"category", "electronics"}});
121/// // Returns: "/api/products?category=electronics"
122/// @endcode
123std::string MakeUrl(std::string_view path, const std::unordered_map<std::string, std::string>& query_args);
124
125/// @brief Make an URL with query arguments
126/// @param path Base URL path
127/// @param query_args Map of query parameters
128/// @param query_multiargs Multimap for query parameters that can have multiple values
129/// @returns Complete URL with query string
130/// @code
131/// http::MultiArgs multi_args = {{"tag", "new"}, {"tag", "featured"}};
132/// auto url = MakeUrl("/api/products", http::Args{{"category", "electronics"}}, multi_args);
133/// // Returns: "/api/products?category=electronics&tag=new&tag=featured"
134/// @endcode
135std::string MakeUrl(std::string_view path, const Args& query_args, MultiArgs query_multiargs);
136
137/// @brief Make an URL with query arguments
138/// @param path Base URL path
139/// @param query_args Initializer list of query parameters as key-value pairs
140/// @returns Complete URL with query string
141/// @code
142/// auto url = MakeUrl("/api/search", {{"q", "smartphone"}, {"sort", "relevance"}});
143/// // Returns: "/api/search?q=smartphone&sort=relevance"
144/// @endcode
145std::string MakeUrl(
146 std::string_view path,
147 std::initializer_list<std::pair<std::string_view, std::string_view>> query_args
148);
149
150/// @brief Make an URL with query arguments
151/// @param path Base URL path
152/// @param query_args vector of query parameters as key-value pairs
153/// @returns Complete URL with query string
154std::string MakeUrl(
155 std::string_view path,
156 const std::vector<std::pair<std::string_view, std::string_view>>& query_args
157);
158
159/// @brief Make a path from a template and arguments
160/// @param path Template string with placeholders in format {name}
161/// @param path_args Map of placeholder names to their values
162/// @returns Formatted path or std::nullopt if formatting fails (e.g., missing placeholder,
163/// invalid format, or empty key in path_args)
164/// @code
165/// auto url = MakeUrlWithPathArgs("/api/v1/users/{user_id}", {{"user_id", "123"}});
166/// // Returns: "/api/v1/users/123"
167/// @endcode
168std::optional<std::string> MakeUrlWithPathArgs(std::string_view path, const PathArgs& path_args);
169
170/// @brief Make an URL with path parameters and query arguments
171/// @param path Template string with placeholders in format {name}
172/// @param path_args Map of placeholder names to their values
173/// @param query_args Map of query parameters
174/// @returns Formatted URL or std::nullopt if path formatting fails
175/// @code
176/// auto url = MakeUrlWithPathArgs("/api/v1/users/{user_id}",
177/// {{"user_id", "123"}},
178/// http::Args{{"filter", "active"}});
179/// // Returns: "/api/v1/users/123?filter=active"
180/// @endcode
181std::optional<std::string> MakeUrlWithPathArgs(
182 std::string_view path,
183 const PathArgs& path_args,
184 const Args& query_args
185);
186
187/// @brief Make an URL with path parameters and query arguments
188/// @param path Template string with placeholders in format {name}
189/// @param path_args Map of placeholder names to their values
190/// @param query_args Map of query parameters
191/// @returns Formatted URL or std::nullopt if path formatting fails
192/// @code
193/// auto url = MakeUrlWithPathArgs("/api/v1/users/{user_id}",
194/// {{"user_id", "123"}},
195/// std::unordered_map<std::string, std::string>{{"page", "1"}});
196/// // Returns: "/api/v1/users/123?page=1"
197/// @endcode
198std::optional<std::string> MakeUrlWithPathArgs(
199 std::string_view path,
200 const PathArgs& path_args,
201 const std::unordered_map<std::string, std::string>& query_args
202);
203
204/// @brief Make an URL with path parameters and query arguments, supporting multiple values for the same key
205/// @param path Template string with placeholders in format {name}
206/// @param path_args Map of placeholder names to their values
207/// @param query_args Map of query parameters
208/// @param query_multiargs Multimap for query parameters that can have multiple values
209/// @returns Formatted URL or std::nullopt if path formatting fails
210/// @code
211/// http::MultiArgs multi_args = {{"tag", "new"}, {"tag", "featured"}};
212/// auto url = MakeUrlWithPathArgs("/api/v1/products/{category}",
213/// {{"category", "electronics"}},
214/// http::Args{{"sort", "price"}},
215/// multi_args);
216/// // Returns: "/api/v1/products/electronics?sort=price&tag=new&tag=featured"
217/// @endcode
218std::optional<std::string> MakeUrlWithPathArgs(
219 std::string_view path,
220 const PathArgs& path_args,
221 const Args& query_args,
222 MultiArgs query_multiargs
223);
224
225/// @brief Make an URL with path parameters and query arguments
226/// @param path Template string with placeholders in format {name}
227/// @param path_args Map of placeholder names to their values
228/// @param query_args Initializer list of query parameters as key-value pairs
229/// @returns Formatted URL or std::nullopt if path formatting fails
230/// @code
231/// auto url = MakeUrlWithPathArgs("/api/v1/search/{term}",
232/// {{"term", "laptop"}},
233/// {{"brand", "apple"}, {"price_max", "2000"}});
234/// // Returns: "/api/v1/search/laptop?brand=apple&price_max=2000"
235/// @endcode
236std::optional<std::string> MakeUrlWithPathArgs(
237 std::string_view path,
238 const PathArgs& path_args,
239 std::initializer_list<std::pair<std::string_view, std::string_view>> query_args
240);
241
242/// @brief Returns URL part before the first '?' character
243/// @param url Full URL to extract from
244/// @returns URL without query string
245/// @code
246/// auto base = ExtractMetaTypeFromUrl("https://example.com/api/users?page=1&sort=name");
247/// // Returns: "https://example.com/api/users"
248/// @endcode
249std::string ExtractMetaTypeFromUrl(std::string_view url);
250std::string_view ExtractMetaTypeFromUrlView(std::string_view url);
251
252// TODO: rename to ExtractPathAndQuery()
253/// @brief Returns HTTP path part of a URL
254/// @param url Full URL to extract from
255/// @returns Path component of the URL
256/// @code
257/// auto path = ExtractPath("https://example.com/api/users");
258/// // Returns: "/api/users"
259/// auto path2 = ExtractPath("example.com/api/users?a=b");
260/// // Returns: "/api/users?a=b"
261/// @endcode
262std::string ExtractPath(std::string_view url);
263std::string_view ExtractPathView(std::string_view url);
264
265/// @brief Returns HTTP path part of a URL
266/// @param url Full URL to extract from
267/// @returns Path component of the URL
268/// @code
269/// auto path = ExtractPath("https://example.com/api/users");
270/// // Returns: "/api/users"
271/// auto path2 = ExtractPath("example.com/api/users?a=b");
272/// // Returns: "/api/users"
273/// @endcode
274std::string ExtractPathOnly(std::string_view url);
275
276/// @brief Returns hostname part of a URL
277/// @param url Full URL to extract from
278/// @returns Hostname component of the URL
279/// @code
280/// auto host = ExtractHostname("https://example.com/api/users");
281/// // Returns: "example.com"
282/// auto host2 = ExtractHostname("https://user:pass@example.com:8080/api");
283/// // Returns: "example.com"
284/// auto host3 = ExtractHostname("http://[::1]:8080/");
285/// // Returns: "[::1]"
286/// @endcode
287std::string ExtractHostname(std::string_view url);
288std::string_view ExtractHostnameView(std::string_view url);
289
290/// @brief Returns scheme part of a URL
291/// @param url Full URL to extract from
292/// @returns Scheme component of the URL
293/// @code
294/// auto scheme = ExtractScheme("https://example.com/api/users");
295/// // Returns: "https"
296/// auto scheme2 = ExtractScheme("http://user:pass@example.com:8080/api");
297/// // Returns: "http"
298/// auto scheme3 = ExtractScheme("ftp://[::1]:8080/");
299/// // Returns: "ftp"
300/// @endcode
301std::string ExtractScheme(std::string_view url);
302std::string_view ExtractSchemeView(std::string_view url);
303
304/// @brief Returns query part of a URL
305/// @param url Full URL to extract from
306/// @returns Query component of the URL
307/// @code
308/// auto query = ExtractQuery("https://example.com/api/users?q=1");
309/// // Returns: "q=1"
310/// auto query2 = ExtractQuery("http://user:pass@example.com:8080/api");
311/// // Returns: ""
312/// auto query3 = ExtractQuery("ftp://[::1]:8080/?q=12&w=23");
313/// // Returns: "q=12&w=23"
314/// @endcode
315std::string ExtractQuery(std::string_view url);
316std::string_view ExtractQueryView(std::string_view url);
317
318/// @brief Returns fragment part of a URL
319/// @param url Full URL to extract from
320/// @returns Fragment component of the URL
321/// @code
322/// auto fragment = ExtractFragment("https://example.com/api/users?q=1");
323/// // Returns: ""
324/// auto fragment2 = ExtractFragment("http://user:pass@example.com:8080/api#123");
325/// // Returns: "123"
326/// auto fragment3 = ExtractFragment("ftp://[::1]:8080/#123?q=12&w=23");
327/// // Returns: "123"
328/// auto fragment4 = ExtractFragment("ftp://[::1]:8080/?q=12&w=23#123");
329/// // Returns: "123"
330/// @endcode
331std::string ExtractFragment(std::string_view url);
332std::string_view ExtractFragmentView(std::string_view url);
333
334/// @brief Returns decomposed URL as a struct,
335/// broken into main parts: scheme, host, path, query, and fragment
337
338namespace impl {
339
340std::string UrlDecode(utils::impl::InternalTag, std::string_view range);
341
342} // namespace impl
343
344} // namespace http
345
346USERVER_NAMESPACE_END