* HTTPi_Response mostly done
authorMichael Wallner <mike@php.net>
Thu, 17 Feb 2005 20:29:25 +0000 (20:29 +0000)
committerMichael Wallner <mike@php.net>
Thu, 17 Feb 2005 20:29:25 +0000 (20:29 +0000)
http.c
http_api.c
php_http.h
php_http_api.h

diff --git a/http.c b/http.c
index d332ef9bc106f5f21f4dbc07ceba9d45c89fc338..bdc64601245b9c18e9309a8612b2dec4e9d0dfe7 100644 (file)
--- a/http.c
+++ b/http.c
@@ -144,6 +144,7 @@ function_entry http_functions[] = {
 #      define OBJ_PROP(o) o->zo.properties
 #      define DCL_PROP(a, t, n, v) zend_declare_property_ ##t(ce, (#n), sizeof(#n), (v), (ZEND_ACC_ ##a) TSRMLS_CC)
 #      define UPD_PROP(o, t, n, v) zend_update_property_ ##t(o->zo.ce, getThis(), (#n), sizeof(#n), (v) TSRMLS_CC)
+#      define SET_PROP(o, n, z) zend_update_property(o->zo.ce, getThis(), (#n), sizeof(#n), (z) TSRMLS_CC)
 #      define GET_PROP(o, n) zend_read_property(o->zo.ce, getThis(), (#n), sizeof(#n), 0 TSRMLS_CC)
 
 /* {{{ HTTPi */
@@ -196,12 +197,17 @@ static inline void _httpi_response_declare_default_properties(zend_class_entry *
        DCL_PROP(PROTECTED, string, eTag, "");
        DCL_PROP(PROTECTED, string, dispoFile, "");
        DCL_PROP(PROTECTED, string, cacheControl, "public");
+       DCL_PROP(PROTECTED, string, data, "");
+       DCL_PROP(PROTECTED, string, file, "");
+       DCL_PROP(PROTECTED, long, stream, 0);
+       DCL_PROP(PROTECTED, long, size, 0);
        DCL_PROP(PROTECTED, long, lastModified, 0);
        DCL_PROP(PROTECTED, long, dispoInline, 0);
        DCL_PROP(PROTECTED, long, cache, 0);
        DCL_PROP(PROTECTED, long, gzip, 0);
 
        DCL_PROP(PRIVATE, long, raw_cache_header, 0);
+       DCL_PROP(PRIVATE, long, send_mode, -1);
 }
 
 #define httpi_response_destroy_object _httpi_response_destroy_object
@@ -253,7 +259,7 @@ zend_function_entry httpi_response_class_methods[] = {
 
        PHP_ME(HTTPi_Response, setGzip, NULL, ZEND_ACC_PUBLIC)
        PHP_ME(HTTPi_Response, getGzip, NULL, ZEND_ACC_PUBLIC)
-/*
+
        PHP_ME(HTTPi_Response, setData, NULL, ZEND_ACC_PUBLIC)
        PHP_ME(HTTPi_Response, getData, NULL, ZEND_ACC_PUBLIC)
 
@@ -263,7 +269,9 @@ zend_function_entry httpi_response_class_methods[] = {
        PHP_ME(HTTPi_Response, setStream, NULL, ZEND_ACC_PUBLIC)
        PHP_ME(HTTPi_Response, getStream, NULL, ZEND_ACC_PUBLIC)
 
-       PHP_ME(HTTPi_Response, send, NULL, ZEND_ACC_PUBLIC)*/
+       PHP_ME(HTTPi_Response, send, NULL, ZEND_ACC_PUBLIC)
+       
+       PHP_ME(HTTPi_Response, getSize, NULL, ZEND_ACC_PUBLIC)
 
        {NULL, NULL, NULL}
 };
@@ -415,6 +423,10 @@ PHP_METHOD(HTTPi_Response, setContentType)
        }
 
        UPD_PROP(obj, string, contentType, ctype);
