PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC)
{
struct tm *gmtime, tmbuf;
- char *date = ecalloc(1, 31);
-
- gmtime = php_gmtime_r(&t, &tmbuf);
- snprintf(date, 30,
- "%s, %02d %s %04d %02d:%02d:%02d GMT",
- days[gmtime->tm_wday], gmtime->tm_mday,
- months[gmtime->tm_mon], gmtime->tm_year + 1900,
- gmtime->tm_hour, gmtime->tm_min, gmtime->tm_sec
- );
- return date;
+
+ if (gmtime = php_gmtime_r(&t, &tmbuf)) {
+ char *date = ecalloc(1, 31);
+ snprintf(date, 30,
+ "%s, %02d %s %04d %02d:%02d:%02d GMT",
+ days[gmtime->tm_wday], gmtime->tm_mday,
+ months[gmtime->tm_mon], gmtime->tm_year + 1900,
+ gmtime->tm_hour, gmtime->tm_min, gmtime->tm_sec
+ );
+ return date;
+ }
+
+ return NULL;
}
/* }}} */
/* a digit */
int val;
char *end;
- if((seconds == -1) && (3 == sscanf(date, "%02d:%02d:%02d", &hours, &minutes, &seconds))) {
+ if ((seconds == -1) &&
+ (3 == sscanf(date, "%02d:%02d:%02d", &hours, &minutes, &seconds))) {
/* time stamp! */
date += 8;
found = 1;
else {
val = (int) strtol(date, &end, 10);
- if ((tz_offset == -1) && ((end - date) == 4) && (val < 1300) && (indate < date) && ((date[-1] == '+' || date[-1] == '-'))) {
+ if ((tz_offset == -1) && ((end - date) == 4) && (val < 1300) &&
+ (indate < date) && ((date[-1] == '+' || date[-1] == '-'))) {
/* four digits and a value less than 1300 and it is preceeded with
a plus or minus. This is a time zone indication. */
found = 1;
}
/* }}} */
-/* {{{ int http_is_range_request(void) */
-PHP_HTTP_API int _http_is_range_request(TSRMLS_D)
-{
- return zend_hash_exists(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]),
- "HTTP_RANGE", sizeof("HTTP_RANGE"));
-}
-/* }}} */
-
-/* {{{ STATUS http_send_status(int) */
-PHP_HTTP_API STATUS _http_send_status(const int status TSRMLS_DC)
-{
- int s = status;
- return sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) s TSRMLS_CC);
-}
-/* }}} */
-
-/* {{{ STATUS http_send_header(char *) */
-PHP_HTTP_API STATUS _http_send_header(const char *header TSRMLS_DC)
-{
- return http_send_status_header(0, header);
-}
-/* }}} */
-
/* {{{ STATUS http_send_status_header(int, char *) */
PHP_HTTP_API STATUS _http_send_status_header(const int status, const char *header TSRMLS_DC)
{
/* {{{ STATUS http_send_last_modified(int) */
PHP_HTTP_API STATUS _http_send_last_modified(const time_t t TSRMLS_DC)
{
- char modified[96] = "Last-Modified: ", *date;
- date = http_date(t);
- strcat(modified, date);
- efree(date);
+ char *date = NULL;
+ if (date = http_date(t)) {
+ char modified[96] = "Last-Modified: ";
+ strcat(modified, date);
+ efree(date);
- /* remember */
- HTTP_G(lmod) = t;
+ /* remember */
+ HTTP_G(lmod) = t;
- return http_send_header(modified);
+ return http_send_header(modified);
+ }
+ return FAILURE;
}
/* }}} */
}
/* }}} */
-/* {{{ http_range_status http_get_request_ranges(zval *zranges, size_t) */
-PHP_HTTP_API http_range_status _http_get_request_ranges(zval *zranges,
+/* {{{ http_range_status http_get_request_ranges(HashTable *ranges, size_t) */
+PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges,
const size_t length TSRMLS_DC)
{
zval *zrange;
array_init(zentry);
add_index_long(zentry, 0, begin);
add_index_long(zentry, 1, end);
- add_next_index_zval(zranges, zentry);
+ zend_hash_next_index_insert(ranges, &zentry, sizeof(zval *), NULL);
begin = -1;
end = -1;
}
/* }}} */
-/* {{{ STATUS http_send_ranges(zval *, void *, size_t, http_send_mode) */
-PHP_HTTP_API STATUS _http_send_ranges(zval *zranges, const void *data, const size_t size, const http_send_mode mode TSRMLS_DC)
+/* {{{ STATUS http_send_ranges(HashTable *, void *, size_t, http_send_mode) */
+PHP_HTTP_API STATUS _http_send_ranges(HashTable *ranges, const void *data, const size_t size, const http_send_mode mode TSRMLS_DC)
{
- int c;
long **begin, **end;
zval **zrange;
- /* Send HTTP 206 Partial Content */
- http_send_status(206);
-
/* single range */
- if ((c = zend_hash_num_elements(Z_ARRVAL_P(zranges))) == 1) {
+ if (zend_hash_num_elements(ranges) == 1) {
char range_header[256] = {0};
- zend_hash_index_find(Z_ARRVAL_P(zranges), 0, (void **) &zrange);
- zend_hash_index_find(Z_ARRVAL_PP(zrange), 0, (void **) &begin);
- zend_hash_index_find(Z_ARRVAL_PP(zrange), 1, (void **) &end);
+ if (SUCCESS != zend_hash_index_find(ranges, 0, (void **) &zrange) ||
+ SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrange), 0, (void **) &begin) ||
+ SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrange), 1, (void **) &end)) {
+ return FAILURE;
+ }
+
+ /* Send HTTP 206 Partial Content */
+ http_send_status(206);
/* send content range header */
snprintf(range_header, 255, "Content-Range: bytes %d-%d/%d", **begin, **end, size);
/* multi range */
else {
- int i;
char bound[23] = {0}, preface[1024] = {0},
multi_header[68] = "Content-Type: multipart/byteranges; boundary=";
+ /* Send HTTP 206 Partial Content */
+ http_send_status(206);
+
+ /* send multipart/byteranges header */
snprintf(bound, 22, "--%d%0.9f", time(NULL), php_combined_lcg(TSRMLS_C));
strncat(multi_header, bound + 2, 21);
http_send_header(multi_header);
/* send each requested chunk */
- for ( i = 0, zend_hash_internal_pointer_reset(Z_ARRVAL_P(zranges));
- i < c;
- i++, zend_hash_move_forward(Z_ARRVAL_P(zranges))) {
- if ( HASH_KEY_NON_EXISTANT == zend_hash_get_current_data(
- Z_ARRVAL_P(zranges), (void **) &zrange) ||
- SUCCESS != zend_hash_index_find(
- Z_ARRVAL_PP(zrange), 0, (void **) &begin) ||
- SUCCESS != zend_hash_index_find(
- Z_ARRVAL_PP(zrange), 1, (void **) &end)) {
+ FOREACH_HASH_VAL(ranges, zrange) {
+ if (SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrange), 0, (void **) &begin) ||
+ SUCCESS != zend_hash_index_find(Z_ARRVAL_PP(zrange), 1, (void **) &end)) {
break;
}
}
/* write boundary once more */
- php_body_write(HTTP_CRLF, 2 TSRMLS_CC);
+ php_body_write(HTTP_CRLF, sizeof(HTTP_CRLF) - 1 TSRMLS_CC);
php_body_write(bound, strlen(bound) TSRMLS_CC);
+ php_body_write("--", 2 TSRMLS_CC);
return SUCCESS;
}
}
/* }}} */
-/* {{{ STATUS http_send(void *, sizezo_t, http_send_mode) */
+/* {{{ STATUS http_send(void *, size_t, http_send_mode) */
PHP_HTTP_API STATUS _http_send(const void *data_ptr, const size_t data_size,
const http_send_mode data_mode TSRMLS_DC)
{
if (!data_ptr) {
return FAILURE;
}
+ if (!data_size) {
+ return SUCCESS;
+ }
/* etag handling */
if (HTTP_G(etag_started)) {
) {
STATUS result = FAILURE;
- zval *zranges = NULL;
- MAKE_STD_ZVAL(zranges);
- array_init(zranges);
+ HashTable ranges;
+ zend_hash_init(&ranges, 0, NULL, ZVAL_PTR_DTOR, 0);
- switch (http_get_request_ranges(zranges, data_size))
+ switch (http_get_request_ranges(&ranges, data_size))
{
case RANGE_NO:
- zval_dtor(zranges);
- efree(zranges);
+ zend_hash_destroy(&ranges);
/* go ahead and send all */
break;
case RANGE_OK:
- result = http_send_ranges(zranges, data_ptr, data_size, data_mode);
- zval_dtor(zranges);
- efree(zranges);
+ result = http_send_ranges(&ranges, data_ptr, data_size, data_mode);
+ zend_hash_destroy(&ranges);
return result;
break;
case RANGE_ERR:
- zval_dtor(zranges);
- efree(zranges);
+ zend_hash_destroy(&ranges);
http_send_status(416);
return FAILURE;
break;
}
/* }}} */
-/* {{{ STATUS http_send_data(zval *) */
-PHP_HTTP_API STATUS _http_send_data(const zval *zdata TSRMLS_DC)
-{
- if (!Z_STRLEN_P(zdata)) {
- return SUCCESS;
- }
- if (!Z_STRVAL_P(zdata)) {
- return FAILURE;
- }
-
- return http_send(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata), SEND_DATA);
-}
-/* }}} */
-
/* {{{ STATUS http_send_stream(php_stream *) */
-PHP_HTTP_API STATUS _http_send_stream(const php_stream *file TSRMLS_DC)
+PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file,
+ zend_bool close_stream TSRMLS_DC)
{
- if (php_stream_stat((php_stream *) file, &HTTP_G(ssb))) {
- return FAILURE;
- }
-
- return http_send(file, HTTP_G(ssb).sb.st_size, SEND_RSRC);
-}
-/* }}} */
-
-/* {{{ STATUS http_send_file(zval *) */
-PHP_HTTP_API STATUS _http_send_file(const zval *zfile TSRMLS_DC)
-{
- php_stream *file;
- STATUS ret;
+ STATUS status;
- if (!Z_STRLEN_P(zfile)) {
+ if ((!file) || php_stream_stat(file, &HTTP_G(ssb))) {
return FAILURE;
}
- if (!(file = php_stream_open_wrapper(Z_STRVAL_P(zfile), "rb",
- REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL))) {
- return FAILURE;
+ status = http_send(file, HTTP_G(ssb).sb.st_size, SEND_RSRC);
+
+ if (close_stream) {
+ php_stream_close(file);
}
- ret = http_send_stream(file);
- php_stream_close(file);
- return ret;
+ return status;
}
/* }}} */
/* }}} */
/* {{{ proto STATUS http_split_response_ex(char *, size_t, zval *, zval *) */
-PHP_HTTP_API STATUS _http_split_response_ex( char *response,
+PHP_HTTP_API STATUS _http_split_response_ex(char *response,
size_t response_len, zval *zheaders, zval *zbody TSRMLS_DC)
{
char *body = NULL;
}
/* }}} */
-/* {{{ proto bool http_match_modified([int timestamp])
+/* {{{ proto bool http_match_modified([int timestamp[, for_range = false]])
*
* Matches the given timestamp against the clients "If-Modified-Since" resp.
* "If-Unmodified-Since" HTTP headers.
PHP_FUNCTION(http_match_modified)
{
long t = -1;
+ zend_bool for_range = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &t) != SUCCESS) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lb", &t, &for_range) != SUCCESS) {
RETURN_FALSE;
}
t = (long) time(NULL);
}
- RETURN_BOOL(http_modified_match("HTTP_IF_MODIFIED_SINCE", t) || http_modified_match("HTTP_IF_UNMODIFIED_SINCE", t));
+ if (for_range) {
+ RETURN_BOOL(http_modified_match("HTTP_IF_UNMODIFIED_SINCE", t));
+ }
+ RETURN_BOOL(http_modified_match("HTTP_IF_MODIFIED_SINCE", t));
}
/* }}} */
-/* {{{ proto bool http_match_etag(string etag)
+/* {{{ proto bool http_match_etag(string etag[, for_range = false])
*
* This matches the given ETag against the clients
* "If-Match" resp. "If-None-Match" HTTP headers.
{
int etag_len;
char *etag;
+ zend_bool for_range = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &etag, &etag_len) != SUCCESS) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|b", &etag, &etag_len, &for_range) != SUCCESS) {
RETURN_FALSE;
}
- RETURN_BOOL(http_etag_match("HTTP_IF_NONE_MATCH", etag) || http_etag_match("HTTP_IF_MATCH", etag));
+ if (for_range) {
+ RETURN_BOOL(http_etag_match("HTTP_IF_MATCH", etag));
+ }
+ RETURN_BOOL(http_etag_match("HTTP_IF_NONE_MATCH", etag));
}
/* }}} */
convert_to_string_ex(&zdata);
http_send_header("Accept-Ranges: bytes");
- RETURN_SUCCESS(http_send_data(zdata));
+ RETURN_SUCCESS(http_send_data(Z_STRVAL_P(zdata), Z_STRLEN_P(zdata)));
}
/* }}} */
*/
PHP_FUNCTION(http_send_file)
{
- zval *zfile;
+ char *file;
+ int flen = 0;
- if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z", &zfile) != SUCCESS) {
+ if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &flen) != SUCCESS) {
+ RETURN_FALSE;
+ }
+ if (!flen) {
RETURN_FALSE;
}
- convert_to_string_ex(&zfile);
http_send_header("Accept-Ranges: bytes");
- RETURN_SUCCESS(http_send_file(zfile));
+ RETURN_SUCCESS(http_send_file(file));
}
/* }}} */
* 0 => array(
* 'Status' => '200 Ok',
* 'Content-Type' => 'text/plain',
+
* 'Content-Language' => 'en-US'
* ),
* 1 => "Hello World!"
/* }}}*/
/* {{{ Sara Golemons http_build_query() */
-#ifndef ZEND_ENGINE_2
+#ifndef ZEND_ENGINE_2
/* {{{ proto string http_build_query(mixed formdata [, string prefix])
Generates a form-encoded query string from an associative array or object. */
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
- */
\ No newline at end of file
+ */
char *pretty_key(char *key, int key_len, int uctitle, int xhyphen);
/* {{{ public API */
+#define http_is_range_request() zend_hash_exists(HTTP_SERVER_VARS, "HTTP_RANGE", sizeof("HTTP_RANGE"))
+
#define http_date(t) _http_date((t) TSRMLS_CC)
PHP_HTTP_API char *_http_date(time_t t TSRMLS_DC);
#define http_parse_date(d) _http_parse_date((d))
PHP_HTTP_API time_t _http_parse_date(const char *date);
-#define http_send_status(s) _http_send_status((s) TSRMLS_CC)
-PHP_HTTP_API inline STATUS _http_send_status(const int status TSRMLS_DC);
-
-#define http_send_header(h) _http_send_header((h) TSRMLS_CC)
-PHP_HTTP_API inline STATUS _http_send_header(const char *header TSRMLS_DC);
-
+#define http_send_status(s) sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (s) TSRMLS_CC)
+#define http_send_header(h) http_send_status_header(0, (h))
#define http_send_status_header(s, h) _http_send_status_header((s), (h) TSRMLS_CC)
PHP_HTTP_API inline STATUS _http_send_status_header(const int status, const char *header TSRMLS_DC);
#define http_lmod(p, m) _http_lmod((p), (m) TSRMLS_CC)
PHP_HTTP_API inline time_t _http_lmod(const void *data_ptr, const http_send_mode data_mode TSRMLS_DC);
-#define http_is_range_request() _http_is_range_request(TSRMLS_C)
-PHP_HTTP_API inline int _http_is_range_request(TSRMLS_D);
-
#define http_ob_etaghandler(o, l, ho, hl, m) _http_ob_etaghandler((o), (l), (ho), (hl), (m) TSRMLS_CC)
PHP_HTTP_API void _http_ob_etaghandler(char *output, uint output_len, char **handled_output, uint *handled_output_len, int mode TSRMLS_DC);
PHP_HTTP_API char *_http_negotiate_q(const char *entry, const zval *supported, const char *def TSRMLS_DC);
#define http_get_request_ranges(r, l) _http_get_request_ranges((r), (l) TSRMLS_CC)
-PHP_HTTP_API http_range_status _http_get_request_ranges(zval *zranges, const size_t length TSRMLS_DC);
+PHP_HTTP_API http_range_status _http_get_request_ranges(HashTable *ranges, const size_t length TSRMLS_DC);
#define http_send_ranges(r, d, s, m) _http_send_ranges((r), (d), (s), (m) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_ranges(zval *zranges, const void *data, const size_t size, const http_send_mode mode TSRMLS_DC);
+PHP_HTTP_API STATUS _http_send_ranges(HashTable *ranges, const void *data, const size_t size, const http_send_mode mode TSRMLS_DC);
+#define http_send_data(d, l) http_send((d), (l), SEND_DATA)
#define http_send(d, s, m) _http_send((d), (s), (m) TSRMLS_CC)
PHP_HTTP_API STATUS _http_send(const void *data, const size_t data_size, const http_send_mode mode TSRMLS_DC);
-#define http_send_data(z) _http_send_data((z) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_data(const zval *zdata TSRMLS_DC);
-
-#define http_send_stream(s) _http_send_stream((s) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_stream(const php_stream *s TSRMLS_DC);
-
-#define http_send_file(f) _http_send_file((f) TSRMLS_CC)
-PHP_HTTP_API STATUS _http_send_file(const zval *zfile TSRMLS_DC);
+#define http_send_file(f) http_send_stream_ex(php_stream_open_wrapper(f, "rb", REPORT_ERRORS|ENFORCE_SAFE_MODE, NULL), 1)
+#define http_send_stream(s) http_send_stream_ex((s), 0)
+#define http_send_stream_ex(s, c) _http_send_stream_ex((s), (c) TSRMLS_CC)
+PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *s, zend_bool close_stream TSRMLS_DC);
#define http_chunked_decode(e, el, d, dl) _http_chunked_decode((e), (el), (d), (dl) TSRMLS_CC)
PHP_HTTP_API STATUS _http_chunked_decode(const char *encoded, const size_t encoded_len, char **decoded, size_t *decoded_len TSRMLS_DC);
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
- */
+ */
\ No newline at end of file