1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, Daniel Stenberg, <daniel@haxx.se>, et al. 9 * 10 * This software is licensed as described in the file COPYING, which 11 * you should have received as part of this distribution. The terms 12 * are also available at http://curl.haxx.se/docs/copyright.html. 13 * 14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 15 * copies of the Software, and permit persons to whom the Software is 16 * furnished to do so, under the terms of the COPYING file. 17 * 18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 19 * KIND, either express or implied. 20 * 21 ***************************************************************************/ 22 23/* Escape and unescape URL encoding in strings. The functions return a new 24 * allocated string or NULL if an error occurred. */ 25 26#include "setup.h" 27#include <ctype.h> 28#include <curl/curl.h> 29 30#include <stdio.h> 31#include <stdlib.h> 32#include <string.h> 33#include "curl_memory.h" 34#include "urldata.h" 35#include "warnless.h" 36#include "non-ascii.h" 37 38#define _MPRINTF_REPLACE /* use our functions only */ 39#include <curl/mprintf.h> 40 41/* The last #include file should be: */ 42#include "memdebug.h" 43 44/* Portable character check (remember EBCDIC). Do not use isalnum() because 45 its behavior is altered by the current locale. 46 See http://tools.ietf.org/html/rfc3986#section-2.3 47*/ 48static bool Curl_isunreserved(unsigned char in) 49{ 50 switch (in) { 51 case '0': case '1': case '2': case '3': case '4': 52 case '5': case '6': case '7': case '8': case '9': 53 case 'a': case 'b': case 'c': case 'd': case 'e': 54 case 'f': case 'g': case 'h': case 'i': case 'j': 55 case 'k': case 'l': case 'm': case 'n': case 'o': 56 case 'p': case 'q': case 'r': case 's': case 't': 57 case 'u': case 'v': case 'w': case 'x': case 'y': case 'z': 58 case 'A': case 'B': case 'C': case 'D': case 'E': 59 case 'F': case 'G': case 'H': case 'I': case 'J': 60 case 'K': case 'L': case 'M': case 'N': case 'O': 61 case 'P': case 'Q': case 'R': case 'S': case 'T': 62 case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z': 63 case '-': case '.': case '_': case '~': 64 return TRUE; 65 default: 66 break; 67 } 68 return FALSE; 69} 70 71/* for ABI-compatibility with previous versions */ 72char *curl_escape(const char *string, int inlength) 73{ 74 return curl_easy_escape(NULL, string, inlength); 75} 76 77/* for ABI-compatibility with previous versions */ 78char *curl_unescape(const char *string, int length) 79{ 80 return curl_easy_unescape(NULL, string, length, NULL); 81} 82 83char *curl_easy_escape(CURL *handle, const char *string, int inlength) 84{ 85 size_t alloc = (inlength?(size_t)inlength:strlen(string))+1; 86 char *ns; 87 char *testing_ptr = NULL; 88 unsigned char in; /* we need to treat the characters unsigned */ 89 size_t newlen = alloc; 90 int strindex=0; 91 size_t length; 92 CURLcode res; 93 94 ns = malloc(alloc); 95 if(!ns) 96 return NULL; 97 98 length = alloc-1; 99 while(length--) { 100 in = *string; 101 102 if(Curl_isunreserved(in)) 103 /* just copy this */ 104 ns[strindex++]=in; 105 else { 106 /* encode it */ 107 newlen += 2; /* the size grows with two, since this'll become a %XX */ 108 if(newlen > alloc) { 109 alloc *= 2; 110 testing_ptr = realloc(ns, alloc); 111 if(!testing_ptr) { 112 free( ns ); 113 return NULL; 114 } 115 else { 116 ns = testing_ptr; 117 } 118 } 119 120 res = Curl_convert_to_network(handle, &in, 1); 121 if(res) { 122 /* Curl_convert_to_network calls failf if unsuccessful */ 123 free(ns); 124 return NULL; 125 } 126 127 snprintf(&ns[strindex], 4, "%%%02X", in); 128 129 strindex+=3; 130 } 131 string++; 132 } 133 ns[strindex]=0; /* terminate it */ 134 return ns; 135} 136 137/* 138 * Unescapes the given URL escaped string of given length. Returns a 139 * pointer to a malloced string with length given in *olen. 140 * If length == 0, the length is assumed to be strlen(string). 141 * If olen == NULL, no output length is stored. 142 */ 143char *curl_easy_unescape(CURL *handle, const char *string, int length, 144 int *olen) 145{ 146 int alloc = (length?length:(int)strlen(string))+1; 147 char *ns = malloc(alloc); 148 unsigned char in; 149 int strindex=0; 150 unsigned long hex; 151 CURLcode res; 152 153 if(!ns) 154 return NULL; 155 156 while(--alloc > 0) { 157 in = *string; 158 if(('%' == in) && ISXDIGIT(string[1]) && ISXDIGIT(string[2])) { 159 /* this is two hexadecimal digits following a '%' */ 160 char hexstr[3]; 161 char *ptr; 162 hexstr[0] = string[1]; 163 hexstr[1] = string[2]; 164 hexstr[2] = 0; 165 166 hex = strtoul(hexstr, &ptr, 16); 167 168 in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */ 169 170 res = Curl_convert_from_network(handle, &in, 1); 171 if(res) { 172 /* Curl_convert_from_network calls failf if unsuccessful */ 173 free(ns); 174 return NULL; 175 } 176 177 string+=2; 178 alloc-=2; 179 } 180 181 ns[strindex++] = in; 182 string++; 183 } 184 ns[strindex]=0; /* terminate it */ 185 186 if(olen) 187 /* store output size */ 188 *olen = strindex; 189 return ns; 190} 191 192/* For operating systems/environments that use different malloc/free 193 systems for the app and for this library, we provide a free that uses 194 the library's memory system */ 195void curl_free(void *p) 196{ 197 if(p) 198 free(p); 199} 200