+       if (HTTP_G(ctype)) {
+               efree(HTTP_G(ctype));
+       }
+       HTTP_G(ctype) = estrndup(ctype, ctype_len);
        RETURN_TRUE;
 }
 /* }}} */
@@ -513,6 +525,274 @@ PHP_METHOD(HTTPi_Response, getETag)
 }
 /* }}} */
 
+/* {{{ proto bool HTTPi_Response::setData(string data)
+ *
+ */
+PHP_METHOD(HTTPi_Response, setData)
+{
+       zval *the_data;
+       getObject(httpi_response_object, obj);
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &the_data)) {
+               RETURN_FALSE;
+       }
+       
+       convert_to_string_ex(&the_data);
+       SET_PROP(obj, data, the_data);
+       UPD_PROP(obj, string, eTag, http_etag(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), SEND_DATA));
+       UPD_PROP(obj, long, size, Z_STRLEN_P(the_data));
+       UPD_PROP(obj, long, lastModified, time(NULL));
+       UPD_PROP(obj, long, send_mode, SEND_DATA);
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string HTTPi_Response::getData()
+ *
+ */
+PHP_METHOD(HTTPi_Response, getData)
+{
+       zval *the_data;
+       getObject(httpi_response_object, obj);
+       
+       if (ZEND_NUM_ARGS()) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       the_data = GET_PROP(obj, data);
+       RETURN_STRINGL(Z_STRVAL_P(the_data), Z_STRLEN_P(the_data), 1);
+}
+/* }}} */
+
+/* {{{ proto bool HTTPi_Response::setStream(resource stream)
+ *
+ */
+PHP_METHOD(HTTPi_Response, setStream)
+{
+       zval *the_stream;
+       php_stream *the_real_stream;
+       getObject(httpi_response_object, obj);
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &the_stream)) {
+               RETURN_FALSE;
+       }
+       
+       php_stream_from_zval(the_real_stream, &the_stream);
+       
+       SET_PROP(obj, stream, the_stream);
+       UPD_PROP(obj, string, eTag, http_etag(the_real_stream, 0, SEND_RSRC));
+       UPD_PROP(obj, long, size, HTTP_G(ssb).sb.st_size);
+       UPD_PROP(obj, long, lastModified, HTTP_G(ssb).sb.st_mtime);
+       UPD_PROP(obj, long, send_mode, SEND_RSRC);
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto resource HTTPi_Response::getStream()
+ *
+ */
+PHP_METHOD(HTTPi_Response, getStream)
+{
+       zval *the_stream;
+       getObject(httpi_response_object, obj);
+       
+       if (ZEND_NUM_ARGS()) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       the_stream = GET_PROP(obj, stream);
+       RETURN_RESOURCE(Z_LVAL_P(the_stream));
+}
+/* }}} */
+
+/* {{{ proto bool HTTPi_Response::setFile(string file)
+ *
+ */
+PHP_METHOD(HTTPi_Response, setFile)
+{
+       char *the_file;
+       int file_len;
+       zval fmtime, fsize;
+       getObject(httpi_response_object, obj);
+       
+       if (SUCCESS != zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &the_file, &file_len)) {
+               RETURN_FALSE;
+       }
+       
+       php_stat(the_file, file_len, FS_SIZE, &fsize TSRMLS_CC);
+       php_stat(the_file, file_len, FS_MTIME, &fmtime TSRMLS_CC);
+       
+       UPD_PROP(obj, string, file, the_file);
+       UPD_PROP(obj, long, size, Z_LVAL(fsize));
+       UPD_PROP(obj, long, lastModified, Z_LVAL(fmtime));
+       UPD_PROP(obj, long, send_mode, -1);
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string HTTPi_Response::getFile()
+ *
+ */
+PHP_METHOD(HTTPi_Response, getFile)
+{
+       zval *the_file;
+       getObject(httpi_response_object, obj);
+       
+       if (ZEND_NUM_ARGS()) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       the_file = GET_PROP(obj, file);
+       RETURN_STRINGL(Z_STRVAL_P(the_file), Z_STRLEN_P(the_file), 1);
+}
+/* }}} */
+
+/* {{{ proto int HTTPi_Response::getSize()
+ *
+ */
+PHP_METHOD(HTTPi_Response, getSize)
+{
+       zval *the_size;
+       getObject(httpi_response_object, obj);
+       
+       if (ZEND_NUM_ARGS()) {
+               WRONG_PARAM_COUNT;
+       }
+       
+       the_size = GET_PROP(obj, size);
+       RETURN_LONG(Z_LVAL_P(the_size));
+}
+/* }}} */
+
+PHP_METHOD(HTTPi_Response, send)
+{
+       zval *do_cache;
+       getObject(httpi_response_object, obj);
+       
+       do_cache = GET_PROP(obj, cache);
+       
+       /* caching */
+       if (Z_LVAL_P(do_cache)) {
+               /* cache header */
+               {
+                       zval *ccontrol = GET_PROP(obj, cacheControl);
+                       if (Z_STRLEN_P(ccontrol)) {
+                               char *cc_header;
+                               zval *cc_raw = GET_PROP(obj, raw_cache_control);
+                               if (Z_LVAL_P(cc_raw)) {
+                                       cc_header = ecalloc(sizeof("Cache-Control: ") + Z_STRLEN_P(ccontrol), 1);
+                                       sprintf(cc_header, "Cache-Control: %s", Z_STRVAL_P(ccontrol));
+                               } else {
+                                       cc_header = ecalloc(sizeof("Cache-Control: , must-revalidate, max-age=0") + Z_STRLEN_P(ccontrol), 1);
+                                       sprintf(cc_header, "Cache-Control: %s, must-revalidate, max-age=0", Z_STRVAL_P(ccontrol));
+                               }
+                               http_send_header(cc_header);
+                               efree(cc_header);
+                       } else {
+                               http_send_header("Cache-Control: public, must-revalidate, max-age=0");
+                       }
+               }
+               /* etag */
+               {
+                       zval *etag = GET_PROP(obj, eTag);
+                       if (Z_STRLEN_P(etag)) {
+                               if ((!http_is_range_request()) && http_etag_match("HTTP_IF_NONE_MATCH", Z_STRVAL_P(etag))) {
+                                       http_send_status(304);
+                                       RETURN_TRUE;
+                               }
+                               http_send_etag(Z_STRVAL_P(etag), Z_STRLEN_P(etag));
+                               if (HTTP_G(etag)) {
+                                       efree(HTTP_G(etag));
+                               }
+                               HTTP_G(etag) = estrndup(Z_STRVAL_P(etag), Z_STRLEN_P(etag));
+                       }
+               }
+               /* last modified */
+               {
+                       zval *lmod = GET_PROP(obj, lastModified);
+                       if (Z_LVAL_P(lmod)) {
+                               if (http_modified_match("HTTP_IF_MODIFIED_SINCE", Z_LVAL_P(lmod))) {
+                                       http_send_status(304);
+                                       RETURN_TRUE;
+                               }
+                               http_send_last_modified(Z_LVAL_P(lmod));
+                               HTTP_G(lmod) = Z_LVAL_P(lmod);
+                       } else {
+                               time_t t = time(NULL);
+                               http_send_last_modified(t);
+                               HTTP_G(lmod) = t;
+                       }
+               }
+       } /* caching done */
+       
+       /* gzip */
+       /* ... */
+       
+       /* content type */
+       {
+               zval *ctype = GET_PROP(obj, contentType);
+               if (Z_STRLEN_P(ctype)) {
+                       char *ctype_header = ecalloc(sizeof("Content-Type: ") + Z_STRLEN_P(ctype), 1);
+                       sprintf(ctype_header, "Content-Type: %s", Z_STRVAL_P(ctype));
+                       http_send_header(ctype_header);
+                       efree(ctype_header);
+                       if (HTTP_G(ctype)) {
+                               efree(HTTP_G(ctype));
+                       }
+                       HTTP_G(ctype) = estrndup(Z_STRVAL_P(ctype), Z_STRLEN_P(ctype));
+               } else {
+                       http_send_header("Content-Type: application/x-octetstream");
+                       if (HTTP_G(ctype)) {
+                               efree(HTTP_G(ctype));
+                       }
+                       HTTP_G(ctype) = estrdup("application/x-octetstream");
+               }
+       }
+       
+       /* content disposition */
+       {
+               zval *dispo_file = GET_PROP(obj, dispoFile);
+               if (Z_STRLEN_P(dispo_file)) {
+                       char *dispo_header;
+                       zval *dispo_inline = GET_PROP(obj, dispoInline);
+                       if (Z_LVAL_P(dispo_inline)) {
+                               dispo_header = ecalloc(sizeof("Content-Disposition: inline; filename=\"\"") + Z_STRLEN_P(dispo_file), 1);
+                               sprintf(dispo_header, "Content-Disposition: inline; filename=\"%s\"", Z_STRVAL_P(dispo_file));
+                       } else {
+                               dispo_header = ecalloc(sizeof("Content-Disposition: attachment; filename=\"\"") + Z_STRLEN_P(dispo_file), 1);
+                               sprintf(dispo_header, "Content-Disposition: attachment; filename=\"%s\"", Z_STRVAL_P(dispo_file));
+                       }
+                       http_send_header(dispo_header);
+                       efree(dispo_header);
+               }
+       }
+       
+       /* send */
+       {
+               zval *send_mode = GET_PROP(obj, send_mode);
+               switch (Z_LVAL_P(send_mode))
+               {
+                       case SEND_DATA:
+                       {
+                               RETURN_SUCCESS(http_send_data(GET_PROP(obj, data)));
+                       }
+                       
+                       case SEND_RSRC:
+                       {
+                               php_stream *the_real_stream;
+                               zval *the_stream = GET_PROP(obj, stream);
+                               php_stream_from_zval(the_real_stream, &the_stream);
+                               RETURN_SUCCESS(http_send_stream(the_real_stream));
+                       }
+                       
+                       default:
+                       {
+                               RETURN_SUCCESS(http_send_file(GET_PROP(obj, file)));
+                       }
+               }
+       }
+}
+
 #endif /* ZEND_ENGINE_2 */
 
 /* {{{ http_module_entry */
