Fix verbose messages which didn't show the test number since r1.89
[privoxy.git] / encode.c
1 const char encode_rcs[] = "$Id: encode.c,v 1.28 2012/12/27 15:48:53 fabiankeil Exp $";
2 /*********************************************************************
3  *
4  * File        :  $Source: /cvsroot/ijbswa/current/encode.c,v $
5  *
6  * Purpose     :  Functions to encode and decode URLs, and also to
7  *                encode cookies and HTML text.
8  *
9  * Copyright   :  Written by and Copyright (C) 2001 the
10  *                Privoxy team. http://www.privoxy.org/
11  *
12  *                Based on the Internet Junkbuster originally written
13  *                by and Copyright (C) 1997 Anonymous Coders and
14  *                Junkbusters Corporation.  http://www.junkbusters.com
15  *
16  *                This program is free software; you can redistribute it
17  *                and/or modify it under the terms of the GNU General
18  *                Public License as published by the Free Software
19  *                Foundation; either version 2 of the License, or (at
20  *                your option) any later version.
21  *
22  *                This program is distributed in the hope that it will
23  *                be useful, but WITHOUT ANY WARRANTY; without even the
24  *                implied warranty of MERCHANTABILITY or FITNESS FOR A
25  *                PARTICULAR PURPOSE.  See the GNU General Public
26  *                License for more details.
27  *
28  *                The GNU General Public License should be included with
29  *                this file.  If not, you can view it at
30  *                http://www.gnu.org/copyleft/gpl.html
31  *                or write to the Free Software Foundation, Inc., 59
32  *                Temple Place - Suite 330, Boston, MA  02111-1307, USA.
33  *
34  *********************************************************************/
35
36
37 #include "config.h"
38
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <assert.h>
43
44 #include "miscutil.h"
45 #include "encode.h"
46
47 const char encode_h_rcs[] = ENCODE_H_VERSION;
48
49 /* Maps special characters in a URL to their equivalent % codes. */
50 static const char url_code_map[256][4] = {
51    "",    "%01", "%02", "%03", "%04", "%05", "%06", "%07", "%08", "%09",
52    "%0A", "%0B", "%0C", "%0D", "%0E", "%0F", "%10", "%11", "%12", "%13",
53    "%14", "%15", "%16", "%17", "%18", "%19", "%1A", "%1B", "%1C", "%1D",
54    "%1E", "%1F", "%20", "%21", "%22", "%23", "%24", "%25", "%26", "%27",
55    "%28", "%29", "",    "%2B", "%2C", "",    "",    "%2F", "",    "",
56    "",    "",    "",    "",    "",    "",    "",    "",    "%3A", "%3B",
57    "%3C", "%3D", "%3E", "%3F", "",    "",    "",    "",    "",    "",
58    "",    "",    "",    "",    "",    "",    "",    "",    "",    "",
59    "",    "",    "",    "",    "",    "",    "",    "",    "",    "",
60    "",    "%5B", "%5C", "%5D", "%5E", "",    "%60", "",    "",    "",
61    "",    "",    "",    "",    "",    "",    "",    "",    "",    "",
62    "",    "",    "",    "",    "",    "",    "",    "",    "",    "",
63    "",    "",    "",    "%7B", "%7C", "%7D", "%7E", "%7F", "%80", "%81",
64    "%82", "%83", "%84", "%85", "%86", "%87", "%88", "%89", "%8A", "%8B",
65    "%8C", "%8D", "%8E", "%8F", "%90", "%91", "%92", "%93", "%94", "%95",
66    "%96", "%97", "%98", "%99", "%9A", "%9B", "%9C", "%9D", "%9E", "%9F",
67    "%A0", "%A1", "%A2", "%A3", "%A4", "%A5", "%A6", "%A7", "%A8", "%A9",
68    "%AA", "%AB", "%AC", "%AD", "%AE", "%AF", "%B0", "%B1", "%B2", "%B3",
69    "%B4", "%B5", "%B6", "%B7", "%B8", "%B9", "%BA", "%BB", "%BC", "%BD",
70    "%BE", "%BF", "%C0", "%C1", "%C2", "%C3", "%C4", "%C5", "%C6", "%C7",
71    "%C8", "%C9", "%CA", "%CB", "%CC", "%CD", "%CE", "%CF", "%D0", "%D1",
72    "%D2", "%D3", "%D4", "%D5", "%D6", "%D7", "%D8", "%D9", "%DA", "%DB",
73    "%DC", "%DD", "%DE", "%DF", "%E0", "%E1", "%E2", "%E3", "%E4", "%E5",
74    "%E6", "%E7", "%E8", "%E9", "%EA", "%EB", "%EC", "%ED", "%EE", "%EF",
75    "%F0", "%F1", "%F2", "%F3", "%F4", "%F5", "%F6", "%F7", "%F8", "%F9",
76    "%FA", "%FB", "%FC", "%FD", "%FE", "%FF"
77 };
78
79 /* Maps special characters in HTML to their equivalent entities. */
80 static const char * const html_code_map[256] = {
81    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
82    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
83    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
84    NULL, NULL, NULL, NULL,"&quot;",NULL,NULL,NULL,"&amp;","&#39;",
85    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
86    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
87    "&lt;",NULL,"&gt;",NULL,NULL, NULL, NULL, NULL, NULL, NULL,
88    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
89    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
90    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
91    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
92    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
93    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
94    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
95    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
96    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
97    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
98    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
99    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
100    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
101    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
102    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
103    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
104    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
105    NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
106    NULL, NULL, NULL, NULL, NULL, NULL
107 };
108
109
110 /*********************************************************************
111  *
112  * Function    :  html_encode
113  *
114  * Description :  Encodes a string so it's not interpreted as
115  *                containing HTML tags or entities.
116  *                Replaces <, >, &, and " with the appropriate HTML
117  *                entities.
118  *
119  * Parameters  :
120  *          1  :  s = String to encode.  Null-terminated.
121  *
122  * Returns     :  Encoded string, newly allocated on the heap.
123  *                Caller is responsible for freeing it with free().
124  *                If s is NULL, or on out-of memory, returns NULL.
125  *
126  *********************************************************************/
127 char * html_encode(const char *s)
128 {
129    char * buf;
130    size_t buf_size;
131
132    if (s == NULL)
133    {
134       return NULL;
135    }
136
137    /* each input char can expand to at most 6 chars */
138    buf_size = (strlen(s) * 6) + 1;
139    buf = (char *) malloc(buf_size);
140
141    if (buf)
142    {
143       char c;
144       char * p = buf;
145       while ((c = *s++) != '\0')
146       {
147          const char * replace_with = html_code_map[(unsigned char) c];
148          if (replace_with != NULL)
149          {
150             const size_t bytes_written = (size_t)(p - buf);
151             assert(bytes_written < buf_size);
152             p += strlcpy(p, replace_with, buf_size - bytes_written);
153          }
154          else
155          {
156             *p++ = c;
157          }
158       }
159
160       *p = '\0';
161
162       assert(strlen(buf) < buf_size);
163    }
164
165    return(buf);
166 }
167
168
169 /*********************************************************************
170  *
171  * Function    :  html_encode_and_free_original
172  *
173  * Description :  Encodes a string so it's not interpreted as
174  *                containing HTML tags or entities.
175  *                Replaces <, >, &, and " with the appropriate HTML
176  *                entities.  Free()s original string.
177  *                If original string is NULL, simply returns NULL.
178  *
179  * Parameters  :
180  *          1  :  s = String to encode.  Null-terminated.
181  *
182  * Returns     :  Encoded string, newly allocated on the heap.
183  *                Caller is responsible for freeing it with free().
184  *                If s is NULL, or on out-of memory, returns NULL.
185  *
186  *********************************************************************/
187 char * html_encode_and_free_original(char *s)
188 {
189    char * result;
190
191    if (s == NULL)
192    {
193       return NULL;
194    }
195
196    result = html_encode(s);
197    free(s);
198
199    return result;
200 }
201
202
203 /*********************************************************************
204  *
205  * Function    :  url_encode
206  *
207  * Description :  Encodes a string so it can be used in a URL
208  *                query string.  Replaces special characters with
209  *                the appropriate %xx codes.
210  *
211  *                XXX: url_query_encode() would be a more fitting
212  *                     name.
213  *
214  * Parameters  :
215  *          1  :  s = String to encode.  Null-terminated.
216  *
217  * Returns     :  Encoded string, newly allocated on the heap.
218  *                Caller is responsible for freeing it with free().
219  *                If s is NULL, or on out-of memory, returns NULL.
220  *
221  *********************************************************************/
222 char * url_encode(const char *s)
223 {
224    char * buf;
225    size_t buf_size;
226
227    if (s == NULL)
228    {
229       return NULL;
230    }
231
232    /* each input char can expand to at most 3 chars */
233    buf_size = (strlen(s) * 3) + 1;
234    buf = (char *) malloc(buf_size);
235
236    if (buf)
237    {
238       char c;
239       char * p = buf;
240       while((c = *s++) != '\0')
241       {
242          const char *replace_with = url_code_map[(unsigned char) c];
243          if (*replace_with != '\0')
244          {
245             const size_t bytes_written = (size_t)(p - buf);
246             assert(bytes_written < buf_size);
247             p += strlcpy(p, replace_with, buf_size - bytes_written);
248          }
249          else
250          {
251             *p++ = c;
252          }
253       }
254
255       *p = '\0';
256
257       assert(strlen(buf) < buf_size);
258    }
259
260    return(buf);
261 }
262
263
264 /*********************************************************************
265  *
266  * Function    :  xdtoi
267  *
268  * Description :  Converts a single hex digit to an integer.
269  *
270  * Parameters  :
271  *          1  :  d = in the range of ['0'..'9', 'A'..'F', 'a'..'f']
272  *
273  * Returns     :  The integer value, or -1 for non-hex characters.
274  *
275  *********************************************************************/
276 static int xdtoi(const int d)
277 {
278    if ((d >= '0') && (d <= '9'))
279    {
280       return(d - '0');
281    }
282    else if ((d >= 'a') && (d <= 'f'))
283    {
284       return(d - 'a' + 10);
285    }
286    else if ((d >= 'A') && (d <= 'F'))
287    {
288       return(d - 'A' + 10);
289    }
290    else
291    {
292       return(-1);
293    }
294 }
295
296
297 /*********************************************************************
298  *
299  * Function    :  xtoi
300  *
301  * Description :  Hex string to integer conversion.
302  *
303  * Parameters  :
304  *          1  :  s = a 2 digit hex string (e.g. "1f").  Only the
305  *                    first two characters will be looked at.
306  *
307  * Returns     :  The integer value, or 0 for non-hex strings.
308  *
309  *********************************************************************/
310 int xtoi(const char *s)
311 {
312    int d1;
313
314    d1 = xdtoi(*s);
315    if (d1 >= 0)
316    {
317       int d2 = xdtoi(*(s+1));
318       if (d2 >= 0)
319       {
320          return (d1 << 4) + d2;
321       }
322    }
323
324    return 0;
325 }
326
327
328 /*********************************************************************
329  *
330  * Function    :  url_decode
331  *
332  * Description :  Decodes a URL query string, replacing %xx codes
333  *                with their decoded form.
334  *
335  * Parameters  :
336  *          1  :  s = String to decode.  Null-terminated.
337  *
338  * Returns     :  Decoded string, newly allocated on the heap.
339  *                Caller is responsible for freeing it with free().
340  *
341  *********************************************************************/
342 char *url_decode(const char * s)
343 {
344    char *buf = malloc(strlen(s) + 1);
345    char *q = buf;
346
347    if (buf)
348    {
349       while (*s)
350       {
351          switch (*s)
352          {
353             case '+':
354                s++;
355                *q++ = ' ';
356                break;
357
358             case '%':
359                if ((*q = (char)xtoi(s + 1)) != '\0')
360                {
361                   s += 3;
362                   q++;
363                }
364                else
365                {
366                   /* malformed, just use it */
367                   *q++ = *s++;
368                }
369                break;
370
371             default:
372                *q++ = *s++;
373                break;
374          }
375       }
376       *q = '\0';
377    }
378
379    return(buf);
380
381 }
382
383
384 /*********************************************************************
385  *
386  * Function    :  percent_encode_url
387  *
388  * Description :  Percent-encodes a string so it no longer contains
389  *                any characters that aren't valid in an URL according
390  *                to RFC 3986.
391  *
392  *                XXX: Do not confuse with encode_url()
393  *
394  * Parameters  :
395  *          1  :  s = String to encode.  Null-terminated.
396  *
397  * Returns     :  Encoded string, newly allocated on the heap.
398  *                Caller is responsible for freeing it with free().
399  *                If s is NULL, or on out-of memory, returns NULL.
400  *
401  *********************************************************************/
402 char *percent_encode_url(const char *s)
403 {
404    static const char allowed_characters[128] = {
405       '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
406       '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
407       '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0',
408       '\0', '\0', '\0', '!',  '\0', '#',  '$',  '%',  '&',  '\'',
409       '(',  ')',  '*',  '+',  ',',  '-',  '.',  '/',  '0',  '1',
410       '2',  '3',  '4',  '5',  '6',  '7',  '8',  '9',  ':',  ';',
411       '\0', '=',  '\0', '?',  '@',  'A',  'B',  'C',  'D',  'E',
412       'F',  'G',  'H',  'I',  'J',  'K',  'L',  'M',  'N',  'O',
413       'P',  'Q',  'R',  'S',  'T',  'U',  'V',  'W',  'X',  'Y',
414       'Z',  '[',  '\0', ']',  '\0', '_',  '\0', 'a',  'b',  'c',
415       'd',  'e',  'f',  'g',  'h',  'i',  'j',  'k',  'l',  'm',
416       'n',  'o',  'p',  'q',  'r',  's',  't',  'u',  'v',  'w',
417       'x',  'y',  'z',  '\0', '\0', '\0', '~',  '\0'
418    };
419    char *buf;
420    size_t buf_size;
421
422    assert(s != NULL);
423
424    /* Each input char can expand to at most 3 chars. */
425    buf_size = (strlen(s) * 3) + 1;
426    buf = (char *)malloc(buf_size);
427
428    if (buf != NULL)
429    {
430       char c;
431       char *p = buf;
432       while ((c = *s++) != '\0')
433       {
434          const unsigned int i = (unsigned char)c;
435          if (i >= sizeof(allowed_characters) || '\0' == allowed_characters[i])
436          {
437             const char *replace_with = url_code_map[i];
438             assert(*replace_with != '\0');
439             if (*replace_with != '\0')
440             {
441                const size_t bytes_written = (size_t)(p - buf);
442                assert(bytes_written < buf_size);
443                p += strlcpy(p, replace_with, buf_size - bytes_written);
444             }
445          }
446          else
447          {
448             *p++ = c;
449          }
450       }
451       *p = '\0';
452
453       assert(strlen(buf) < buf_size);
454    }
455
456    return(buf);
457
458 }
459
460
461 /*
462   Local Variables:
463   tab-width: 3
464   end:
465 */