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