@@ -1532,11 +1812,7 @@ PHP_MINIT_FUNCTION(http)
 {
        ZEND_INIT_MODULE_GLOBALS(http, php_http_init_globals, NULL);
        REGISTER_INI_ENTRIES();
-       /*
-       REGISTER_LONG_CONSTANT("HTTP_GET", HTTP_GET, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("HTTP_HEAD", HTTP_HEAD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("HTTP_POST", HTTP_POST, CONST_CS | CONST_PERSISTENT);
-       */
+
 #ifdef HTTP_HAVE_CURL
        REGISTER_LONG_CONSTANT("HTTP_AUTH_BASIC", CURLAUTH_BASIC, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("HTTP_AUTH_DIGEST", CURLAUTH_DIGEST, CONST_CS | CONST_PERSISTENT);
@@ -1544,6 +1820,11 @@ PHP_MINIT_FUNCTION(http)
 #endif
 
 #ifdef ZEND_ENGINE_2
+       /*
+       REGISTER_LONG_CONSTANT("HTTP_GET", HTTP_GET, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("HTTP_HEAD", HTTP_HEAD, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("HTTP_POST", HTTP_POST, CONST_CS | CONST_PERSISTENT);
+       */
        HTTP_REGISTER_CLASS(HTTPi, httpi, NULL, ZEND_ACC_FINAL_CLASS);
        HTTP_REGISTER_CLASS_EX(HTTPi_Response, httpi_response, NULL, 0);
 #endif
index 4718e3d1b1fcdcbc4233e05526dc53768aaacb82..0c5c44512926a84cf898ebcc66b16a2fe1a4bc61 100644 (file)
@@ -134,10 +134,6 @@ static const struct time_zone {
 /* {{{ internals */
 
 static int http_sort_q(const void *a, const void *b TSRMLS_DC);
-#define http_etag(e, p, l, m) _http_etag((e), (p), (l), (m) TSRMLS_CC)
-static inline char *_http_etag(char **new_etag, const void *data_ptr, const size_t data_len, const http_send_mode data_mode TSRMLS_DC);
-#define http_is_range_request() _http_is_range_request(TSRMLS_C)
-static inline int _http_is_range_request(TSRMLS_D);
 #define http_send_chunk(d, b, e, m) _http_send_chunk((d), (b), (e), (m) TSRMLS_CC)
 static STATUS _http_send_chunk(const void *data, const size_t begin, const size_t end, const http_send_mode mode TSRMLS_DC);
 
@@ -182,32 +178,14 @@ static inline char *_http_curl_getinfoname(CURLINFO i TSRMLS_DC);
 #endif
 /* }}} HAVE_CURL */
 
-/* {{{ static int http_sort_q(const void *, const void *) */
-static int http_sort_q(const void *a, const void *b TSRMLS_DC)
-{
-       Bucket *f, *s;
-       zval result, *first, *second;
-
-       f = *((Bucket **) a);
-       s = *((Bucket **) b);
-
-       first = *((zval **) f->pData);
-       second= *((zval **) s->pData);
-
-       if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
-               return 0;
-       }
-       return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
-}
-/* }}} */
-
-/* {{{ static inline char *http_etag(char **, void *, size_t, http_send_mode) */
-static inline char *_http_etag(char **new_etag, const void *data_ptr,
-       const size_t data_len, const http_send_mode data_mode TSRMLS_DC)
+/* {{{ inline char *http_etag(void *, size_t, http_send_mode) */
+inline char *_http_etag(const void *data_ptr, const size_t data_len, 
+       const http_send_mode data_mode TSRMLS_DC)
 {
-       char ssb_buf[127];
+       char ssb_buf[128] = {0};
        unsigned char digest[16];
        PHP_MD5_CTX ctx;
+       char *new_etag = ecalloc(33, 1);
 
        PHP_MD5Init(&ctx);
 
@@ -218,6 +196,11 @@ static inline char *_http_etag(char **new_etag, const void *data_ptr,
                break;
 
                case SEND_RSRC:
+                       if (!HTTP_G(ssb).sb.st_ino) {
+                               if (php_stream_stat((php_stream *) data_ptr, &HTTP_G(ssb))) {
+                                       return NULL;
+                               }
+                       }
                        snprintf(ssb_buf, 127, "%l=%l=%l",
                                HTTP_G(ssb).sb.st_mtime,
                                HTTP_G(ssb).sb.st_ino,
@@ -227,25 +210,45 @@ static inline char *_http_etag(char **new_etag, const void *data_ptr,
                break;
 
                default:
+                       efree(new_etag);
                        return NULL;
                break;
        }
 
        PHP_MD5Final(digest, &ctx);
-       make_digest(*new_etag, digest);
+       make_digest(new_etag, digest);
 
-       return *new_etag;
+       return new_etag;
 }
 /* }}} */
 
-/* {{{ static inline int http_is_range_request(void) */
-static inline int _http_is_range_request(TSRMLS_D)
+/* {{{inline int http_is_range_request(void) */
+inline int _http_is_range_request(TSRMLS_D)
 {
        return zend_hash_exists(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]),
                "HTTP_RANGE", strlen("HTTP_RANGE") + 1);
 }
 /* }}} */
 
+/* {{{ static int http_sort_q(const void *, const void *) */
+static int http_sort_q(const void *a, const void *b TSRMLS_DC)
+{
+       Bucket *f, *s;
+       zval result, *first, *second;
+
+       f = *((Bucket **) a);
+       s = *((Bucket **) b);
+
+       first = *((zval **) f->pData);
+       second= *((zval **) s->pData);
+
+       if (numeric_compare_function(&result, first, second TSRMLS_CC) != SUCCESS) {
+               return 0;
+       }
+       return (Z_LVAL(result) > 0 ? -1 : (Z_LVAL(result) < 0 ? 1 : 0));
+}
+/* }}} */
+
 /* {{{ static STATUS http_send_chunk(const void *, size_t, size_t,
        http_send_mode) */
 static STATUS _http_send_chunk(const void *data, const size_t begin,
@@ -1588,13 +1591,12 @@ PHP_HTTP_API STATUS _http_send(const void *data_ptr, const size_t data_size,
 
        /* etag handling */
        if (HTTP_G(etag_started)) {
-               char *etag = ecalloc(33, 1);
+               char *etag;
                /* interrupt */
                HTTP_G(etag_started) = 0;
                /* never ever use the output to compute the ETag if http_send() is used */
                php_end_ob_buffer(0, 0 TSRMLS_CC);
-               if (NULL == http_etag(&etag, data_ptr, data_size, data_mode)) {
-                       efree(etag);
+               if (!(etag = http_etag(data_ptr, data_size, data_mode))) {
                        return FAILURE;
                }
 
@@ -1897,7 +1899,7 @@ PHP_HTTP_API STATUS _http_get(const char *URL, HashTable *options,
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize curl");
                return FAILURE;
        }
-       
+
        rs = http_get_ex(ch, URL, options, info, data, data_len);
        curl_easy_cleanup(ch);
        return rs;
@@ -1936,7 +1938,7 @@ PHP_HTTP_API STATUS _http_head(const char *URL, HashTable *options,
                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not initialize curl");
                return FAILURE;
        }
-       
+
        rs = http_head_ex(ch, URL, options, info, data, data_len);
        curl_easy_cleanup(ch);
        return rs;
index 86cedff125881f4e4c9617b060e1e3714927f84a..43b5fad697e9e95e4a0428bc7dec068e8e75a3f5 100644 (file)
@@ -76,14 +76,15 @@ PHP_METHOD(HTTPi_Response, getCache);
 PHP_METHOD(HTTPi_Response, setCacheControl);
 PHP_METHOD(HTTPi_Response, getCacheControl);
 PHP_METHOD(HTTPi_Response, setGzip);
-PHP_METHOD(HTTPi_Response, getGzip);/*
+PHP_METHOD(HTTPi_Response, getGzip);
 PHP_METHOD(HTTPi_Response, setData);
 PHP_METHOD(HTTPi_Response, getData);
 PHP_METHOD(HTTPi_Response, setFile);
 PHP_METHOD(HTTPi_Response, getFile);
 PHP_METHOD(HTTPi_Response, setStream);
 PHP_METHOD(HTTPi_Response, getStream);
-PHP_METHOD(HTTPi_Response, send);*/
+PHP_METHOD(HTTPi_Response, send);
+PHP_METHOD(HTTPi_Response, getSize);
 
 #endif /* ZEND_ENGINE_2 */
 
index c776ba82e5a904df3d9f696c2a44e258dbc16701..7ec4f2f6e85fca9b201505658b2f41dbe3268387 100644 (file)
@@ -90,6 +90,11 @@ typedef enum {
                }
 /* }}} */
 
+#define http_etag(p, l, m) _http_etag((p), (l), (m) TSRMLS_CC)
+inline char *_http_etag(const void *data_ptr, const size_t data_len, const http_send_mode data_mode TSRMLS_DC);
+#define http_is_range_request() _http_is_range_request(TSRMLS_C)
+inline int _http_is_range_request(TSRMLS_D);
+
 /* {{{ public API */
 #define http_date(t) _http_date((t) TSRMLS_CC)
 PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC);