- even better use a object struct member for that crap
[m6w6/ext-http] / http_message_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 "php.h"
23 #include "php_http.h"
24 #include "php_http_std_defs.h"
25 #include "php_http_message_api.h"
26 #include "php_http_headers_api.h"
27
28 #include "phpstr/phpstr.h"
29
30 PHP_HTTP_API http_message *_http_message_init_ex(http_message *message, http_message_type type)
31 {
32 if (!message) {
33 message = ecalloc(1, sizeof(http_message));
34 }
35
36 message->type = type;
37 message->nested = NULL;
38 phpstr_init(&message->body);
39 zend_hash_init(&message->hdrs, 0, NULL, ZVAL_PTR_DTOR, 0);
40
41 return message;
42 }
43
44 PHP_HTTP_API http_message *_http_message_parse_ex(http_message *msg, char *message, size_t message_length, zend_bool dup TSRMLS_DC)
45 {
46 char *body = NULL;
47 size_t header_length = 0;
48 zend_bool free_msg = msg ? 0 : 1;
49
50 if (message_length < HTTP_MSG_MIN_SIZE) {
51 return NULL;
52 }
53
54 if (!message) {
55 return NULL;
56 }
57
58 msg = http_message_init(msg);
59 msg->len = message_length;
60 msg->raw = dup ? estrndup(message, message_length) : message;
61
62 if (body = strstr(message, HTTP_CRLF HTTP_CRLF)) {
63 body += lenof(HTTP_CRLF HTTP_CRLF);
64 header_length = body - message;
65 } else {
66 header_length = message_length;
67 }
68
69 if (SUCCESS != http_parse_headers_cb(message, header_length, &msg->hdrs, 1, http_message_parse_headers_callback, (void **) &msg)) {
70 if (free_msg) {
71 http_message_free(msg);
72 }
73 return NULL;
74 }
75
76 if (body) {
77 phpstr_from_string_ex(PHPSTR(msg), body, message_length - header_length);
78 }
79
80 return msg;
81 }
82
83 PHP_HTTP_API void _http_message_parse_headers_callback(void **message, char *http_line, size_t line_length, HashTable **headers TSRMLS_DC)
84 {
85 http_message *old = (http_message *) *message;
86 http_message *new;
87
88 if (old->type || zend_hash_num_elements(&old->hdrs) || PHPSTR_LEN(old)) {
89 new = http_message_new();
90
91 new->nested = old;
92 *message = new;
93 *headers = &new->hdrs;
94 } else {
95 new = old;
96 }
97
98 // response
99 if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) {
100 new->type = HTTP_MSG_RESPONSE;
101 new->info.response.http_version = atof(http_line + lenof("HTTP/"));
102 new->info.response.status = atoi(http_line + lenof("HTTP/1.1 "));
103 } else
104 // request
105 if (!strncmp(http_line + line_length - lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) {
106 const char *method_sep_uri = strchr(http_line, ' ');
107
108 new->type = HTTP_MSG_REQUEST;
109 new->info.request.http_version = atof(http_line + line_length - lenof("1.1"));
110 new->info.request.method = estrndup(http_line, method_sep_uri - http_line);
111 new->info.request.URI = estrndup(method_sep_uri + 1, http_line + line_length - method_sep_uri - 1 - lenof(" HTTP/1.1"));
112 }
113 }
114
115 PHP_HTTP_API void _http_message_tostring(http_message *msg, char **string, size_t *length)
116 {
117 phpstr str;
118 char *key, *data;
119 ulong idx;
120 zval **header;
121
122 phpstr_init_ex(&str, msg->len, 1);
123 /* set sane alloc size */
124 str.size = 4096;
125
126 switch (msg->type)
127 {
128 case HTTP_MSG_REQUEST:
129 phpstr_appendf(&str, "%s %s HTTP/%1.1f" HTTP_CRLF,
130 msg->info.request.method,
131 msg->info.request.URI,
132 msg->info.request.http_version);
133 break;
134
135 case HTTP_MSG_RESPONSE:
136 phpstr_appendf(&str, "HTTP/%1.1f %d" HTTP_CRLF,
137 msg->info.response.http_version,
138 msg->info.response.status);
139 break;
140 }
141
142 FOREACH_HASH_KEYVAL(&msg->hdrs, key, idx, header) {
143 if (key) {
144 zval **single_header;
145
146 switch (Z_TYPE_PP(header))
147 {
148 case IS_STRING:
149 phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(header));
150 break;
151
152 case IS_ARRAY:
153 FOREACH_VAL(*header, single_header) {
154 phpstr_appendf(&str, "%s: %s" HTTP_CRLF, key, Z_STRVAL_PP(single_header));
155 }
156 break;
157 }
158
159 key = NULL;
160 }
161 }
162
163 phpstr_appends(&str, HTTP_CRLF);
164 phpstr_append(&str, PHPSTR_VAL(msg), PHPSTR_LEN(msg));
165
166 data = phpstr_data(&str, string, length);
167 if (!string) {
168 efree(data);
169 }
170
171 phpstr_dtor(&str);
172 }
173
174 PHP_HTTP_API void _http_message_dtor(http_message *message)
175 {
176 if (message) {
177 zend_hash_destroy(&message->hdrs);
178 phpstr_dtor(PHPSTR(message));
179 if (message->raw) {
180 efree(message->raw);
181 message->raw = NULL;
182 }
183 if (message->type == HTTP_MSG_REQUEST) {
184 if (message->info.request.method) {
185 efree(message->info.request.method);
186 message->info.request.method = NULL;
187 }
188 if (message->info.request.URI) {
189 efree(message->info.request.URI);
190 message->info.request.URI = NULL;
191 }
192 }
193 }
194 }
195
196 PHP_HTTP_API void _http_message_free(http_message *message)
197 {
198 if (message) {
199 if (message->nested) {
200 http_message_free(message->nested);
201 }
202 http_message_dtor(message);
203 efree(message);
204 }
205 }
206
207 /*
208 * Local variables:
209 * tab-width: 4
210 * c-basic-offset: 4
211 * End:
212 * vim600: noet sw=4 ts=4 fdm=marker
213 * vim<600: noet sw=4 ts=4
214 */
215