- add put methods for HttpRequest
[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,
168 "Invalid character (expected 0x0D 0x0A; got: 0x%x 0x%x)", *n_ptr, *(n_ptr + 1));
169 } else {
170 char *error = estrndup(n_ptr, strcspn(n_ptr, "\r\n \0"));
171 http_error_ex(E_WARNING, HTTP_E_PARSE, "Invalid chunk size: '%s' at pos %d", error, n_ptr - encoded);
172 efree(error);
173 efree(decoded);
174 }
175
176 return NULL;
177 }
178 } else {
179 e_ptr = n_ptr;
180 }
181
182 /* reached the end */
183 if (!chunk_len) {
184 break;
185 }
186
187 memcpy(d_ptr, e_ptr += 2, chunk_len);
188 d_ptr += chunk_len;
189 e_ptr += chunk_len + 2;
190 *decoded_len += chunk_len;
191 }
192
193 return e_ptr;
194 }
195 /* }}} */
196
197 /* {{{ STATUS http_split_response(zval *, zval *, zval *) */
198 PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC)
199 {
200 char *b = NULL;
201 size_t l = 0;
202 STATUS status = http_split_response_ex(Z_STRVAL_P(response), Z_STRLEN_P(response), Z_ARRVAL_P(headers), &b, &l);
203 ZVAL_STRINGL(body, b, l, 0);
204 return status;
205 }
206 /* }}} */
207
208 /* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
209 PHP_HTTP_API STATUS _http_split_response_ex(char *response, size_t response_len,
210 HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
211 {
212 char *header = response, *real_body = NULL;
213
214 while (0 < (response_len - (response - header + 4))) {
215 if ( (*response++ == '\r') &&
216 (*response++ == '\n') &&
217 (*response++ == '\r') &&
218 (*response++ == '\n')) {
219 real_body = response;
220 break;
221 }
222 }
223
224 if (real_body && (*body_len = (response_len - (real_body - header)))) {
225 *body = ecalloc(1, *body_len + 1);
226 memcpy(*body, real_body, *body_len);
227 }
228
229 return http_parse_headers_ex(header, headers, 1);
230 }
231 /* }}} */
232
233 /*
234 * Local variables:
235 * tab-width: 4
236 * c-basic-offset: 4
237 * End:
238 * vim600: noet sw=4 ts=4 fdm=marker
239 * vim<600: noet sw=4 ts=4
240 */
241