- http_build_url() replaces http_absolute_(url|uri)/http_build_uri;
[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
26 #include "php_http_api.h"
27 #include "php_http_url_api.h"
28
29 ZEND_EXTERN_MODULE_GLOBALS(http);
30
31 PHP_HTTP_API char *_http_absolute_url(const char *url TSRMLS_DC)
32 {
33 char *abs = estrdup(url);
34 php_url *purl = php_url_parse(abs);
35
36 STR_SET(abs, NULL);
37
38 if (purl) {
39 http_build_url(purl, NULL, NULL, &abs, NULL);
40 php_url_free(purl);
41 }
42
43 return abs;
44 }
45
46 /* {{{ void http_build_url(const php_url *, const php_url *, php_url **, char **, size_t *) */
47 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)
48 {
49 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
50 struct servent *se;
51 #endif
52 php_url *url = emalloc(sizeof(php_url));
53
54 #define __URLCPY(n) \
55 url->n = (new_url&&new_url->n) ? estrdup(new_url->n) : ((old_url&&old_url->n) ? estrdup(old_url->n) : NULL)
56 url->port = (new_url&&new_url->port) ? new_url->port : ((old_url) ? old_url->port : 0);
57 __URLCPY(scheme);
58 __URLCPY(user);
59 __URLCPY(pass);
60 __URLCPY(host);
61 __URLCPY(path);
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 /* FIXXME: dirname(REQUEST_URI) if path is relative */
104 if (!url->path) {
105 if (SG(request_info).request_uri) {
106 const char *q = strchr(SG(request_info).request_uri, '?');
107
108 if (q) {
109 url->path = estrndup(SG(request_info).request_uri, q - SG(request_info).request_uri);
110 } else {
111 url->path = estrdup(SG(request_info).request_uri);
112 }
113 } else {
114 url->path = ecalloc(1, 1);
115 }
116 }
117
118 if (url->port) {
119 if ( ((url->port == 80) && !strcmp(url->scheme, "http"))
120 || ((url->port ==443) && !strcmp(url->scheme, "https"))
121 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
122 || ((se = getservbyname(url->scheme, "tcp")) && se->s_port &&
123 (url->port == ntohs(se->s_port)))
124 #endif
125 ) {
126 url->port = 0;
127 }
128 }
129
130 if (url_str) {
131 size_t len;
132
133 *url_str = emalloc(HTTP_URL_MAXLEN + 1);
134
135 **url_str = '\0';
136 strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN);
137 strlcat(*url_str, "://", HTTP_URL_MAXLEN);
138
139 if (url->user && *url->user) {
140 strlcat(*url_str, url->user, HTTP_URL_MAXLEN);
141 if (url->pass && *url->pass) {
142 strlcat(*url_str, ":", HTTP_URL_MAXLEN);
143 strlcat(*url_str, url->pass, HTTP_URL_MAXLEN);
144 }
145 strlcat(*url_str, "@", HTTP_URL_MAXLEN);
146 }
147
148 strlcat(*url_str, url->host, HTTP_URL_MAXLEN);
149
150 if (url->port) {
151 char port_str[6] = {0};
152
153 snprintf(port_str, 5, "%d", (int) url->port);
154 strlcat(*url_str, ":", HTTP_URL_MAXLEN);
155 strlcat(*url_str, port_str, HTTP_URL_MAXLEN);
156 }
157
158 if (*url->path != '/') {
159 strlcat(*url_str, "/", HTTP_URL_MAXLEN);
160 }
161 strlcat(*url_str, url->path, HTTP_URL_MAXLEN);
162
163 if (url->query && *url->query) {
164 strlcat(*url_str, "?", HTTP_URL_MAXLEN);
165 strlcat(*url_str, url->query, HTTP_URL_MAXLEN);
166 }
167
168 if (url->fragment && *url->fragment) {
169 strlcat(*url_str, "#", HTTP_URL_MAXLEN);
170 strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN);
171 }
172
173 if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) {
174 http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN");
175 }
176 if (url_len) {
177 *url_len = len;
178 }
179 }
180
181 if (url_ptr) {
182 *url_ptr = url;
183 } else {
184 php_url_free(url);
185 }
186 }
187 /* }}} */
188
189 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
190 PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
191 char *pre_encoded_data, size_t pre_encoded_len,
192 char **encoded_data, size_t *encoded_len TSRMLS_DC)
193 {
194 char *arg_sep;
195 size_t arg_sep_len;
196 phpstr *qstr = phpstr_new();
197
198 if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
199 arg_sep = HTTP_URL_ARGSEP;
200 arg_sep_len = lenof(HTTP_URL_ARGSEP);
201 }
202
203 if (pre_encoded_len && pre_encoded_data) {
204 phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
205 }
206
207 if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
208 phpstr_free(&qstr);
209 return FAILURE;
210 }
211
212 phpstr_data(qstr, encoded_data, encoded_len);
213 phpstr_free(&qstr);
214
215 return SUCCESS;
216 }
217 /* }}} */
218
219 /* {{{ http_urlencode_hash_recursive */
220 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)
221 {
222 char *key = NULL;
223 uint len = 0;
224 ulong idx = 0;
225 zval **data = NULL;
226 HashPosition pos;
227
228 if (!ht || !str) {
229 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
230 return FAILURE;
231 }
232 if (ht->nApplyCount > 0) {
233 return SUCCESS;
234 }
235
236 FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) {
237 char *encoded_key;
238 int encoded_len;
239 phpstr new_prefix;
240
241 if (!data || !*data) {
242 return FAILURE;
243 }
244
245 if (key) {
246 if (len && key[len - 1] == '\0') {
247 --len;
248 }
249 encoded_key = php_url_encode(key, len, &encoded_len);
250 key = NULL;
251 } else {
252 encoded_len = spprintf(&encoded_key, 0, "%ld", idx);
253 }
254
255 {
256 phpstr_init(&new_prefix);
257 if (prefix && prefix_len) {
258 phpstr_append(&new_prefix, prefix, prefix_len);
259 phpstr_appends(&new_prefix, "[");
260 }
261
262 phpstr_append(&new_prefix, encoded_key, encoded_len);
263 efree(encoded_key);
264
265 if (prefix && prefix_len) {
266 phpstr_appends(&new_prefix, "]");
267 }
268 phpstr_fix(&new_prefix);
269 }
270
271 if (Z_TYPE_PP(data) == IS_ARRAY) {
272 STATUS status;
273 ++ht->nApplyCount;
274 status = http_urlencode_hash_recursive(Z_ARRVAL_PP(data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
275 --ht->nApplyCount;
276 if (SUCCESS != status) {
277 phpstr_dtor(&new_prefix);
278 return FAILURE;
279 }
280 } else {
281 char *encoded_val;
282 int encoded_len;
283 zval *cpy, *val = convert_to_type_ex(IS_STRING, *data, &cpy);
284
285 if (PHPSTR_LEN(str)) {
286 phpstr_append(str, arg_sep, arg_sep_len);
287 }
288 phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
289 phpstr_appends(str, "=");
290
291 encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
292 phpstr_append(str, encoded_val, encoded_len);
293 efree(encoded_val);
294
295 if (cpy) {
296 zval_ptr_dtor(&cpy);
297 }
298 }
299
300 phpstr_dtor(&new_prefix);
301 }
302 return SUCCESS;
303 }
304 /* }}} */
305
306 /*
307 * Local variables:
308 * tab-width: 4
309 * c-basic-offset: 4
310 * End:
311 * vim600: noet sw=4 ts=4 fdm=marker
312 * vim<600: noet sw=4 ts=4
313 */
314