2 +--------------------------------------------------------------------+
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 +--------------------------------------------------------------------+
20 #include "ext/standard/php_string.h"
21 #include "ext/standard/url.h"
24 #include "php_http_std_defs.h"
25 #include "php_http_api.h"
26 #include "php_http_headers_api.h"
27 #include "php_http_info_api.h"
31 ZEND_EXTERN_MODULE_GLOBALS(http
);
34 # define HTTP_DBG_NEG 0
38 PHP_MINIT_FUNCTION(http_headers
)
40 HTTP_LONG_CONSTANT("HTTP_REDIRECT", HTTP_REDIRECT
);
41 HTTP_LONG_CONSTANT("HTTP_REDIRECT_PERM", HTTP_REDIRECT_PERM
);
42 HTTP_LONG_CONSTANT("HTTP_REDIRECT_POST", HTTP_REDIRECT_POST
);
43 HTTP_LONG_CONSTANT("HTTP_REDIRECT_TEMP", HTTP_REDIRECT_TEMP
);
49 /* {{{ static int http_sort_q(const void *, const void *) */
50 static int http_sort_q(const void *a
, const void *b TSRMLS_DC
)
53 zval result
, *first
, *second
;
58 first
= *((zval
**) f
->pData
);
59 second
= *((zval
**) s
->pData
);
61 if (numeric_compare_function(&result
, first
, second TSRMLS_CC
) != SUCCESS
) {
64 return (Z_LVAL(result
) > 0 ? -1 : (Z_LVAL(result
) < 0 ? 1 : 0));
68 /* {{{ char *http_negotiate_language_func */
69 char *_http_negotiate_language_func(const char *test
, double *quality
, HashTable
*supported TSRMLS_DC
)
73 const char *dash_test
;
75 FOREACH_HASH_VAL(pos
, supported
, value
) {
77 fprintf(stderr
, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value
), test
);
79 if (!strcasecmp(Z_STRVAL_PP(value
), test
)) {
80 return Z_STRVAL_PP(value
);
84 /* no distinct match found, so try primaries */
85 if ((dash_test
= strchr(test
, '-'))) {
86 FOREACH_HASH_VAL(pos
, supported
, value
) {
87 int len
= dash_test
- test
;
89 fprintf(stderr
, "strncasecmp('%s', '%s', %d)\n", Z_STRVAL_PP(value
), test
, len
);
91 if ( (!strncasecmp(Z_STRVAL_PP(value
), test
, len
)) &&
92 ( (Z_STRVAL_PP(value
)[len
] == '\0') ||
93 (Z_STRVAL_PP(value
)[len
] == '-'))) {
95 return Z_STRVAL_PP(value
);
104 /* {{{ char *http_negotiate_default_func */
105 char *_http_negotiate_default_func(const char *test
, double *quality
, HashTable
*supported TSRMLS_DC
)
110 FOREACH_HASH_VAL(pos
, supported
, value
) {
112 fprintf(stderr
, "strcasecmp('%s', '%s')\n", Z_STRVAL_PP(value
), test
);
114 if (!strcasecmp(Z_STRVAL_PP(value
), test
)) {
115 return Z_STRVAL_PP(value
);
123 /* {{{ HashTable *http_negotiate_q(const char *, HashTable *, negotiate_func_t) */
124 PHP_HTTP_API HashTable
*_http_negotiate_q(const char *header
, HashTable
*supported
, negotiate_func_t neg TSRMLS_DC
)
127 HashTable
*result
= NULL
;
130 fprintf(stderr
, "Reading header %s: ", header
);
132 HTTP_GSC(accept
, header
, NULL
);
134 fprintf(stderr
, "%s\n", Z_STRVAL_P(accept
));
137 if (Z_STRLEN_P(accept
)) {
142 ZVAL_STRINGL(&ex_del
, ",", 1, 0);
145 php_explode(&ex_del
, accept
, &ex_arr
, -1);
147 if (zend_hash_num_elements(Z_ARRVAL(ex_arr
)) > 0) {
155 FOREACH_HASH_VAL(pos
, Z_ARRVAL(ex_arr
), entry
) {
158 char *selected
, *identifier
, *freeme
;
159 const char *separator
;
162 fprintf(stderr
, "Checking %s\n", Z_STRVAL_PP(entry
));
165 if ((separator
= strchr(Z_STRVAL_PP(entry
), ';'))) {
166 const char *ptr
= separator
;
168 while (*++ptr
&& !isdigit(*ptr
) && '.' != *ptr
);
171 identifier
= estrndup(Z_STRVAL_PP(entry
), ident_len
= separator
- Z_STRVAL_PP(entry
));
173 quality
= 1000.0 - i
++;
174 identifier
= estrndup(Z_STRVAL_PP(entry
), ident_len
= Z_STRLEN_PP(entry
));
178 while (isspace(*identifier
)) {
182 while (ident_len
&& isspace(identifier
[ident_len
- 1])) {
183 identifier
[--ident_len
] = '\0';
186 if ((selected
= neg(identifier
, &quality
, supported TSRMLS_CC
))) {
187 /* don't overwrite previously set with higher quality */
188 if (!zend_hash_exists(Z_ARRVAL(array
), selected
, strlen(selected
) + 1)) {
189 add_assoc_double(&array
, selected
, quality
);
196 result
= Z_ARRVAL(array
);
197 zend_hash_sort(result
, zend_qsort
, http_sort_q
, 0 TSRMLS_CC
);
207 /* {{{ http_range_status http_get_request_ranges(HashTable *ranges, size_t) */
208 PHP_HTTP_API http_range_status
_http_get_request_ranges(HashTable
*ranges
, size_t length TSRMLS_DC
)
212 long begin
= -1, end
= -1, *ptr
;
214 HTTP_GSC(zrange
, "HTTP_RANGE", RANGE_NO
);
215 range
= Z_STRVAL_P(zrange
);
217 if (strncmp(range
, "bytes=", sizeof("bytes=") - 1)) {
222 range
+= sizeof("bytes=") - 1;
225 switch (c
= *(range
++))
228 /* allow 000... - shall we? */
234 case '1': case '2': case '3':
235 case '4': case '5': case '6':
236 case '7': case '8': case '9':
238 * If the value of the pointer is already set (non-negative)
239 * then multiply its value by ten and add the current value,
240 * else initialise the pointers value with the current value
242 * This let us recognize empty fields when validating the
243 * ranges, i.e. a "-10" for begin and "12345" for the end
244 * was the following range request: "Range: bytes=0-12345";
245 * While a "-1" for begin and "12345" for the end would
246 * have been: "Range: bytes=-12345".
261 /* IE - ignore for now */
268 /* validate ranges */
277 /* "0-0" or overflow */
278 if (end
== -10 || length
<= (size_t) end
) {
286 /* "-", "-0" or overflow */
287 if (end
== -1 || end
== -10 || length
<= (size_t) end
) {
290 begin
= length
- end
;
305 if (length
<= (size_t) begin
) {
313 if ( (length
<= (size_t) begin
) ||
314 (length
<= (size_t) end
) ||
325 MAKE_STD_ZVAL(zentry
);
327 add_index_long(zentry
, 0, begin
);
328 add_index_long(zentry
, 1, end
);
329 zend_hash_next_index_insert(ranges
, &zentry
, sizeof(zval
*), NULL
);
347 /* {{{ STATUS http_parse_headers(char *, HashTable *, zend_bool) */
348 PHP_HTTP_API STATUS
_http_parse_headers_ex(const char *header
, HashTable
*headers
, zend_bool prettify
,
349 http_info_callback callback_func
, void **callback_data TSRMLS_DC
)
351 const char *colon
= NULL
, *line
= NULL
, *begin
= header
;
352 const char *body
= http_locate_body(header
);
356 INIT_ZARR(array
, headers
);
359 header_len
= body
- header
;
361 header_len
= strlen(header
) + 1;
365 while (header_len
>= (size_t) (line
- begin
)) {
367 /* note: valgrind may choke on that -- should be safe though */
377 --value_len
; /* we don't have CR so value length is one char less */
379 if ((!(*line
- 1)) || ((*line
!= ' ') && (*line
!= '\t'))) {
382 /* response/request line */
383 if (SUCCESS
== http_info_parse(header
, &i
)) {
384 callback_func(callback_data
, &headers
, &i TSRMLS_CC
);
386 Z_ARRVAL(array
) = headers
;
389 /* "header: value" pair */
393 if (header
!= colon
) {
394 zval
**previous
= NULL
;
396 int keylen
= colon
- header
;
397 char *key
= estrndup(header
, keylen
);
400 key
= pretty_key(key
, keylen
, 1, 1);
403 value_len
+= line
- colon
- 1;
405 /* skip leading ws */
406 while (isspace(*(++colon
))) --value_len
;
407 /* skip trailing ws */
408 while (isspace(colon
[value_len
- 1])) --value_len
;
411 value
= estrndup(colon
, value_len
);
417 /* if we already have got such a header make an array of those */
418 if (SUCCESS
== zend_hash_find(headers
, key
, keylen
+ 1, (void **) &previous
)) {
419 /* convert to array */
420 if (Z_TYPE_PP(previous
) != IS_ARRAY
) {
421 convert_to_array(*previous
);
423 add_next_index_stringl(*previous
, value
, value_len
, 0);
425 add_assoc_stringl(&array
, key
, value
, value_len
, 0);
432 header
+= line
- header
;
441 /* {{{ void http_get_request_headers_ex(HashTable *, zend_bool) */
442 PHP_HTTP_API
void _http_get_request_headers_ex(HashTable
*headers
, zend_bool prettify TSRMLS_DC
)
450 Z_ARRVAL(array
) = headers
;
452 if (SUCCESS
== zend_hash_find(&EG(symbol_table
), "_SERVER", sizeof("_SERVER"), (void **) &hsv
)) {
453 FOREACH_KEYLEN(pos
, *hsv
, key
, keylen
, idx
) {
454 if (key
&& keylen
> 6 && !strncmp(key
, "HTTP_", 5)) {
455 zval
**header
, *orig
;
460 key
= pretty_key(estrndup(key
, keylen
), keylen
, 1, 1);
463 zend_hash_get_current_data_ex(Z_ARRVAL_PP(hsv
), (void **) &header
, &pos
);
466 convert_to_string_ex(header
);
467 add_assoc_stringl(&array
, key
, Z_STRVAL_PP(header
), Z_STRLEN_PP(header
), 1);
468 if (orig
!= *header
) {
469 zval_ptr_dtor(header
);
484 /* {{{ zend_bool http_match_request_header(char *, char *) */
485 PHP_HTTP_API zend_bool
_http_match_request_header_ex(const char *header
, const char *value
, zend_bool match_case TSRMLS_DC
)
488 uint name_len
= strlen(header
);
489 zend_bool result
= 0;
493 name
= pretty_key(estrndup(header
, name_len
), name_len
, 1, 1);
494 zend_hash_init(&headers
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
495 http_get_request_headers_ex(&headers
, 1);
497 if (SUCCESS
== zend_hash_find(&headers
, name
, name_len
+1, (void **) &data
)) {
498 result
= (match_case
? strcmp(Z_STRVAL_PP(data
), value
) : strcasecmp(Z_STRVAL_PP(data
), value
)) ? 0 : 1;
500 zend_hash_destroy(&headers
);
513 * vim600: noet sw=4 ts=4 fdm=marker
514 * vim<600: noet sw=4 ts=4