- separated http_check_method() from http_check_allowed_methods()
[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 /* {{{ STATUS http_check_method(char *) */
105 STATUS _http_check_method_ex(const char *method, const char *methods)
106 {
107 const char *found;
108
109 if ( (found = strstr(methods, method)) &&
110 (found == method || !isalpha(found[-1])) &&
111 (!isalpha(found[strlen(method) + 1]))) {
112 return SUCCESS;
113 }
114 return FAILURE;
115 }
116 /* }}} */
117
118 /* {{{ zval *http_get_server_var_ex(char *, size_t) */
119 PHP_HTTP_API zval *_http_get_server_var_ex(const char *key, size_t key_size, zend_bool check TSRMLS_DC)
120 {
121 zval **var;
122 if (SUCCESS == zend_hash_find(HTTP_SERVER_VARS, (char *) key, key_size, (void **) &var)) {
123 if (check) {
124 return Z_STRVAL_PP(var) && Z_STRLEN_PP(var) ? *var : NULL;
125 } else {
126 return *var;
127 }
128 }
129 return NULL;
130 }
131 /* }}} */
132
133
134 /* {{{ char *http_chunked_decode(char *, size_t, char **, size_t *) */
135 PHP_HTTP_API char *_http_chunked_decode(const char *encoded, size_t encoded_len,
136 char **decoded, size_t *decoded_len TSRMLS_DC)
137 {
138 const char *e_ptr;
139 char *d_ptr;
140
141 *decoded_len = 0;
142 *decoded = ecalloc(1, encoded_len);
143 d_ptr = *decoded;
144 e_ptr = encoded;
145
146 while (((e_ptr - encoded) - encoded_len) > 0) {
147 char hex_len[9] = {0};
148 size_t chunk_len = 0;
149 int i = 0;
150
151 /* read in chunk size */
152 while (isxdigit(*e_ptr)) {
153 if (i == 9) {
154 http_error_ex(E_WARNING, HTTP_E_PARSE, "Chunk size is too long: 0x%s...", hex_len);
155 efree(*decoded);
156 return NULL;
157 }
158 hex_len[i++] = *e_ptr++;
159 }
160
161 /* reached the end */
162 if (!strcmp(hex_len, "0")) {
163 break;
164 }
165
166 /* new line */
167 if (strncmp(e_ptr, HTTP_CRLF, 2)) {
168 http_error_ex(E_WARNING, HTTP_E_PARSE,
169 "Invalid character (expected 0x0D 0x0A; got: 0x%x(%c) 0x%x(%c))",
170 *e_ptr, *e_ptr, *(e_ptr + 1), *(e_ptr + 1));
171 efree(*decoded);
172 return NULL;
173 }
174
175 /* hex to long */
176 {
177 char *error = NULL;
178 chunk_len = strtol(hex_len, &error, 16);
179 if (error == hex_len) {
180 http_error_ex(E_WARNING, HTTP_E_PARSE, "Invalid chunk size string: '%s'", hex_len);
181 efree(*decoded);
182 return NULL;
183 }
184 }
185
186 memcpy(d_ptr, e_ptr += 2, chunk_len);
187 d_ptr += chunk_len;
188 e_ptr += chunk_len + 2;
189 *decoded_len += chunk_len;
190 }
191
192 return e_ptr;
193 }
194 /* }}} */
195
196 /* {{{ STATUS http_split_response(zval *, zval *, zval *) */
197 PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC)
198 {
199 char *b = NULL;
200 size_t l = 0;
201 STATUS status = http_split_response_ex(Z_STRVAL_P(response), Z_STRLEN_P(response), Z_ARRVAL_P(headers), &b, &l);
202 ZVAL_STRINGL(body, b, l, 0);
203 return status;
204 }
205 /* }}} */
206
207 /* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
208 PHP_HTTP_API STATUS _http_split_response_ex(char *response, size_t response_len,
209 HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
210 {
211 char *header = response, *real_body = NULL;
212
213 while (0 < (response_len - (response - header + 4))) {
214 if ( (*response++ == '\r') &&
215 (*response++ == '\n') &&
216 (*response++ == '\r') &&
217 (*response++ == '\n')) {
218 real_body = response;
219 break;
220 }
221 }
222
223 if (real_body && (*body_len = (response_len - (real_body - header)))) {
224 *body = ecalloc(1, *body_len + 1);
225 memcpy(*body, real_body, *body_len);
226 }
227
228 return http_parse_headers_ex(header, real_body ? response_len - *body_len : response_len, headers, 1);
229 }
230 /* }}} */
231
232 /*
233 * Local variables:
234 * tab-width: 4
235 * c-basic-offset: 4
236 * End:
237 * vim600: noet sw=4 ts=4 fdm=marker
238 * vim<600: noet sw=4 ts=4
239 */
240