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