- add etag generation through mhash
authorMichael Wallner <mike@php.net>
Thu, 25 Aug 2005 11:51:39 +0000 (11:51 +0000)
committerMichael Wallner <mike@php.net>
Thu, 25 Aug 2005 11:51:39 +0000 (11:51 +0000)
- fix several memleaks

KnownIssues.txt
config.m4
config.w32
http.c
http_cache_api.c
http_response_object.c
missing.c
php_http.h
php_http_cache_api.h

index dfe8c82e684dab7529dff9b75d9edc5bbc5b48f5..04e55a6ea0bea65a908cc926e5d56440f8e26c30 100644 (file)
@@ -2,8 +2,7 @@ Known Issues
 ============
 $Id$
 
-HttpResponse class is infunctional with current ZendEngine2,
+HttpResponse class may be infunctional with current ZendEngine2,
 a fix is pending.
 
-http_chunked_decode() still depends on CRLF.
 
index de29b53aca886a1000baead649779fbaadc0af79..25570f4febfb32f2ad53d03fde08660394b04fea 100644 (file)
--- a/config.m4
+++ b/config.m4
@@ -5,6 +5,8 @@ PHP_ARG_ENABLE([http], [whether to enable extended HTTP support],
 [  --enable-http           Enable extended HTTP support])
 PHP_ARG_WITH([curl], [for CURL support],
 [  --with-curl[=DIR]       Include CURL support])
+PHP_ARG_WITH([mhash], [for mhash support],
+[  --with-mhash[=DIR]      Include mhash support])
 
 if test "$PHP_HTTP" != "no"; then
 
@@ -68,6 +70,24 @@ dnl ----
 
        fi
 
+dnl ----
+dnl MHASH
+dnl ----
+
+       if test "$PHP_MHASH" != "no"; then
+               for i in $PHP_MHASH /usr/local /usr /opt/mhash; do
+                       test -f $i/include/mhash.h && MHASH_DIR=$i && break
+               done
+       
+               if test -z "$MHASH_DIR"; then
+                       AC_MSG_ERROR(Please reinstall libmhash - cannot find mhash.h)
+               fi
+       
+               PHP_ADD_INCLUDE($MHASH_DIR/include)
+               PHP_ADD_LIBRARY_WITH_PATH(mhash, $MHASH_DIR/lib, MHASH_SHARED_LIBADD)
+               AC_DEFINE(HAVE_LIBMHASH,1,[HAve mhash support])
+       fi
+
 dnl ----
 dnl DONE
 dnl ----
index 941ca4d67d0723cc7d8d2128a5e1e042b9e95f3b..39a642766701fba1cff8ae5cf6a4f78ef57fb393 100644 (file)
@@ -2,8 +2,19 @@
 // $Id$
 
 ARG_ENABLE("http", "whether to enable extended HTTP support", "no");
