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