2 +----------------------------------------------------------------------+
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.0 of the PHP license, that |
6 | is bundled with this package in the file LICENSE, and is available |
7 | through the world-wide-web at http://www.php.net/license/3_0.txt. |
8 | If you did not receive a copy of the PHP license and are unable to |
9 | obtain it through the world-wide-web, please send a note to |
10 | license@php.net so we can mail you a copy immediately. |
11 +----------------------------------------------------------------------+
12 | Copyright (c) 2004-2005 Michael Wallner <mike@php.net> |
13 +----------------------------------------------------------------------+
25 #include "ext/standard/php_string.h"
26 #include "ext/standard/url.h"
29 #include "php_http_std_defs.h"
30 #include "php_http_api.h"
31 #include "php_http_headers_api.h"
33 /* {{{ static int http_sort_q(const void *, const void *) */
34 static int http_sort_q(const void *a
, const void *b TSRMLS_DC
)
37 zval result
, *first
, *second
;
42 first
= *((zval
**) f
->pData
);
43 second
= *((zval
**) s
->pData
);
45 if (numeric_compare_function(&result
, first
, second TSRMLS_CC
) != SUCCESS
) {
48 return (Z_LVAL(result
) > 0 ? -1 : (Z_LVAL(result
) < 0 ? 1 : 0));
52 /* {{{ char *http_negotiate_q(char *, HashTable *, char *) */
53 PHP_HTTP_API
char *_http_negotiate_q(const char *entry
, const HashTable
*supported
, const char *def TSRMLS_DC
)
55 zval
*zaccept
, zdelim
, zarray
, zentries
, **zentry
, **zsupp
;
56 char *q_ptr
= NULL
, *key
= NULL
;
61 HTTP_GSC(zaccept
, entry
, estrdup(def
));
64 array_init(&zentries
);
66 Z_STRVAL(zdelim
) = ",";
69 php_explode(&zdelim
, zaccept
, &zarray
, -1);
71 FOREACH_HASH_VAL(Z_ARRVAL(zarray
), zentry
) {
72 if (q_ptr
= strrchr(Z_STRVAL_PP(zentry
), ';')) {
73 qual
= strtod(q_ptr
+ 3, NULL
);
79 FOREACH_HASH_VAL((HashTable
*)supported
, zsupp
) {
80 if (!strcasecmp(Z_STRVAL_PP(zsupp
), Z_STRVAL_PP(zentry
))) {
81 add_assoc_double(&zentries
, Z_STRVAL_PP(zsupp
), qual
);
88 zend_hash_sort(Z_ARRVAL(zentries
), zend_qsort
, http_sort_q
, 0 TSRMLS_CC
);
90 FOREACH_HASH_KEY(Z_ARRVAL(zentries
), key
, idx
) {
103 /* {{{ http_range_status http_get_request_ranges(HashTable *ranges, size_t) */
104 PHP_HTTP_API http_range_status
_http_get_request_ranges(HashTable
*ranges
, size_t length TSRMLS_DC
)
108 long begin
= -1, end
= -1, *ptr
;
110 HTTP_GSC(zrange
, "HTTP_RANGE", RANGE_NO
);
111 range
= Z_STRVAL_P(zrange
);
113 if (strncmp(range
, "bytes=", sizeof("bytes=") - 1)) {
114 php_error_docref(NULL TSRMLS_CC
, E_NOTICE
, "Range header misses bytes=");
119 range
+= sizeof("bytes=") - 1;
122 switch (c
= *(range
++))
128 case '1': case '2': case '3':
129 case '4': case '5': case '6':
130 case '7': case '8': case '9':
132 * If the value of the pointer is already set (non-negative)
133 * then multiply its value by ten and add the current value,
134 * else initialise the pointers value with the current value
136 * This let us recognize empty fields when validating the
137 * ranges, i.e. a "-10" for begin and "12345" for the end
138 * was the following range request: "Range: bytes=0-12345";
139 * While a "-1" for begin and "12345" for the end would
140 * have been: "Range: bytes=-12345".
155 /* IE - ignore for now */
162 /* validate ranges */
171 /* "0-0" or overflow */
172 if (end
== -10 || length
<= end
) {
180 /* "-", "-0" or overflow */
181 if (end
== -1 || end
== -10 || length
<= end
) {
184 begin
= length
- end
;
199 if (length
<= begin
) {
207 if ( (length
<= begin
) ||
219 MAKE_STD_ZVAL(zentry
);
221 add_index_long(zentry
, 0, begin
);
222 add_index_long(zentry
, 1, end
);
223 zend_hash_next_index_insert(ranges
, &zentry
, sizeof(zval
*), NULL
);
241 /* {{{ STATUS http_parse_headers(char *, size_t, HashTable *, zend_bool) */
242 PHP_HTTP_API STATUS
_http_parse_headers_ex(const char *header
, size_t header_len
,
243 HashTable
*headers
, zend_bool prettify TSRMLS_DC
)
245 const char *colon
= NULL
, *line
= NULL
, *begin
= header
;
248 Z_ARRVAL(array
) = headers
;
250 if (header_len
< 2) {
255 if (!strncmp(header
, "HTTP/1.", 7)) {
256 char *end
= strstr(header
, HTTP_CRLF
);
257 size_t len
= end
- (header
+ lenof("HTTP/1.x "));
258 char *val
= estrndup(header
+ lenof("HTTP/1.x "), len
);
260 add_assoc_stringl(&array
, "Status", val
, len
, 0);
266 while (header_len
>= (line
- begin
)) {
272 --value_len
; /* we don't have CR so value length is one char less */
274 if (colon
&& ((!(*line
- 1)) || ((*line
!= ' ') && (*line
!= '\t')))) {
277 if (header
!= colon
) {
278 zval
**previous
= NULL
;
279 char *value
= empty_string
;
280 int keylen
= colon
- header
;
281 char *key
= estrndup(header
, keylen
);
284 key
= pretty_key(key
, keylen
, 1, 1);
287 value_len
+= line
- colon
- 1;
289 /* skip leading ws */
290 while (isspace(*(++colon
))) --value_len
;
291 /* skip trailing ws */
292 while (isspace(colon
[value_len
- 1])) --value_len
;
295 value
= estrndup(colon
, value_len
);
300 /* if we already have got such a header make an array of those */
301 if (SUCCESS
== zend_hash_find(headers
, key
, keylen
+ 1, (void **) &previous
)) {
302 /* already an array? - just add */
303 if (Z_TYPE_PP(previous
) == IS_ARRAY
) {
304 add_next_index_stringl(*previous
, value
, value_len
, 0);
306 /* create the array */
308 MAKE_STD_ZVAL(new_array
);
309 array_init(new_array
);
311 add_next_index_stringl(new_array
, Z_STRVAL_PP(previous
), Z_STRLEN_PP(previous
), 1);
312 add_next_index_stringl(new_array
, value
, value_len
, 0);
313 add_assoc_zval(&array
, key
, new_array
);
318 add_assoc_stringl(&array
, key
, value
, value_len
, 0);
325 header
+= line
- header
;
341 PHP_HTTP_API STATUS
_http_parse_cookie(const char *cookie
, HashTable
*values TSRMLS_DC
)
343 const char *key
= cookie
, *val
= NULL
;
344 int vallen
= 0, keylen
= 0, done
= 0;
347 Z_ARRVAL(array
) = values
;
349 if (!(val
= strchr(cookie
, '='))) {
353 #define HTTP_COOKIE_VAL(array, k, str, len) \
355 const char *encoded = str; \
356 char *decoded = NULL; \
357 int decoded_len = 0, encoded_len = len; \
358 decoded = estrndup(encoded, encoded_len); \
359 decoded_len = php_url_decode(decoded, encoded_len); \
360 add_assoc_stringl(array, k, decoded, decoded_len, 0); \
362 #define HTTP_COOKIE_FIXKEY() \
364 while (isspace(*key)) ++key; \
365 keylen = val - key; \
366 while (isspace(key[keylen - 1])) --keylen; \
368 #define HTTP_COOKIE_FIXVAL() \
371 while (isspace(*val)) ++val; \
372 vallen = key - val; \
373 while (isspace(val[vallen - 1])) --vallen; \
376 HTTP_COOKIE_FIXKEY();
377 HTTP_COOKIE_VAL(&array
, "name", key
, keylen
);
379 /* just a name=value cookie */
380 if (!(key
= strchr(val
, ';'))) {
381 key
= val
+ strlen(val
);
382 HTTP_COOKIE_FIXVAL();
383 HTTP_COOKIE_VAL(&array
, "value", val
, vallen
);
385 /* additional info appended */
389 HTTP_COOKIE_FIXVAL();
390 HTTP_COOKIE_VAL(&array
, "value", val
, vallen
);
393 if (!(val
= strchr(key
, '='))) {
397 HTTP_COOKIE_FIXKEY();
398 keydup
= estrndup(key
, keylen
);
399 if (!(key
= strchr(val
, ';'))) {
401 key
= val
+ strlen(val
);
403 HTTP_COOKIE_FIXVAL();
404 HTTP_COOKIE_VAL(&array
, keydup
, val
, vallen
);
412 /* {{{ void http_get_request_headers_ex(HashTable *, zend_bool) */
413 PHP_HTTP_API
void _http_get_request_headers_ex(HashTable
*headers
, zend_bool prettify TSRMLS_DC
)
419 Z_ARRVAL(array
) = headers
;
421 FOREACH_HASH_KEY(HTTP_SERVER_VARS
, key
, idx
) {
422 if (key
&& !strncmp(key
, "HTTP_", 5)) {
427 key
= pretty_key(key
, strlen(key
), 1, 1);
430 zend_hash_get_current_data(HTTP_SERVER_VARS
, (void **) &header
);
431 add_assoc_stringl(&array
, key
, Z_STRVAL_PP(header
), Z_STRLEN_PP(header
), 1);
444 * vim600: noet sw=4 ts=4 fdm=marker
445 * vim<600: noet sw=4 ts=4