- path has been copied twice
[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(query);
63 __URLCPY(fragment);
64
65 if (!url->scheme) {
66 switch (url->port)
67 {
68 case 443:
69 url->scheme = estrndup("https", lenof("https"));
70 break;
71
72 #if !defined(PHP_WIN32) && !defined(HAVE_NETDB_H)
73 default:
74 #endif
75 case 80:
76 url->scheme = estrndup("http", lenof("http"));
77 break;
78
79 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
80 default:
81 if ((se = getservbyport(htons(url->port), "tcp")) && se->s_name) {
82 url->scheme = estrdup(se->s_name);
83 } else {
84 url->scheme = estrndup("http", lenof("http"));
85 }
86 break;
87 #endif
88 }
89 }
90
91 if (!url->host) {
92 zval *zhost;
93
94 if ((((zhost = http_get_server_var("HTTP_HOST")) ||
95 (zhost = http_get_server_var("SERVER_NAME")))) && Z_STRLEN_P(zhost)) {
96 url->host = estrndup(Z_STRVAL_P(zhost), Z_STRLEN_P(zhost));
97 } else {
98 url->host = estrndup("localhost", lenof("localhost"));
99 }
100 }
101
102 /* FIXXME: dirname(REQUEST_URI) if path is relative */
103 if (!url->path) {
104 if (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 = ecalloc(1, 1);
114 }
115 }
116
117 if (url->port) {
118 if ( ((url->port == 80) && !strcmp(url->scheme, "http"))
119 || ((url->port ==443) && !strcmp(url->scheme, "https"))
120 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
121 || ((se = getservbyname(url->scheme, "tcp")) && se->s_port &&
122 (url->port == ntohs(se->s_port)))
123 #endif
124 ) {
125 url->port = 0;
126 }
127 }
128
129 if (url_str) {
130 size_t len;
131
132 *url_str = emalloc(HTTP_URL_MAXLEN + 1);
133
134 **url_str = '\0';
135 strlcat(*url_str, url->scheme, HTTP_URL_MAXLEN);
136 strlcat(*url_str, "://", HTTP_URL_MAXLEN);
137
138 if (url->user && *url->user) {
139 strlcat(*url_str, url->user, HTTP_URL_MAXLEN);
140 if (url->pass && *url->pass) {
141 strlcat(*url_str, ":", HTTP_URL_MAXLEN);
142 strlcat(*url_str, url->pass, HTTP_URL_MAXLEN);
143 }
144 strlcat(*url_str, "@", HTTP_URL_MAXLEN);
145 }
146
147 strlcat(*url_str, url->host, HTTP_URL_MAXLEN);
148
149 if (url->port) {
150 char port_str[6] = {0};
151
152 snprintf(port_str, 5, "%d", (int) url->port);
153 strlcat(*url_str, ":", HTTP_URL_MAXLEN);
154 strlcat(*url_str, port_str, HTTP_URL_MAXLEN);
155 }
156
157 if (*url->path != '/') {
158 strlcat(*url_str, "/", HTTP_URL_MAXLEN);
159 }
160 strlcat(*url_str, url->path, HTTP_URL_MAXLEN);
161
162 if (url->query && *url->query) {
163 strlcat(*url_str, "?", HTTP_URL_MAXLEN);
164 strlcat(*url_str, url->query, HTTP_URL_MAXLEN);
165 }
166
167 if (url->fragment && *url->fragment) {
168 strlcat(*url_str, "#", HTTP_URL_MAXLEN);
169 strlcat(*url_str, url->fragment, HTTP_URL_MAXLEN);
170 }
171
172 if (HTTP_URL_MAXLEN == (len = strlen(*url_str))) {
173 http_error(HE_NOTICE, HTTP_E_URL, "Length of URL exceeds HTTP_URL_MAXLEN");
174 }
175 if (url_len) {
176 *url_len = len;
177 }
178 }
179
180 if (url_ptr) {
181 *url_ptr = url;
182 } else {
183 php_url_free(url);
184 }
185 }
186 /* }}} */
187
188 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
189 PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
190 char *pre_encoded_data, size_t pre_encoded_len,
191 char **encoded_data, size_t *encoded_len TSRMLS_DC)
192 {
193 char *arg_sep;
194 size_t arg_sep_len;
195 phpstr *qstr = phpstr_new();
196
197 if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
198 arg_sep = HTTP_URL_ARGSEP;
199 arg_sep_len = lenof(HTTP_URL_ARGSEP);
200 }
201
202 if (pre_encoded_len && pre_encoded_data) {
203 phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
204 }
205
206 if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
207 phpstr_free(&qstr);
208 return FAILURE;
209 }
210
211 phpstr_data(qstr, encoded_data, encoded_len);
212 phpstr_free(&qstr);
213
214 return SUCCESS;
215 }
216 /* }}} */
217
218 /* {{{ http_urlencode_hash_recursive */
219 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)
220 {
221 char *key = NULL;
222 uint len = 0;
223 ulong idx = 0;
224 zval **data = NULL;
225 HashPosition pos;
226
227 if (!ht || !str) {
228 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
229 return FAILURE;
230 }
231 if (ht->nApplyCount > 0) {
232 return SUCCESS;
233 }
234
235 FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) {
236 char *encoded_key;
237 int encoded_len;
238 phpstr new_prefix;
239
240 if (!data || !*data) {
241 return FAILURE;
242 }
243
244 if (key) {
245 if (len && key[len - 1] == '\0') {
246 --len;
247 }
248 encoded_key = php_url_encode(key, len, &encoded_len);
249 key = NULL;
250 } else {
251 encoded_len = spprintf(&encoded_key, 0, "%ld", idx);
252 }
253
254 {
255 phpstr_init(&new_prefix);
256 if (prefix && prefix_len) {
257 phpstr_append(&new_prefix, prefix, prefix_len);
258 phpstr_appends(&new_prefix, "[");
259 }
260
261 phpstr_append(&new_prefix, encoded_key, encoded_len);
262 efree(encoded_key);
263
264 if (prefix && prefix_len) {
265 phpstr_appends(&new_prefix, "]");
266 }
267 phpstr_fix(&new_prefix);
268 }
269
270 if (Z_TYPE_PP(data) == IS_ARRAY) {
271 STATUS status;
272 ++ht->nApplyCount;
273 status = http_urlencode_hash_recursive(Z_ARRVAL_PP(data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
274 --ht->nApplyCount;
275 if (SUCCESS != status) {
276 phpstr_dtor(&new_prefix);
277 return FAILURE;
278 }
279 } else {
280 char *encoded_val;
281 int encoded_len;
282 zval *cpy, *val = convert_to_type_ex(IS_STRING, *data, &cpy);
283
284 if (PHPSTR_LEN(str)) {
285 phpstr_append(str, arg_sep, arg_sep_len);
286 }
287 phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
288 phpstr_appends(str, "=");
289
290 encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
291 phpstr_append(str, encoded_val, encoded_len);
292 efree(encoded_val);
293
294 if (cpy) {
295 zval_ptr_dtor(&cpy);
296 }
297 }
298
299 phpstr_dtor(&new_prefix);
300 }
301 return SUCCESS;
302 }
303 /* }}} */
304
305 /*
306 * Local variables:
307 * tab-width: 4
308 * c-basic-offset: 4
309 * End:
310 * vim600: noet sw=4 ts=4 fdm=marker
311 * vim<600: noet sw=4 ts=4
312 */
313