Kea 2.5.8
url.cc
Go to the documentation of this file.
1// Copyright (C) 2017-2021 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
10#include <http/url.h>
11#include <boost/lexical_cast.hpp>
12#include <sstream>
13
14#include <iostream>
15
16namespace isc {
17namespace http {
18
19Url::Url(const std::string& url)
20 : url_(url), valid_(false), error_message_(), scheme_(Url::HTTPS),
21 hostname_(), port_(0), path_() {
22 parse();
23}
24
25bool
26Url::operator<(const Url& url) const {
27 return (url_ < url.rawUrl());
28}
29
32 checkValid();
33 return (scheme_);
34}
35
36std::string
37Url::getHostname() const {
38 checkValid();
39 return (hostname_);
40}
41
42std::string
44 std::string hostname = getHostname();
45 if ((hostname.length() >= 2) && (hostname.at(0) == '[')) {
46 return (hostname.substr(1, hostname.length() - 2));
47 }
48
49 return (hostname);
50}
51
52unsigned
53Url::getPort() const {
54 checkValid();
55 return (port_);
56}
57
58std::string
59Url::getPath() const {
60 checkValid();
61 return (path_);
62}
63
64std::string
65Url::toText() const {
66 std::ostringstream s;
67 s << (getScheme() == HTTP ? "http" : "https");
68 s << "://" << getHostname();
69
70 if (getPort() != 0) {
71 s << ":" << getPort();
72 }
73
74 s << getPath();
75
76 return (s.str());
77}
78
79void
80Url::checkValid() const {
81 if (!isValid()) {
82 isc_throw(InvalidOperation, "invalid URL " << url_ << ": " << error_message_);
83 }
84}
85
86void
87Url::parse() {
88 valid_ = false;
89 error_message_.clear();
90 scheme_ = Url::HTTPS;
91 hostname_.clear();
92 port_ = 0;
93 path_.clear();
94
95 std::ostringstream error;
96
97 // Retrieve scheme
98 size_t offset = url_.find(":");
99 if ((offset == 0) || (offset == std::string::npos)) {
100 error << "url " << url_ << " lacks http or https scheme";
101 error_message_ = error.str();
102 return;
103 }
104
105 // Validate scheme.
106 std::string scheme = url_.substr(0, offset);
107 if (scheme == "http") {
108 scheme_ = Url::HTTP;
109
110 } else if (scheme == "https") {
111 scheme_ = Url::HTTPS;
112
113 } else {
114 error << "invalid scheme " << scheme << " in " << url_;
115 error_message_ = error.str();
116 return;
117 }
118
119 // Colon and two slashes should follow the scheme
120 if (url_.substr(offset, 3) != "://") {
121 error << "expected :// after scheme in " << url_;
122 error_message_ = error.str();
123 return;
124 }
125
126 // Move forward to hostname.
127 offset += 3;
128 if (offset >= url_.length()) {
129 error << "hostname missing in " << url_;
130 error_message_ = error.str();
131 return;
132 }
133
134 size_t offset2 = 0;
135
136 // IPv6 address is specified within [ ].
137 if (url_.at(offset) == '[') {
138 offset2 = url_.find(']', offset);
139 if (offset2 == std::string::npos) {
140 error << "expected ] after IPv6 address in " << url_;
141 error_message_ = error.str();
142 return;
143
144 } else if (offset2 == offset + 1) {
145 error << "expected IPv6 address within [] in " << url_;
146 error_message_ = error.str();
147 return;
148 }
149
150 // Move one character beyond the ].
151 ++offset2;
152
153 } else {
154 // There is a normal hostname or IPv4 address. It is terminated
155 // by the colon (for port number), a slash (if no port number) or
156 // goes up to the end of the URL.
157 offset2 = url_.find(":", offset);
158 if (offset2 == std::string::npos) {
159 offset2 = url_.find("/", offset);
160 if (offset2 == std::string::npos) {
161 // No port number and no slash.
162 offset2 = url_.length();
163 }
164 }
165 }
166
167 // Extract the hostname.
168 hostname_ = url_.substr(offset, offset2 - offset);
169
170 // If there is no port number and no path, simply return and mark the
171 // URL as valid.
172 if (offset2 == url_.length()) {
173 valid_ = true;
174 return;
175 }
176
177 // If there is a port number, we need to read it and convert to
178 // numeric value.
179 if (url_.at(offset2) == ':') {
180 if (offset2 == url_.length() - 1) {
181 error << "expected port number after : in " << url_;
182 error_message_ = error.str();
183 return;
184 }
185 // Move to the port number.
186 ++offset2;
187
188 // Port number may be terminated by a slash or by the end of URL.
189 size_t slash_offset = url_.find('/', offset2);
190 std::string port_str;
191 if (slash_offset == std::string::npos) {
192 port_str = url_.substr(offset2);
193 } else {
194 port_str = url_.substr(offset2, slash_offset - offset2);
195 }
196
197 try {
198 // Try to convert the port number to numeric value.
199 port_ = boost::lexical_cast<unsigned>(port_str);
200
201 } catch (...) {
202 error << "invalid port number " << port_str << " in " << url_;
203 error_message_ = error.str();
204 return;
205 }
206
207 // Go to the end of the port section.
208 offset2 = slash_offset;
209 }
210
211 // If there is anything left in the URL, we consider it a path.
212 if (offset2 != std::string::npos) {
213 path_ = url_.substr(offset2);
214 if (path_.empty()) {
215 path_ = "/";
216 }
217 }
218
219 valid_ = true;
220}
221
222} // end of namespace isc::http
223} // end of namespace isc
A generic exception that is thrown if a function is called in a prohibited way.
Represents an URL.
Definition: url.h:20
std::string toText() const
Returns textual representation of the URL.
Definition: url.cc:65
std::string getStrippedHostname() const
Returns hostname stripped from [ ] characters surrounding IPv6 address.
Definition: url.cc:43
unsigned getPort() const
Returns port number.
Definition: url.cc:53
Scheme getScheme() const
Returns parsed scheme.
Definition: url.cc:31
bool operator<(const Url &url) const
compares URLs lexically.
Definition: url.cc:26
Url(const std::string &url)
Constructor.
Definition: url.cc:19
bool isValid() const
Checks if the URL is valid.
Definition: url.h:47
std::string getPath() const
Returns path.
Definition: url.cc:59
const std::string & rawUrl() const
Returns the raw, unparsed URL string.
Definition: url.h:87
Scheme
Scheme: https or http.
Definition: url.h:24
#define isc_throw(type, stream)
A shortcut macro to insert known values into exception arguments.
@ error
Definition: db_log.h:118
Defines the logger used by the top-level component of kea-lfc.