- add flush() to encoding stream (filters)
[m6w6/ext-http] / http_url_api.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2005, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 /* $Id$ */
14
15 #ifdef HAVE_CONFIG_H
16 # include "config.h"
17 #endif
18
19 #define HTTP_WANT_NETDB
20 #include "php_http.h"
21
22 #include "SAPI.h"
23 #include "zend_ini.h"
24 #include "php_output.h"
25 #include "ext/standard/php_string.h"
26
27 #include "php_http_api.h"
28 #include "php_http_url_api.h"
29
30 ZEND_EXTERN_MODULE_GLOBALS(http);
31
32 PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC)
33 {
34 char *abs = estrdup(url);
35 php_url *purl = php_url_parse(abs);
36
37 STR_SET(abs, NULL);
38
39 if (purl) {
40 http_build_url(purl, NULL, NULL, &abs, NULL);
41 php_url_free(purl);
42 }
43
44 return abs;
45 }
46
47 /* {{{ void http_build_url(const php_url *, const php_url *, php_url **, char **, size_t *) */
48 PHP_HTTP_API void _http_build_url(const php_url *old_url, const php_url *new_url, php_url **url_ptr, char **url_str, size_t *url_len TSRMLS_DC)
49 {
50 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
51 struct servent *se;
52 #endif
53 php_url *url = emalloc(sizeof(php_url));
54
55 #define __URLCPY(n) \
56 url->n = (new_url&&new_url->n) ? estrdup(new_url->n) : ((old_url&&old_url->n) ? estrdup(old_url->n) : NULL)
57 url->port = (new_url&&new_url->port) ? new_url->port : ((old_url) ? old_url->port : 0);
58 __URLCPY(scheme);
59 __URLCPY(user);
60 __URLCPY(pass);
61 __URLCPY(host);
62 __URLCPY(path);
63 __URLCPY(query);
64 __URLCPY(fragment);
65
66 if (!url->scheme) {
67 switch (url->port)
68 {
69 case 443:
70 url->scheme = estrndup("https", lenof("https"));
71 break;
72
73 #if !defined(PHP_WIN32) && !defined(HAVE_NETDB_H)
74 default:
75 #endif
76 case 80:
77 url->scheme = estrndup("http", lenof("http"));
78 break;
79
80 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
81 default:
82 if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
83 url->scheme = estrdup(se->s_name);
84 } else {
85 url->scheme = estrndup("http", lenof("http"));
86 }
87 break;
88 #endif
89 }
90 }
91
92 if (!url->host) {
93 zval *zhost;
94
95 if ((((zhost = http_get_server_var("HTTP_HOST")) ||
96 (zhost = http_get_server_var("SERVER_NAME")))) && Z_STRLEN_P(zhost)) {
97 url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
98 } else {
99 url->host = estrndup("localhost", lenof("localhost"));
100 }
101 }
102
103 if (!url->path) {
104 if (SG(request_info).request_uri && *SG(request_info).request_uri) {
105 const char *q = strchr(SG(request_info).request_uri, '?');
106
107 if (q) {
108 url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
109 } else {
110 url->path = estrdup(SG(request_info).request_uri);
111 }
112 } else {
113 url->path = estrndup("/", 1);
114 }
115 } else if (*url->path != '/') {
116 if (SG(request_info).request_uri && *SG(request_info).request_uri) {
117 const char *q = strchr(SG(request_info).request_uri, '?');
118 char *uri, *path;
119 size_t len;
120
121 if (q) {
122 uri = estrndup(SG(request_info).request_uri, len = q - SG(request_info).request_uri);
123 } else {
124 uri = estrndup(SG(request_info).request_uri, len = strlen(SG(request_info).request_uri));
125 }
126
127 php_dirname(uri, len);
128 spprintf(&path, 0, "%s/%s", uri, url->path);
129 efree(uri);
130 STR_SET(url->path, path);
131 } else {
132 char *uri;
133
134 spprintf(&uri, 0, "/%s", url->path);
135 STR_SET(url->path, uri);
136 }
137 }
138
139 if (url->port) {
140 if ( ((url->port == 80) && !strcmp(url->scheme, "http"))
141 || ((url->port ==443) && !strcmp(url->scheme, "https"))
142 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
143 || ((se = getservbyname(url->scheme, "tcp")) && se->s_port &&
144 (url->port == ntohs(se->s_port)))
145 #endif
146 ) {
147 url->port = 0;
148 }
149 }
150
151 if (url_str) {
152 size_t len;
153
154 *url_str = emalloc(HTTP_URL_MAXLEN + 1);
155
156 **url_str = '\0';
157 strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN);
158 strlcat(*url_str, "://", HTTP_URL_MAXLEN);
159
160 if (url->user && *url->user) {
161 strlcat(*url_str, url->user, HTTP_URL_MAXLEN);
162 if (url->pass && *url->pass) {
163 strlcat(*url_str, ":", HTTP_URL_MAXLEN);
164 strlcat(*url_str, url->pass, HTTP_URL_MAXLEN);
165 }
166 strlcat(*url_str, "@", HTTP_URL_MAXLEN);
167 }
168
169 strlcat(*url_str, url->host, HTTP_URL_MAXLEN);
170
171 if (url->port) {
172 char port_str[6] = {0};
173
174 snprintf(port_str, 5, "%d", (int) url->port);
175 strlcat(*url_str, ":", HTTP_URL_MAXLEN);
176 strlcat(*url_str, port_str, HTTP_URL_MAXLEN);
177 }
178
179 if (*url->path != '/') {
180 strlcat(*url_str, "/", HTTP_URL_MAXLEN);
181 }
182 strlcat(*url_str, url->path, HTTP_URL_MAXLEN);
183
184 if (url->query && *url->query) {
185 strlcat(*url_str, "?", HTTP_URL_MAXLEN);
186 strlcat(*url_str, url->query, HTTP_URL_MAXLEN);
187 }
188
189 if (url->fragment && *url->fragment) {
190 strlcat(*url_str, "#", HTTP_URL_MAXLEN);
191 strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN);
192 }
193
194 if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) {
195 http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN");
196 }
197 if (url_len) {
198 *url_len = len;
199 }
200 }
201
202 if (url_ptr) {
203 *url_ptr = url;
204 } else {
205 php_url_free(url);
206 }
207 }
208 /* }}} */
209
210 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
211 PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
212 char *pre_encoded_data, size_t pre_encoded_len,
213 char **encoded_data, size_t *encoded_len TSRMLS_DC)
214 {
215 char *arg_sep;
216 size_t arg_sep_len;
217 phpstr *qstr = phpstr_new();
218
219 if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
220 arg_sep = HTTP_URL_ARGSEP;
221 arg_sep_len = lenof(HTTP_URL_ARGSEP);
222 }
223
224 if (pre_encoded_len && pre_encoded_data) {
225 phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
226 }
227
228 if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
229 phpstr_free(&qstr);
230 return FAILURE;
231 }
232
233 phpstr_data(qstr, encoded_data, encoded_len);
234 phpstr_free(&qstr);
235
236 return SUCCESS;
237 }
238 /* }}} */
239
240 /* {{{ http_urlencode_hash_recursive */
241 PHP_HTTP_API STATUS _http_urlencode_hash_recursive(HashTable *ht, phpstr *str, const char *arg_sep, size_t arg_sep_len, const char *prefix, size_t prefix_len TSRMLS_DC)
242 {
243 char *key = NULL;
244 uint len = 0;
245 ulong idx = 0;
246 zval **data = NULL;
247 HashPosition pos;
248
249 if (!ht || !str) {
250 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
251 return FAILURE;
252 }
253 if (ht->nApplyCount > 0) {
254 return SUCCESS;
255 }
256
257 FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) {
258 char *encoded_key;
259 int encoded_len;
260 phpstr new_prefix;
261
262 if (!data || !*data) {
263 return FAILURE;
264 }
265
266 if (key) {
267 if (len && key[len - 1] == '\0') {
268 --len;
269 }
270 encoded_key = php_url_encode(key, len, &encoded_len);
271 key = NULL;
272 } else {
273 encoded_len = spprintf(&encoded_key, 0, "%ld", idx);
274 }
275
276 {
277 phpstr_init(&new_prefix);
278 if (prefix && prefix_len) {
279 phpstr_append(&new_prefix, prefix, prefix_len);
280 phpstr_appends(&new_prefix, "[");
281 }
282
283 phpstr_append(&new_prefix, encoded_key, encoded_len);
284 efree(encoded_key);
285
286 if (prefix && prefix_len) {
287 phpstr_appends(&new_prefix, "]");
288 }
289 phpstr_fix(&new_prefix);
290 }
291
292 if (Z_TYPE_PP(data) == IS_ARRAY) {
293 STATUS status;
294 ++ht->nApplyCount;
295 status = http_urlencode_hash_recursive(Z_ARRVAL_PP(data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
296 --ht->nApplyCount;
297 if (SUCCESS != status) {
298 phpstr_dtor(&new_prefix);
299 return FAILURE;
300 }
301 } else {
302 zval *val;
303
304 ALLOC_ZVAL(val);
305 *val = **data;
306 INIT_PZVAL(val);
307 zval_copy_ctor(val);
308 convert_to_string(val);
309
310 if (PHPSTR_LEN(str)) {
311 phpstr_append(str, arg_sep, arg_sep_len);
312 }
313 phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
314 phpstr_appends(str, "=");
315
316 if (Z_STRLEN_P(val) && Z_STRVAL_P(val)) {
317 char *encoded_val;
318 int encoded_len;
319
320 encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
321 phpstr_append(str, encoded_val, encoded_len);
322 efree(encoded_val);
323 }
324
325 zval_ptr_dtor(&val);
326 }
327 phpstr_dtor(&new_prefix);
328 }
329 return SUCCESS;
330 }
331 /* }}} */
332
333 /*
334 * Local variables:
335 * tab-width: 4
336 * c-basic-offset: 4
337 * End:
338 * vim600: noet sw=4 ts=4 fdm=marker
339 * vim<600: noet sw=4 ts=4
340 */
341