- module/includes cleanup
[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(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 = se->s_port;
87 }
88 #endif
89 } else {
90 furl.port = (furl.scheme[4] == 's') ? 443 : 80;
91 }
92
93 if (host) {
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 char port_string[8] = {0};
139 snprintf(port_string, 7, ":%u", furl.port);
140 HTTP_URI_STRLCATL(URL, full_len, port_string);
141 }
142
143 if (furl.path) {
144 if (furl.path[0] != '/') {
145 HTTP_URI_STRLCATS(URL, full_len, "/");
146 }
147 HTTP_URI_STRLCATL(URL, full_len, furl.path);
148 } else {
149 HTTP_URI_STRLCATS(URL, full_len, "/");
150 }
151
152 if (furl.query) {
153 HTTP_URI_STRLCATS(URL, full_len, "?");
154 HTTP_URI_STRLCATL(URL, full_len, furl.query);
155 }
156
157 if (furl.fragment) {
158 HTTP_URI_STRLCATS(URL, full_len, "#");
159 HTTP_URI_STRLCATL(URL, full_len, furl.fragment);
160 }
161
162 if (scheme) {
163 efree(scheme);
164 }
165 php_url_free(purl);
166 efree(uri);
167
168 return URL;
169 }
170 /* }}} */
171
172 /* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
173 PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
174 char *pre_encoded_data, size_t pre_encoded_len,
175 char **encoded_data, size_t *encoded_len TSRMLS_DC)
176 {
177 char *arg_sep;
178 size_t arg_sep_len;
179 phpstr *qstr = phpstr_new();
180
181 if (override_argsep || !(arg_sep_len = strlen(arg_sep = INI_STR("arg_separator.output")))) {
182 arg_sep = HTTP_URL_ARGSEP;
183 arg_sep_len = lenof(HTTP_URL_ARGSEP);
184 }
185
186 if (pre_encoded_len && pre_encoded_data) {
187 phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
188 }
189
190 if (SUCCESS != http_urlencode_hash_recursive(hash, qstr, arg_sep, arg_sep_len, NULL, 0)) {
191 phpstr_free(&qstr);
192 return FAILURE;
193 }
194
195 phpstr_data(qstr, encoded_data, encoded_len);
196 phpstr_free(&qstr);
197
198 return SUCCESS;
199 }
200 /* }}} */
201
202 /* {{{ http_urlencode_hash_recursive */
203 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)
204 {
205 char *key = NULL;
206 uint len = 0;
207 ulong idx = 0;
208 zval **data = NULL;
209 HashPosition pos;
210
211 if (!ht || !str) {
212 http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid parameters");
213 return FAILURE;
214 }
215 if (ht->nApplyCount > 0) {
216 return SUCCESS;
217 }
218
219 FOREACH_HASH_KEYLENVAL(pos, ht, key, len, idx, data) {
220 char *encoded_key;
221 int encoded_len;
222 phpstr new_prefix;
223
224 if (!data || !*data) {
225 return FAILURE;
226 }
227
228 if (key) {
229 if (len && key[len - 1] == '\0') {
230 --len;
231 }
232 encoded_key = php_url_encode(key, len, &encoded_len);
233 key = NULL;
234 } else {
235 encoded_len = spprintf(&encoded_key, 0, "%ld", idx);
236 }
237
238 {
239 phpstr_init(&new_prefix);
240 if (prefix && prefix_len) {
241 phpstr_append(&new_prefix, prefix, prefix_len);
242 phpstr_appends(&new_prefix, "[");
243 }
244
245 phpstr_append(&new_prefix, encoded_key, encoded_len);
246 efree(encoded_key);
247
248 if (prefix && prefix_len) {
249 phpstr_appends(&new_prefix, "]");
250 }
251 phpstr_fix(&new_prefix);
252 }
253
254 if (Z_TYPE_PP(data) == IS_ARRAY) {
255 STATUS status;
256 ++ht->nApplyCount;
257 status = http_urlencode_hash_recursive(Z_ARRVAL_PP(data), str, arg_sep, arg_sep_len, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
258 --ht->nApplyCount;
259 if (SUCCESS != status) {
260 phpstr_dtor(&new_prefix);
261 return FAILURE;
262 }
263 } else {
264 char *encoded_val;
265 int encoded_len;
266 zval *cpy, *val = convert_to_type_ex(IS_STRING, *data, &cpy);
267
268 if (PHPSTR_LEN(str)) {
269 phpstr_append(str, arg_sep, arg_sep_len);
270 }
271 phpstr_append(str, PHPSTR_VAL(&new_prefix), PHPSTR_LEN(&new_prefix));
272 phpstr_appends(str, "=");
273
274 encoded_val = php_url_encode(Z_STRVAL_P(val), Z_STRLEN_P(val), &encoded_len);
275 phpstr_append(str, encoded_val, encoded_len);
276 efree(encoded_val);
277
278 if (cpy) {
279 zval_ptr_dtor(&cpy);
280 }
281 }
282
283 phpstr_dtor(&new_prefix);
284 }
285 return SUCCESS;
286 }
287 /* }}} */
288
289 /*
290 * Local variables:
291 * tab-width: 4
292 * c-basic-offset: 4
293 * End:
294 * vim600: noet sw=4 ts=4 fdm=marker
295 * vim<600: noet sw=4 ts=4
296 */
297