+ while (isspace(http_line[line_length-1])) --line_length;
+
+ // response
+ if (!strncmp(http_line, "HTTP/1.", lenof("HTTP/1."))) {
+ new->type = HTTP_MSG_RESPONSE;
+ new->info.response.http_version = atof(http_line + lenof("HTTP/"));
+ new->info.response.code = atoi(http_line + lenof("HTTP/1.1 "));
+ } else
+ // request
+ if (!strncmp(http_line + line_length - lenof("HTTP/1.1"), "HTTP/1.", lenof("HTTP/1."))) {
+ const char *method_sep_uri = strchr(http_line, ' ');
+ new->type = HTTP_MSG_REQUEST;
+ new->info.request.http_version = atof(http_line + line_length - lenof("1.1"));
+ new->info.request.method = estrndup(http_line, method_sep_uri - http_line);
+ new->info.request.URI = estrndup(method_sep_uri + 1, http_line + line_length - method_sep_uri - 1 - lenof(" HTTP/1.1"));
+ }
+}
+
+#define http_message_init_type _http_message_init_type
+static inline void _http_message_init_type(http_message *message, http_message_type type)
+{
+ switch (message->type = type)
+ {
+ case HTTP_MSG_RESPONSE:
+ message->info.response.http_version = .0;
+ message->info.response.code = 0;
+ break;
+
+ case HTTP_MSG_REQUEST:
+ message->info.request.http_version = .0;
+ message->info.request.method = NULL;
+ message->info.request.URI = NULL;
+ break;
+
+ case HTTP_MSG_NONE:
+ default:
+ break;
+ }
+}
+
+#define http_message_header(m, h) _http_message_header_ex((m), (h), sizeof(h))
+#define http_message_header_ex _http_message_header_ex
+static inline zval *_http_message_header_ex(http_message *msg, char *key_str, size_t key_len)
+{
+ zval **header;
+ if (SUCCESS == zend_hash_find(&msg->hdrs, key_str, key_len, (void **) &header)) {
+ return *header;