ResponseCode WebSocketConnection::InitializeCanonicalQueryString()

in network/WebSocket/WebSocketConnection.cpp [429:550]


        ResponseCode WebSocketConnection::InitializeCanonicalQueryString(util::String &canonical_query_string) const {
            char amz_date[MAX_LEN_FOR_UTCTIME + 1];
            char date_stamp[MAX_LEN_FOR_UTCTIME + 1];
            size_t date_stamp_len;
            size_t amz_date_len;

            {
                // C Style time functions are NOT thread safe, need locking
                std::lock_guard<std::mutex> time_ops_guard(time_ops_lock_);

                // Get current system time
                auto now = std::chrono::system_clock::now();
                std::time_t current_time = std::chrono::system_clock::to_time_t(now);

                // Get time, not required to free this
                struct tm *curr_utc_time = gmtime(&current_time);
                if (nullptr == curr_utc_time) {
                    AWS_LOG_ERROR(WEBSOCKET_WRAPPER_LOG_TAG, "Failed to get UTC Date!!");
                    return ResponseCode::WEBSOCKET_GET_UTC_TIME_FAILED;
                }
                amz_date_len = std::strftime(amz_date, MAX_LEN_FOR_UTCTIME + 1, LONG_DATE_FORMAT_STR, curr_utc_time);
                date_stamp_len =
                    std::strftime(date_stamp, MAX_LEN_FOR_UTCTIME + 1, SIMPLE_DATE_FORMAT_STR, curr_utc_time);
                if (0 == amz_date_len || 0 == date_stamp_len) {
                    AWS_LOG_ERROR(WEBSOCKET_WRAPPER_LOG_TAG, "Failed to convert UTC date to required format!!");
                    return ResponseCode::WEBSOCKET_GET_UTC_TIME_FAILED;
                }
                AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "AmzDate: %s  DateStamp: %s", amz_date, date_stamp);
            }

            AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "Region: %s", aws_region_.c_str());
            util::String credential_scope;
            util::String credential_scope_url_encode;
            InitializeCredentialScope(date_stamp, date_stamp_len, credential_scope, credential_scope_url_encode);

            AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "Credential Scope Url Encoded: %s",
                          credential_scope_url_encode.c_str());

            // X-Amz-Algorithm
            canonical_query_string.append(X_AMZ_ALGORITHM);
            canonical_query_string.append("=");
            canonical_query_string.append(AWS_HMAC_SHA256);

            // X-Amz-Credential
            canonical_query_string.append("&");
            canonical_query_string.append(X_AMZ_CREDENTIAL);
            canonical_query_string.append("=");
            canonical_query_string.append(aws_access_key_id_);
            canonical_query_string.append(SLASH_URLENCODE);
            canonical_query_string.append(credential_scope_url_encode);

            // -> X-Amz-Date
            canonical_query_string.append("&");
            canonical_query_string.append(X_AMZ_DATE);
            canonical_query_string.append("=");
            canonical_query_string.append(amz_date, amz_date_len);

            // -> X-Amz-Expires
            canonical_query_string.append("&");
            canonical_query_string.append(X_AMZ_EXPIRES);
            canonical_query_string.append("=86400");

            // -> X-Amz-SignedHeaders
            canonical_query_string.append("&");
            canonical_query_string.append(X_AMZ_SIGNED_HEADERS);
            canonical_query_string.append("=host");
            AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "CanonicalQuery: %s", canonical_query_string.c_str());

            // Create canonical header string
            util::String canonical_headers;
            canonical_headers.reserve(CANONICAL_HEADER_BUF_LEN);
            canonical_headers.append("host:");
            canonical_headers.append(endpoint_);
            AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "CanonicalHeaders: %s", canonical_headers.c_str());

            // Create canonical request
            util::String canonical_request;
            canonical_request.reserve(CANONICAL_REQUEST_BUF_LEN);
            canonical_request.append(METHOD);
            canonical_request.append("\n");
            canonical_request.append(CANONICAL_URI);
            canonical_request.append("\n");
            canonical_request.append(canonical_query_string);
            canonical_request.append("\n");
            canonical_request.append(canonical_headers);
            canonical_request.append("\n\nhost\n");
            canonical_request.append(EMPTY_BODY_SHA256);
            AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "CanonicalRequest: %s", canonical_request.c_str());

            // Create string to sign
            util::Vector<unsigned char> signed_str;
            signed_str.resize(MAX_SIGNATURE_LEN);
            unsigned int signed_string_len = 0;
            InitializeSignedString(amz_date, date_stamp, date_stamp_len, amz_date_len, credential_scope,
                                   canonical_request, signed_str, signed_string_len);

            // Complete canonical query string
            canonical_query_string.append("&");
            canonical_query_string.append(X_AMZ_SIGNATURE);
            canonical_query_string.append("=");

            size_t itr;
            unsigned char c;
            char temp[3];
            for (itr = 0; itr < signed_string_len; itr++) {
                c = signed_str[itr];
                snprintf(temp, 3, "%02x", c);
                canonical_query_string.append(temp, 2);
            }

            // -> Check session token
            if (0 < aws_session_token_.length()) {
                canonical_query_string.append("&");
                canonical_query_string.append(X_AMZ_SECURITY_TOKEN);
                canonical_query_string.append("=");
                util::String encoded_string = util::String(aws_session_token_);
                UrlEncode(encoded_string, NOT_ENCODED_CHARS);
                canonical_query_string.append(encoded_string);
            }
            AWS_LOG_DEBUG(WEBSOCKET_WRAPPER_LOG_TAG, "CompletedCanonicalQuery: %s", canonical_query_string.c_str());
            return ResponseCode::SUCCESS;
        }