+ARG_WITH("mhash", "mhash support", "no");
 
 if (PHP_HTTP != "no") {
+
+       if (PHP_MHASH != "no") {
+               if (CHECK_HEADER_ADD_INCLUDE('mhash.h', 'CFLAGS_HTTP') &&
+                               CHECK_LIB('libmhash.lib', 'mhash')) {
+                       AC_DEFINE('HAVE_LIBMHASH', 1 , "Have mhash library");
+               } else {
+                       WARNING("mhash not enabled; libraries and headers not found");
+               }
+       }
+
        EXTENSION("http",
                "missing.c http.c http_functions.c http_exception_object.c "+
                "http_util_object.c http_message_object.c http_requestpool_object.c "+
diff --git a/http.c b/http.c
index 61ee3e7f7b951e877db2b1ec50e7d25aed8b9145..1c901d17ed541a9c0043aea10214fe8ae72a9408 100644 (file)
--- a/http.c
+++ b/http.c
@@ -29,6 +29,7 @@
 #include "php_http_std_defs.h"
 #include "php_http_api.h"
 #include "php_http_send_api.h"
+#include "php_http_cache_api.h"
 #ifdef HTTP_HAVE_CURL
 #      include "php_http_request_api.h"
 #endif
@@ -190,6 +191,7 @@ PHP_INI_BEGIN()
 #ifdef ZEND_ENGINE_2
        HTTP_PHP_INI_ENTRY("http.only_exceptions", "0", PHP_INI_ALL, OnUpdateBool, only_exceptions)
 #endif
+       HTTP_PHP_INI_ENTRY("http.etag_mode", "-2", PHP_INI_ALL, OnUpdateLong, etag.mode)
 PHP_INI_END()
 /* }}} */
 
@@ -204,6 +206,10 @@ PHP_MINIT_FUNCTION(http)
 #endif
 
        REGISTER_INI_ENTRIES();
+       
+       HTTP_LONG_CONSTANT("HTTP_ETAG_MD5", HTTP_ETAG_MD5);
+       HTTP_LONG_CONSTANT("HTTP_ETAG_SHA1", HTTP_ETAG_SHA1);
+       HTTP_LONG_CONSTANT("HTTP_ETAG_MHASH", HTTP_ETAG_MHASH);
 
 #ifdef HTTP_HAVE_CURL
        if (CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)) {
index 52d76ea079eceb8a00c55a420a8949631b5ad337..0c96f4a2593059fa274c214eb0f9e6f56b26e025 100644 (file)
@@ -24,6 +24,7 @@
 #include "php_streams.h"
 #include "php_output.h"
 #include "ext/standard/md5.h"
+#include "ext/standard/sha1.h"
 
 #include "php_http.h"
 #include "php_http_std_defs.h"
@@ -39,47 +40,39 @@ PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_m
 {
        php_stream_statbuf ssb;
        char ssb_buf[128] = {0};
-       unsigned char digest[16];
-       PHP_MD5_CTX ctx;
-       char *new_etag = ecalloc(1, 33);
-
-       PHP_MD5Init(&ctx);
-
+       size_t ssb_len;
+       void *ctx = http_etag_init();
+       
        switch (data_mode)
        {
                case SEND_DATA:
-                       PHP_MD5Update(&ctx, data_ptr, data_len);
+                       http_etag_update(ctx, data_ptr, data_len);
                break;
 
                case SEND_RSRC:
                {
                        if (php_stream_stat((php_stream *) data_ptr, &ssb)) {
-                               efree(new_etag);
+                               efree(ctx);
                                return NULL;
                        }
-
-                       snprintf(ssb_buf, 127, "%ld=%ld=%ld", ssb.sb.st_mtime, ssb.sb.st_ino, ssb.sb.st_size);
-                       PHP_MD5Update(&ctx, ssb_buf, strlen(ssb_buf));
+                       ssb_len = snprintf(ssb_buf, 127, "%ld=%ld=%ld", ssb.sb.st_mtime, ssb.sb.st_ino, ssb.sb.st_size);
+                       http_etag_update(ctx, ssb_buf, ssb_len);
                }
                break;
 
                default:
                {
                        if (php_stream_stat_path((char *) data_ptr, &ssb)) {
-                               efree(new_etag);
+                               efree(ctx);
                                return NULL;
                        }
-
-                       snprintf(ssb_buf, 127, "%ld=%ld=%ld", ssb.sb.st_mtime, ssb.sb.st_ino, ssb.sb.st_size);
-                       PHP_MD5Update(&ctx, ssb_buf, strlen(ssb_buf));
+                       ssb_len = snprintf(ssb_buf, 127, "%ld=%ld=%ld", ssb.sb.st_mtime, ssb.sb.st_ino, ssb.sb.st_size);
+                       http_etag_update(ctx, ssb_buf, ssb_len);
                }
                break;
        }
 
-       PHP_MD5Final(digest, &ctx);
-       make_digest(new_etag, digest);
-
-       return new_etag;
+       return http_etag_finish(ctx);
 }
 /* }}} */
 
@@ -205,33 +198,38 @@ PHP_HTTP_API STATUS _http_cache_etag(const char *etag, size_t etag_len,
 PHP_HTTP_API void _http_ob_etaghandler(char *output, uint output_len,
        char **handled_output, uint *handled_output_len, int mode TSRMLS_DC)
 {
-       char etag[33] = { 0 };
-       unsigned char digest[16];
+       char etag[41] = { 0 };
+       unsigned char digest[20];
 
        if (mode & PHP_OUTPUT_HANDLER_START) {
+               if (HTTP_G(etag).started) {
+                       http_error(HE_WARNING, HTTP_E_RUNTIME, "ob_etaghandler can only be used once");
+                       return;
+               }
                HTTP_G(etag).started = 1;
-               PHP_MD5Init(&HTTP_G(etag).md5ctx);
+               HTTP_G(etag).ctx = http_etag_init();
        }
 
-       PHP_MD5Update(&HTTP_G(etag).md5ctx, output, output_len);
+       http_etag_update(HTTP_G(etag).ctx, output, output_len);
 
        if (mode & PHP_OUTPUT_HANDLER_END) {
-               PHP_MD5Final(digest, &HTTP_G(etag).md5ctx);
-
+               char *etag = http_etag_finish(HTTP_G(etag).ctx);
+               
                /* just do that if desired */
                if (HTTP_G(etag).started) {
                        char *sent_header = NULL;
                        
-                       make_digest(etag, digest);
                        http_send_cache_control(HTTP_DEFAULT_CACHECONTROL, lenof(HTTP_DEFAULT_CACHECONTROL));
-                       http_send_etag_ex(etag, 32, &sent_header);
-
+                       http_send_etag_ex(etag, strlen(etag), &sent_header);
+                       
                        if (http_match_etag("HTTP_IF_NONE_MATCH", etag)) {
+                               efree(etag);
                                http_exit_ex(304, sent_header, NULL, 0);
                        } else {
                                STR_FREE(sent_header);
                        }
                }
+               efree(etag);
        }
 
        *handled_output_len = output_len;
index 0fb12486612fe9f07f860008f8ef3042d4667552..5e588eae0ef4010ebb953adfb0864f3dfef379e5 100644 (file)
@@ -773,19 +773,19 @@ PHP_METHOD(HttpResponse, send)
 
        /* capture mode */
        if (Z_BVAL_P(GET_STATIC_PROP(catch))) {
-               zval *the_data;
+               zval the_data;
 
-               MAKE_STD_ZVAL(the_data);
-               php_ob_get_buffer(the_data TSRMLS_CC);
-
-               SET_STATIC_PROP(data, the_data);
+               INIT_PZVAL(&the_data);
+               php_ob_get_buffer(&the_data TSRMLS_CC);
+               SET_STATIC_PROP(data, &the_data);
                ZVAL_LONG(GET_STATIC_PROP(mode), SEND_DATA);
 
                if (!Z_STRLEN_P(GET_STATIC_PROP(eTag))) {
-                       char *etag = http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA);
+                       char *etag = http_etag(Z_STRVAL(the_data), Z_STRLEN(the_data), SEND_DATA);
                        UPD_STATIC_PROP(string, eTag, etag);
                        efree(etag);
                }
+               zval_dtor(&the_data);
 
                clean_ob = 1;
        }
@@ -919,14 +919,14 @@ PHP_METHOD(HttpResponse, send)
  */
 PHP_METHOD(HttpResponse, capture)
 {
-       zval *do_catch;
+       zval do_catch;
 
        NO_ARGS;
 
-       MAKE_STD_ZVAL(do_catch);
-       ZVAL_LONG(do_catch, 1);
+       INIT_PZVAL(&do_catch);
+       ZVAL_LONG(&do_catch, 1);
 
-       SET_STATIC_PROP(catch, do_catch);
+       SET_STATIC_PROP(catch, &do_catch);
 
        php_end_ob_buffers(0 TSRMLS_CC);
        php_start_ob_buffer(NULL, 0, 0 TSRMLS_CC);
index dcf4709a84b8dab11cb267790e757e13c7003c6c..fea611c8eb5718f86ed3a05d51b0d724ccfdc8a4 100644 (file)
--- a/missing.c
+++ b/missing.c
@@ -38,6 +38,7 @@ static inline zval *tmp_zval(void)
 
 static void dup_zval(zval **z)
 {
+       zval *o = *z;
        zval_add_ref(z);
        SEPARATE_ZVAL(z);
 }
@@ -145,7 +146,7 @@ int zend_update_static_property(zend_class_entry *scope, char *name, size_t name
                }
                retval = SUCCESS;
        }
-       
+       zval_ptr_dtor(&value);
        EG(scope) = old_scope;
        
        return retval;
@@ -190,7 +191,7 @@ void zend_fix_static_properties(zend_class_entry *ce, HashTable *static_members
 {
        zend_hash_copy(static_members, ce->static_members, (copy_ctor_func_t) zval_add_ref, NULL, sizeof(zval *));
        zend_hash_destroy(ce->static_members);
-       zend_hash_init_ex(ce->static_members, 0, NULL, ZVAL_PTR_DTOR, 1, 0);
+       zend_hash_init_ex(ce->static_members, static_members->nNumOfElements, NULL, ZVAL_PTR_DTOR, 1, 0);
 }
 
 void zend_init_static_properties(zend_class_entry *ce, HashTable *static_members TSRMLS_DC)
index 4dffa673c31061d6e09c831c9da712ad93d61801..9137b812c6eecb7036535f8ed42169d1fdb3f53b 100644 (file)
@@ -28,6 +28,7 @@
 #      include <curl/curl.h>
 #endif
 #include "ext/standard/md5.h"
+#include "ext/standard/sha1.h"
 #include "phpstr/phpstr.h"
 
 extern zend_module_entry http_module_entry;
@@ -41,8 +42,9 @@ ZEND_BEGIN_MODULE_GLOBALS(http)
        zend_bool only_exceptions;
 #endif
        struct _http_globals_etag {
+               long mode;
+               void *ctx;
                zend_bool started;
-               PHP_MD5_CTX md5ctx;
        } etag;
 
        struct _http_globals_log {
index e420963f0301b67cb4a5dccd3fea752c1ea9fdb3..8a9e55d83c820dab7ab6ec9ff6b1ee712d9c94fa 100644 (file)
 #define PHP_HTTP_CACHE_API_H
 
 #include "php_http_std_defs.h"
+#include "php_http.h"
 #include "php_http_api.h"
 #include "php_http_send_api.h"
 
+#include "zend_ini.h"
+
+#ifdef HAVE_LIBMHASH
+#      include <mhash.h>
+#endif
+
+ZEND_EXTERN_MODULE_GLOBALS(http);
+
+typedef enum {
+       HTTP_ETAG_MD5 = -2,
+       HTTP_ETAG_SHA1 = -1,
+       HTTP_ETAG_MHASH = 0,
+} http_etag_mode;
+
+#ifdef HAVE_LIBMHASH
+static void *http_etag_alloc_mhash_digest(size_t size)
+{
+       return emalloc(size);
+}
+#endif
+
+#define http_etag_digest(d, l) _http_etag_digest((d), (l) TSRMLS_CC)
+static inline char *_http_etag_digest(const unsigned char *digest, int len TSRMLS_DC)
+{
+       int i;
+       char *hex = emalloc(len * 2 + 1);
+       char *ptr = hex;
+       
+       /* optimize this --
+               look at apache's make_etag */
+       for (i = 0; i < len; ++i) {
+               sprintf(ptr, "%02x", digest[i]);
+               ptr += 2;
+       }
+       *ptr = '\0';
+       
+       return hex;
+}
+
+#define http_etag_init() _http_etag_init(TSRMLS_C)
+static inline void *_http_etag_init(TSRMLS_D)
+{
+       void *ctx;
+       long mode = INI_INT("http.etag_mode");
+       
+       switch (mode)
+       {
+               case HTTP_ETAG_SHA1:
+                       PHP_SHA1Init(ctx = emalloc(sizeof(PHP_SHA1_CTX)));
+               break;
+               
+               case HTTP_ETAG_MD5:
+invalid_flag:
+                       PHP_MD5Init(ctx = emalloc(sizeof(PHP_MD5_CTX)));
+               break;
+               
+               default:
+               {
+#ifdef HAVE_LIBMHASH
+                       if ((mode >= 0) && (mode <= mhash_count())) {
+                               ctx = mhash_init(mode);
+                       }
+                       if ((!ctx) || (ctx == MHASH_FAILED))
+#endif
+                       {
+                               HTTP_G(etag).mode = HTTP_ETAG_MD5;
+                               goto invalid_flag;
+                       }
+               }
+               break;
+       }
+       
+       return ctx;
+}
+
+#define http_etag_finish(c) _http_etag_finish((c) TSRMLS_CC)
+static inline char *_http_etag_finish(void *ctx TSRMLS_DC)
+{
+       char *etag = NULL;
+       unsigned char digest[20];
+       long mode = INI_INT("http.etag_mode");
+       
+       switch (mode)
+       {
+               case HTTP_ETAG_SHA1:
+                       PHP_SHA1Final(digest, ctx);
+                       etag = http_etag_digest(digest, 20);
+                       efree(ctx);
+               break;
+               
+               case HTTP_ETAG_MD5:
+                       PHP_MD5Final(digest, ctx);
+                       etag = http_etag_digest(digest, 16);
+                       efree(ctx);
+               break;
+               
+               default:
+               {
+#ifdef HAVE_LIBMHASH
+                       unsigned char *mhash_digest = mhash_end_m(ctx, http_etag_alloc_mhash_digest);
+                       etag = http_etag_digest(mhash_digest, mhash_get_block_size(mode));
+                       efree(mhash_digest);
+#endif
+               }
+               break;
+       }
+       
+       return etag;
+}
+
+#define http_etag_update(c, d, l) _http_etag_update((c), (d), (l) TSRMLS_CC)
+static inline void _http_etag_update(void *ctx, const char *data_ptr, size_t data_len TSRMLS_DC)
+{
+       switch (INI_INT("http.etag_mode"))
+       {
+               case HTTP_ETAG_SHA1:
+                       PHP_SHA1Update(ctx, data_ptr, data_len);
+               break;
+               
+               case HTTP_ETAG_MD5:
+                       PHP_MD5Update(ctx, data_ptr, data_len);
+               break;
+               
+               default:
+#ifdef HAVE_LIBMHASH
+                       mhash(ctx, data_ptr, data_len);
+#endif
+               break;
+       }
+}
+
 #define http_etag(p, l, m) _http_etag((p), (l), (m) TSRMLS_CC)
 PHP_HTTP_API char *_http_etag(const void *data_ptr, size_t data_len, http_send_mode data_mode TSRMLS_DC);