in src/source/Common/AwsV4Signer.c [249:403]
STATUS getCanonicalQueryParams(PCHAR pUrl, UINT32 urlLen, BOOL uriEncode, PCHAR* ppQuery, PUINT32 pQueryLen)
{
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
PCHAR pUriStart, pEndPtr, pQueryParamStart, pQueryParamEnd, pParamValue, pNewParam, pCurPtr, pParam, pQuery = NULL;
BOOL iterate = TRUE, inserted, firstParam = TRUE, defaultPath;
PSingleList pSingleList = NULL;
PSingleListNode pCurNode, pPrevNode;
UINT32 nameLen, valueLen, maxLen, remaining, queryLen = 0;
UINT64 item;
CHK(pUrl != NULL && pQueryLen != NULL && ppQuery != NULL, STATUS_NULL_ARG);
if (urlLen == 0) {
urlLen = (UINT32) STRNLEN(pUrl, MAX_URI_CHAR_LEN);
}
pEndPtr = pUrl + urlLen;
// Set the start of the query params to the end of the canonical uri
CHK_STATUS(getCanonicalUri(pUrl, urlLen, &pUriStart, &pQueryParamStart, &defaultPath));
// Check if we have any params
CHK(*pQueryParamStart == '?', retStatus);
// Skip the '?'
pQueryParamStart++;
// Create the single list to hold the sorted params
CHK_STATUS(singleListCreate(&pSingleList));
while (iterate) {
pQueryParamEnd = STRNCHR(pQueryParamStart, (UINT32)(pEndPtr - pQueryParamStart), '&');
if (pQueryParamEnd == NULL) {
// break the loop
iterate = FALSE;
pQueryParamEnd = pEndPtr;
}
// Process the resulting param name and value
CHK(NULL != (pParamValue = STRNCHR(pQueryParamStart, (UINT32)(pQueryParamEnd - pQueryParamStart), '=')), STATUS_INVALID_ARG);
nameLen = (UINT32)(pParamValue - pQueryParamStart);
// Advance param start past '='
pParamValue++;
valueLen = (UINT32)(pQueryParamEnd - pParamValue);
// Max len is 3 times the size of the allocation to account for max bloat for encoding
maxLen = MIN(MAX_URI_CHAR_LEN, nameLen + 1 + valueLen * 3 + 1);
CHK(NULL != (pNewParam = (PCHAR) MEMALLOC(maxLen * SIZEOF(CHAR))), STATUS_NOT_ENOUGH_MEMORY);
pCurPtr = pNewParam;
// Reconstruct the query string
MEMCPY(pCurPtr, pQueryParamStart, nameLen * SIZEOF(CHAR));
pCurPtr += nameLen;
*pCurPtr++ = '=';
// Calculate the remaining, taking into account '=' and the NULL terminator
remaining = maxLen - nameLen - 1 - 1;
// Encode the value
if (uriEncode) {
CHK_STATUS(uriEncodeString(pParamValue, valueLen, pCurPtr, &remaining));
} else {
STRNCPY(pCurPtr, pParamValue, valueLen);
}
// Iterate through the list and insert in an alpha order
CHK_STATUS(singleListGetHeadNode(pSingleList, &pCurNode));
inserted = FALSE;
pPrevNode = NULL;
while (!inserted && pCurNode != NULL) {
CHK_STATUS(singleListGetNodeData(pCurNode, &item));
pParam = (PCHAR) item;
if (STRCMP(pNewParam, pParam) <= 0) {
if (pPrevNode == NULL) {
// Insert at the head
CHK_STATUS(singleListInsertItemHead(pSingleList, (UINT64) pNewParam));
} else {
CHK_STATUS(singleListInsertItemAfter(pSingleList, pPrevNode, (UINT64) pNewParam));
}
// Early return
inserted = TRUE;
}
pPrevNode = pCurNode;
CHK_STATUS(singleListGetNextNode(pCurNode, &pCurNode));
}
if (!inserted) {
// If not inserted then add to the tail
CHK_STATUS(singleListInsertItemTail(pSingleList, (UINT64) pNewParam));
}
// Advance the start
pQueryParamStart = pQueryParamEnd + 1;
}
// Now, we can re-create the query params
remaining = MAX_URI_CHAR_LEN;
CHK(NULL != (pQuery = (PCHAR) MEMALLOC(remaining + 1)), STATUS_NOT_ENOUGH_MEMORY);
*(pQuery + remaining) = '\0';
pCurPtr = pQuery;
CHK_STATUS(singleListGetHeadNode(pSingleList, &pCurNode));
while (pCurNode != NULL) {
CHK_STATUS(singleListGetNodeData(pCurNode, &item));
pParam = (PCHAR) item;
// Account for '&'
maxLen = (UINT32) STRLEN(pParam);
CHK(maxLen + 1 < remaining, STATUS_INVALID_ARG);
if (firstParam) {
firstParam = FALSE;
} else {
*pCurPtr++ = '&';
}
MEMCPY(pCurPtr, pParam, maxLen * SIZEOF(CHAR));
pCurPtr += maxLen;
CHK_STATUS(singleListGetNextNode(pCurNode, &pCurNode));
}
*pCurPtr = '\0';
queryLen = (UINT32)(pCurPtr - pQuery);
CleanUp:
if (pSingleList != NULL) {
singleListClear(pSingleList, TRUE);
singleListFree(pSingleList);
}
if (ppQuery != NULL) {
*ppQuery = pQuery;
}
if (pQueryLen != NULL) {
*pQueryLen = queryLen;
}
LEAVES();
return retStatus;
}