Line data Source code
1 : /*
2 : Copyright 2013-2015 Paul Colby
3 :
4 : This file is part of libqtaws.
5 :
6 : Libqtaws is free software: you can redistribute it and/or modify
7 : it under the terms of the GNU Lesser General Public License as published by
8 : the Free Software Foundation, either version 3 of the License, or
9 : (at your option) any later version.
10 :
11 : Libqtaws is distributed in the hope that it will be useful,
12 : but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : GNU Lesser General Public License for more details.
15 :
16 : You should have received a copy of the GNU Lesser General Public License
17 : along with libqtaws. If not, see <http://www.gnu.org/licenses/>.
18 : */
19 :
20 : #include "awsendpoint.h"
21 : #include "awsendpoint_p.h"
22 :
23 : #include <QDebug>
24 : #include <QFile>
25 : #include <QMutexLocker>
26 :
27 : QTAWS_BEGIN_NAMESPACE
28 :
29 : /**
30 : * @class AwsEndpoint
31 : *
32 : * @brief Provides AWS endpoint information.
33 : *
34 : * @note This class provides fairly low-level access to AWS endpoint data.
35 : * You should consider using the AwsRegion and/or various
36 : * AwsService-derived classes in preference to using this class
37 : * directly where possible.
38 : *
39 : * This class parses the `endpoint.xml` data available at
40 : * http://aws-sdk-configurations.amazonwebservices.com/endpoints.xml
41 : *
42 : * The `endpoint.xml` file is embedded as a resource in the libqtaws
43 : * library - not fetched remotely at runtime.
44 : *
45 : * Example usage:
46 : * @code
47 : * AwsEndpoint endpoint(QLatin1String("cloudformation.us-east-1.amazonaws.com"));
48 : *
49 : * endpoint.hostName(); // "cloudformation.us-east-1.amazonaws.com"
50 : * endpoint.regionName(); // "us-east-1"
51 : * endpoint.serviceName(); // "cloudformation"
52 : *
53 : * endpoint.supportedRegions(); // [ "us-east-1" ]
54 : *
55 : * endpoint.isSupported(AwsEndpoint::HTTP); // false
56 : * endpoint.isSupported(AwsEndpoint::HTTPS); // true
57 : *
58 : * QUrl ec2 = AwsEndpoint::getEndpoint("ap-southeast-2", "ec2");
59 : * QUrl iam = AwsEndpoint::getEndpoint("ap-southeast-2", "iam");
60 : *
61 : * ec2.host(); // "ec2.ap-southeast-2.amazonaws.com"
62 : * iam.host(); // "iam.amazonaws.com"
63 : * @endcode
64 : *
65 : * @see AwsRegion
66 : * @see AwsService
67 : */
68 :
69 : /**
70 : * @brief Constructs a new AwsEndpoint object.
71 : *
72 : * @param hostName Name of an AWS host, encoded as UTF-8.
73 : */
74 186 : AwsEndpoint::AwsEndpoint(const QByteArray &hostName)
75 186 : : d_ptr(new AwsEndpointPrivate(this))
76 : {
77 186 : Q_D(AwsEndpoint);
78 186 : d->hostName = QString::fromUtf8(hostName);
79 186 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
80 186 : if (AwsEndpointPrivate::hosts.contains(d->hostName)) {
81 184 : if (!AwsEndpointPrivate::hosts[d->hostName].regionNames.empty()) {
82 184 : d->regionName = AwsEndpointPrivate::hosts[d->hostName].regionNames.first();
83 : }
84 184 : d->serviceName = AwsEndpointPrivate::hosts[d->hostName].serviceName;
85 186 : }
86 186 : }
87 :
88 : /**
89 : * @brief Constructs a new AwsEndpoint object.
90 : *
91 : * @param hostName Name of an AWS host.
92 : */
93 989 : AwsEndpoint::AwsEndpoint(const QString &hostName)
94 989 : : d_ptr(new AwsEndpointPrivate(this))
95 : {
96 989 : Q_D(AwsEndpoint);
97 989 : d->hostName = hostName;
98 989 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
99 989 : if (AwsEndpointPrivate::hosts.contains(d->hostName)) {
100 976 : if (!AwsEndpointPrivate::hosts[d->hostName].regionNames.empty()) {
101 976 : d->regionName = AwsEndpointPrivate::hosts[d->hostName].regionNames.first();
102 : }
103 976 : d->serviceName = AwsEndpointPrivate::hosts[d->hostName].serviceName;
104 989 : }
105 989 : }
106 :
107 : /**
108 : * @brief AwsEndpoint destructor.
109 : */
110 1175 : AwsEndpoint::~AwsEndpoint()
111 : {
112 1175 : delete d_ptr;
113 1175 : }
114 :
115 : /**
116 : * @brief Get a QUrl for an AWS endpoint.
117 : *
118 : * This function will return a QUrl object for accessing an AWS service. The
119 : * region and service names must match those used by Amazon.
120 : *
121 : * If the specified region and/or service are not known to be valid for AWS, or
122 : * the service is not supported in the specified region, then an invalid QUrl
123 : * will be returned.
124 : *
125 : * @note An invalid QUrl is one for which QUrl::isValid returns `false`.
126 : *
127 : * The \p transport parameter may be used to specify one or more transports to
128 : * consider. If the specified AWS endpoint exists, but does not support //any//
129 : * of the given transports, then an invalid QUrl is returned.
130 : *
131 : * Where it makes sense to do so, the resulting QUrl's scheme will be set
132 : * according to the requested transport. For example, if the selected transport
133 : * is AwsEndpoint::HTTPS, then the resulting QUrl's schems will be set to
134 : * "https".
135 : *
136 : * If \p transport includes both AwsEndpoint::HTTP //and// AwsEndpoint::HTTPS,
137 : * and both are supported by the AWS endpoint, then "https" will be chosed in
138 : * preference to "http".
139 : *
140 : * @note It is possible for the returned QUrl to specify a host that is not
141 : * located in, nor dedicated to the specified region. For examepl, if
142 : * requesting an endpoint for the `iam` service in `ap-southeast-2`, the
143 : * return endpoint is for a host (`iam.amazonaws.com`) which provides
144 : * the `ami` services for all regions, not just `ap-southeast-2`.
145 : * Services known to behave like this include: `cloudfront`, `iam`,
146 : * `importexport`, `route53`, and `sts`.
147 : *
148 : * Example usage:
149 : * @code
150 : * QUrl ec2 = AwsEndpoint::getEndpoint("ap-southeast-2", "ec2");
151 : * QUrl iam = AwsEndpoint::getEndpoint("ap-southeast-2", "iam");
152 : * ec2.host(); // "ec2.ap-southeast-2.amazonaws.com"
153 : * iam.host(); // "iam.amazonaws.com"
154 : * @endcode
155 : *
156 : * @param regionName Endpoint's region name.
157 : * @param serviceName Endpoint's service name.
158 : * @param transport Optional network transport(s) for the endpoint.
159 : *
160 : * @return A QUrl representing the AWS endpoint, or an invalid QUrl if there
161 : * is no such _known_ AWS endpoint.
162 : */
163 1969 : QUrl AwsEndpoint::getEndpoint(const QString ®ionName, const QString &serviceName,
164 : const Transports transport)
165 : {
166 1969 : AwsEndpointPrivate::loadEndpointData();
167 1969 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
168 3937 : if ((!AwsEndpointPrivate::regions.contains(regionName)) ||
169 1968 : (!AwsEndpointPrivate::regions[regionName].services.contains(serviceName))) {
170 33 : return QUrl();
171 : }
172 : const AwsEndpointPrivate::RegionEndpointInfo &endpointInfo =
173 1936 : AwsEndpointPrivate::regions[regionName].services[serviceName];
174 1936 : if (!(endpointInfo.transports & transport)) {
175 455 : return QUrl();
176 : }
177 :
178 2962 : QUrl url;
179 1481 : url.setHost(endpointInfo.hostName);
180 1481 : if ((endpointInfo.transports & HTTPS) && (transport & HTTPS))
181 1279 : url.setScheme(QLatin1String("https"));
182 202 : else if ((endpointInfo.transports & HTTP) && (transport & HTTP))
183 200 : url.setScheme(QLatin1String("http"));
184 : /// @todo Handle SMTP here?
185 3450 : return url;
186 : }
187 :
188 : /**
189 : * @brief Get the name of host represented by this endpoint.
190 : *
191 : * @return Name of host represented by this endpoint.
192 : */
193 744 : QString AwsEndpoint::hostName() const
194 : {
195 744 : Q_D(const AwsEndpoint);
196 744 : return d->hostName;
197 : }
198 :
199 : /**
200 : * @brief Is a region / service / transport combination supported by Amazon?
201 : *
202 : * @param regionName AWS region name to check support for.
203 : * @param serviceName AWS service name to check support for.
204 : * @param transport Optional transport to check support for.
205 : *
206 : * @return `true` if the service is supported in the \p regionName region for at least
207 : * one of the specified transports, `false` otherwise.
208 : */
209 3624 : bool AwsEndpoint::isSupported(const QString ®ionName, const QString &serviceName, const Transports transport)
210 : {
211 3624 : AwsEndpointPrivate::loadEndpointData();
212 3624 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
213 7242 : return ((AwsEndpointPrivate::regions.contains(regionName)) &&
214 14484 : (AwsEndpointPrivate::regions[regionName].services.contains(serviceName)) &&
215 10860 : (AwsEndpointPrivate::regions[regionName].services[serviceName].transports & transport));
216 : }
217 :
218 : /**
219 : * @brief Is the given transport supported by this endpoint?
220 : *
221 : * @param transport Transport to check for support for.
222 : *
223 : * @return `true` if the transport is supported by this endpoint, `false` otherwise.
224 : */
225 557 : bool AwsEndpoint::isSupported(const Transport transport) const
226 : {
227 557 : return isSupported(regionName(), serviceName(), AwsEndpoint::Transports(transport));
228 : }
229 :
230 : /**
231 : * @brief Is this endpoint valid?
232 : *
233 : * An endpoint is considered valid if the host specified during construction is
234 : * a known AWS host, and thus we know what region and service(s) it supports.
235 : *
236 : * For example:
237 : * @code
238 : * AwsEndpoint good(QLatin1String("cloudformation.us-east-1.amazonaws.com"));
239 : * AwsEndpoint bad(QLatin1String("example.com"));
240 : * Q_ASSERT(good.isValid()); // good is valid.
241 : * Q_ASSERT(!bad.isValid()); // bad is not.
242 : * @endcode
243 : *
244 : * @return `true` if this endpoint is valid, `false` otherwise.
245 : */
246 372 : bool AwsEndpoint::isValid() const
247 : {
248 372 : return ((!hostName().isEmpty()) && (!regionName().isEmpty()) && (!serviceName().isEmpty()));
249 : }
250 :
251 : /**
252 : * @brief Get this endpoint's full service name.
253 : *
254 : * The full service name is a human-readbale form. For example, the full name for
255 : * the `cloudsearch` service is `Amazon CloudSearch`. Likewise, the full name for
256 : * the `rds` service is `Amazon Relational Database Service`.
257 : *
258 : * @return This endpoint's full service name.
259 : *
260 : * @see serviceName
261 : */
262 35 : QString AwsEndpoint::fullServiceName() const
263 : {
264 35 : return fullServiceName(serviceName());
265 : }
266 :
267 : /**
268 : * @brief Get the full name for given service.
269 : *
270 : * The full service name is a human-readbale form. For example, the full name for
271 : * the `cloudsearch` service is `Amazon CloudSearch`. Likewise, the full name for
272 : * the `rds` service is `Amazon Relational Database Service`.
273 : *
274 : * @param serviceName Canonical AWS service name to get the full name of.
275 : *
276 : * @return This endpoint's full service name.
277 : *
278 : * @see serviceName
279 : */
280 70 : QString AwsEndpoint::fullServiceName(const QString &serviceName)
281 : {
282 70 : AwsEndpointPrivate::loadEndpointData();
283 70 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
284 : const QHash<QString, AwsEndpointPrivate::ServiceInfo>::const_iterator
285 70 : service = AwsEndpointPrivate::services.constFind(serviceName);
286 70 : return (service == AwsEndpointPrivate::services.constEnd()) ? QString() : service.value().fullName;
287 : }
288 :
289 : /**
290 : * @brief Get this endpoint's _primary_ region name.
291 : *
292 : * It is possible for a single endpiont to support multuple regions, such as
293 : * `iam.amazonaws.com`, which provides the `ami` servive for all (non-government)
294 : * regions.
295 : *
296 : * In these cases, this function returns the primary region in which the service
297 : * is located. The AwsEndpoint::supportedRegions function may be used to fetch
298 : * the full list of regions this endpoint supports.
299 : *
300 : * @return This endpoint's region name.
301 : *
302 : * @see supportedRegions
303 : */
304 1411 : QString AwsEndpoint::regionName() const
305 : {
306 1411 : Q_D(const AwsEndpoint);
307 1411 : return d->regionName;
308 : }
309 :
310 : /**
311 : * @brief Get this endpoint's service name.
312 : *
313 : * @return This endpoint's service name.
314 : *
315 : * @see fullServiceName
316 : */
317 1600 : QString AwsEndpoint::serviceName() const
318 : {
319 1600 : Q_D(const AwsEndpoint);
320 1600 : return d->serviceName;
321 : }
322 :
323 : /**
324 : * @brief Get the full list of regions this endpoint supports.
325 : *
326 : * Alternatvely, AwsEndpoint::regionName may be used to get this endpoint's
327 : * _primary_ region.
328 : *
329 : * @param transport Optional transport to check for support.
330 : *
331 : * @return A list of all regions this endpoint supports for //at least one// of
332 : * the specified transports.
333 : *
334 : * @see regionName
335 : */
336 154 : QStringList AwsEndpoint::supportedRegions(const Transports transport) const
337 : {
338 154 : return supportedRegions(serviceName(), transport);
339 : }
340 :
341 : /**
342 : * @brief Get a list of regions that supported for a given service.
343 : *
344 : * @param serviceName AWS service to get the supported regions for.
345 : * @param transport Optional transport(s) to check for support.
346 : *
347 : * @return A list of AWS regions supported for the given service, for
348 : * _at least one_ of the specified transports.
349 : */
350 380 : QStringList AwsEndpoint::supportedRegions(const QString &serviceName, const Transports transport)
351 : {
352 380 : AwsEndpointPrivate::loadEndpointData();
353 380 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
354 :
355 380 : if (transport == AnyTransport) {
356 64 : return AwsEndpointPrivate::services[serviceName].regionNames;
357 : }
358 :
359 632 : QStringList regions;
360 2495 : foreach (const QString ®ionName, AwsEndpointPrivate::services[serviceName].regionNames) {
361 2179 : if (AwsEndpointPrivate::regions[regionName].services[serviceName].transports & transport)
362 1718 : regions.append(regionName);
363 316 : }
364 696 : return regions;
365 : }
366 :
367 : /**
368 : * @brief Get a list of services that support a given region.
369 : *
370 : * @param regionName AWS region to get the supported services for.
371 : * @param transport Optional transport(s) to check for support.
372 : *
373 : * @return A list of AWS services supported for the given region, for
374 : * _at least one_ of the specified transports.
375 : */
376 128 : QStringList AwsEndpoint::supportedServices(const QString ®ionName, const Transports transport)
377 : {
378 128 : AwsEndpointPrivate::loadEndpointData();
379 128 : QMutexLocker locker(&AwsEndpointPrivate::mutex);
380 :
381 128 : if (transport == AnyTransport) {
382 18 : return AwsEndpointPrivate::regions[regionName].services.keys();
383 : }
384 :
385 220 : QStringList serviceNames;
386 110 : const AwsEndpointPrivate::RegionServices &services = AwsEndpointPrivate::regions[regionName].services;
387 2738 : for (AwsEndpointPrivate::RegionServices::const_iterator iter = services.constBegin(); iter != services.constEnd(); ++iter) {
388 2628 : if (iter.value().transports & transport)
389 1718 : serviceNames.append(iter.key());
390 : }
391 238 : return serviceNames;
392 : }
393 :
394 : /**
395 : * @internal
396 : *
397 : * @class AwsEndpointPrivate
398 : *
399 : * @brief Private implementation for AwsEndpoint.
400 : */
401 :
402 1 : QHash<QString, AwsEndpointPrivate::HostInfo> AwsEndpointPrivate::hosts; ///< Hash of hostnames to HostInfo.
403 1 : QHash<QString, AwsEndpointPrivate::RegionInfo> AwsEndpointPrivate::regions; ///< Hash of region names to RegionInfo.
404 1 : QHash<QString, AwsEndpointPrivate::ServiceInfo> AwsEndpointPrivate::services; ///< Hash of service names to ServiceInfo.
405 :
406 1 : QMutex AwsEndpointPrivate::mutex(QMutex::Recursive); ///< Mutex for protecting access to static members.
407 :
408 : /**
409 : * @internal
410 : *
411 : * @brief Constructs a new AwsEndpointPrivate object.
412 : *
413 : * @param q Pointer to this object's public AwsEndpoint instance.
414 : *
415 : * @see http://aws-sdk-configurations.amazonwebservices.com/endpoints.xml
416 : */
417 1175 : AwsEndpointPrivate::AwsEndpointPrivate(AwsEndpoint * const q)
418 1175 : : q_ptr(q)
419 : {
420 1175 : loadEndpointData();
421 1175 : }
422 :
423 : /**
424 : * @internal
425 : *
426 : * @brief Load endpoint data
427 : *
428 : * This function parses AWS endpoint data in XML format. The XML data is
429 : * expected to match the same format as the file provided by Amazon at
430 : * http://aws-sdk-configurations.amazonwebservices.com/endpoints.xml
431 : *
432 : * If _any_ data has been loaded previously, this function will return
433 : * immediately with no parsing performed.
434 : *
435 : * @param fileName Name of the endpoint XML data file to load.
436 : */
437 7349 : void AwsEndpointPrivate::loadEndpointData(const QString &fileName)
438 : {
439 7349 : QMutexLocker locker(&mutex);
440 7349 : if (!hosts.empty()) {
441 10372 : return; // Already loaded.
442 : }
443 :
444 : // Open the data file.
445 8652 : QFile file(fileName);
446 8652 : loadEndpointData(file);
447 : }
448 :
449 : /**
450 : * @internal
451 : *
452 : * @brief Load endpoint data
453 : *
454 : * This function parses AWS endpoint data in XML format. The XML data is
455 : * expected to match the same format as the file provided by Amazon at
456 : * http://aws-sdk-configurations.amazonwebservices.com/endpoints.xml
457 : *
458 : * If _any_ data has been loaded previously, this function will return
459 : * immediately with no parsing performed.
460 : *
461 : * @param device Device to parse XML data from.
462 : */
463 4328 : void AwsEndpointPrivate::loadEndpointData(QIODevice &device)
464 : {
465 4328 : QMutexLocker locker(&mutex);
466 4328 : if (!hosts.empty()) {
467 1 : return; // Already loaded.
468 : }
469 :
470 : // Open the device, if not already open.
471 4327 : if ((!device.isOpen()) && (!device.open(QIODevice::ReadOnly))) {
472 1 : qWarning() << "AwsEndpoint:" << device.errorString();
473 1 : return;
474 : }
475 :
476 : // Parse the data.
477 8652 : QXmlStreamReader xml(&device);
478 8652 : loadEndpointData(xml);
479 : }
480 :
481 : /**
482 : * @internal
483 : *
484 : * @brief Load endpoint data
485 : *
486 : * This function parses AWS endpoint data in XML format. The XML data is
487 : * expected to match the same format as the file provided by Amazon at
488 : * http://aws-sdk-configurations.amazonwebservices.com/endpoints.xml
489 : *
490 : * If _any_ data has been loaded previously, this function will return
491 : * immediately with no parsing performed.
492 : *
493 : * @param xml XML document to parse.
494 : */
495 4328 : void AwsEndpointPrivate::loadEndpointData(QXmlStreamReader &xml)
496 : {
497 4328 : QMutexLocker locker(&mutex);
498 4328 : if (!hosts.empty()) {
499 4328 : return; // Already loaded.
500 : }
501 :
502 : // Parse the XML data.
503 21635 : while (xml.readNextStartElement()) {
504 12979 : if (xml.name() == QLatin1String("Regions")) {
505 4326 : parseRegions(xml);
506 8653 : } else if (xml.name() == QLatin1String("Services")) {
507 4326 : parseServices(xml);
508 4327 : } else if (xml.name() != QLatin1String("XML")) {
509 1 : qDebug() << Q_FUNC_INFO << "ignoring" << xml.name();
510 : }
511 : }
512 4328 : if (xml.hasError()) {
513 1 : qWarning() << "AwsEndpoint:" << xml.errorString();
514 : }
515 4328 : Q_ASSERT(!xml.hasError());
516 4328 : Q_ASSERT(!hosts.isEmpty());
517 4328 : Q_ASSERT(!regions.isEmpty());
518 4328 : Q_ASSERT(!services.isEmpty());
519 : }
520 :
521 : /**
522 : * @internal
523 : *
524 : * @brief Parse a `Region` element from Amazon's endpoint XML data
525 : *
526 : * This function parses XML elements like:
527 : *
528 : * @code{xml}
529 : * <Region>
530 : * <Name>us-east-1</Name>
531 : * <Endpoint>
532 : * <ServiceName>cloudformation</ServiceName>
533 : * <Http>false</Http>
534 : * <Https>true</Https>
535 : * <Hostname>cloudformation.us-east-1.amazonaws.com</Hostname>
536 : * </Endpoint>
537 : * <Endpoint>
538 : * <ServiceName>cloudfront</ServiceName>
539 : * <Http>true</Http>
540 : * <Https>true</Https>
541 : * <Hostname>cloudfront.amazonaws.com</Hostname>
542 : * </Endpoint>
543 : * </Region>
544 : * @endcode
545 : *
546 : * The parsed entries are automatically added to AwsEndpointPrivate::hosts
547 : * and AwsEndpointPrivate::regions.
548 : *
549 : * @param xml XML element to parse.
550 : *
551 : * @see parseRegion
552 : */
553 38944 : void AwsEndpointPrivate::parseRegion(QXmlStreamReader &xml)
554 : {
555 38944 : QString regionName;
556 1064268 : while ((!xml.atEnd()) && (xml.readNextStartElement())) {
557 986380 : if (xml.name() == QLatin1String("Name")) {
558 38944 : regionName = xml.readElementText();
559 947436 : } else if (xml.name() == QLatin1String("Endpoint")) {
560 947426 : Q_ASSERT(!regionName.isEmpty());
561 947426 : RegionEndpointInfo endpoint;
562 1894852 : QString serviceName;
563 5684552 : while ((!xml.atEnd()) && (xml.readNextStartElement())) {
564 3789700 : if (xml.name() == QLatin1String("ServiceName")) {
565 947426 : serviceName = xml.readElementText();
566 2842274 : } else if (xml.name() == QLatin1String("Http")) {
567 947418 : if (xml.readElementText() == QLatin1String("true")) {
568 432612 : endpoint.transports |= AwsEndpoint::HTTP;
569 : }
570 1894856 : } else if (xml.name() == QLatin1String("Https")) {
571 947418 : if (xml.readElementText() == QLatin1String("true")) {
572 947406 : endpoint.transports |= AwsEndpoint::HTTPS;
573 : }
574 947438 : } else if (xml.name() == QLatin1String("Hostname")) {
575 947426 : endpoint.hostName = xml.readElementText();
576 : } else {
577 12 : qDebug() << Q_FUNC_INFO << "ignoring" << xml.name();
578 12 : xml.skipCurrentElement();
579 : }
580 : }
581 947426 : Q_ASSERT(!serviceName.isEmpty());
582 :
583 947426 : if (serviceName == QLatin1String("email")) {
584 4326 : endpoint.transports |= AwsEndpoint::SMTP;
585 : }
586 :
587 947426 : Q_ASSERT((!hosts.contains(endpoint.hostName)) || (hosts.value(endpoint.hostName).serviceName == serviceName));
588 947426 : hosts[endpoint.hostName].regionNames.append(regionName);
589 947426 : hosts[endpoint.hostName].serviceName = serviceName;
590 1894852 : regions[regionName].services[serviceName] = endpoint;
591 : //qDebug() << Q_FUNC_INFO << regionName << serviceName << (int)endpoint.transports << endpoint.hostName;
592 : } else {
593 10 : qDebug() << Q_FUNC_INFO << "ignoring" << xml.name();
594 10 : xml.skipCurrentElement();
595 : }
596 38944 : }
597 38944 : }
598 :
599 : /**
600 : * @internal
601 : *
602 : * @brief Parse a `Regions` element from Amazon's endpoint XML data
603 : *
604 : * This function parse an XML element containing a list of `Region` elements.
605 : * See AwsEndpointPrivate::parseRegion for the `Region` element format.
606 : *
607 : * The parsed entries are automatically added to AwsEndpointPrivate::hosts
608 : * and AwsEndpointPrivate::regions.
609 : *
610 : * @param xml XML element containing regions to parse.
611 : *
612 : * @see parseRegion
613 : */
614 4329 : void AwsEndpointPrivate::parseRegions(QXmlStreamReader &xml)
615 : {
616 47607 : while ((!xml.atEnd()) && (xml.readNextStartElement())) {
617 38949 : if (xml.name() == QLatin1String("Region")) {
618 38940 : parseRegion(xml);
619 : } else {
620 9 : qDebug() << Q_FUNC_INFO << "ignoring" << xml.name();
621 9 : xml.skipCurrentElement();
622 : }
623 : }
624 4329 : }
625 :
626 : /**
627 : * @internal
628 : *
629 : * @brief Parse a `Service` element from Amazon's endpoint XML data
630 : *
631 : * This function parses XML elements like:
632 : *
633 : * @code{xml}
634 : * <Service>
635 : * <Name>cloudformation</Name>
636 : * <FullName>Amazon CloudFormation</FullName>
637 : * <RegionName>us-east-1</RegionName>
638 : * <RegionName>us-west-1</RegionName>
639 : * <RegionName>us-west-2</RegionName>
640 : * <RegionName>eu-west-1</RegionName>
641 : * <RegionName>ap-northeast-1</RegionName>
642 : * <RegionName>ap-southeast-1</RegionName>
643 : * <RegionName>ap-southeast-2</RegionName>
644 : * <RegionName>sa-east-1</RegionName>
645 : * </Service>
646 : * @endcode
647 : *
648 : * The parsed entries are automatically added to AwsEndpointPrivate::services.
649 : *
650 : * @param xml XML element to parse.
651 : *
652 : * @see parseServices
653 : */
654 138436 : void AwsEndpointPrivate::parseService(QXmlStreamReader &xml)
655 : {
656 138436 : QString serviceName;
657 1501160 : while ((!xml.atEnd()) && (xml.readNextStartElement())) {
658 1224288 : if (xml.name() == QLatin1String("Name")) {
659 138436 : serviceName = xml.readElementText();
660 1085852 : } else if (xml.name() == QLatin1String("FullName")) {
661 138436 : Q_ASSERT(!serviceName.isEmpty());
662 138436 : services[serviceName].fullName = xml.readElementText();
663 947416 : } else if (xml.name() == QLatin1String("RegionName")) {
664 947408 : Q_ASSERT(!serviceName.isEmpty());
665 947408 : const QString ®ionName = xml.readElementText();
666 947408 : services[serviceName].regionNames.append(regionName);
667 : //qDebug() << Q_FUNC_INFO << serviceName << services[serviceName].fullName << regionName;
668 : } else {
669 8 : qDebug() << Q_FUNC_INFO << "ignoring" << xml.name();
670 8 : xml.skipCurrentElement();
671 : }
672 138436 : }
673 138436 : }
674 :
675 : /**
676 : * @internal
677 : *
678 : * @brief Parse a `Services` element from Amazon's endpoint XML data
679 : *
680 : * This function parses an XML element containing a list of `Service` elements.
681 : * See AwsEndpointPrivate::parseServices for the `Service` element format.
682 : *
683 : * The parsed entries are automatically added to AwsEndpointPrivate::services.
684 : *
685 : * @param xml XML element containing services to parse.
686 : *
687 : * @see parseService
688 : */
689 4327 : void AwsEndpointPrivate::parseServices(QXmlStreamReader &xml)
690 : {
691 147089 : while ((!xml.atEnd()) && (xml.readNextStartElement())) {
692 138435 : if (xml.name() == QLatin1String("Service")) {
693 138434 : parseService(xml);
694 : } else {
695 1 : qDebug() << Q_FUNC_INFO << "ignoring" << xml.name();
696 1 : xml.skipCurrentElement();
697 : }
698 : }
699 4330 : }
700 :
701 : QTAWS_END_NAMESPACE
|