Add: 92) The statistics currently aren't calculated correctly by Privoxy
[privoxy.git] / encode.c
1 const char encode_rcs[] = "$Id: encode.c,v 1.16 2010/06/13 12:27:39 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 * const url_code_map[256] = {
51    NULL, "%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", "+",   "%21", "%22", "%23", "%24", "%25", "%26", "%27",
55    "%28", "%29", NULL,  "%2B", "%2C", NULL,  NULL,  "%2F", NULL,  NULL,
56    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  "%3A", "%3B",
57    "%3C", "%3D", "%3E", "%3F", NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
58    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
59    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
60    NULL,  "%5B", "%5C", "%5D", "%5E", NULL,  "%60", NULL,  NULL,  NULL,
61    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
62    NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,  NULL,
63    NULL,  NULL,  NULL,  "%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 entites. */
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;","&apos;",
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
163    assert(strlen(buf) < buf_size);
164    return(buf);
165 }
166
167
168 /*********************************************************************
169  *
170  * Function    :  html_encode_and_free_original
171  *
172  * Description :  Encodes a string so it's not interpreted as
173  *                containing HTML tags or entities.
174  *                Replaces <, >, &, and " with the appropriate HTML
175  *                entities.  Free()s original string.
176  *                If original string is NULL, simply returns NULL.
177  *
178  * Parameters  :
179  *          1  :  s = String to encode.  Null-terminated.
180  *
181  * Returns     :  Encoded string, newly allocated on the heap. 
182  *                Caller is responsible for freeing it with free().
183  *                If s is NULL, or on out-of memory, returns NULL.
184  *
185  *********************************************************************/
186 char * html_encode_and_free_original(char *s)
187 {
188    char * result;
189    
190    if (s == NULL)
191    {
192       return NULL;
193    }
194
195    result = html_encode(s);
196    free(s);
197
198    return result;
199 }
200
201
202 /*********************************************************************
203  *
204  * Function    :  url_encode
205  *
206  * Description :  Encodes a string so it can be used in a URL
207  *                query string.  Replaces special characters with
208  *                the appropriate %xx codes.
209  *
210  * Parameters  :
211  *          1  :  s = String to encode.  Null-terminated.
212  *
213  * Returns     :  Encoded string, newly allocated on the heap. 
214  *                Caller is responsible for freeing it with free().
215  *                If s is NULL, or on out-of memory, returns NULL.
216  *
217  *********************************************************************/
218 char * url_encode(const char *s)
219 {
220    char * buf;
221    size_t buf_size;
222
223    if (s == NULL)
224    {
225       return NULL;
226    }
227
228    /* each input char can expand to at most 3 chars */
229    buf_size = (strlen(s) * 3) + 1;
230    buf = (char *) malloc(buf_size);
231
232    if (buf)
233    {
234       char c;
235       char * p = buf;
236       while( (c = *s++) != '\0')
237       {
238          const char * replace_with = url_code_map[(unsigned char) c];
239          if (replace_with != NULL)
240          {
241             const size_t bytes_written = (size_t)(p - buf);
242             assert(bytes_written < buf_size);
243             p += strlcpy(p, replace_with, buf_size - bytes_written);
244          }
245          else
246          {
247             *p++ = c;
248          }
249       }
250
251       *p = '\0';
252
253    }
254
255    assert(strlen(buf) < buf_size);
256    return(buf);
257 }
258
259
260 /*********************************************************************
261  *
262  * Function    :  xdtoi
263  *
264  * Description :  Converts a single hex digit to an integer.
265  *
266  * Parameters  :
267  *          1  :  d = in the range of ['0'..'9', 'A'..'F', 'a'..'f']
268  *
269  * Returns     :  The integer value, or -1 for non-hex characters.
270  *
271  *********************************************************************/
272 static int xdtoi(const int d)
273 {
274    if ((d >= '0') && (d <= '9'))
275    {
276       return(d - '0');
277    }
278    else if ((d >= 'a') && (d <= 'f')) 
279    {
280       return(d - 'a' + 10);
281    }
282    else if ((d >= 'A') && (d <= 'F'))
283    {
284       return(d - 'A' + 10);
285    }
286    else
287    {
288       return(-1);
289    }
290 }
291
292
293 /*********************************************************************
294  *
295  * Function    :  xtoi
296  *
297  * Description :  Hex string to integer conversion.
298  *
299  * Parameters  :
300  *          1  :  s = a 2 digit hex string (e.g. "1f").  Only the
301  *                    first two characters will be looked at.
302  *
303  * Returns     :  The integer value, or 0 for non-hex strings.
304  *
305  *********************************************************************/
306 int xtoi(const char *s)
307 {
308    int d1;
309
310    d1 = xdtoi(*s);
311    if(d1 >= 0)
312    {
313       int d2 = xdtoi(*(s+1));
314       if(d2 >= 0)
315       {
316          return (d1 << 4) + d2;
317       }
318    }
319
320    return 0;
321 }
322
323
324 /*********************************************************************
325  *
326  * Function    :  url_decode
327  *
328  * Description :  Decodes a URL query string, replacing %xx codes
329  *                with their decoded form.
330  *
331  * Parameters  :
332  *          1  :  s = String to decode.  Null-terminated.
333  *
334  * Returns     :  Decoded string, newly allocated on the heap. 
335  *                Caller is responsible for freeing it with free().
336  *
337  *********************************************************************/
338 char *url_decode(const char * s)
339 {
340    char *buf = malloc(strlen(s) + 1);
341    char *q = buf;
342
343    if (buf)
344    {
345       while (*s)
346       {
347          switch (*s)
348          {
349             case '+':
350                s++;
351                *q++ = ' ';
352                break;
353
354             case '%':
355                if ((*q = (char)xtoi(s + 1)) != '\0')
356                {
357                   s += 3;
358                   q++;
359                }
360                else
361                {
362                   /* malformed, just use it */
363                   *q++ = *s++;
364                }
365                break;
366
367             default:
368                *q++ = *s++;
369                break;
370          }
371       }
372       *q = '\0';
373    }
374
375    return(buf);
376
377 }
378
379
380 /*
381   Local Variables:
382   tab-width: 3
383   end:
384 */