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 +----------------------------------------------------------------------+
24 #include "php_http_std_defs.h"
25 #include "php_http_message_api.h"
26 #include "php_http_api.h"
27 #include "php_http_headers_api.h"
29 #include "phpstr/phpstr.h"
31 #define http_message_parse_nested(msg, begin, length) _http_message_parse_nested((msg), (begin), (length) TSRMLS_CC)
32 static inline http_message
*_http_message_parse_nested(http_message
*msg
, const char *begin
, size_t length TSRMLS_DC
)
36 while (isspace(*begin
)) {
43 if (new = http_message_parse(begin
, length
)) {
50 PHP_HTTP_API http_message
*_http_message_init_ex(http_message
*message
, http_message_type type
)
53 message
= ecalloc(1, sizeof(http_message
));
57 message
->nested
= NULL
;
58 phpstr_init(&message
->body
);
59 zend_hash_init(&message
->hdrs
, 0, NULL
, ZVAL_PTR_DTOR
, 0);
64 PHP_HTTP_API http_message
*_http_message_parse_ex(http_message
*msg
, const char *message
, size_t message_length TSRMLS_DC
)
67 size_t header_length
= 0;
68 zend_bool free_msg
= msg
? 0 : 1;
70 if (message_length
< HTTP_MSG_MIN_SIZE
) {
78 msg
= http_message_init(msg
);
80 if (body
= strstr(message
, HTTP_CRLF HTTP_CRLF
)) {
81 body
+= lenof(HTTP_CRLF HTTP_CRLF
);
82 header_length
= body
- message
;
84 header_length
= message_length
;
87 if (SUCCESS
!= http_parse_headers_cb((char *)message
, header_length
, &msg
->hdrs
, 1, http_message_parse_headers_callback
, (void **) &msg
)) {
89 http_message_free(msg
);
98 if (SUCCESS
== zend_hash_find(&msg
->hdrs
, "Content-Length", sizeof("Content-Length"), (void **) &c
)) {
99 long len
= atol(Z_STRVAL_PP(c
));
100 phpstr_from_string_ex(PHPSTR(msg
), body
, len
);
101 if (nested
= http_message_parse_nested(msg
, body
+ len
, message
+ message_length
- body
- len
)) {
105 SUCCESS
== zend_hash_find(&msg
->hdrs
, "Transfer-Encoding", sizeof("Transfer-Encoding"), (void **) &c
) &&
106 !strcasecmp("chunked", Z_STRVAL_PP(c
))) {
111 if (end
= http_chunked_decode(body
, message_length
- header_length
, &decoded
, &decoded_len
)) {
112 phpstr_from_string_ex(PHPSTR(msg
), decoded
, decoded_len
);
114 if (nested
= http_message_parse_nested(msg
, end
, message
+ message_length
- end
)) {
119 phpstr_from_string_ex(PHPSTR(msg
), body
, message_length
- header_length
);
126 PHP_HTTP_API
void _http_message_parse_headers_callback(void **message
, char *http_line
, size_t line_length
, HashTable
**headers TSRMLS_DC
)
128 http_message
*old
= (http_message
*) *message
;
131 if (old
->type
|| zend_hash_num_elements(&old
->hdrs
) || PHPSTR_LEN(old
)) {
132 new = http_message_new();
136 *headers
= &new->hdrs
;
142 if (!strncmp(http_line
, "HTTP/1.", lenof("HTTP/1."))) {
143 new->type
= HTTP_MSG_RESPONSE
;
144 new->info
.response
.http_version
= atof(http_line
+ lenof("HTTP/"));
145 new->info
.response
.code
= atoi(http_line
+ lenof("HTTP/1.1 "));
148 if (!strncmp(http_line
+ line_length
- lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) {
149 const char *method_sep_uri
= strchr(http_line
, ' ');
151 new->type
= HTTP_MSG_REQUEST
;
152 new->info
.request
.http_version
= atof(http_line
+ line_length
- lenof("1.1"));
153 new->info
.request
.method
= estrndup(http_line
, method_sep_uri
- http_line
);
154 new->info
.request
.URI
= estrndup(method_sep_uri
+ 1, http_line
+ line_length
- method_sep_uri
- 1 - lenof(" HTTP/1.1"));
158 PHP_HTTP_API
void _http_message_tostring(http_message
*msg
, char **string
, size_t *length
)
165 phpstr_init_ex(&str
, 4096, 0);
171 case HTTP_MSG_REQUEST
:
172 phpstr_appendf(&str
, "%s %s HTTP/%1.1f" HTTP_CRLF
,
173 msg
->info
.request
.method
,
174 msg
->info
.request
.URI
,
175 msg
->info
.request
.http_version
);
178 case HTTP_MSG_RESPONSE
:
179 phpstr_appendf(&str
, "HTTP/%1.1f %d" HTTP_CRLF
,
180 msg
->info
.response
.http_version
,
181 msg
->info
.response
.code
);
185 FOREACH_HASH_KEYVAL(&msg
->hdrs
, key
, idx
, header
) {
187 zval
**single_header
;
189 switch (Z_TYPE_PP(header
))
192 phpstr_appendf(&str
, "%s: %s" HTTP_CRLF
, key
, Z_STRVAL_PP(header
));
196 FOREACH_VAL(*header
, single_header
) {
197 phpstr_appendf(&str
, "%s: %s" HTTP_CRLF
, key
, Z_STRVAL_PP(single_header
));
206 phpstr_appends(&str
, HTTP_CRLF
);
207 phpstr_append(&str
, PHPSTR_VAL(msg
), PHPSTR_LEN(msg
));
208 phpstr_appends(&str
, HTTP_CRLF
);
210 } while (msg
= msg
->nested
);
212 data
= phpstr_data(&str
, string
, length
);
220 PHP_HTTP_API
void _http_message_dtor(http_message
*message
)
223 zend_hash_destroy(&message
->hdrs
);
224 phpstr_dtor(PHPSTR(message
));
225 if (message
->type
== HTTP_MSG_REQUEST
) {
226 if (message
->info
.request
.method
) {
227 efree(message
->info
.request
.method
);
228 message
->info
.request
.method
= NULL
;
230 if (message
->info
.request
.URI
) {
231 efree(message
->info
.request
.URI
);
232 message
->info
.request
.URI
= NULL
;
238 PHP_HTTP_API
void _http_message_free(http_message
*message
)
241 if (message
->nested
) {
242 http_message_free(message
->nested
);
243 message
->nested
= NULL
;
245 http_message_dtor(message
);
255 * vim600: noet sw=4 ts=4 fdm=marker
256 * vim<600: noet sw=4 ts=4