-
- /* protocol defaults to http */
- if (!proto || !strlen(proto)) {
- proto = "http";
- }
-
- /* get host name */
- if ( (zhost = http_get_server_var("HTTP_HOST")) ||
- (zhost = http_get_server_var("SERVER_NAME"))) {
- host = Z_STRVAL_P(zhost);
- } else {
- host = "localhost";
- }
-
-
- /* glue together */
- if (url[0] == '/') {
- snprintf(URI, HTTP_URI_MAXLEN, "%s://%s%s", proto, host, url);
- } else if (SG(request_info).request_uri) {
- path = estrdup(SG(request_info).request_uri);
- php_dirname(path, strlen(path));
- snprintf(URI, HTTP_URI_MAXLEN, "%s://%s%s/%s", proto, host, path, url);
- efree(path);
- } else {
- snprintf(URI, HTTP_URI_MAXLEN, "%s://%s/%s", proto, host, url);
- }
-
- /* strip everything after a new line */
- PTR = URI;
- while (*PTR != 0) {
- if (*PTR == '\n' || *PTR == '\r') {
- *PTR = 0;
- break;
- }
- PTR++;
- }
-
- return estrdup(URI);
-}
-/* }}} */
-
-/* {{{ char *http_negotiate_q(char *, zval *, char *, hash_entry_type) */
-PHP_HTTP_API char *_http_negotiate_q(const char *entry, const zval *supported,
- const char *def TSRMLS_DC)
-{
- zval *zaccept, *zarray, *zdelim, **zentry, *zentries, **zsupp;
- char *q_ptr, *result;
- int i, c;
- double qual;
-
- HTTP_GSC(zaccept, entry, estrdup(def));
-
- MAKE_STD_ZVAL(zarray);
- array_init(zarray);
-
- MAKE_STD_ZVAL(zdelim);
- ZVAL_STRING(zdelim, ",", 0);
- php_explode(zdelim, zaccept, zarray, -1);
- efree(zdelim);
-
- MAKE_STD_ZVAL(zentries);
- array_init(zentries);
-
- c = zend_hash_num_elements(Z_ARRVAL_P(zarray));
- for (i = 0; i < c; i++, zend_hash_move_forward(Z_ARRVAL_P(zarray))) {
-
- if (SUCCESS != zend_hash_get_current_data(
- Z_ARRVAL_P(zarray), (void **) &zentry)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "Cannot parse %s header: %s", entry, Z_STRVAL_P(zaccept));
- break;
- }
-
- /* check for qualifier */
- if (NULL != (q_ptr = strrchr(Z_STRVAL_PP(zentry), ';'))) {
- qual = strtod(q_ptr + 3, NULL);
- } else {
- qual = 1000.0 - 1;
- }
-
- /* walk through the supported array */
- for ( zend_hash_internal_pointer_reset(Z_ARRVAL_P(supported));
- SUCCESS == zend_hash_get_current_data(
- Z_ARRVAL_P(supported), (void **) &zsupp);
- zend_hash_move_forward(Z_ARRVAL_P(supported))) {
- if (!strcasecmp(Z_STRVAL_PP(zsupp), Z_STRVAL_PP(zentry))) {
- add_assoc_double(zentries, Z_STRVAL_PP(zsupp), qual);
- break;
- }
- }
- }
-
- zval_dtor(zarray);
- efree(zarray);
-
- zend_hash_internal_pointer_reset(Z_ARRVAL_P(zentries));
-
- if ( (SUCCESS != zend_hash_sort(Z_ARRVAL_P(zentries), zend_qsort,
- http_sort_q, 0 TSRMLS_CC)) ||
- (HASH_KEY_NON_EXISTANT == zend_hash_get_current_key(
- Z_ARRVAL_P(zentries), &result, 0, 1))) {
- result = estrdup(def);
- }
-
- zval_dtor(zentries);
- efree(zentries);
-
- return result;
-}
-/* }}} */
-
-/* {{{ http_range_status http_get_request_ranges(zval *zranges, size_t) */
-PHP_HTTP_API http_range_status _http_get_request_ranges(zval *zranges,
- const size_t length TSRMLS_DC)
-{
- zval *zrange, *zentry, **zentries;
- char *range, c;
- long begin = -1, end = -1, *ptr;
-
- HTTP_GSC(zrange, "HTTP_RANGE", RANGE_NO);
- range = Z_STRVAL_P(zrange);
-
- if (strncmp(range, "bytes=", strlen("bytes="))) {
- php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Range header misses bytes=");
- return RANGE_ERR;
- }
-
- ptr = &begin;
- range += strlen("bytes=");
-
- do {
- switch (c = *(range++))
- {
- case '0':
- *ptr *= 10;
- break;
-
- case '1': case '2': case '3':
- case '4': case '5': case '6':
- case '7': case '8': case '9':
- /*
- * If the value of the pointer is already set (non-negative)
- * then multiply its value by ten and add the current value,
- * else initialise the pointers value with the current value
- * --
- * This let us recognize empty fields when validating the
- * ranges, i.e. a "-10" for begin and "12345" for the end
- * was the following range request: "Range: bytes=0-12345";
- * While a "-1" for begin and "12345" for the end would
- * have been: "Range: bytes=-12345".
- */
- if (*ptr > 0) {
- *ptr *= 10;
- *ptr += c - '0';
- } else {
- *ptr = c - '0';
- }
- break;
-
- case '-':
- ptr = &end;
- break;
-
- case ' ':
- /* IE - ignore for now */
- break;
-
- case 0:
- case ',':
-
- if (length) {
- /* validate ranges */
- switch (begin)
- {
- /* "0-12345" */
- case -10:
- if ((length - end) < 1) {
- return RANGE_ERR;
- }
- begin = 0;
- break;
-
- /* "-12345" */
- case -1:
- if ((length - end) < 1) {
- return RANGE_ERR;
- }
- begin = length - end;
- end = length;
- break;
-
- /* "12345-(xxx)" */
- default:
- switch (end)
- {
- /* "12345-" */
- case -1:
- if ((length - begin) < 1) {
- return RANGE_ERR;
- }
- end = length - 1;
- break;
-
- /* "12345-67890" */
- default:
- if ( ((length - begin) < 1) ||
- ((length - end) < 1) ||
- ((begin - end) >= 0)) {
- return RANGE_ERR;
- }
- break;
- }
- break;
- }
- }
-
- zentry = (zval *) zentries++;
- MAKE_STD_ZVAL(zentry);
- array_init(zentry);
- add_index_long(zentry, 0, begin);
- add_index_long(zentry, 1, end);
- add_next_index_zval(zranges, zentry);
-
- begin = -1;
- end = -1;
- ptr = &begin;
- break;
-
- default:
- return RANGE_ERR;
- break;
- }
- } while (c != 0);
-
- return RANGE_OK;
-}
-/* }}} */
-
-/* {{{ 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)
-{
- zval **zrange;
- long **begin, **end;
- char range_header[255], multi_header[68] = "Content-Type: multipart/byteranges; boundary=", bound[23], preface[1024];
- int i, c;
-
- /* Send HTTP 206 Partial Content */
- http_send_status(206);
-
- /* single range */
- if ((c = zend_hash_num_elements(Z_ARRVAL_P(zranges))) == 1) {
- 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);
-
- /* send content range header */
- snprintf(range_header, 255, "Content-Range: bytes %d-%d/%d", **begin, **end, size);
- http_send_header(range_header);
-
- /* send requested chunk */
- return http_send_chunk(data, **begin, **end + 1, mode);
- }
-
- /* multi range */
-
- snprintf(bound, 23, "--%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)) {
- break;
- }
-
- snprintf(preface, 1024,
- "\r\n%s\r\nContent-Type: %s\r\nContent-Range: bytes %d-%d/%d\r\n\r\n", bound,
- HTTP_G(ctype) ? HTTP_G(ctype) : "application/x-octetstream",
- **begin, **end, size);
- php_body_write(preface, strlen(preface) TSRMLS_CC);
- http_send_chunk(data, **begin, **end + 1, mode);
- }
-
- /* write boundary once more */
- php_body_write("\r\n", 1 TSRMLS_CC);
- php_body_write(bound, strlen(bound) TSRMLS_CC);
-
- return SUCCESS;
-}
-/* }}} */
-
-/* {{{ STATUS http_send(void *, sizezo_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)
-{
- char *new_etag = NULL;
- int is_range_request = http_is_range_request();
-
- if (!data_ptr) {
- return FAILURE;
- }
-
- /* etag handling */
- if (HTTP_G(etag_started)) {
- new_etag = (char *) emalloc(33);
-
- /* never ever use the output to compute the ETag if http_send() is used */
- HTTP_G(etag_started) = 0;
- php_end_ob_buffer(0, 0 TSRMLS_CC);
- if (NULL == http_etag(&new_etag, data_ptr, data_size, data_mode)) {
- efree(new_etag);
- return FAILURE;
- }
-
- /* send 304 Not Modified if etag matches */
- if ((!is_range_request) && http_etag_match("HTTP_IF_NONE_MATCH", new_etag)) {
- efree(new_etag);
- return http_send_status(304);
- }
-
- http_send_etag(new_etag, 32);
- efree(new_etag);
- }