Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: STM32F746_iothub_client_sample_mqtt f767zi_mqtt iothub_client_sample_amqp iothub_client_sample_http ... more
urlencode.c
00001 // Copyright (c) Microsoft. All rights reserved. 00002 // Licensed under the MIT license. See LICENSE file in the project root for full license information. 00003 00004 #include <stdlib.h> 00005 #include <stddef.h> 00006 #include <string.h> 00007 #include "azure_c_shared_utility/gballoc.h" 00008 #include "azure_c_shared_utility/urlencode.h" 00009 #include "azure_c_shared_utility/xlogging.h" 00010 #include "azure_c_shared_utility/strings.h" 00011 #include "azure_c_shared_utility/crt_abstractions.h" 00012 00013 #define NIBBLE_TO_STRING(c) (char)((c) < 10 ? (c) + '0' : (c) - 10 + 'a') 00014 #define NIBBLE_FROM_STRING(c) (char)(ISDIGIT(c) ? (c) - '0' : TOUPPER(c) + 10 - 'A') 00015 #define IS_HEXDIGIT(c) ( \ 00016 ((c >= '0') && (c <= '9')) || \ 00017 ((c >= 'A') && (c <= 'F')) || \ 00018 ((c >= 'a') && (c <= 'f')) \ 00019 ) 00020 #define IS_PRINTABLE(c) ( \ 00021 (c == 0) || \ 00022 (c == '!') || \ 00023 (c == '(') || (c == ')') || (c == '*') || \ 00024 (c == '-') || (c == '.') || \ 00025 ((c >= '0') && (c <= '9')) || \ 00026 ((c >= 'A') && (c <= 'Z')) || \ 00027 (c == '_') || \ 00028 ((c >= 'a') && (c <= 'z')) \ 00029 ) 00030 00031 /*The below macros are to be called on the big nibble of a hex value*/ 00032 #define IS_IN_ASCII_RANGE(c) ( \ 00033 (c >= '0') && (c <= '7') \ 00034 ) 00035 #define IS_IN_EXTENDED_ASCII_RANGE(c) ( \ 00036 ((c >= '8') && (c <= '9')) || \ 00037 ((c >= 'A') && (c <= 'F')) || \ 00038 ((c >= 'a') && (c <= 'f')) \ 00039 ) 00040 #define IS_IN_CONTINUATION_BYTE_RANGE(c) ( \ 00041 (c == '8') || (c == '9') || \ 00042 (c == 'A') || (c == 'B') || \ 00043 (c == 'a') || (c == 'b') \ 00044 ) 00045 #define IS_IN_LEADING_BYTE_RANGE(c) ( \ 00046 ((c >= 'C') && (c <= 'F')) || \ 00047 ((c >= 'c') && (c <= 'f')) \ 00048 ) 00049 #define IS_IN_UNSUPPORTED_LEADING_BYTE_RANGE(c) ( \ 00050 ((c >= 'D') && (c <= 'F')) || \ 00051 ((c >= 'd') && (c <= 'f')) \ 00052 ) 00053 00054 static size_t URL_PrintableChar(unsigned char charVal, char* buffer) 00055 { 00056 size_t size; 00057 if (IS_PRINTABLE(charVal)) 00058 { 00059 buffer[0] = (char)charVal; 00060 size = 1; 00061 } 00062 else 00063 { 00064 char bigNibbleStr; 00065 char littleNibbleStr; 00066 unsigned char bigNibbleVal = charVal >> 4; 00067 unsigned char littleNibbleVal = charVal & 0x0F; 00068 00069 if (bigNibbleVal >= 0x0C) 00070 { 00071 bigNibbleVal -= 0x04; 00072 } 00073 00074 bigNibbleStr = NIBBLE_TO_STRING(bigNibbleVal); 00075 littleNibbleStr = NIBBLE_TO_STRING(littleNibbleVal); 00076 00077 buffer[0] = '%'; 00078 00079 if (charVal < 0x80) 00080 { 00081 buffer[1] = bigNibbleStr; 00082 buffer[2] = littleNibbleStr; 00083 size = 3; 00084 } 00085 else 00086 { 00087 buffer[1] = 'c'; 00088 buffer[3] = '%'; 00089 buffer[4] = bigNibbleStr; 00090 buffer[5] = littleNibbleStr; 00091 if (charVal < 0xC0) 00092 { 00093 buffer[2] = '2'; 00094 } 00095 else 00096 { 00097 buffer[2] = '3'; 00098 } 00099 size = 6; 00100 } 00101 } 00102 00103 return size; 00104 } 00105 00106 static size_t calculateDecodedStringSize(const char* encodedString, size_t len) 00107 { 00108 size_t decodedSize = 0; 00109 00110 if (encodedString == NULL) 00111 { 00112 LogError("Null encoded string"); 00113 } 00114 else if (len == 0) 00115 { 00116 decodedSize = 1; //for null terminator 00117 } 00118 else 00119 { 00120 size_t remaining_len = len; 00121 size_t next_step = 0; 00122 size_t i = 0; 00123 while (i < len) 00124 { 00125 //percent encoded character 00126 if (encodedString[i] == '%') 00127 { 00128 if (remaining_len < 3 || !IS_HEXDIGIT(encodedString[i+1]) || !IS_HEXDIGIT(encodedString[i+2])) 00129 { 00130 LogError("Incomplete or invalid percent encoding"); 00131 break; 00132 } 00133 else if (!IS_IN_ASCII_RANGE(encodedString[i+1])) 00134 { 00135 LogError("Out of range of characters accepted by this decoder"); 00136 break; 00137 } 00138 else 00139 { 00140 decodedSize++; 00141 next_step = 3; 00142 } 00143 } 00144 else if (!IS_PRINTABLE(encodedString[i])) 00145 { 00146 LogError("Unprintable value in encoded string"); 00147 break; 00148 } 00149 //safe character 00150 else 00151 { 00152 decodedSize++; 00153 next_step = 1; 00154 } 00155 00156 i += next_step; 00157 remaining_len -= next_step; 00158 } 00159 00160 if (encodedString[i] != '\0') //i.e. broke out of above loop due to error 00161 { 00162 decodedSize = 0; 00163 } 00164 else 00165 { 00166 decodedSize++; //add space for the null terminator 00167 } 00168 } 00169 return decodedSize; 00170 } 00171 00172 static unsigned char charFromNibbles(char bigNibbleStr, char littleNibbleStr) 00173 { 00174 unsigned char bigNibbleVal = NIBBLE_FROM_STRING(bigNibbleStr); 00175 unsigned char littleNibbleVal = NIBBLE_FROM_STRING(littleNibbleStr); 00176 00177 return bigNibbleVal << 4 | littleNibbleVal; 00178 } 00179 00180 static void createDecodedString(const char* input, size_t input_size, char* output) 00181 { 00182 /* Note that there is no danger of reckless indexing here, as calculateDecodedStringSize() 00183 has already checked lengths of strings to ensure the formatting is always correct*/ 00184 size_t i = 0; 00185 while (i <= input_size) //the <= instead of < ensures the '\0' will be copied 00186 { 00187 if (input[i] != '%') 00188 { 00189 *output++ = input[i]; 00190 i++; 00191 } 00192 else 00193 { 00194 *output++ = charFromNibbles(input[i+1], input[i+2]); 00195 i += 3; 00196 } 00197 } 00198 } 00199 00200 static size_t URL_PrintableCharSize(unsigned char charVal) 00201 { 00202 size_t size; 00203 if (IS_PRINTABLE(charVal)) 00204 { 00205 size = 1; 00206 } 00207 else 00208 { 00209 if (charVal < 0x80) 00210 { 00211 size = 3; 00212 } 00213 else 00214 { 00215 size = 6; 00216 } 00217 } 00218 return size; 00219 } 00220 00221 static STRING_HANDLE encode_url_data(const char* text) 00222 { 00223 STRING_HANDLE result; 00224 size_t lengthOfResult = 0; 00225 char* encodedURL; 00226 unsigned char currentUnsignedChar; 00227 const char* iterator = text; 00228 00229 /*Codes_SRS_URL_ENCODE_06_003: [If input is a zero length string then URL_Encode will return a zero length string.]*/ 00230 do 00231 { 00232 currentUnsignedChar = (unsigned char)(*iterator++); 00233 lengthOfResult += URL_PrintableCharSize(currentUnsignedChar); 00234 } while (currentUnsignedChar != 0); 00235 00236 if ((encodedURL = (char*)malloc(lengthOfResult)) == NULL) 00237 { 00238 /*Codes_SRS_URL_ENCODE_06_002: [If an error occurs during the encoding of input then URL_Encode will return NULL.]*/ 00239 result = NULL; 00240 LogError("URL_Encode:: MALLOC failure on encode."); 00241 } 00242 else 00243 { 00244 size_t currentEncodePosition = 0; 00245 iterator = text;; 00246 do 00247 { 00248 currentUnsignedChar = (unsigned char)(*iterator++); 00249 currentEncodePosition += URL_PrintableChar(currentUnsignedChar, &encodedURL[currentEncodePosition]); 00250 } while (currentUnsignedChar != 0); 00251 00252 result = STRING_new_with_memory(encodedURL); 00253 if (result == NULL) 00254 { 00255 LogError("URL_Encode:: MALLOC failure on encode."); 00256 free(encodedURL); 00257 } 00258 } 00259 return result; 00260 } 00261 00262 STRING_HANDLE URL_EncodeString(const char* textEncode) 00263 { 00264 STRING_HANDLE result; 00265 if (textEncode == NULL) 00266 { 00267 result = NULL; 00268 } 00269 else 00270 { 00271 result = encode_url_data(textEncode); 00272 } 00273 return result; 00274 } 00275 00276 STRING_HANDLE URL_Encode(STRING_HANDLE input) 00277 { 00278 STRING_HANDLE result; 00279 if (input == NULL) 00280 { 00281 /*Codes_SRS_URL_ENCODE_06_001: [If input is NULL then URL_Encode will return NULL.]*/ 00282 result = NULL; 00283 LogError("URL_Encode:: NULL input"); 00284 } 00285 else 00286 { 00287 result = encode_url_data(STRING_c_str(input)); 00288 } 00289 return result; 00290 } 00291 00292 STRING_HANDLE URL_DecodeString(const char* textDecode) 00293 { 00294 STRING_HANDLE result; 00295 if (textDecode == NULL) 00296 { 00297 result = NULL; 00298 } 00299 else 00300 { 00301 STRING_HANDLE tempString = STRING_construct(textDecode); 00302 if (tempString == NULL) 00303 { 00304 result = NULL; 00305 } 00306 else 00307 { 00308 result = URL_Decode(tempString); 00309 STRING_delete(tempString); 00310 } 00311 } 00312 return result; 00313 } 00314 00315 STRING_HANDLE URL_Decode(STRING_HANDLE input) 00316 { 00317 STRING_HANDLE result; 00318 if (input == NULL) 00319 { 00320 LogError("URL_Decode:: NULL input"); 00321 result = NULL; 00322 } 00323 else 00324 { 00325 size_t decodedStringSize; 00326 char* decodedString; 00327 const char* inputString = STRING_c_str(input); 00328 size_t inputLen = strlen(inputString); 00329 if ((decodedStringSize = calculateDecodedStringSize(inputString, inputLen)) == 0) 00330 { 00331 LogError("URL_Decode:: Invalid input string"); 00332 result = NULL; 00333 } 00334 else if ((decodedString = (char*)malloc(decodedStringSize)) == NULL) 00335 { 00336 LogError("URL_Decode:: MALLOC failure on decode."); 00337 result = NULL; 00338 } 00339 else 00340 { 00341 createDecodedString(inputString, inputLen, decodedString); 00342 result = STRING_new_with_memory(decodedString); 00343 if (result == NULL) 00344 { 00345 LogError("URL_Decode:: MALLOC failure on decode"); 00346 free(decodedString); 00347 } 00348 } 00349 } 00350 return result; 00351 }
Generated on Wed Jul 13 2022 23:38:02 by
1.7.2
