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