- fix logic error
[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/url.h"
26
27 #include "php_http_api.h"
28 #include "php_http_url_api.h"
29
30 ZEND_EXTERN_MODULE_GLOBALS(http);
31
32 /* {{{ char *http_absolute_url(char *) */
33 PHP_HTTP_API char *_http_absolute_url_ex(
34 const char *url, size_t url_len,
35 const char *proto, size_t proto_len,
36 const char *host, size_t host_len,
37 unsigned port TSRMLS_DC)
38 {
39 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
40 struct servent *se;
41 #endif
42 php_url *purl = NULL, furl;
43 size_t full_len = 0;
44 zval *zhost = NULL;
45 char *scheme = NULL, *uri, *URL;
46
47 if ((!url || !url_len) && (
48 (!(url = SG(request_info).request_uri)) ||
49 (!(url_len = strlen(SG(request_info).request_uri))))) {
50 http_error(HE_WARNING, HTTP_E_RUNTIME, "Cannot build an absolute URI if supplied URL and REQUEST_URI is empty");
51 return NULL;
52 }
53
54 URL = ecalloc(1, HTTP_URI_MAXLEN + 1);
55 uri = estrndup(url, url_len);
56 if (!(purl = php_url_parse(uri))) {
57 http_error_ex(HE_WARNING, HTTP_E_URL, "Could not parse supplied URL: %s", url);
58 return NULL;
59 }
60
61 furl.user = purl->user;
62 furl.pass = purl->pass;
63 furl.path = purl->path;
64 furl.query = purl->query;
65 furl.fragment = purl->fragment;
66
67 if (proto && proto_len) {
68 furl.scheme = scheme = estrdup(proto);
69 } else if (purl->scheme) {
70 furl.scheme = purl->scheme;
71 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
72 } else if (port && (se = getservbyport(htons(port), "tcp"))) {
73 furl.scheme = (scheme = estrdup(se->s_name));
74 #endif
75 } else {
76 furl.scheme = "http";
77 }
78
79 if (port) {
80 furl.port = port;
81 } else if (purl->port) {
82 furl.port = purl->port;
83 } else if (strncmp(furl.scheme, "http", 4)) {
84 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
85 if ((se = getservbyname(furl.scheme, "tcp"))) {
86 furl.port = ntohs(se->s_port);
87 }
88 #endif
89 } else {
90 furl.port = (furl.scheme[4] == 's') ? 443 : 80;
91 }
92
93 if (host && host_len) {
94 furl.host = (char *) host;
95 } else if (purl->host) {
96 furl.host = purl->host;
97 } else if ( (zhost = http_get_server_var("HTTP_HOST")) ||
98 (zhost = http_get_server_var("SERVER_NAME"))) {
99 furl.host = Z_STRVAL_P(zhost);
100 } else {
101 furl.host = "localhost";
102 }
103
104 #define HTTP_URI_STRLCATS(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, sizeof(add_string)-1)
105 #define HTTP_URI_STRLCATL(URL, full_len, add_string) HTTP_URI_STRLCAT(URL, full_len, add_string, strlen(add_string))
106 #define HTTP_URI_STRLCAT(URL, full_len, add_string, add_len) \
107 if ((full_len += add_len) > HTTP_URI_MAXLEN) { \
108 http_error_ex(HE_NOTICE, HTTP_E_URL, \
109 "Absolute URI would have exceeded max URI length (%d bytes) - " \
110 "tried to add %d bytes ('%s')", \
111 HTTP_URI_MAXLEN, add_len, add_string); \
112 if (scheme) { \
113 efree(scheme); \
114 } \
115 php_url_free(purl); \
116 efree(uri); \
117 return URL; \
118 } else { \
119 strcat(URL, add_string); \
120 }
121
122 HTTP_URI_STRLCATL(URL, full_len, furl.scheme);
123 HTTP_URI_STRLCATS(URL, full_len, "://");
124
125 if (furl.user) {
126 HTTP_URI_STRLCATL(URL, full_len, furl.user);
127 if (furl.pass) {
128 HTTP_URI_STRLCATS(URL, full_len, ":");
129 HTTP_URI_STRLCATL(URL, full_len, furl.pass);
130 }
131 HTTP_URI_STRLCATS(URL, full_len, "@");
132 }
133
134 HTTP_URI_STRLCATL(URL, full_len, furl.host);
135
136 if ( (!strcmp(furl.scheme, "http") && (furl.port != 80)) ||
137 (!strcmp(furl.scheme, "https") && (furl.port != 443))
138 #if defined(PHP_WIN32) || defined(HAVE_NETDB_H)
139 || ((!(se = getservbyname(furl.scheme, "tcp"))) || (ntohs(se->s_port) != furl.port))
140 #endif
141 ) {
142 char port_string[8] = {0};
143 snprintf(port_string, 7, ":%u", furl.port);
144 HTTP_URI_STRLCATL(URL, full_len, port_string);
145 }
146
147 if (furl.path) {
148 if (furl.path[0] != '/') {
149 HTTP_URI_STRLCATS(URL, full_len, "/");
150 }
151 HTTP_URI_STRLCATL(URL, full_len, furl.path);
152 } else {
153 HTTP_URI_STRLCATS(URL, full_len, "/");
154 }
155
156 if (furl.query) {
157 HTTP_URI_STRLCATS(URL, full_len, "?");
158 HTTP_URI_STRLCATL(URL, full_len, furl.query);
159 }
160
161 if (furl.fragment) {
162 HTTP_URI_STRLCATS(URL, full_len, "#");
163 HTTP_URI_STRLCATL(URL, full_len, furl.fragment);
164 }
165
166 if (scheme) {
167 efree(scheme);
168 }
169 php_url_free(purl);
170 efree(uri);
171
172 return URL;
173 }
174 /* }}} */
175
176 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
177 PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
178 char *pre_encoded_data, size_t pre_encoded_len,
179 char **encoded_data, size_t *encoded_len TSRMLS_DC)
180 {
181 char *arg_sep;
182 size_t arg_sep_len;
183 phpstr *qstr = phpstr_new();
184
185 if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
186 arg_sep = HTTP_URL_ARGSEP;
187 arg_sep_len = lenof(HTTP_URL_ARGSEP);
188 }
189
190 if (pre_encoded_len && pre_encoded_data) {
191 phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
192 }
193
194 if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
195 phpstr_free(&qstr);
196 return FAILURE;
197 }
198
199 phpstr_data(qstr, encoded_data, encoded_len);
200 phpstr_free(&qstr);
201
202 return SUCCESS;
203 }
204 /* }}} */
205
206 /* {{{ http_urlencode_hash_recursive */
207 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)
208 {
209 char *key = NULL;
210 uint len = 0;
211 ulong idx = 0;
212 zval **data = NULL;
213 HashPosition pos;
214
215 if (!ht || !str) {
216 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
217 return FAILURE;
218 }
219 if (ht->nApplyCount > 0) {
220 return SUCCESS;
221 }
222
223 FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) {
224 char *encoded_key;
225 int encoded_len;
226 phpstr new_prefix;
227
228 if (!data || !*data) {
229 return FAILURE;
230 }
231
232 if (key) {
233 if (len && key[len - 1] == '\0') {
234 --len;
235 }
236 encoded_key = php_url_encode(key, len, &encoded_len);
237 key = NULL;
238 } else {
239 encoded_len = spprintf(&encoded_key, 0, "%ld", idx);
240 }
241
242 {
243 phpstr_init(&new_prefix);
244 if (prefix && prefix_len) {
245 phpstr_append(&new_prefix, prefix, prefix_len);
246 phpstr_appends(&new_prefix, "[");
247 }
248
249 phpstr_append(&new_prefix, encoded_key, encoded_len);
250 efree(encoded_key);
251
252 if (prefix && prefix_len) {
253 phpstr_appends(&new_prefix, "]");
254 }
255 phpstr_fix(&new_prefix);
256 }
257
258 if (Z_TYPE_PP(data) == IS_ARRAY) {
259 STATUS status;
260 ++ht->nApplyCount;
261 status = http_urlencode_hash_recursive(Z_ARRVAL_PP(data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
262 --ht->nApplyCount;
263 if (SUCCESS != status) {
264 phpstr_dtor(&new_prefix);
265 return FAILURE;
266 }
267 } else {
268 char *encoded_val;
269 int encoded_len;
270 zval *cpy, *val = convert_to_type_ex(IS_STRING, *data, &cpy);
271
272 if (PHPSTR_LEN(str)) {
273 phpstr_append(str, arg_sep, arg_sep_len);
274 }
275 phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
276 phpstr_appends(str, "=");
277
278 encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
279 phpstr_append(str, encoded_val, encoded_len);
280 efree(encoded_val);
281
282 if (cpy) {
283 zval_ptr_dtor(&cpy);
284 }
285 }
286
287 phpstr_dtor(&new_prefix);
288 }
289 return SUCCESS;
290 }
291 /* }}} */
292
293 /*
294 * Local variables:
295 * tab-width: 4
296 * c-basic-offset: 4
297 * End:
298 * vim600: noet sw=4 ts=4 fdm=marker
299 * vim<600: noet sw=4 ts=4
300 */
301