1 /*
2 * Portions taken from libapreq 1.33.
3 * Copyright 2007 The Apache Software Foundation.
4 * Used under the Apache License v2.0.
5 * http://search.cpan.org/~stas/libapreq-1.33/
6 */
7
8 #ifndef __USE_GNU
9 #define __USE_GNU
10 #endif
11 #include <string.h>
12 #include <ctype.h>
13 #include <stdio.h>
14 #include <stdlib.h>
15
16 #include "parser.h"
17
18 static
19 void
req_plustospace(char * str)20 req_plustospace(char* str)
21 {
22 register int x;
23 for(x=0;str[x];x++)
24 if(str[x] == '+')
25 str[x] = ' ';
26 }
27
28 static
29 char
x2c(char * what)30 x2c(char* what)
31 {
32 register char digit;
33
34 digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A') + 10 : (what[0] - '0'));
35 digit *= 16;
36 digit += (what[1] >= 'A' ? ((what[1] & 0xdf) - 'A') + 10 : (what[1] - '0'));
37 return digit;
38 }
39
40 static
41 unsigned int
utf8_convert(char * str)42 utf8_convert(char* str)
43 {
44 long x = 0;
45 int i = 0;
46 while (i < 4 ) {
47 if ( isxdigit(str[i]) != 0 ) {
48 if( isdigit(str[i]) != 0 ) {
49 x = x * 16 + str[i] - '0';
50 }
51 else {
52 str[i] = tolower( str[i] );
53 x = x * 16 + str[i] - 'a' + 10;
54 }
55 }
56 else {
57 return 0;
58 }
59 i++;
60 }
61 if(i < 3)
62 return 0;
63 return (x);
64 }
65
66 static
67 int
unescape_url_u(char * url)68 unescape_url_u(char* url)
69 {
70 register int x, y, badesc, badpath;
71
72 badesc = 0;
73 badpath = 0;
74 for (x = 0, y = 0; url[y]; ++x, ++y) {
75 if (url[y] != '%'){
76 url[x] = url[y];
77 }
78 else {
79 if(url[y + 1] == 'u' || url[y + 1] == 'U'){
80 unsigned int c = utf8_convert(&url[y + 2]);
81 y += 5;
82 if(c < 0x80){
83 url[x] = c;
84 }
85 else if(c < 0x800) {
86 url[x] = 0xc0 | (c >> 6);
87 url[++x] = 0x80 | (c & 0x3f);
88 }
89 else if(c < 0x10000){
90 url[x] = (0xe0 | (c >> 12));
91 url[++x] = (0x80 | ((c >> 6) & 0x3f));
92 url[++x] = (0x80 | (c & 0x3f));
93 }
94 else if(c < 0x200000){
95 url[x] = 0xf0 | (c >> 18);
96 url[++x] = 0x80 | ((c >> 12) & 0x3f);
97 url[++x] = 0x80 | ((c >> 6) & 0x3f);
98 url[++x] = 0x80 | (c & 0x3f);
99 }
100 else if(c < 0x4000000){
101 url[x] = 0xf8 | (c >> 24);
102 url[++x] = 0x80 | ((c >> 18) & 0x3f);
103 url[++x] = 0x80 | ((c >> 12) & 0x3f);
104 url[++x] = 0x80 | ((c >> 6) & 0x3f);
105 url[++x] = 0x80 | (c & 0x3f);
106 }
107 else if(c < 0x8000000){
108 url[x] = 0xfe | (c >> 30);
109 url[++x] = 0x80 | ((c >> 24) & 0x3f);
110 url[++x] = 0x80 | ((c >> 18) & 0x3f);
111 url[++x] = 0x80 | ((c >> 12) & 0x3f);
112 url[++x] = 0x80 | ((c >> 6) & 0x3f);
113 url[++x] = 0x80 | (c & 0x3f);
114 }
115 }
116 else {
117 if (!isxdigit(url[y + 1]) || !isxdigit(url[y + 2])) {
118 badesc = 1;
119 url[x] = '%';
120 }
121 else {
122 url[x] = x2c(&url[y + 1]);
123 y += 2;
124 if (url[x] == '/' || url[x] == '\0')
125 badpath = 1;
126 }
127 }
128 }
129 }
130 url[x] = '\0';
131 if (badesc)
132 return 0;
133 else if (badpath)
134 return 0;
135 else
136 return 1;
137 }
138
139 static
140 char*
_strndup(char * str,size_t len)141 _strndup(char* str, size_t len)
142 {
143 char *dup = (char*) malloc(len+1);
144 if (dup) {
145 strncpy(dup, str, len);
146 dup[len] = '\0';
147 }
148 return dup;
149 }
150
151
152 static
153 char*
urlword(char ** line)154 urlword(char** line)
155 {
156 char* res = 0;
157 char* pos = *line;
158 char ch;
159
160 while ( (ch = *pos) != '\0' && ch != ';' && ch != '&') {
161 ++pos;
162 }
163
164 res = _strndup(*line, pos - *line);
165
166 while (ch == ';' || ch == '&') {
167 ++pos;
168 ch = *pos;
169 }
170
171 *line = pos;
172
173 return res;
174 }
175
176 char*
getword(char ** line,char stop)177 getword(char** line, char stop)
178 {
179 char* pos = *line;
180 int len;
181 char* res;
182
183 while ((*pos != stop) && *pos) {
184 ++pos;
185 }
186
187 len = pos - *line;
188 res = (char*)malloc(len + 1);
189 memcpy(res, *line, len);
190 res[len] = 0;
191
192 if (stop) {
193 while (*pos == stop) {
194 ++pos;
195 }
196 }
197 *line = pos;
198
199 return res;
200 }
201
202 SV*
_split_to_parms(char * data)203 _split_to_parms(char* data)
204 {
205 char* val;
206 HV* hash = 0;
207
208 while (*data && (val = urlword(&data))) {
209 char* val_orig = val;
210 char* key = getword(&val, '=');
211
212 req_plustospace((char*)key);
213 unescape_url_u((char*)key);
214 req_plustospace((char*)val);
215 unescape_url_u((char*)val);
216
217 if (!hash) {
218 hash = newHV();
219 }
220
221 int klen = strlen(key);
222 SV* newval = newSVpv(val, 0);
223
224 if (hv_exists(hash, key, klen)) {
225 /* this param already exists */
226
227 SV** entry = hv_fetch(hash, key, klen, 0);
228 if (!entry) {
229 return 0;
230 }
231
232 if (SvROK(*entry) && SvTYPE(SvRV(*entry)) == SVt_PVAV) {
233 /* already an arrayref, just push to the end */
234 av_push((AV*) SvRV(*entry), newval);
235 }
236 else {
237 /* just a scalar; wrap the new and old values in an arrayref */
238 SV* values[2] = { *entry, newval };
239 AV* array = av_make(2, values); /* this copies the SVs... */
240 SvREFCNT_dec(newval); /* ... so destroy the original. */
241 SV* aref = newRV_noinc((SV*) array); /* create an array ref... */
242 hv_store(hash, key, klen, aref, 0); /* ... and stash it in the hash */
243 }
244 }
245 else {
246 /* no existing param, pop this one in */
247 hv_store(hash, key, klen, newval, 0);
248 }
249
250 free(key);
251 free(val_orig);
252 }
253
254 return hash ? newRV_noinc((SV*) hash) : 0;
255 }
256