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