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 "php_output.h"
26 #include "ext/standard/md5.h"
29 #include "php_http_std_defs.h"
30 #include "php_http_api.h"
31 #include "php_http_send_api.h"
32 #include "php_http_cache_api.h"
33 #include "php_http_headers_api.h"
36 # include "php_http_exception_object.h"
39 ZEND_EXTERN_MODULE_GLOBALS(http
);
41 /* char *pretty_key(char *, size_t, zend_bool, zebd_bool) */
42 char *_http_pretty_key(char *key
, size_t key_len
, zend_bool uctitle
, zend_bool xhyphen
)
46 if (wasalpha
= isalpha(key
[0])) {
47 key
[0] = uctitle
? toupper(key
[0]) : tolower(key
[0]);
49 for (i
= 1; i
< key_len
; i
++) {
50 if (isalpha(key
[i
])) {
51 key
[i
] = ((!wasalpha
) && uctitle
) ? toupper(key
[i
]) : tolower(key
[i
]);
54 if (xhyphen
&& (key
[i
] == '_')) {
65 /* {{{ void http_error(long, long, char*) */
66 void _http_error_ex(long type
, long code
, const char *format
, ...)
71 va_start(args
, format
);
72 if (type
== E_THROW
) {
75 vspprintf(&message
, 0, format
, args
);
76 zend_throw_exception(http_exception_get_default(), message
, code TSRMLS_CC
);
81 if (type
!= E_THROW
) {
82 php_verror(NULL
, "", type
, format
, args TSRMLS_CC
);
88 /* {{{ static STATUS http_ob_stack_get(php_ob_buffer *, php_ob_buffer **) */
89 static STATUS
http_ob_stack_get(php_ob_buffer
*o
, php_ob_buffer
**s
)
92 php_ob_buffer
*b
= emalloc(sizeof(php_ob_buffer
));
93 b
->handler_name
= estrdup(o
->handler_name
);
94 b
->buffer
= estrndup(o
->buffer
, o
->text_length
);
95 b
->text_length
= o
->text_length
;
96 b
->chunk_size
= o
->chunk_size
;
103 /* {{{ zval *http_get_server_var_ex(char *, size_t) */
104 PHP_HTTP_API zval
*_http_get_server_var_ex(const char *key
, size_t key_size
, zend_bool check TSRMLS_DC
)
107 if (SUCCESS
== zend_hash_find(HTTP_SERVER_VARS
, (char *) key
, key_size
, (void **) &var
)) {
109 return Z_STRVAL_PP(var
) && Z_STRLEN_PP(var
) ? *var
: NULL
;
118 /* {{{ void http_ob_etaghandler(char *, uint, char **, uint *, int) */
119 PHP_HTTP_API
void _http_ob_etaghandler(char *output
, uint output_len
,
120 char **handled_output
, uint
*handled_output_len
, int mode TSRMLS_DC
)
122 char etag
[33] = { 0 };
123 unsigned char digest
[16];
125 if (mode
& PHP_OUTPUT_HANDLER_START
) {
126 PHP_MD5Init(&HTTP_G(etag_md5
));
129 PHP_MD5Update(&HTTP_G(etag_md5
), output
, output_len
);
131 if (mode
& PHP_OUTPUT_HANDLER_END
) {
132 PHP_MD5Final(digest
, &HTTP_G(etag_md5
));
134 /* just do that if desired */
135 if (HTTP_G(etag_started
)) {
136 make_digest(etag
, digest
);
138 if (http_etag_match("HTTP_IF_NONE_MATCH", etag
)) {
139 http_send_status(304);
142 http_send_etag(etag
, 32);
147 *handled_output_len
= output_len
;
148 *handled_output
= estrndup(output
, output_len
);
152 /* {{{ STATUS http_start_ob_handler(php_output_handler_func_t, char *, uint, zend_bool) */
153 PHP_HTTP_API STATUS
_http_start_ob_handler(php_output_handler_func_t handler_func
,
154 char *handler_name
, uint chunk_size
, zend_bool erase TSRMLS_DC
)
156 php_ob_buffer
**stack
;
159 if (count
= OG(ob_nesting_level
)) {
160 stack
= ecalloc(count
, sizeof(php_ob_buffer
*));
163 zend_stack_apply_with_argument(&OG(ob_buffers
), ZEND_STACK_APPLY_BOTTOMUP
,
164 (int (*)(void *elem
, void *)) http_ob_stack_get
, stack
);
168 http_ob_stack_get(&OG(active_ob_buffer
), stack
);
171 while (OG(ob_nesting_level
)) {
172 php_end_ob_buffer(0, 0 TSRMLS_CC
);
176 php_ob_set_internal_handler(handler_func
, chunk_size
, handler_name
, erase TSRMLS_CC
);
178 for (i
= 0; i
< count
; i
++) {
179 php_ob_buffer
*s
= stack
[i
];
180 if (strcmp(s
->handler_name
, "default output handler")) {
181 php_start_ob_buffer_named(s
->handler_name
, s
->chunk_size
, s
->erase TSRMLS_CC
);
183 php_body_write(s
->buffer
, s
->text_length TSRMLS_CC
);
184 efree(s
->handler_name
);
196 /* {{{ STATUS http_chunked_decode(char *, size_t, char **, size_t *) */
197 PHP_HTTP_API STATUS
_http_chunked_decode(const char *encoded
, size_t encoded_len
,
198 char **decoded
, size_t *decoded_len TSRMLS_DC
)
204 *decoded
= ecalloc(1, encoded_len
);
208 while (((e_ptr
- encoded
) - encoded_len
) > 0) {
209 char hex_len
[9] = {0};
210 size_t chunk_len
= 0;
213 /* read in chunk size */
214 while (isxdigit(*e_ptr
)) {
216 http_error_ex(E_WARNING
, HTTP_E_PARSE
, "Chunk size is too long: 0x%s...", hex_len
);
220 hex_len
[i
++] = *e_ptr
++;
223 /* reached the end */
224 if (!strcmp(hex_len
, "0")) {
229 if (strncmp(e_ptr
, HTTP_CRLF
, 2)) {
230 http_error_ex(E_WARNING
, HTTP_E_PARSE
, "Invalid character (expected 0x0D 0x0A; got: %x %x)", *e_ptr
, *(e_ptr
+ 1));
238 chunk_len
= strtol(hex_len
, &error
, 16);
239 if (error
== hex_len
) {
240 http_error_ex(E_WARNING
, HTTP_E_PARSE
, "Invalid chunk size string: '%s'", hex_len
);
246 memcpy(d_ptr
, e_ptr
+= 2, chunk_len
);
248 e_ptr
+= chunk_len
+ 2;
249 *decoded_len
+= chunk_len
;
256 /* {{{ STATUS http_split_response(zval *, zval *, zval *) */
257 PHP_HTTP_API STATUS
_http_split_response(zval
*response
, zval
*headers
, zval
*body TSRMLS_DC
)
261 STATUS status
= http_split_response_ex(Z_STRVAL_P(response
), Z_STRLEN_P(response
), Z_ARRVAL_P(headers
), &b
, &l
);
262 ZVAL_STRINGL(body
, b
, l
, 0);
267 /* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
268 PHP_HTTP_API STATUS
_http_split_response_ex(char *response
, size_t response_len
,
269 HashTable
*headers
, char **body
, size_t *body_len TSRMLS_DC
)
271 char *header
= response
, *real_body
= NULL
;
273 while (0 < (response_len
- (response
- header
+ 4))) {
274 if ( (*response
++ == '\r') &&
275 (*response
++ == '\n') &&
276 (*response
++ == '\r') &&
277 (*response
++ == '\n')) {
278 real_body
= response
;
283 if (real_body
&& (*body_len
= (response_len
- (real_body
- header
)))) {
284 *body
= ecalloc(1, *body_len
+ 1);
285 memcpy(*body
, real_body
, *body_len
);
288 return http_parse_headers_ex(header
, real_body
? response_len
- *body_len
: response_len
, headers
, 1);
297 * vim600: noet sw=4 ts=4 fdm=marker
298 * vim<600: noet sw=4 ts=4