- added missing methods (except setBody) for HttpMessage
[m6w6/ext-http] / http_api.c
1 /*
2 +----------------------------------------------------------------------+
3 | PECL :: http |
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 +----------------------------------------------------------------------+
14 */
15
16 /* $Id$ */
17
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
21
22 #include <ctype.h>
23
24 #include "php.h"
25 #include "php_output.h"
26 #include "ext/standard/md5.h"
27
28 #include "php_http.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"
34
35 #ifdef ZEND_ENGINE_2
36 # include "php_http_exception_object.h"
37 #endif
38
39 ZEND_EXTERN_MODULE_GLOBALS(http);
40
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)
43 {
44 if (key && key_len) {
45 unsigned i, wasalpha;
46 if (wasalpha = isalpha(key[0])) {
47 key[0] = uctitle ? toupper(key[0]) : tolower(key[0]);
48 }
49 for (i = 1; i < key_len; i++) {
50 if (isalpha(key[i])) {
51 key[i] = ((!wasalpha) && uctitle) ? toupper(key[i]) : tolower(key[i]);
52 wasalpha = 1;
53 } else {
54 if (xhyphen && (key[i] == '_')) {
55 key[i] = '-';
56 }
57 wasalpha = 0;
58 }
59 }
60 }
61 return key;
62 }
63 /* }}} */
64
65 /* {{{ void http_error(long, long, char*) */
66 void _http_error_ex(long type, long code, const char *format, ...)
67 {
68 va_list args;
69 TSRMLS_FETCH();
70
71 va_start(args, format);
72 if (type == E_THROW) {
73 #ifdef ZEND_ENGINE_2
74 char *message;
75 vspprintf(&message, 0, format, args);
76 zend_throw_exception(http_exception_get_default(), message, code TSRMLS_CC);
77 #else
78 type = E_WARNING;
79 #endif
80 }
81 if (type != E_THROW) {
82 php_verror(NULL, "", type, format, args TSRMLS_CC);
83 }
84 va_end(args);
85 }
86 /* }}} */
87
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)
90 {
91 static int i = 0;
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;
97 b->erase = o->erase;
98 s[i++] = b;
99 return SUCCESS;
100 }
101 /* }}} */
102
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)
105 {
106 zval **var;
107 if (SUCCESS == zend_hash_find(HTTP_SERVER_VARS, (char *) key, key_size, (void **) &var)) {
108 if (check) {
109 return Z_STRVAL_PP(var) && Z_STRLEN_PP(var) ? *var : NULL;
110 } else {
111 return *var;
112 }
113 }
114 return NULL;
115 }
116 /* }}} */
117
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)
121 {
122 char etag[33] = { 0 };
123 unsigned char digest[16];
124
125 if (mode & PHP_OUTPUT_HANDLER_START) {
126 PHP_MD5Init(&HTTP_G(etag_md5));
127 }
128
129 PHP_MD5Update(&HTTP_G(etag_md5), output, output_len);
130
131 if (mode & PHP_OUTPUT_HANDLER_END) {
132 PHP_MD5Final(digest, &HTTP_G(etag_md5));
133
134 /* just do that if desired */
135 if (HTTP_G(etag_started)) {
136 make_digest(etag, digest);
137
138 if (http_etag_match("HTTP_IF_NONE_MATCH", etag)) {
139 http_send_status(304);
140 zend_bailout();
141 } else {
142 http_send_etag(etag, 32);
143 }
144 }
145 }
146
147 *handled_output_len = output_len;
148 *handled_output = estrndup(output, output_len);
149 }
150 /* }}} */
151
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)
155 {
156 php_ob_buffer **stack;
157 int count, i;
158
159 if (count = OG(ob_nesting_level)) {
160 stack = ecalloc(count, sizeof(php_ob_buffer *));
161
162 if (count > 1) {
163 zend_stack_apply_with_argument(&OG(ob_buffers), ZEND_STACK_APPLY_BOTTOMUP,
164 (int (*)(void *elem, void *)) http_ob_stack_get, stack);
165 }
166
167 if (count > 0) {
168 http_ob_stack_get(&OG(active_ob_buffer), stack);
169 }
170
171 while (OG(ob_nesting_level)) {
172 php_end_ob_buffer(0, 0 TSRMLS_CC);
173 }
174 }
175
176 php_ob_set_internal_handler(handler_func, chunk_size, handler_name, erase TSRMLS_CC);
177
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);
182 }
183 php_body_write(s->buffer, s->text_length TSRMLS_CC);
184 efree(s->handler_name);
185 efree(s->buffer);
186 efree(s);
187 }
188 if (count) {
189 efree(stack);
190 }
191
192 return SUCCESS;
193 }
194 /* }}} */
195
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)
199 {
200 const char *e_ptr;
201 char *d_ptr;
202
203 *decoded_len = 0;
204 *decoded = ecalloc(1, encoded_len);
205 d_ptr = *decoded;
206 e_ptr = encoded;
207
208 while (((e_ptr - encoded) - encoded_len) > 0) {
209 char hex_len[9] = {0};
210 size_t chunk_len = 0;
211 int i = 0;
212
213 /* read in chunk size */
214 while (isxdigit(*e_ptr)) {
215 if (i == 9) {
216 http_error_ex(E_WARNING, HTTP_E_PARSE, "Chunk size is too long: 0x%s...", hex_len);
217 efree(*decoded);
218 return FAILURE;
219 }
220 hex_len[i++] = *e_ptr++;
221 }
222
223 /* reached the end */
224 if (!strcmp(hex_len, "0")) {
225 break;
226 }
227
228 /* new line */
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));
231 efree(*decoded);
232 return FAILURE;
233 }
234
235 /* hex to long */
236 {
237 char *error = NULL;
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);
241 efree(*decoded);
242 return FAILURE;
243 }
244 }
245
246 memcpy(d_ptr, e_ptr += 2, chunk_len);
247 d_ptr += chunk_len;
248 e_ptr += chunk_len + 2;
249 *decoded_len += chunk_len;
250 }
251
252 return SUCCESS;
253 }
254 /* }}} */
255
256 /* {{{ STATUS http_split_response(zval *, zval *, zval *) */
257 PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC)
258 {
259 char *b = NULL;
260 size_t l = 0;
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);
263 return status;
264 }
265 /* }}} */
266
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)
270 {
271 char *header = response, *real_body = NULL;
272
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;
279 break;
280 }
281 }
282
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);
286 }
287
288 return http_parse_headers_ex(header, real_body ? response_len - *body_len : response_len, headers, 1);
289 }
290 /* }}} */
291
292 /*
293 * Local variables:
294 * tab-width: 4
295 * c-basic-offset: 4
296 * End:
297 * vim600: noet sw=4 ts=4 fdm=marker
298 * vim<600: noet sw=4 ts=4
299 */
300