STATUS generateCanonicalRequestString()

in src/source/Common/AwsV4Signer.c [414:522]


STATUS generateCanonicalRequestString(PRequestInfo pRequestInfo, PCHAR pRequestStr, PUINT32 pRequestLen)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS;
    PCHAR pCurPtr, pVerbString, pUriStart, pUriEnd, pQueryStart, pQueryEnd;
    UINT32 requestLen = 0, curLen, urlLen, len, itemCount;
    BOOL defaultPath;

    CHK(pRequestInfo != NULL && pRequestLen != NULL, STATUS_NULL_ARG);

    CHK_STATUS(singleListGetNodeCount(pRequestInfo->pRequestHeaders, &itemCount));

    // Calculate the rough max size first including the new lines and hex of the 256 bit hash (2 * 32)
    //    CanonicalRequest =
    //            HTTPRequestMethod + '\n' +
    //            CanonicalURI + '\n' +
    //            CanonicalQueryString + '\n' +
    //            CanonicalHeaders + '\n' +
    //            SignedHeaders + '\n' +
    //            HexEncode(Hash(RequestPayload))
    requestLen = MAX_REQUEST_VERB_STRING_LEN + 1 + MAX_URI_CHAR_LEN + 1 + MAX_URI_CHAR_LEN + 1 +
        itemCount * (MAX_REQUEST_HEADER_NAME_LEN + 1 + MAX_REQUEST_HEADER_VALUE_LEN + 1) + itemCount * (MAX_REQUEST_HEADER_NAME_LEN + 1) +
        SHA256_DIGEST_LENGTH * 2 + 1;

    // See if we only are interested in the size
    CHK(pRequestStr != NULL, retStatus);

    pCurPtr = pRequestStr;
    requestLen = *pRequestLen;
    curLen = 0;

    // Get the request verb string
    pVerbString = getRequestVerbString(pRequestInfo->verb);
    CHK(pVerbString != NULL, STATUS_INVALID_ARG);
    len = (UINT32) STRLEN(pVerbString);
    CHK(curLen + len + 1 <= requestLen, STATUS_BUFFER_TOO_SMALL);
    MEMCPY(pCurPtr, pVerbString, SIZEOF(CHAR) * len);
    pCurPtr += len;
    *pCurPtr++ = '\n';
    curLen += len + 1;

    // Store the length of the URL
    urlLen = (UINT32) STRLEN(pRequestInfo->url);

    // Get the canonical URI
    CHK_STATUS(getCanonicalUri(pRequestInfo->url, urlLen, &pUriStart, &pUriEnd, &defaultPath));
    len = defaultPath ? 1 : (UINT32)(pUriEnd - pUriStart);

    CHK(curLen + len + 1 <= requestLen, STATUS_BUFFER_TOO_SMALL);
    MEMCPY(pCurPtr, pUriStart, len * SIZEOF(CHAR));
    pCurPtr += len;
    *pCurPtr++ = '\n';
    curLen += len + 1;

    // Get the canonical query.
    // We assume the params have been URI encoded and the in an ascending order
    pQueryEnd = pRequestInfo->url + urlLen;

    // The start of the query params is either end of the URI or ? so we skip one in that case
    pQueryStart = (pUriEnd == pQueryEnd) ? pUriEnd : pUriEnd + 1;

    len = (UINT32)(pQueryEnd - pQueryStart);
    CHK(curLen + len + 1 <= requestLen, STATUS_BUFFER_TOO_SMALL);
    MEMCPY(pCurPtr, pQueryStart, len * SIZEOF(CHAR));
    pCurPtr += len;
    *pCurPtr++ = '\n';
    curLen += len + 1;

    len = requestLen - curLen;
    CHK_STATUS(generateCanonicalHeaders(pRequestInfo, pCurPtr, &len));
    CHK(curLen + len + 1 <= requestLen, STATUS_BUFFER_TOO_SMALL);
    pCurPtr += len;

    *pCurPtr++ = '\n';
    curLen += len + 1;

    len = requestLen - curLen;
    CHK_STATUS(generateSignedHeaders(pRequestInfo, pCurPtr, &len));
    CHK(curLen + len + 1 <= requestLen, STATUS_BUFFER_TOO_SMALL);
    pCurPtr += len;
    *pCurPtr++ = '\n';
    curLen += len + 1;

    // Generate the hex encoded hash
    len = SHA256_DIGEST_LENGTH * 2;
    CHK(curLen + len <= requestLen, STATUS_BUFFER_TOO_SMALL);
    if (pRequestInfo->body == NULL) {
        // Streaming treats this portion as if the body were empty
        CHK_STATUS(hexEncodedSha256((PBYTE) EMPTY_STRING, 0, pCurPtr));
    } else {
        // standard signing
        CHK_STATUS(hexEncodedSha256((PBYTE) pRequestInfo->body, pRequestInfo->bodySize, pCurPtr));
    }

    pCurPtr += len;
    curLen += len;

    CHK(curLen <= requestLen, STATUS_BUFFER_TOO_SMALL);
    requestLen = curLen;

CleanUp:

    if (pRequestLen != NULL) {
        *pRequestLen = requestLen;
    }

    LEAVES();
    return retStatus;
}