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-2007, Michael Wallner <mike@php.net> |
10 : +--------------------------------------------------------------------+
11 : */
12 :
13 : /* $Id: http_request_method_api.c,v 1.27 2007/02/07 11:50:27 mike Exp $ */
14 :
15 : #define HTTP_WANT_CURL
16 : #include "php_http.h"
17 :
18 : #include "php_http_api.h"
19 : #include "php_http_request_api.h"
20 : #include "php_http_request_method_api.h"
21 :
22 : #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY)
23 : # include "php_http_request_object.h"
24 : #endif
25 :
26 : /* {{{ char *http_request_methods[] */
27 : static const char *const http_request_methods[] = {
28 : "UNKNOWN",
29 : /* HTTP/1.1 */
30 : "GET",
31 : "HEAD",
32 : "POST",
33 : "PUT",
34 : "DELETE",
35 : "OPTIONS",
36 : "TRACE",
37 : "CONNECT",
38 : /* WebDAV - RFC 2518 */
39 : "PROPFIND",
40 : "PROPPATCH",
41 : "MKCOL",
42 : "COPY",
43 : "MOVE",
44 : "LOCK",
45 : "UNLOCK",
46 : /* WebDAV Versioning - RFC 3253 */
47 : "VERSION-CONTROL",
48 : "REPORT",
49 : "CHECKOUT",
50 : "CHECKIN",
51 : "UNCHECKOUT",
52 : "MKWORKSPACE",
53 : "UPDATE",
54 : "LABEL",
55 : "MERGE",
56 : "BASELINE-CONTROL",
57 : "MKACTIVITY",
58 : /* WebDAV Access Control - RFC 3744 */
59 : "ACL",
60 : NULL
61 : };
62 : /* }}} */
63 :
64 : /* {{{ */
65 : PHP_MINIT_FUNCTION(http_request_method)
66 220 : {
67 : /* HTTP/1.1 */
68 220 : HTTP_LONG_CONSTANT("HTTP_METH_GET", HTTP_GET);
69 220 : HTTP_LONG_CONSTANT("HTTP_METH_HEAD", HTTP_HEAD);
70 220 : HTTP_LONG_CONSTANT("HTTP_METH_POST", HTTP_POST);
71 220 : HTTP_LONG_CONSTANT("HTTP_METH_PUT", HTTP_PUT);
72 220 : HTTP_LONG_CONSTANT("HTTP_METH_DELETE", HTTP_DELETE);
73 220 : HTTP_LONG_CONSTANT("HTTP_METH_OPTIONS", HTTP_OPTIONS);
74 220 : HTTP_LONG_CONSTANT("HTTP_METH_TRACE", HTTP_TRACE);
75 220 : HTTP_LONG_CONSTANT("HTTP_METH_CONNECT", HTTP_CONNECT);
76 : /* WebDAV - RFC 2518 */
77 220 : HTTP_LONG_CONSTANT("HTTP_METH_PROPFIND", HTTP_PROPFIND);
78 220 : HTTP_LONG_CONSTANT("HTTP_METH_PROPPATCH", HTTP_PROPPATCH);
79 220 : HTTP_LONG_CONSTANT("HTTP_METH_MKCOL", HTTP_MKCOL);
80 220 : HTTP_LONG_CONSTANT("HTTP_METH_COPY", HTTP_COPY);
81 220 : HTTP_LONG_CONSTANT("HTTP_METH_MOVE", HTTP_MOVE);
82 220 : HTTP_LONG_CONSTANT("HTTP_METH_LOCK", HTTP_LOCK);
83 220 : HTTP_LONG_CONSTANT("HTTP_METH_UNLOCK", HTTP_UNLOCK);
84 : /* WebDAV Versioning - RFC 3253 */
85 220 : HTTP_LONG_CONSTANT("HTTP_METH_VERSION_CONTROL", HTTP_VERSION_CONTROL);
86 220 : HTTP_LONG_CONSTANT("HTTP_METH_REPORT", HTTP_REPORT);
87 220 : HTTP_LONG_CONSTANT("HTTP_METH_CHECKOUT", HTTP_CHECKOUT);
88 220 : HTTP_LONG_CONSTANT("HTTP_METH_CHECKIN", HTTP_CHECKIN);
89 220 : HTTP_LONG_CONSTANT("HTTP_METH_UNCHECKOUT", HTTP_UNCHECKOUT);
90 220 : HTTP_LONG_CONSTANT("HTTP_METH_MKWORKSPACE", HTTP_MKWORKSPACE);
91 220 : HTTP_LONG_CONSTANT("HTTP_METH_UPDATE", HTTP_UPDATE);
92 220 : HTTP_LONG_CONSTANT("HTTP_METH_LABEL", HTTP_LABEL);
93 220 : HTTP_LONG_CONSTANT("HTTP_METH_MERGE", HTTP_MERGE);
94 220 : HTTP_LONG_CONSTANT("HTTP_METH_BASELINE_CONTROL", HTTP_BASELINE_CONTROL);
95 220 : HTTP_LONG_CONSTANT("HTTP_METH_MKACTIVITY", HTTP_MKACTIVITY);
96 : /* WebDAV Access Control - RFC 3744 */
97 220 : HTTP_LONG_CONSTANT("HTTP_METH_ACL", HTTP_ACL);
98 :
99 220 : return SUCCESS;
100 : }
101 :
102 : PHP_RINIT_FUNCTION(http_request_method)
103 219 : {
104 219 : HTTP_G->request.methods.custom.entries = ecalloc(1, sizeof(http_request_method_entry *));
105 :
106 219 : if (HTTP_G->request.methods.custom.ini && *HTTP_G->request.methods.custom.ini) {
107 : HashPosition pos;
108 : HashTable methods;
109 : zval **data;
110 :
111 0 : zend_hash_init(&methods, 0, NULL, ZVAL_PTR_DTOR, 0);
112 0 : http_parse_params(HTTP_G->request.methods.custom.ini, HTTP_PARAMS_DEFAULT, &methods);
113 0 : FOREACH_HASH_VAL(pos, &methods, data) {
114 0 : if (Z_TYPE_PP(data) == IS_STRING) {
115 0 : http_request_method_register(Z_STRVAL_PP(data), Z_STRLEN_PP(data));
116 : }
117 : }
118 0 : zend_hash_destroy(&methods);
119 : }
120 219 : return SUCCESS;
121 : }
122 :
123 : PHP_RSHUTDOWN_FUNCTION(http_request_method)
124 219 : {
125 : int i;
126 219 : http_request_method_entry **ptr = HTTP_G->request.methods.custom.entries;
127 :
128 225 : for (i = 0; i < HTTP_G->request.methods.custom.count; ++i) {
129 6 : if (ptr[i]) {
130 1 : http_request_method_unregister(HTTP_CUSTOM_REQUEST_METHOD_START + i);
131 : }
132 : }
133 219 : efree(HTTP_G->request.methods.custom.entries);
134 :
135 219 : return SUCCESS;
136 : }
137 : /* }}} */
138 :
139 : /* {{{ char *http_request_method_name(http_request_method) */
140 : PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC)
141 30 : {
142 30 : http_request_method_entry **ptr = HTTP_G->request.methods.custom.entries;
143 :
144 30 : if (HTTP_STD_REQUEST_METHOD(m)) {
145 27 : return http_request_methods[m];
146 : }
147 :
148 3 : if ( (HTTP_CUSTOM_REQUEST_METHOD(m) >= 0) &&
149 : (HTTP_CUSTOM_REQUEST_METHOD(m) < HTTP_G->request.methods.custom.count) &&
150 : (ptr[HTTP_CUSTOM_REQUEST_METHOD(m)])) {
151 1 : return ptr[HTTP_CUSTOM_REQUEST_METHOD(m)]->name;
152 : }
153 :
154 2 : return http_request_methods[0];
155 : }
156 : /* }}} */
157 :
158 : /* {{{ int http_request_method_exists(zend_bool, ulong, char *) */
159 : PHP_HTTP_API int _http_request_method_exists(zend_bool by_name, http_request_method id, const char *name TSRMLS_DC)
160 96 : {
161 : int i;
162 96 : http_request_method_entry **ptr = HTTP_G->request.methods.custom.entries;
163 :
164 96 : if (by_name) {
165 1190 : for (i = HTTP_MIN_REQUEST_METHOD; i < HTTP_MAX_REQUEST_METHOD; ++i) {
166 1161 : if (!strcasecmp(name, http_request_methods[i])) {
167 27 : return i;
168 : }
169 : }
170 94 : for (i = 0; i < HTTP_G->request.methods.custom.count; ++i) {
171 75 : if (ptr[i] && !strcasecmp(name, ptr[i]->name)) {
172 10 : return HTTP_CUSTOM_REQUEST_METHOD_START + i;
173 : }
174 : }
175 40 : } else if (HTTP_STD_REQUEST_METHOD(id)) {
176 27 : return id;
177 13 : } else if ( (HTTP_CUSTOM_REQUEST_METHOD(id) >= 0) &&
178 : (HTTP_CUSTOM_REQUEST_METHOD(id) < HTTP_G->request.methods.custom.count) &&
179 : (ptr[HTTP_CUSTOM_REQUEST_METHOD(id)])) {
180 6 : return id;
181 : }
182 :
183 26 : return 0;
184 : }
185 : /* }}} */
186 :
187 : /* {{{ int http_request_method_register(char *) */
188 : PHP_HTTP_API int _http_request_method_register(const char *method_name, int method_name_len TSRMLS_DC)
189 6 : {
190 : int i, meth_num;
191 : char *http_method, *method, *mconst;
192 6 : http_request_method_entry **ptr = HTTP_G->request.methods.custom.entries;
193 :
194 6 : if (!HTTP_IS_CTYPE(alpha, *method_name)) {
195 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method does not start with a character (%s)", method_name);
196 0 : return 0;
197 : }
198 :
199 6 : if (http_request_method_exists(1, 0, method_name)) {
200 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method does already exist (%s)", method_name);
201 0 : return 0;
202 : }
203 :
204 6 : method = emalloc(method_name_len + 1);
205 6 : mconst = emalloc(method_name_len + 1);
206 22 : for (i = 0; i < method_name_len; ++i) {
207 16 : switch (method_name[i]) {
208 : case '-':
209 0 : method[i] = '-';
210 0 : mconst[i] = '_';
211 0 : break;
212 :
213 : default:
214 16 : if (!HTTP_IS_CTYPE(alnum, method_name[i])) {
215 0 : efree(method);
216 0 : efree(mconst);
217 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method contains illegal characters (%s)", method_name);
218 0 : return 0;
219 : }
220 16 : mconst[i] = method[i] = HTTP_TO_CTYPE(upper, method_name[i]);
221 : break;
222 : }
223 : }
224 6 : method[method_name_len] = '\0';
225 6 : mconst[method_name_len] = '\0';
226 :
227 6 : ptr = erealloc(ptr, sizeof(http_request_method_entry *) * (HTTP_G->request.methods.custom.count + 1));
228 6 : HTTP_G->request.methods.custom.entries = ptr;
229 6 : ptr[HTTP_G->request.methods.custom.count] = emalloc(sizeof(http_request_method_entry));
230 6 : ptr[HTTP_G->request.methods.custom.count]->name = method;
231 6 : ptr[HTTP_G->request.methods.custom.count]->cnst = mconst;
232 6 : meth_num = HTTP_CUSTOM_REQUEST_METHOD_START + HTTP_G->request.methods.custom.count++;
233 :
234 6 : method_name_len = spprintf(&http_method, 0, "HTTP_METH_%s", mconst);
235 6 : zend_register_long_constant(http_method, method_name_len + 1, meth_num, CONST_CS, http_module_number TSRMLS_CC);
236 6 : efree(http_method);
237 :
238 : #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY)
239 6 : method_name_len = spprintf(&http_method, 0, "METH_%s", mconst);
240 6 : zend_declare_class_constant_long(http_request_object_ce, http_method, method_name_len, meth_num TSRMLS_CC);
241 6 : efree(http_method);
242 : #endif
243 :
244 6 : return meth_num;
245 : }
246 : /* }}} */
247 :
248 : /* {{{ STATUS http_request_method_unregister(int) */
249 : PHP_HTTP_API STATUS _http_request_method_unregister(int method TSRMLS_DC)
250 6 : {
251 : char *http_method;
252 : int method_len;
253 6 : http_request_method_entry **ptr = HTTP_G->request.methods.custom.entries;
254 :
255 6 : if (HTTP_STD_REQUEST_METHOD(method)) {
256 0 : http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Standard request methods cannot be unregistered");
257 0 : return FAILURE;
258 : }
259 :
260 6 : if ( (HTTP_CUSTOM_REQUEST_METHOD(method) < 0) ||
261 : (HTTP_CUSTOM_REQUEST_METHOD(method) > HTTP_G->request.methods.custom.count) ||
262 : (!ptr[HTTP_CUSTOM_REQUEST_METHOD(method)])) {
263 0 : http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Custom request method with id %d does not exist", method);
264 0 : return FAILURE;
265 : }
266 :
267 : #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY)
268 6 : method_len = spprintf(&http_method, 0, "METH_%s", ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->cnst);
269 6 : if (SUCCESS != zend_hash_del(&http_request_object_ce->constants_table, http_method, method_len + 1)) {
270 0 : http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: HttpRequest::%s", http_method);
271 0 : efree(http_method);
272 0 : return FAILURE;
273 : }
274 6 : efree(http_method);
275 : #endif
276 :
277 6 : method_len = spprintf(&http_method, 0, "HTTP_METH_%s", ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->cnst);
278 6 : if (SUCCESS != zend_hash_del(EG(zend_constants), http_method, method_len + 1)) {
279 0 : http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: %s", http_method);
280 0 : efree(http_method);
281 0 : return FAILURE;
282 : }
283 6 : efree(http_method);
284 :
285 6 : efree(ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->name);
286 6 : efree(ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->cnst);
287 6 : efree(ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]);
288 6 : ptr[HTTP_CUSTOM_REQUEST_METHOD(method)] = NULL;
289 :
290 6 : return SUCCESS;
291 : }
292 : /* }}} */
293 :
294 : /*
295 : * Local variables:
296 : * tab-width: 4
297 : * c-basic-offset: 4
298 : * End:
299 : * vim600: noet sw=4 ts=4 fdm=marker
300 : * vim<600: noet sw=4 ts=4
301 : */
302 :
|