LCOV - code coverage report
Current view: top level - core - awsendpoint.cpp (source / functions) Hit Total Coverage
Test: libqtaws 0.1.0 Lines: 194 194 100.0 %
Date: 2015-06-16 07:50:35 Functions: 25 25 100.0 %

          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 &regionName, 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 &regionName, 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 &regionName, 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 &regionName, 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 &regionName = 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

Generated by: LCOV version 1.11