2 +----------------------------------------------------------------------+
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 +----------------------------------------------------------------------+
25 #include "ext/standard/url.h"
30 #include "php_http_std_defs.h"
31 #include "php_http_api.h"
32 #include "php_http_headers_api.h"
33 #include "php_http_send_api.h"
36 # include "zend_exceptions.h"
37 # include "php_http_exception_object.h"
40 ZEND_EXTERN_MODULE_GLOBALS(http
);
42 /* char *pretty_key(char *, size_t, zend_bool, zebd_bool) */
43 char *_http_pretty_key(char *key
, size_t key_len
, zend_bool uctitle
, zend_bool xhyphen
)
48 if (wasalpha
= isalpha((int) key
[0])) {
49 key
[0] = (char) (uctitle
? toupper((int) key
[0]) : tolower((int) key
[0]));
51 for (i
= 1; i
< key_len
; i
++) {
52 if (isalpha((int) key
[i
])) {
53 key
[i
] = (char) (((!wasalpha
) && uctitle
) ? toupper((int) key
[i
]) : tolower((int) key
[i
]));
56 if (xhyphen
&& (key
[i
] == '_')) {
68 void _http_key_list_default_decoder(const char *encoded
, size_t encoded_len
, char **decoded
, size_t *decoded_len TSRMLS_DC
)
70 *decoded
= estrndup(encoded
, encoded_len
);
71 *decoded_len
= (size_t) php_url_decode(*decoded
, encoded_len
);
76 STATUS
_http_parse_key_list(const char *list
, HashTable
*items
, char separator
, http_key_list_decode_t decode
, zend_bool first_entry_is_name_value_pair TSRMLS_DC
)
78 const char *key
= list
, *val
= NULL
;
79 int vallen
= 0, keylen
= 0, done
= 0;
82 Z_ARRVAL(array
) = items
;
84 if (!(val
= strchr(list
, '='))) {
88 #define HTTP_KEYLIST_VAL(array, k, str, len) \
93 decode(str, len, &decoded, &decoded_len TSRMLS_CC); \
95 decoded = estrdup(str); \
98 add_assoc_stringl(array, k, decoded, decoded_len, 0); \
100 #define HTTP_KEYLIST_FIXKEY() \
102 while (isspace(*key)) ++key; \
103 keylen = val - key; \
104 while (isspace(key[keylen - 1])) --keylen; \
106 #define HTTP_KEYLIST_FIXVAL() \
109 while (isspace(*val)) ++val; \
110 vallen = key - val; \
111 while (isspace(val[vallen - 1])) --vallen; \
114 HTTP_KEYLIST_FIXKEY();
116 if (first_entry_is_name_value_pair
) {
117 HTTP_KEYLIST_VAL(&array
, "name", key
, keylen
);
119 /* just one name=value */
120 if (!(key
= strchr(val
, separator
))) {
121 key
= val
+ strlen(val
);
122 HTTP_KEYLIST_FIXVAL();
123 HTTP_KEYLIST_VAL(&array
, "value", val
, vallen
);
126 /* additional info appended */
128 HTTP_KEYLIST_FIXVAL();
129 HTTP_KEYLIST_VAL(&array
, "value", val
, vallen
);
136 if (!(val
= strchr(key
, '='))) {
140 /* start at 0 if first_entry_is_name_value_pair==0 */
141 if (zend_hash_num_elements(items
)) {
145 HTTP_KEYLIST_FIXKEY();
146 keydup
= estrndup(key
, keylen
);
147 if (!(key
= strchr(val
, separator
))) {
149 key
= val
+ strlen(val
);
151 HTTP_KEYLIST_FIXVAL();
152 HTTP_KEYLIST_VAL(&array
, keydup
, val
, vallen
);
160 /* {{{ void http_error(long, long, char*) */
161 void _http_error_ex(long type
, long code
, const char *format
, ...)
166 va_start(args
, format
);
167 if (type
== E_THROW
) {
170 vspprintf(&message
, 0, format
, args
);
171 zend_throw_exception(http_exception_get_for_code(code
), message
, code TSRMLS_CC
);
176 if (type
!= E_THROW
) {
177 php_verror(NULL
, "", type
, format
, args TSRMLS_CC
);
183 /* {{{ STATUS http_exit(int, char*) */
184 STATUS
_http_exit_ex(int status
, char *header
, zend_bool free_header TSRMLS_DC
)
186 if (SUCCESS
!= http_send_status_header(status
, header
)) {
187 http_error_ex(E_WARNING
, HTTP_E_HEADER
, "Failed to exit with status/header: %d - %s", status
, header
? header
: "");
188 if (free_header
&& header
) {
193 if (free_header
&& header
) {
202 /* {{{ STATUS http_check_method(char *) */
203 STATUS
_http_check_method_ex(const char *method
, const char *methods
)
207 if ( (found
= strstr(methods
, method
)) &&
208 (found
== method
|| !isalpha(found
[-1])) &&
209 (!isalpha(found
[strlen(method
) + 1]))) {
216 /* {{{ zval *http_get_server_var_ex(char *, size_t) */
217 PHP_HTTP_API zval
*_http_get_server_var_ex(const char *key
, size_t key_size
, zend_bool check TSRMLS_DC
)
220 if (SUCCESS
== zend_hash_find(HTTP_SERVER_VARS
, (char *) key
, key_size
, (void **) &var
)) {
222 return Z_STRVAL_PP(var
) && Z_STRLEN_PP(var
) ? *var
: NULL
;
231 /* {{{ zend_bool http_get_request_body(char **, size_t *) */
232 PHP_HTTP_API STATUS
_http_get_request_body_ex(char **body
, size_t *length
, zend_bool dup TSRMLS_DC
)
237 if (SG(request_info
).raw_post_data
) {
238 *length
= SG(request_info
).raw_post_data_length
;
239 *body
= (char *) (dup
? estrndup(SG(request_info
).raw_post_data
, *length
) : SG(request_info
).raw_post_data
);
246 /* {{{ char *http_chunked_decode(char *, size_t, char **, size_t *) */
247 PHP_HTTP_API
const char *_http_chunked_decode(const char *encoded
, size_t encoded_len
,
248 char **decoded
, size_t *decoded_len TSRMLS_DC
)
254 *decoded
= ecalloc(1, encoded_len
);
258 while (((e_ptr
- encoded
) - encoded_len
) > 0) {
261 size_t chunk_len
= 0;
263 chunk_len
= strtol(e_ptr
, &n_ptr
, 16);
266 * - we could not read in chunk size
267 * - chunk size is not followed by HTTP_CRLF|NUL
269 if ((n_ptr
== e_ptr
) || (*n_ptr
&& (no_crlf
= strncmp(n_ptr
, HTTP_CRLF
, lenof(HTTP_CRLF
))))) {
270 /* don't fail on apperently not encoded data */
271 if (e_ptr
== encoded
) {
272 memcpy(*decoded
, encoded
, encoded_len
);
273 *decoded_len
= encoded_len
;
274 return encoded
+ encoded_len
;
278 http_error_ex(E_WARNING
, HTTP_E_PARSE
, "Invalid character (expected 0x0D 0x0A; got: 0x%x 0x%x)", *n_ptr
, *(n_ptr
+ 1));
280 char *error
= estrndup(n_ptr
, strcspn(n_ptr
, "\r\n \0"));
281 http_error_ex(E_WARNING
, HTTP_E_PARSE
, "Invalid chunk size: '%s' at pos %d", error
, n_ptr
- encoded
);
291 /* reached the end */
296 memcpy(d_ptr
, e_ptr
+= 2, chunk_len
);
298 e_ptr
+= chunk_len
+ 2;
299 *decoded_len
+= chunk_len
;
306 /* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
307 PHP_HTTP_API STATUS
_http_split_response(char *response
, size_t response_len
,
308 HashTable
*headers
, char **body
, size_t *body_len TSRMLS_DC
)
310 char *header
= response
, *real_body
= NULL
;
312 while (0 < (response_len
- (response
- header
+ 4))) {
313 if ( (*response
++ == '\r') &&
314 (*response
++ == '\n') &&
315 (*response
++ == '\r') &&
316 (*response
++ == '\n')) {
317 real_body
= response
;
322 if (real_body
&& (*body_len
= (response_len
- (real_body
- header
)))) {
323 *body
= ecalloc(1, *body_len
+ 1);
324 memcpy(*body
, real_body
, *body_len
);
327 return http_parse_headers_ex(header
, headers
, 1);
336 * vim600: noet sw=4 ts=4 fdm=marker
337 * vim<600: noet sw=4 ts=4