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