-
Notifications
You must be signed in to change notification settings - Fork 7
/
url.h
92 lines (74 loc) · 2.78 KB
/
url.h
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
#pragma once
#include <algorithm>
#include <string>
#include <sstream>
#include <string_view>
// Somewhat taken from https://stackoverflow.com/a/11044337
struct Uri
{
private:
typedef std::string_view::const_iterator iterator_t;
public:
std::string_view Protocol, Host, Port, Path, QueryString;
static Uri Parse(const std::string_view& uri)
{
Uri result;
if (uri.length() == 0)
return result;
iterator_t uriEnd = uri.end();
iterator_t queryStart = std::find(uri.begin(), uriEnd, '?');
iterator_t protocolStart = uri.begin();
iterator_t protocolEnd = std::find(protocolStart, uriEnd, ':');
if (protocolEnd != uriEnd)
{
std::string_view prot = &*(protocolEnd);
if ((prot.length() > 3) && (prot.substr(0, 3) == "://"))
{
result.Protocol = make_string_view(uri, protocolStart, protocolEnd);
protocolEnd += 3;
}
else
protocolEnd = uri.begin();
}
else
protocolEnd = uri.begin();
iterator_t hostStart = protocolEnd;
iterator_t pathStart = std::find(hostStart, uriEnd, '/');
iterator_t hostEnd = std::find(protocolEnd, (pathStart != uriEnd) ? pathStart : queryStart, ':');
result.Host = make_string_view(uri, hostStart, hostEnd);
if ((hostEnd != uriEnd) && ((&*(hostEnd))[0] == ':'))
{
hostEnd++;
iterator_t portEnd = (pathStart != uriEnd) ? pathStart : queryStart;
result.Port = make_string_view(uri, hostEnd, portEnd);
}
if (pathStart != uriEnd)
result.Path = make_string_view(uri, pathStart, queryStart);
if (queryStart != uriEnd)
result.QueryString = make_string_view(uri, queryStart, uri.end());
return result;
}
static std::string CreateUri(std::string_view Protocol, std::string_view Host, std::string_view Port, std::string_view Path, std::string_view QueryString) {
std::ostringstream str;
if (!Protocol.empty()) {
str.write(Protocol.data(), Protocol.size());
str.write("://", 3);
}
str.write(Host.data(), Host.size());
if (!Port.empty()) {
str.write(":", 1);
str.write(Port.data(), Port.size());
}
if (!Path.empty()) {
str.write(Path.data(), Path.size());
}
if (!QueryString.empty()) {
str.write(QueryString.data(), QueryString.size());
}
return str.str();
}
private:
static constexpr std::string_view make_string_view(const std::string_view& base, iterator_t first, iterator_t last) {
return base.substr(std::distance(base.begin(), first), std::distance(first, last));
}
};