X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-http;a=blobdiff_plain;f=http_request_method_api.c;h=5be28c17add665c621eac813d2e7fccc323bf1dd;hp=f1bd6510e4c7135171a9261560326821d95c1424;hb=ad5f896b03adaa073134a00108a9cdf00720673a;hpb=32e91737086db53bb1fd9ed9f79d693c43ec459f diff --git a/http_request_method_api.c b/http_request_method_api.c index f1bd651..5be28c1 100644 --- a/http_request_method_api.c +++ b/http_request_method_api.c @@ -6,16 +6,12 @@ | modification, are permitted provided that the conditions mentioned | | in the accompanying LICENSE file are met. | +--------------------------------------------------------------------+ - | Copyright (c) 2004-2006, Michael Wallner | + | Copyright (c) 2004-2010, Michael Wallner | +--------------------------------------------------------------------+ */ /* $Id$ */ -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - #define HTTP_WANT_CURL #include "php_http.h" @@ -103,188 +99,216 @@ PHP_MINIT_FUNCTION(http_request_method) return SUCCESS; } -PHP_RINIT_FUNCTION(http_request_method) +static void free_method(void *el) { - HTTP_G(request).methods.custom.entries = ecalloc(1, sizeof(http_request_method_entry *)); - - return SUCCESS; + efree(*(char **)el); } -PHP_RSHUTDOWN_FUNCTION(http_request_method) +static void unregister_method(const char *name TSRMLS_DC) { - int i; - getGlobals(G); - http_request_method_entry **ptr = G->request.methods.custom.entries; + char *ptr, tmp[sizeof("HTTP_METH_") + HTTP_REQUEST_METHOD_MAXLEN] = "HTTP_METH_"; - for (i = 0; i < G->request.methods.custom.count; ++i) { - if (ptr[i]) { - http_request_method_unregister(HTTP_CUSTOM_REQUEST_METHOD_START + i); + strlcpy(tmp + lenof("HTTP_METH_"), name, HTTP_REQUEST_METHOD_MAXLEN); + for (ptr = tmp + lenof("HTTP_METH_"); *ptr; ++ptr) { + if (*ptr == '-') { + *ptr = '_'; } } - efree(G->request.methods.custom.entries); - return SUCCESS; -} -/* }}} */ - -/* {{{ char *http_request_method_name(http_request_method) */ -PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC) -{ - getGlobals(G); - http_request_method_entry **ptr = G->request.methods.custom.entries; - - if (HTTP_STD_REQUEST_METHOD(m)) { - return http_request_methods[m]; +#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY) + if (SUCCESS != zend_hash_del(&http_request_object_ce->constants_table, tmp + lenof("HTTP_"), strlen(tmp + lenof("HTTP_")) + 1)) { + http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: HttpRequest::%s", tmp + lenof("HTTP_")); } - - if ( (HTTP_CUSTOM_REQUEST_METHOD(m) >= 0) && - (HTTP_CUSTOM_REQUEST_METHOD(m) < G->request.methods.custom.count) && - (ptr[HTTP_CUSTOM_REQUEST_METHOD(m)])) { - return ptr[HTTP_CUSTOM_REQUEST_METHOD(m)]->name; +#endif + if (SUCCESS != zend_hash_del(EG(zend_constants), tmp, strlen(tmp) + 1)) { + http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: %s", tmp); } - - return http_request_methods[0]; } -/* }}} */ -/* {{{ int http_request_method_exists(zend_bool, ulong, char *) */ -PHP_HTTP_API int _http_request_method_exists(zend_bool by_name, http_request_method id, const char *name TSRMLS_DC) +PHP_RINIT_FUNCTION(http_request_method) { - int i; - getGlobals(G); - http_request_method_entry **ptr = G->request.methods.custom.entries; + HashTable ht; - if (by_name) { - for (i = HTTP_MIN_REQUEST_METHOD; i < HTTP_MAX_REQUEST_METHOD; ++i) { - if (!strcasecmp(name, http_request_methods[i])) { - return i; - } - } - for (i = 0; i < G->request.methods.custom.count; ++i) { - if (ptr[i] && !strcasecmp(name, ptr[i]->name)) { - return HTTP_CUSTOM_REQUEST_METHOD_START + i; + zend_hash_init(&HTTP_G->request.methods.registered, 0, NULL, free_method, 0); +#define HTTP_METH_REG(m) \ + { \ + char *_m=estrdup(m); \ + zend_hash_next_index_insert(&HTTP_G->request.methods.registered, (void *) &_m, sizeof(char *), NULL); \ + } + HTTP_METH_REG("UNKNOWN"); + /* HTTP/1.1 */ + HTTP_METH_REG("GET"); + HTTP_METH_REG("HEAD"); + HTTP_METH_REG("POST"); + HTTP_METH_REG("PUT"); + HTTP_METH_REG("DELETE"); + HTTP_METH_REG("OPTIONS"); + HTTP_METH_REG("TRACE"); + HTTP_METH_REG("CONNECT"); + /* WebDAV - RFC 2518 */ + HTTP_METH_REG("PROPFIND"); + HTTP_METH_REG("PROPPATCH"); + HTTP_METH_REG("MKCOL"); + HTTP_METH_REG("COPY"); + HTTP_METH_REG("MOVE"); + HTTP_METH_REG("LOCK"); + HTTP_METH_REG("UNLOCK"); + /* WebDAV Versioning - RFC 3253 */ + HTTP_METH_REG("VERSION-CONTROL"); + HTTP_METH_REG("REPORT"); + HTTP_METH_REG("CHECKOUT"); + HTTP_METH_REG("CHECKIN"); + HTTP_METH_REG("UNCHECKOUT"); + HTTP_METH_REG("MKWORKSPACE"); + HTTP_METH_REG("UPDATE"); + HTTP_METH_REG("LABEL"); + HTTP_METH_REG("MERGE"); + HTTP_METH_REG("BASELINE-CONTROL"); + HTTP_METH_REG("MKACTIVITY"); + /* WebDAV Access Control - RFC 3744 */ + HTTP_METH_REG("ACL"); + + zend_hash_init(&ht, 0, NULL, ZVAL_PTR_DTOR, 0); + if (*HTTP_G->request.methods.custom && SUCCESS == http_parse_params(HTTP_G->request.methods.custom, HTTP_PARAMS_DEFAULT, &ht)) { + HashPosition pos; + zval **val; + + FOREACH_HASH_VAL(pos, &ht, val) { + if (Z_TYPE_PP(val) == IS_STRING) { + http_request_method_register(Z_STRVAL_PP(val), Z_STRLEN_PP(val)); } } - } else if (HTTP_STD_REQUEST_METHOD(id)) { - return id; - } else if ( (HTTP_CUSTOM_REQUEST_METHOD(id) >= 0) && - (HTTP_CUSTOM_REQUEST_METHOD(id) < G->request.methods.custom.count) && - (ptr[HTTP_CUSTOM_REQUEST_METHOD(id)])) { - return id; } + zend_hash_destroy(&ht); - return 0; + return SUCCESS; } -/* }}} */ -/* {{{ int http_request_method_register(char *) */ -PHP_HTTP_API int _http_request_method_register(const char *method_name, int method_name_len TSRMLS_DC) +PHP_RSHUTDOWN_FUNCTION(http_request_method) { - int i, meth_num; - char *http_method, *method, *mconst; - getGlobals(G); - http_request_method_entry **ptr = G->request.methods.custom.entries; + char **name; + int i, c = zend_hash_next_free_element(&HTTP_G->request.methods.registered); - if (!isalpha(*method_name)) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method does not start with a character (%s)", method_name); - return 0; + for (i = HTTP_MAX_REQUEST_METHOD; i < c; ++i) { + if (SUCCESS == zend_hash_index_find(&HTTP_G->request.methods.registered, i, (void *) &name)) { + unregister_method(*name TSRMLS_CC); + } } - if (http_request_method_exists(1, 0, method_name)) { - http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method does already exist (%s)", method_name); - return 0; + zend_hash_destroy(&HTTP_G->request.methods.registered); + return SUCCESS; +} + +#define http_request_method_cncl(m, c) _http_request_method_cncl_ex((m), strlen(m), (c) TSRMLS_CC) +#define http_request_method_cncl_ex(m, l, c) _http_request_method_cncl_ex((m), (l), (c) TSRMLS_CC) +static STATUS _http_request_method_cncl_ex(const char *method_name, int method_name_len, char **cnst TSRMLS_DC) +{ + int i; + char *cncl; + + if (method_name_len >= HTTP_REQUEST_METHOD_MAXLEN) { + http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method too long (%s)", method_name); } + cncl = emalloc(method_name_len + 1); - method = emalloc(method_name_len + 1); - mconst = emalloc(method_name_len + 1); for (i = 0; i < method_name_len; ++i) { - switch (method_name[i]) - { + switch (method_name[i]) { case '-': - method[i] = '-'; - mconst[i] = '_'; - break; + cncl[i] = '-'; + break; default: - if (!isalnum(method_name[i])) { - efree(method); - efree(mconst); + if (!HTTP_IS_CTYPE(alnum, method_name[i])) { + efree(cncl); http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Request method contains illegal characters (%s)", method_name); - return 0; + return FAILURE; } - mconst[i] = method[i] = toupper(method_name[i]); - break; + cncl[i] = HTTP_TO_CTYPE(upper, method_name[i]); + break; } } - method[method_name_len] = '\0'; - mconst[method_name_len] = '\0'; + cncl[method_name_len] = '\0'; + + *cnst = cncl; + return SUCCESS; +} + +PHP_HTTP_API const char *_http_request_method_name(http_request_method m TSRMLS_DC) +{ + char **name; - ptr = erealloc(ptr, sizeof(http_request_method_entry *) * (G->request.methods.custom.count + 1)); - G->request.methods.custom.entries = ptr; - ptr[G->request.methods.custom.count] = emalloc(sizeof(http_request_method_entry)); - ptr[G->request.methods.custom.count]->name = method; - ptr[G->request.methods.custom.count]->cnst = mconst; - meth_num = HTTP_CUSTOM_REQUEST_METHOD_START + G->request.methods.custom.count++; + if (SUCCESS == zend_hash_index_find(&HTTP_G->request.methods.registered, m, (void *) &name)) { + return *name; + } + return "UNKNOWN"; +} - method_name_len = spprintf(&http_method, 0, "HTTP_METH_%s", mconst); - zend_register_long_constant(http_method, method_name_len + 1, meth_num, CONST_CS, http_module_number TSRMLS_CC); - efree(http_method); +PHP_HTTP_API int _http_request_method_exists(int by_name, http_request_method id_num, const char *id_str TSRMLS_DC) +{ + char *id_dup; + if (by_name && (SUCCESS == http_request_method_cncl(id_str, &id_dup))) { + char **name; + HashPosition pos; + HashKey key = initHashKey(0); + + FOREACH_HASH_KEYVAL(pos, &HTTP_G->request.methods.registered, key, name) { + if (key.type == HASH_KEY_IS_LONG && !strcmp(*name, id_dup)) { + efree(id_dup); + return key.num; + } + } + efree(id_dup); + } else if (zend_hash_index_exists(&HTTP_G->request.methods.registered, id_num)){ + return id_num; + } + return 0; +} + +PHP_HTTP_API int _http_request_method_register(const char *method_str, int method_len TSRMLS_DC) +{ + char *method_dup, *ptr, tmp[sizeof("HTTP_METH_") + HTTP_REQUEST_METHOD_MAXLEN] = "HTTP_METH_"; + int method_num = http_request_method_exists(1, 0, method_str); + + if (!method_num && (SUCCESS == http_request_method_cncl_ex(method_str, method_len, &method_dup))) { + method_num = zend_hash_next_free_element(&HTTP_G->request.methods.registered); + zend_hash_index_update(&HTTP_G->request.methods.registered, method_num, (void *) &method_dup, sizeof(char *), NULL); + + strlcpy(tmp + lenof("HTTP_METH_"), method_dup, HTTP_REQUEST_METHOD_MAXLEN); + for (ptr = tmp + lenof("HTTP_METH_"); *ptr; ++ptr) { + if (*ptr == '-') { + *ptr = '_'; + } + } + + zend_register_long_constant(tmp, strlen(tmp) + 1, method_num, CONST_CS, http_module_number TSRMLS_CC); #if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY) - method_name_len = spprintf(&http_method, 0, "METH_%s", mconst); - zend_declare_class_constant_long(http_request_object_ce, http_method, method_name_len, meth_num TSRMLS_CC); - efree(http_method); + zend_declare_class_constant_long(http_request_object_ce, tmp + lenof("HTTP_"), strlen(tmp + lenof("HTTP_")), method_num TSRMLS_CC); #endif + } - return meth_num; + return method_num; } -/* }}} */ -/* {{{ STATUS http_request_method_unregister(int) */ PHP_HTTP_API STATUS _http_request_method_unregister(int method TSRMLS_DC) { - char *http_method; - int method_len; - getGlobals(G); - http_request_method_entry **ptr = G->request.methods.custom.entries; + char **name; if (HTTP_STD_REQUEST_METHOD(method)) { http_error_ex(HE_WARNING, HTTP_E_REQUEST_METHOD, "Standard request methods cannot be unregistered"); return FAILURE; } - if ( (HTTP_CUSTOM_REQUEST_METHOD(method) < 0) || - (HTTP_CUSTOM_REQUEST_METHOD(method) > G->request.methods.custom.count) || - (!ptr[HTTP_CUSTOM_REQUEST_METHOD(method)])) { - http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Custom request method with id %lu does not exist", method); + if (SUCCESS != zend_hash_index_find(&HTTP_G->request.methods.registered, method, (void *) &name)) { + http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Custom request method with id %d does not exist", method); return FAILURE; } -#if defined(ZEND_ENGINE_2) && defined(HTTP_HAVE_CURL) && !defined(WONKY) - method_len = spprintf(&http_method, 0, "METH_%s", ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->cnst); - if (SUCCESS != zend_hash_del(&http_request_object_ce->constants_table, http_method, method_len + 1)) { - http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: HttpRequest::%s", http_method); - efree(http_method); - return FAILURE; - } - efree(http_method); -#endif - - method_len = spprintf(&http_method, 0, "HTTP_METH_%s", ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->cnst); - if (SUCCESS != zend_hash_del(EG(zend_constants), http_method, method_len + 1)) { - http_error_ex(HE_NOTICE, HTTP_E_REQUEST_METHOD, "Could not unregister request method: %s", http_method); - efree(http_method); - return FAILURE; - } - efree(http_method); - - efree(ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->name); - efree(ptr[HTTP_CUSTOM_REQUEST_METHOD(method)]->cnst); - STR_SET(ptr[HTTP_CUSTOM_REQUEST_METHOD(method)], NULL); + unregister_method(*name TSRMLS_CC); + zend_hash_index_del(&HTTP_G->request.methods.registered, method); return SUCCESS; } -/* }}} */ /* * Local variables: