- unify script termination
[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
26 #include "php_http.h"
27 #include "php_http_std_defs.h"
28 #include "php_http_api.h"
29 #include "php_http_headers_api.h"
30 #include "php_http_send_api.h"
31
32 #ifdef ZEND_ENGINE_2
33 # include "php_http_exception_object.h"
34 #endif
35
36 ZEND_EXTERN_MODULE_GLOBALS(http);
37
38 /* char *pretty_key(char *, size_t, zend_bool, zebd_bool) */
39 char *_http_pretty_key(char *key, size_t key_len, zend_bool uctitle, zend_bool xhyphen)
40 {
41 if (key && key_len) {
42 unsigned i, wasalpha;
43 if (wasalpha = isalpha(key[0])) {
44 key[0] = uctitle ? toupper(key[0]) : tolower(key[0]);
45 }
46 for (i = 1; i < key_len; i++) {
47 if (isalpha(key[i])) {
48 key[i] = ((!wasalpha) && uctitle) ? toupper(key[i]) : tolower(key[i]);
49 wasalpha = 1;
50 } else {
51 if (xhyphen && (key[i] == '_')) {
52 key[i] = '-';
53 }
54 wasalpha = 0;
55 }
56 }
57 }
58 return key;
59 }
60 /* }}} */
61
62 /* {{{ void http_error(long, long, char*) */
63 void _http_error_ex(long type, long code, const char *format, ...)
64 {
65 va_list args;
66 TSRMLS_FETCH();
67
68 va_start(args, format);
69 if (type == E_THROW) {
70 #ifdef ZEND_ENGINE_2
71 char *message;
72 vspprintf(&message, 0, format, args);
73 zend_throw_exception(http_exception_get_default(), message, code TSRMLS_CC);
74 #else
75 type = E_WARNING;
76 #endif
77 }
78 if (type != E_THROW) {
79 php_verror(NULL, "", type, format, args TSRMLS_CC);
80 }
81 va_end(args);
82 }
83 /* }}} */
84
85 /* {{{ STATUS http_exit(int, char*) */
86 STATUS _http_exit_ex(int status, char *header, zend_bool free_header TSRMLS_DC)
87 {
88 if (SUCCESS != http_send_status_header(status, header)) {
89 http_error_ex(E_WARNING, HTTP_E_HEADER, "Failed to exit with status/header: %d - %s", status, header ? header : "");
90 if (free_header && header) {
91 efree(header);
92 }
93 return FAILURE;
94 }
95 if (free_header && header) {
96 efree(header);
97 }
98 zend_bailout();
99 /* fake */
100 return SUCCESS;
101 }
102 /* }}} */
103
104 /* {{{ zval *http_get_server_var_ex(char *, size_t) */
105 PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_size, zend_bool check TSRMLS_DC)
106 {
107 zval **var;
108 if (SUCCESS == zend_hash_find(HTTP_SERVER_VARS, (char *) key, key_size, (void **) &var)) {
109 if (check) {
110 return Z_STRVAL_PP(var) && Z_STRLEN_PP(var) ? *var : NULL;
111 } else {
112 return *var;
113 }
114 }
115 return NULL;
116 }
117 /* }}} */
118
119
120 /* {{{ STATUS http_chunked_decode(char *, size_t, char **, size_t *) */
121 PHP_HTTP_API STATUS _http_chunked_decode(const char *encoded, size_t encoded_len,
122 char **decoded, size_t *decoded_len TSRMLS_DC)
123 {
124 const char *e_ptr;
125 char *d_ptr;
126
127 *decoded_len = 0;
128 *decoded = ecalloc(1, encoded_len);
129 d_ptr = *decoded;
130 e_ptr = encoded;
131
132 while (((e_ptr - encoded) - encoded_len) > 0) {
133 char hex_len[9] = {0};
134 size_t chunk_len = 0;
135 int i = 0;
136
137 /* read in chunk size */
138 while (isxdigit(*e_ptr)) {
139 if (i == 9) {
140 http_error_ex(E_WARNING, HTTP_E_PARSE, "Chunk size is too long: 0x%s...", hex_len);
141 efree(*decoded);
142 return FAILURE;
143 }
144 hex_len[i++] = *e_ptr++;
145 }
146
147 /* reached the end */
148 if (!strcmp(hex_len, "0")) {
149 break;
150 }
151
152 /* new line */
153 if (strncmp(e_ptr, HTTP_CRLF, 2)) {
154 http_error_ex(E_WARNING, HTTP_E_PARSE, "Invalid character (expected 0x0D 0x0A; got: %x %x)", *e_ptr, *(e_ptr + 1));
155 efree(*decoded);
156 return FAILURE;
157 }
158
159 /* hex to long */
160 {
161 char *error = NULL;
162 chunk_len = strtol(hex_len, &error, 16);
163 if (error == hex_len) {
164 http_error_ex(E_WARNING, HTTP_E_PARSE, "Invalid chunk size string: '%s'", hex_len);
165 efree(*decoded);
166 return FAILURE;
167 }
168 }
169
170 memcpy(d_ptr, e_ptr += 2, chunk_len);
171 d_ptr += chunk_len;
172 e_ptr += chunk_len + 2;
173 *decoded_len += chunk_len;
174 }
175
176 return SUCCESS;
177 }
178 /* }}} */
179
180 /* {{{ STATUS http_split_response(zval *, zval *, zval *) */
181 PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC)
182 {
183 char *b = NULL;
184 size_t l = 0;
185 STATUS status = http_split_response_ex(Z_STRVAL_P(response), Z_STRLEN_P(response), Z_ARRVAL_P(headers), &b, &l);
186 ZVAL_STRINGL(body, b, l, 0);
187 return status;
188 }
189 /* }}} */
190
191 /* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
192 PHP_HTTP_API STATUS _http_split_response_ex(char *response, size_t response_len,
193 HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
194 {
195 char *header = response, *real_body = NULL;
196
197 while (0 < (response_len - (response - header + 4))) {
198 if ( (*response++ == '\r') &&
199 (*response++ == '\n') &&
200 (*response++ == '\r') &&
201 (*response++ == '\n')) {
202 real_body = response;
203 break;
204 }
205 }
206
207 if (real_body && (*body_len = (response_len - (real_body - header)))) {
208 *body = ecalloc(1, *body_len + 1);
209 memcpy(*body, real_body, *body_len);
210 }
211
212 return http_parse_headers_ex(header, real_body ? response_len - *body_len : response_len, headers, 1);
213 }
214 /* }}} */
215
216 /*
217 * Local variables:
218 * tab-width: 4
219 * c-basic-offset: 4
220 * End:
221 * vim600: noet sw=4 ts=4 fdm=marker
222 * vim<600: noet sw=4 ts=4
223 */
224