- last mhash algo was missed
[m6w6/ext-http] / http_url_api.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21 #include "php.h"
22
23 #include "SAPI.h"
24 #include "zend_ini.h"
25 #include "php_output.h"
26 #include "ext/standard/url.h"
27
28 #include "php_http.h"
29 #include "php_http_api.h"
30 #include "php_http_url_api.h"
31 #include "php_http_std_defs.h"
32
33 #include "phpstr/phpstr.h"
34
35 #ifdef PHP_WIN32
36 # include <winsock2.h>
37 #elif defined(HAVE_NETDB_H)
38 # include <netdb.h>
39 #endif
40
41 ZEND_EXTERN_MODULE_GLOBALS(http);
42
43 /* {{{ char *http_absolute_url(char *) */
44 PHP_HTTP_API char *_http_absolute_url_ex(
45 const char *url, size_t url_len,
46 const char *proto, size_t proto_len,
47 const char *host, size_t host_len,
48 unsigned port TSRMLS_DC)
49 {
50 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
51 struct servent *se;
52 #endif
53 php_url *purl = NULL, furl;
54 size_t full_len = 0;
55 zval *zhost = NULL;
56 char *scheme = NULL, *uri, *URL;
57
58 if ((!url || !url_len) && (
59 (!(url = SG(request_info).request_uri)) ||
60 (!(url_len = strlen(SG(request_info).request_uri))))) {
61 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty");
62 return NULL;
63 }
64
65 URL = ecalloc(1, HTTP_URI_MAXLEN + 1);
66 uri = estrndup(url, url_len);
67 if (!(purl = php_url_parse(uri))) {
68 http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse supplied URL: %s", url);
69 return NULL;
70 }
71
72 furl.user = purl->user;
73 furl.pass = purl->pass;
74 furl.path = purl->path;
75 furl.query = purl->query;
76 furl.fragment = purl->fragment;
77
78 if (proto && proto_len) {
79 furl.scheme = scheme = estrdup(proto);
80 } else if (purl->scheme) {
81 furl.scheme = purl->scheme;
82 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
83 } else if (port && (se = getservbyport(port, "tcp"))) {
84 furl.scheme = (scheme = estrdup(se->s_name));
85 #endif
86 } else {
87 furl.scheme = "http";
88 }
89
90 if (port) {
91 furl.port = port;
92 } else if (purl->port) {
93 furl.port = purl->port;
94 } else if (strncmp(furl.scheme, "http", 4)) {
95 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
96 if (se = getservbyname(furl.scheme, "tcp")) {
97 furl.port = se->s_port;
98 }
99 #endif
100 } else {
101 furl.port = (furl.scheme[4] == 's') ? 443 : 80;
102 }
103
104 if (host) {
105 furl.host = (char *) host;
106 } else if (purl->host) {
107 furl.host = purl->host;
108 } else if ( (zhost = http_get_server_var("HTTP_HOST")) ||
109 (zhost = http_get_server_var("SERVER_NAME"))) {
110 furl.host = Z_STRVAL_P(zhost);
111 } else {
112 furl.host = "localhost";
113 }
114
115 #define HTTP_URI_STRLCATS(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, sizeof(add_string)-1)
116 #define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string))
117 #define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \
118 if ((full_len += add_len) > HTTP_URI_MAXLEN) { \
119 http_error_ex(HE_NOTICE, HTTP_E_URL, \
120 "Absolute URI would have exceeded max URI length (%d bytes) - " \
121 "tried to add %d bytes ('%s')", \
122 HTTP_URI_MAXLEN, add_len, add_string); \
123 if (scheme) { \
124 efree(scheme); \
125 } \
126 php_url_free(purl); \
127 efree(uri); \
128 return URL; \
129 } else { \
130 strcat(URL, add_string); \
131 }
132
133 HTTP_URI_STRLCATL(URL, full_len, furl.scheme);
134 HTTP_URI_STRLCATS(URL, full_len, "://");
135
136 if (furl.user) {
137 HTTP_URI_STRLCATL(URL, full_len, furl.user);
138 if (furl.pass) {
139 HTTP_URI_STRLCATS(URL, full_len, ":");
140 HTTP_URI_STRLCATL(URL, full_len, furl.pass);
141 }
142 HTTP_URI_STRLCATS(URL, full_len, "@");
143 }
144
145 HTTP_URI_STRLCATL(URL, full_len, furl.host);
146
147 if ( (!strcmp(furl.scheme, "http") && (furl.port != 80)) ||
148 (!strcmp(furl.scheme, "https") && (furl.port != 443))) {
149 char port_string[8] = {0};
150 snprintf(port_string, 7, ":%u", furl.port);
151 HTTP_URI_STRLCATL(URL, full_len, port_string);
152 }
153
154 if (furl.path) {
155 if (furl.path[0] != '/') {
156 HTTP_URI_STRLCATS(URL, full_len, "/");
157 }
158 HTTP_URI_STRLCATL(URL, full_len, furl.path);
159 } else {
160 HTTP_URI_STRLCATS(URL, full_len, "/");
161 }
162
163 if (furl.query) {
164 HTTP_URI_STRLCATS(URL, full_len, "?");
165 HTTP_URI_STRLCATL(URL, full_len, furl.query);
166 }
167
168 if (furl.fragment) {
169 HTTP_URI_STRLCATS(URL, full_len, "#");
170 HTTP_URI_STRLCATL(URL, full_len, furl.fragment);
171 }
172
173 if (scheme) {
174 efree(scheme);
175 }
176 php_url_free(purl);
177 efree(uri);
178
179 return URL;
180 }
181 /* }}} */
182
183 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
184 PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
185 char *pre_encoded_data, size_t pre_encoded_len,
186 char **encoded_data, size_t *encoded_len TSRMLS_DC)
187 {
188 char *arg_sep;
189 phpstr *qstr = phpstr_new();
190
191 if (override_argsep || !strlen(arg_sep = INI_STR("arg_separator.output"))) {
192 arg_sep = HTTP_URL_ARGSEP;
193 }
194
195 if (pre_encoded_len && pre_encoded_data) {
196 phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
197 }
198
199 if (SUCCESS != http_urlencode_hash_implementation(hash, qstr, arg_sep)) {
200 phpstr_free(&qstr);
201 return FAILURE;
202 }
203
204 phpstr_data(qstr, encoded_data, encoded_len);
205 phpstr_free(&qstr);
206
207 return SUCCESS;
208 }
209 /* }}} */
210
211 /* {{{ http_urlencode_hash_implementation
212 Original Author: Sara Golemon <pollita@php.net> */
213 PHP_HTTP_API STATUS _http_urlencode_hash_implementation_ex(
214 HashTable *ht, phpstr *formstr, char *arg_sep,
215 const char *num_prefix, int num_prefix_len,
216 const char *key_prefix, int key_prefix_len,
217 const char *key_suffix, int key_suffix_len,
218 zval *type TSRMLS_DC)
219 {
220 char *key = NULL, *ekey, *newprefix, *p;
221 int arg_sep_len, ekey_len, key_type, newprefix_len;
222 uint key_len;
223 ulong idx;
224 zval **zdata = NULL, *copyzval;
225
226 if (!ht || !formstr) {
227 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
228 return FAILURE;
229 }
230
231 if (ht->nApplyCount > 0) {
232 /* Prevent recursion */
233 return SUCCESS;
234 }
235
236 if (!arg_sep || !strlen(arg_sep)) {
237 arg_sep = HTTP_URL_ARGSEP;
238 }
239 arg_sep_len = strlen(arg_sep);
240
241 for (zend_hash_internal_pointer_reset(ht);
242 (key_type = zend_hash_get_current_key_ex(ht, &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT;
243 zend_hash_move_forward(ht)
244 ) {
245 if (key_type == HASH_KEY_IS_STRING && key_len && key[key_len-1] == '\0') {
246 /* We don't want that trailing NULL */
247 key_len -= 1;
248 }
249
250 #ifdef ZEND_ENGINE_2
251 /* handling for private & protected object properties */
252 if (key && *key == '\0' && type != NULL) {
253 char *tmp;
254
255 zend_object *zobj = zend_objects_get_address(type TSRMLS_CC);
256 if (zend_check_property_access(zobj, key TSRMLS_CC) != SUCCESS) {
257 /* private or protected property access outside of the class */
258 continue;
259 }
260 zend_unmangle_property_name(key, &tmp, &key);
261 key_len = strlen(key);
262 }
263 #endif
264
265 if (zend_hash_get_current_data_ex(ht, (void **)&zdata, NULL) == FAILURE || !zdata || !(*zdata)) {
266 http_error(HE_WARNING, HTTP_E_ENCODING, "Error traversing form data array.");
267 return FAILURE;
268 }
269 if (Z_TYPE_PP(zdata) == IS_ARRAY || Z_TYPE_PP(zdata) == IS_OBJECT) {
270 if (key_type == HASH_KEY_IS_STRING) {
271 ekey = php_url_encode(key, key_len, &ekey_len);
272 newprefix_len = key_suffix_len + ekey_len + key_prefix_len + 1;
273 newprefix = emalloc(newprefix_len + 1);
274 p = newprefix;
275
276 if (key_prefix) {
277 memcpy(p, key_prefix, key_prefix_len);
278 p += key_prefix_len;
279 }
280
281 memcpy(p, ekey, ekey_len);
282 p += ekey_len;
283 efree(ekey);
284
285 if (key_suffix) {
286 memcpy(p, key_suffix, key_suffix_len);
287 p += key_suffix_len;
288 }
289
290 *(p++) = '[';
291 *p = '\0';
292 } else {
293 /* Is an integer key */
294 ekey_len = spprintf(&ekey, 12, "%ld", idx);
295 newprefix_len = key_prefix_len + num_prefix_len + ekey_len + key_suffix_len + 1;
296 newprefix = emalloc(newprefix_len + 1);
297 p = newprefix;
298
299 if (key_prefix) {
300 memcpy(p, key_prefix, key_prefix_len);
301 p += key_prefix_len;
302 }
303
304 memcpy(p, num_prefix, num_prefix_len);
305 p += num_prefix_len;
306
307 memcpy(p, ekey, ekey_len);
308 p += ekey_len;
309 efree(ekey);
310
311 if (key_suffix) {
312 memcpy(p, key_suffix, key_suffix_len);
313 p += key_suffix_len;
314 }
315 *(p++) = '[';
316 *p = '\0';
317 }
318 ht->nApplyCount++;
319 http_urlencode_hash_implementation_ex(HASH_OF(*zdata), formstr, arg_sep,
320 NULL, 0, newprefix, newprefix_len, "]", 1, (Z_TYPE_PP(zdata) == IS_OBJECT ? *zdata : NULL));
321 ht->nApplyCount--;
322 efree(newprefix);
323 } else if (Z_TYPE_PP(zdata) == IS_NULL || Z_TYPE_PP(zdata) == IS_RESOURCE) {
324 /* Skip these types */
325 continue;
326 } else {
327 if (formstr->used) {
328 phpstr_append(formstr, arg_sep, arg_sep_len);
329 }
330 /* Simple key=value */
331 phpstr_append(formstr, key_prefix, key_prefix_len);
332 if (key_type == HASH_KEY_IS_STRING) {
333 ekey = php_url_encode(key, key_len, &ekey_len);
334 phpstr_append(formstr, ekey, ekey_len);
335 efree(ekey);
336 } else {
337 /* Numeric key */
338 if (num_prefix) {
339 phpstr_append(formstr, num_prefix, num_prefix_len);
340 }
341 ekey_len = spprintf(&ekey, 12, "%ld", idx);
342 phpstr_append(formstr, ekey, ekey_len);
343 efree(ekey);
344 }
345 phpstr_append(formstr, key_suffix, key_suffix_len);
346 phpstr_appends(formstr, "=");
347 switch (Z_TYPE_PP(zdata)) {
348 case IS_STRING:
349 ekey = php_url_encode(Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata), &ekey_len);
350 break;
351 case IS_LONG:
352 case IS_BOOL:
353 ekey_len = spprintf(&ekey, 12, "%ld", Z_LVAL_PP(zdata));
354 break;
355 case IS_DOUBLE:
356 ekey_len = spprintf(&ekey, 48, "%.*G", (int) EG(precision), Z_DVAL_PP(zdata));
357 break;
358 default:
359 /* fall back on convert to string */
360 MAKE_STD_ZVAL(copyzval);
361 *copyzval = **zdata;
362 zval_copy_ctor(copyzval);
363 convert_to_string_ex(&copyzval);
364 ekey = php_url_encode(Z_STRVAL_P(copyzval), Z_STRLEN_P(copyzval), &ekey_len);
365 zval_ptr_dtor(&copyzval);
366 }
367 phpstr_append(formstr, ekey, ekey_len);
368 efree(ekey);
369 }
370 }
371
372 return SUCCESS;
373 }
374 /* }}} */
375
376 /*
377 * Local variables:
378 * tab-width: 4
379 * c-basic-offset: 4
380 * End:
381 * vim600: noet sw=4 ts=4 fdm=marker
382 * vim<600: noet sw=4 ts=4
383 */
384