fix test
[m6w6/ext-http] / src / php_http_info.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: http |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2004-2014, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13 #include "php_http_api.h"
14
15 php_http_info_t *php_http_info_init(php_http_info_t *i TSRMLS_DC)
16 {
17 if (!i) {
18 i = emalloc(sizeof(*i));
19 }
20
21 memset(i, 0, sizeof(*i));
22
23 return i;
24 }
25
26 void php_http_info_dtor(php_http_info_t *i)
27 {
28 switch (i->type) {
29 case PHP_HTTP_REQUEST:
30 PTR_SET(PHP_HTTP_INFO(i).request.method, NULL);
31 PTR_SET(PHP_HTTP_INFO(i).request.url, NULL);
32 break;
33
34 case PHP_HTTP_RESPONSE:
35 PTR_SET(PHP_HTTP_INFO(i).response.status, NULL);
36 break;
37
38 default:
39 break;
40 }
41 }
42
43 void php_http_info_free(php_http_info_t **i)
44 {
45 if (*i) {
46 php_http_info_dtor(*i);
47 efree(*i);
48 *i = NULL;
49 }
50 }
51
52 php_http_info_t *php_http_info_parse(php_http_info_t *info, const char *pre_header TSRMLS_DC)
53 {
54 const char *end, *http, *off;
55 zend_bool free_info = !info;
56
57 /* sane parameter */
58 if ((!pre_header) || (!*pre_header)) {
59 return NULL;
60 }
61
62 /* where's the end of the line */
63 if (!(end = php_http_locate_eol(pre_header, NULL))) {
64 end = pre_header + strlen(pre_header);
65 }
66
67 /* there must be HTTP/1.x in the line */
68 if (!(http = php_http_locate_str(pre_header, end - pre_header, "HTTP/", lenof("HTTP/")))) {
69 return NULL;
70 }
71
72 info = php_http_info_init(info TSRMLS_CC);
73
74 if (!php_http_version_parse(&info->http.version, http TSRMLS_CC)) {
75 if (free_info) {
76 php_http_info_free(&info);
77 }
78 return NULL;
79 }
80
81 /* clumsy fix for changed libcurl behaviour in 7.49.1, see https://github.com/curl/curl/issues/888 */
82 off = &http[lenof("HTTP/X")];
83 if (info->http.version.major < 2) {
84 off += 2;
85 }
86
87 /* and nothing than SPACE or NUL after HTTP/X(.x) */
88 if (*off && (!PHP_HTTP_IS_CTYPE(space, *off))) {
89 if (free_info) {
90 php_http_info_free(&info);
91 }
92 return NULL;
93 }
94
95 #if 0
96 {
97 char *line = estrndup(pre_header, end - pre_header);
98 fprintf(stderr, "http_parse_info('%s')\n", line);
99 efree(line);
100 }
101 #endif
102
103 /* is response */
104 if (pre_header == http) {
105 const char *status = NULL, *code = off;
106
107 info->type = PHP_HTTP_RESPONSE;
108 while (' ' == *code) ++code;
109 if (end > code) {
110 /* rfc7230#3.1.2 The status-code element is a 3-digit integer code */
111 PHP_HTTP_INFO(info).response.code = 100*(*code++ - '0');
112 PHP_HTTP_INFO(info).response.code += 10*(*code++ - '0');
113 PHP_HTTP_INFO(info).response.code += *code++ - '0';
114 if (PHP_HTTP_INFO(info).response.code < 100 || PHP_HTTP_INFO(info).response.code > 599) {
115 if (free_info) {
116 php_http_info_free(&info);
117 }
118 return NULL;
119 }
120 status = code;
121 } else {
122 PHP_HTTP_INFO(info).response.code = 0;
123 }
124 if (status && end > status) {
125 while (' ' == *status) ++status;
126 PHP_HTTP_INFO(info).response.status = estrndup(status, end - status);
127 } else {
128 PHP_HTTP_INFO(info).response.status = NULL;
129 }
130
131 return info;
132 }
133
134 /* is request */
135 else if (*(http - 1) == ' ' && (!*off || *off == '\r' || *off == '\n')) {
136 const char *url = strchr(pre_header, ' ');
137
138 info->type = PHP_HTTP_REQUEST;
139 if (url && http > url) {
140 size_t url_len = url - pre_header;
141
142 PHP_HTTP_INFO(info).request.method = estrndup(pre_header, url_len);
143
144 while (' ' == *url) ++url;
145 while (' ' == *(http-1)) --http;
146
147 if (http > url) {
148 /* CONNECT presents an authority only */
149 if (strcasecmp(PHP_HTTP_INFO(info).request.method, "CONNECT")) {
150 PHP_HTTP_INFO(info).request.url = php_http_url_parse(url, http - url, PHP_HTTP_URL_STDFLAGS TSRMLS_CC);
151 } else {
152 PHP_HTTP_INFO(info).request.url = php_http_url_parse_authority(url, http - url, PHP_HTTP_URL_STDFLAGS TSRMLS_CC);
153 }
154 if (!PHP_HTTP_INFO(info).request.url) {
155 PTR_SET(PHP_HTTP_INFO(info).request.method, NULL);
156 return NULL;
157 }
158 } else {
159 PTR_SET(PHP_HTTP_INFO(info).request.method, NULL);
160 return NULL;
161 }
162 } else {
163 PHP_HTTP_INFO(info).request.method = NULL;
164 PHP_HTTP_INFO(info).request.url = NULL;
165 }
166
167 return info;
168 }
169
170 /* some darn header containing HTTP/X(.x) */
171 else {
172 if (free_info) {
173 php_http_info_free(&info);
174 }
175 return NULL;
176 }
177 }
178
179 /*
180 * Local variables:
181 * tab-width: 4
182 * c-basic-offset: 4
183 * End:
184 * vim600: noet sw=4 ts=4 fdm=marker
185 * vim<600: noet sw=4 ts=4
186 */
187