- win32 build now has libcurl v7.16.0
[m6w6/ext-http] / http_send_api.c
index 88a27e1a7684cf83d6a82b422a76cf59fcd7e90c..1fe1d4d913433791a3cac81f49d28618ddafa156 100644 (file)
@@ -35,28 +35,12 @@ static inline void _http_flush(void *nothing, const char *data, size_t data_len
        php_end_ob_buffer(1, 1 TSRMLS_CC);
        sapi_flush(TSRMLS_C);
        
-#define HTTP_MSEC(s) (s * 1000)
-#define HTTP_USEC(s) (HTTP_MSEC(s) * 1000)
-#define HTTP_NSEC(s) (HTTP_USEC(s) * 1000)
-#define HTTP_NANOSEC (1000 * 1000 * 1000)
-#define HTTP_DIFFSEC (0.001)
-
-       if (HTTP_G->send.throttle_delay >= HTTP_DIFFSEC) {
-#if defined(PHP_WIN32)
-               Sleep((DWORD) HTTP_MSEC(HTTP_G->send.throttle_delay));
-#elif defined(HAVE_USLEEP)
-               usleep(HTTP_USEC(HTTP_G->send.throttle_delay));
-#elif defined(HAVE_NANOSLEEP)
-               struct timespec req, rem;
-
-               req.tv_sec = (time_t) HTTP_G->send.throttle_delay;
-               req.tv_nsec = HTTP_NSEC(HTTP_G->send.throttle_delay) % HTTP_NANOSEC;
-
-               while (nanosleep(&req, &rem) && (errno == EINTR) && (HTTP_NSEC(rem.tv_sec) + rem.tv_nsec) > HTTP_NSEC(HTTP_DIFFSEC))) {
-                       req.tv_sec = rem.tv_sec;
-                       req.tv_nsec = rem.tv_nsec;
-               }
+#if 0
+       fprintf(stderr, "Flushing after writing %u bytes\n", (uint) data_len);
 #endif
+       
+       if (HTTP_G->send.throttle_delay >= HTTP_DIFFSEC) {
+               http_sleep(HTTP_G->send.throttle_delay);
        }
 }
 /* }}} */
