- char *proto_ptr, *host, *path, *PTR, *URI = ecalloc(1, HTTP_URI_MAXLEN + 1);
- zval *zhost;
-
- if (!url || !strlen(url)) {
- if (!SG(request_info).request_uri) {
- return NULL;
- }
- url = SG(request_info).request_uri;
- }
- /* Mess around with already absolute URIs */
- else if (proto_ptr = strstr(url, "://")) {
- if (!proto || !strncmp(url, proto, strlen(proto))) {
- strncpy(URI, url, HTTP_URI_MAXLEN);
- return URI;
- } else {
- snprintf(URI, HTTP_URI_MAXLEN, "%s%s", proto, proto_ptr + 3);
- return URI;
- }
- }
-
- /* 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 */
- if ((PTR = strchr(URI, '\r')) || (PTR = strchr(URI, '\n'))) {
- PTR = 0;
- }
-
- return 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 - i;
- }
-
- /* 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;
- 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_NO;
- }
-
- 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;
- }
- }
- {
- zval *zentry;
- 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_NO;
- 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)
-{
- 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) {
- 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);
-
- /* 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 */
- else {
- int i;
- char bound[23] = {0}, preface[1024] = {0},
- multi_header[68] = "Content-Type: multipart/byteranges; boundary=";
-
- 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)) {
- break;
- }
-
- snprintf(preface, 1023,
- HTTP_CRLF "%s"
- HTTP_CRLF "Content-Type: %s"
- HTTP_CRLF "Content-Range: bytes %ld-%ld/%ld"
- HTTP_CRLF
- HTTP_CRLF,
-
- 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(HTTP_CRLF, 2 TSRMLS_CC);
- php_body_write(bound, strlen(bound) TSRMLS_CC);