- add http_match_request_header()
[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 int no_crlf = 0;
149 char *n_ptr;
150 size_t chunk_len = 0;
151
152 chunk_len = strtol(e_ptr, &n_ptr, 16);
153
154 /* check if:
155 * - we could not read in chunk size
156 * - chunk size is not followed by HTTP_CRLF|NUL
157 */
158 if ((n_ptr == e_ptr) || (*n_ptr && (no_crlf = strncmp(n_ptr, HTTP_CRLF, lenof(HTTP_CRLF))))) {
159 /* don't fail on apperently not encoded data */
160 if (e_ptr == encoded) {
161 memcpy(*decoded, encoded, encoded_len);
162 *decoded_len = encoded_len;
163 return encoded + encoded_len;
164 } else {
165 efree(*decoded);
166 if (no_crlf) {
167 http_error_ex(E_WARNING, HTTP_E_PARSE, "Invalid character (expected 0x0D 0x0A; got: 0x%x 0x%x)", *n_ptr, *(n_ptr + 1));
168 } else {
169 char *error = estrndup(n_ptr, strcspn(n_ptr, "\r\n \0"));
170 http_error_ex(E_WARNING, HTTP_E_PARSE, "Invalid chunk size: '%s' at pos %d", error, n_ptr - encoded);
171 efree(error);
172 }
173
174 return NULL;
175 }
176 } else {
177 e_ptr = n_ptr;
178 }
179
180 /* reached the end */
181 if (!chunk_len) {
182 break;
183 }
184
185 memcpy(d_ptr, e_ptr += 2, chunk_len);
186 d_ptr += chunk_len;
187 e_ptr += chunk_len + 2;
188 *decoded_len += chunk_len;
189 }
190
191 return e_ptr;
192 }
193 /* }}} */
194
195 /* {{{ STATUS http_split_response(zval *, zval *, zval *) */
196 PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC)
197 {
198 char *b = NULL;
199 size_t l = 0;
200 STATUS status = http_split_response_ex(Z_STRVAL_P(response), Z_STRLEN_P(response), Z_ARRVAL_P(headers), &b, &l);
201 ZVAL_STRINGL(body, b, l, 0);
202 return status;
203 }
204 /* }}} */
205
206 /* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
207 PHP_HTTP_API STATUS _http_split_response_ex(char *response, size_t response_len,
208 HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
209 {
210 char *header = response, *real_body = NULL;
211
212 while (0 < (response_len - (response - header + 4))) {
213 if ( (*response++ == '\r') &&
214 (*response++ == '\n') &&
215 (*response++ == '\r') &&
216 (*response++ == '\n')) {
217 real_body = response;
218 break;
219 }
220 }
221
222 if (real_body && (*body_len = (response_len - (real_body - header)))) {
223 *body = ecalloc(1, *body_len + 1);
224 memcpy(*body, real_body, *body_len);
225 }
226
227 return http_parse_headers_ex(header, headers, 1);
228 }
229 /* }}} */
230
231 /*
232 * Local variables:
233 * tab-width: 4
234 * c-basic-offset: 4
235 * End:
236 * vim600: noet sw=4 ts=4 fdm=marker
237 * vim<600: noet sw=4 ts=4
238 */
239