/** * @brief Create an AWS V3 Signature canonical headers string. * * This function constructs a canonical string containing all of the headers * in the given request. * * @note \p request will typically not include a `Host` header at this stage, * however Qt will add an appropriate `Host` header when the request is * performed. So, if \p request does not include a `Host` header yet, * this function will include a derived `Host` header in the canonical * headers to allow for it. * * @note This function is only applicable to the `AWS3` format, not `AWS3-HTTPS`. * * @param[in] request The network request to fetch the canonical headers from. * @param[out] signedHeaders A semi-colon separated list of the names of all headers * included in the result. * * @return An AWS V3 Signature canonical headers string. * * @see http://docs.aws.amazon.com/general/latest/gr/sigV3-create-canonical-request.html * @see canonicalHeader */ QByteArray AwsSignatureV3Private::canonicalHeaders(const QNetworkRequest &request, QByteArray * const signedHeaders) const { Q_CHECK_PTR(signedHeaders); signedHeaders->clear(); /* Note, Amazon says we should combine duplicate headers with comma separators... * conveniently for us, QNetworkRequest requires that to have been done already. * See note in QNetworkRequest::setRawHeader. */ // Convert the raw headers list to a map to sort on (lowercased) header names only. QMap<QByteArray,QByteArray> headers; foreach (const QByteArray &rawHeader, request.rawHeaderList()) { headers.insert(rawHeader.toLower(), request.rawHeader(rawHeader)); } // The "host" header is not included in QNetworkRequest::rawHeaderList, but will be sent by Qt. headers.insert("host", request.url().host().toUtf8()); // Convert the headers map to a canonical string, keeping track of which headers we've included too. QByteArray canonicalHeaders; for (QMap<QByteArray,QByteArray>::const_iterator iter = headers.constBegin(); iter != headers.constEnd(); ++iter) { // Only include "host" and "x-amz-*" headers. Note, Amazon documentation states that latter as // "x-amz-" (ie with the trailing '-'), yet the official Amazon Java SDK tests for a "x-amz" // prefix. Thus the Java SDK would include headers with keys like "x-amzfoo", but here we do not // since that would disagree with the official documentation. if ((iter.key() == "host") || (iter.key().startsWith("x-amz-"))) { canonicalHeaders += canonicalHeader(iter.key(), iter.value()) + '\n'; if (!signedHeaders->isEmpty()) *signedHeaders += ';'; *signedHeaders += iter.key(); } } return canonicalHeaders; }
/** * @brief Create an AWS V4 Signature canonical headers string. * * This function constructs a canonical string containing all of the headers * in the given request. * * @note \p request will typically not include a `Host` header at this stage, * however Qt will add an appropriate `Host` header when the request is * performed. So, if \p request does not include a `Host` header yet, * this function will include a derived `Host` header in the canonical * headers to allow for it. * * @param[in] request The network request to fetch the canonical headers from. * @param[out] signedHeaders A semi-colon separated list of the names of all headers * included in the result. * * @return An AWS V4 Signature canonical headers string. * * @see http://docs.aws.amazon.com/general/latest/gr/sigv4-create-canonical-request.html * @see canonicalHeader */ QByteArray AwsSignatureV4Private::canonicalHeaders(const QNetworkRequest &request, QByteArray * const signedHeaders) const { Q_CHECK_PTR(signedHeaders); signedHeaders->clear(); /* Note, Amazon says we should combine duplicate headers with comma separators... * conveniently for us, QNetworkRequest requires that to have been done already. * See note in QNetworkRequest::setRawHeader. */ // Convert the raw headers list to a map to sort on (lowercased) header names only. QMap<QByteArray,QByteArray> headers; foreach (const QByteArray &rawHeader, request.rawHeaderList()) { headers.insert(rawHeader.toLower(), request.rawHeader(rawHeader)); } // The "host" header is not included in QNetworkRequest::rawHeaderList, but will be sent by Qt. headers.insert("host", request.url().host().toUtf8()); // Convert the headers map to a canonical string, keeping track of which headers we've included too. QByteArray canonicalHeaders; for (QMap<QByteArray,QByteArray>::const_iterator iter = headers.constBegin(); iter != headers.constEnd(); ++iter) { canonicalHeaders += canonicalHeader(iter.key(), iter.value()) + '\n'; if (!signedHeaders->isEmpty()) *signedHeaders += ';'; *signedHeaders += iter.key(); } return canonicalHeaders; }