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