@@ -67,7 +51,7 @@ static inline void _http_send_response_start(void **buffer, size_t content_lengt
 {
        int encoding;
        
-       if ((encoding = http_encoding_response_start(content_length))) {
+       if ((encoding = http_encoding_response_start(content_length, 0))) {
 #ifdef HTTP_HAVE_ZLIB
                *buffer = http_encoding_deflate_stream_init(NULL, 
                        (encoding == HTTP_ENCODING_GZIP) ? 
@@ -81,20 +65,26 @@ static inline void _http_send_response_start(void **buffer, size_t content_lengt
 #define http_send_response_data_plain(b, d, dl) _http_send_response_data_plain((b), (d), (dl) TSRMLS_CC)
 static inline void _http_send_response_data_plain(void **buffer, const char *data, size_t data_len TSRMLS_DC)
 {
-       if (HTTP_G->send.deflate.encoding) {
+       if (HTTP_G->send.deflate.response && HTTP_G->send.deflate.encoding) {
 #ifdef HTTP_HAVE_ZLIB
                char *encoded;
                size_t encoded_len;
                http_encoding_stream *s = *((http_encoding_stream **) buffer);
                
                http_encoding_deflate_stream_update(s, data, data_len, &encoded, &encoded_len);
-               phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC);
+               if (HTTP_G->send.buffer_size) {
+                       phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC);
+               } else {
+                       http_flush(encoded, encoded_len);
+               }
                efree(encoded);
 #else
                http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug");
 #endif
-       } else {
+       } else if (HTTP_G->send.buffer_size) {
                phpstr_chunked_output((phpstr **) buffer, data, data_len, HTTP_G->send.buffer_size, _http_flush, NULL TSRMLS_CC);
+       } else {
+               http_flush(data, data_len);
        }
 }
 /* }}} */
@@ -147,20 +137,24 @@ static inline void _http_send_response_data_fetch(void **buffer, const void *dat
 #define http_send_response_finish(b) _http_send_response_finish((b) TSRMLS_CC)
 static inline void _http_send_response_finish(void **buffer TSRMLS_DC)
 {
-       if (HTTP_G->send.deflate.encoding) {
+       if (HTTP_G->send.deflate.response && HTTP_G->send.deflate.encoding) {
 #ifdef HTTP_HAVE_ZLIB
                char *encoded = NULL;
                size_t encoded_len = 0;
                http_encoding_stream *s = *((http_encoding_stream **) buffer);
                
                http_encoding_deflate_stream_finish(s, &encoded, &encoded_len);
-               phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, 0, _http_flush, NULL TSRMLS_CC);
+               if (HTTP_G->send.buffer_size) {
+                       phpstr_chunked_output((phpstr **) &s->storage, encoded, encoded_len, 0, _http_flush, NULL TSRMLS_CC);
+               } else {
+                       http_flush(encoded, encoded_len);
+               }
                http_encoding_deflate_stream_free(&s);
                STR_FREE(encoded);
 #else
                http_error(HE_ERROR, HTTP_E_RESPONSE, "Attempt to send GZIP response despite being able to do so; please report this bug");
 #endif
-       } else {
+       } else if (HTTP_G->send.buffer_size) {
                phpstr_chunked_output((phpstr **) buffer, NULL, 0, 0, _http_flush, NULL TSRMLS_CC);
        }
 }
@@ -180,21 +174,81 @@ PHP_MINIT_FUNCTION(http_send)
 }
 /* }}} */
 
+/* {{{ http_find_header */
+typedef struct {
+       const char *h;
+       size_t l;
+} http_response_header_t;
+
+static int http_find_header(void *data, void *arg)
+{
+       http_response_header_t *h = arg;
+       sapi_header_struct *s = data;
+       
+       return (!strncasecmp(s->header, h->h, h->l)) && s->header[h->l] == ':';
+}
+/* }}} */
+
+/* {{{ void http_hide_header(char *) */
+PHP_HTTP_API void _http_hide_header_ex(const char *name, size_t name_len TSRMLS_DC)
+{
+       http_response_header_t h = {name, name_len};
+       zend_llist_del_element(&SG(sapi_headers).headers, (void *) &h, http_find_header);
+}
+/* }}} */
+
+/* {{{ void http_send_header_zval(char*, zval **, zend_bool) */
+PHP_HTTP_API void _http_send_header_zval_ex(const char *name, size_t name_len, zval **val, zend_bool replace TSRMLS_DC)
+{
+       if (!val || !*val || Z_TYPE_PP(val) == IS_NULL || (Z_TYPE_PP(val) == IS_STRING && !Z_STRLEN_PP(val))) {
+               http_hide_header_ex(name, name_len);
+       } else if (Z_TYPE_PP(val) == IS_ARRAY || Z_TYPE_PP(val) == IS_OBJECT) {
+               zend_bool first = replace;
+               zval **data;
+               HashPosition pos;
+               
+               FOREACH_HASH_VAL(pos, HASH_OF(*val), data) {
+                       zval *orig = *data;
+                       
+                       convert_to_string_ex(data);
+                       http_send_header_ex(name, name_len, Z_STRVAL_PP(data), Z_STRLEN_PP(data), first, NULL);
+                       if (orig != *data) {
+                               zval_ptr_dtor(data);
+                       }
+                       first = 0;
+               }
+       } else {
+               zval *orig = *val;
+               
+               convert_to_string_ex(val);
+               http_send_header_ex(name, name_len, Z_STRVAL_PP(val), Z_STRLEN_PP(val), replace, NULL);
+               if (orig != *val) {
+                       zval_ptr_dtor(val);
+               }
+       }
+}
+/* }}} */
 
 /* {{{ STATUS http_send_header(char *, char *, zend_bool) */
 PHP_HTTP_API STATUS _http_send_header_ex(const char *name, size_t name_len, const char *value, size_t value_len, zend_bool replace, char **sent_header TSRMLS_DC)
 {
        STATUS ret;
-       size_t header_len = sizeof(": ") + name_len + value_len + 1;
-       char *header = emalloc(header_len + 1);
-
-       header[header_len] = '\0';
-       header_len = snprintf(header, header_len, "%s: %s", name, value);
-       ret = http_send_header_string_ex(header, header_len, replace);
-       if (sent_header) {
-               *sent_header = header;
+       
+       if (value && value_len) {
+               size_t header_len = sizeof(": ") + name_len + value_len + 1;
+               char *header = emalloc(header_len + 1);
+       
+               header[header_len] = '\0';
+               header_len = snprintf(header, header_len, "%s: %s", name, value);
+               ret = http_send_header_string_ex(header, header_len, replace);
+               if (sent_header) {
+                       *sent_header = header;
+               } else {
+                       efree(header);
+               }
        } else {
-               efree(header);
+               http_hide_header_ex(name, name_len);
+               ret = SUCCESS;
        }
        return ret;
 }
@@ -457,8 +511,8 @@ PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file, zend_bool close_strea
        if ((!file) || php_stream_stat(file, &ssb)) {
                char *defct = sapi_get_default_content_type(TSRMLS_C);
                
+               http_hide_header("Content-Disposition");
                http_send_content_type(defct, strlen(defct));
-               http_send_header_string("Content-Disposition:");
                http_error(HE_WARNING, HTTP_E_RESPONSE, "File not found; stat failed");
                STR_FREE(defct);
                
@@ -484,15 +538,13 @@ PHP_HTTP_API char *_http_guess_content_type(const char *magicfile, long magicmod
        char *ct = NULL;
 
 #ifdef HTTP_HAVE_MAGIC
-       struct magic_set *magic;
+       struct magic_set *magic = NULL;
        
        HTTP_CHECK_OPEN_BASEDIR(magicfile, return NULL);
        
-       /*      magic_load() fails if MAGIC_MIME is set because it 
-               cowardly adds .mime to the file name */
-       magic = magic_open(magicmode &~ MAGIC_MIME);
-       
-       if (!magic) {
+       if (!data_ptr) {
+               http_error(HE_WARNING, HTTP_E_INVALID_PARAM, "Supplied payload is empty");
+       } else if (!(magic = magic_open(magicmode &~ MAGIC_MIME))) {
                http_error_ex(HE_WARNING, HTTP_E_INVALID_PARAM, "Invalid magic mode: %ld", magicmode);
        } else if (-1 == magic_load(magic, magicfile)) {
                http_error_ex(HE_WARNING, HTTP_E_RUNTIME, "Failed to load magic database '%s' (%s)", magicfile, magic_error(magic));