-
-/* {{{ STATUS http_send(void *, size_t, http_send_mode) */
-PHP_HTTP_API STATUS _http_send(const void *data_ptr, size_t data_size, http_send_mode data_mode TSRMLS_DC)
-{
- HashTable ranges;
- http_range_status range_status;
- int cache_etag = 0;
-
- if (!data_ptr) {
- return FAILURE;
- }
- if (!data_size) {
- return SUCCESS;
- }
-
- /* stop on-the-fly etag generation */
- if (cache_etag = HTTP_G(etag_started)) {
- /* interrupt */
- HTTP_G(etag_started) = 0;
- /* never ever use the output to compute the ETag if http_send() is used */
- php_end_ob_buffers(0 TSRMLS_CC);
- }
-
- zend_hash_init(&ranges, 0, NULL, ZVAL_PTR_DTOR, 0);
- range_status = http_get_request_ranges(&ranges, data_size);
-
- if (range_status == RANGE_ERR) {
- zend_hash_destroy(&ranges);
- http_send_status(416);
- return FAILURE;
- }
-
- /* Range Request - only send ranges if entity hasn't changed */
- if ( range_status == RANGE_OK &&
- http_etag_match_ex("HTTP_IF_MATCH", HTTP_G(etag), 0) &&
- http_modified_match_ex("HTTP_IF_UNMODIFIED_SINCE", HTTP_G(lmod), 0)) {
- STATUS result = http_send_ranges(&ranges, data_ptr, data_size, data_mode);
- zend_hash_destroy(&ranges);
- return result;
- }
-
- zend_hash_destroy(&ranges);
-
- /* send 304 Not Modified if etag matches */
- if (cache_etag) {
- char *etag = NULL;
- int etag_match = 0;
-
- if (!(etag = http_etag(data_ptr, data_size, data_mode))) {
- return FAILURE;
- }
-
- http_send_etag(etag, 32);
- etag_match = http_etag_match("HTTP_IF_NONE_MATCH", etag);
- efree(etag);
-
- if (etag_match) {
- return http_send_status(304);
- }
- }
-
- /* send 304 Not Modified if last modified matches */
- if (http_modified_match("HTTP_IF_MODIFIED_SINCE", HTTP_G(lmod))) {
- return http_send_status(304);
- }
-
- /* send full entity */
- return http_send_chunk(data_ptr, 0, data_size, data_mode);
-}
-/* }}} */
-
-/* {{{ STATUS http_send_stream(php_stream *) */
-PHP_HTTP_API STATUS _http_send_stream_ex(php_stream *file, zend_bool close_stream TSRMLS_DC)
-{
- STATUS status;
-
- if ((!file) || php_stream_stat(file, &HTTP_G(ssb))) {
- return FAILURE;
- }
-
- status = http_send(file, HTTP_G(ssb).sb.st_size, SEND_RSRC);
-
- if (close_stream) {
- php_stream_close(file);
- }
-
- return status;
-}
-/* }}} */
-
-/* {{{ STATUS http_chunked_decode(char *, size_t, char **, size_t *) */
-PHP_HTTP_API STATUS _http_chunked_decode(const char *encoded, size_t encoded_len,
- char **decoded, size_t *decoded_len TSRMLS_DC)
-{
- const char *e_ptr;
- char *d_ptr;
-
- *decoded_len = 0;
- *decoded = ecalloc(1, encoded_len);
- d_ptr = *decoded;
- e_ptr = encoded;
-
- while (((e_ptr - encoded) - encoded_len) > 0) {
- char hex_len[9] = {0};
- size_t chunk_len = 0;
- int i = 0;
-
- /* read in chunk size */
- while (isxdigit(*e_ptr)) {
- if (i == 9) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "Chunk size is too long: 0x%s...", hex_len);
- efree(*decoded);
- return FAILURE;
- }
- hex_len[i++] = *e_ptr++;
- }
-
- /* reached the end */
- if (!strcmp(hex_len, "0")) {
- break;
- }
-
- /* new line */
- if (strncmp(e_ptr, HTTP_CRLF, 2)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "Invalid character (expected 0x0D 0x0A; got: %x %x)",
- *e_ptr, *(e_ptr + 1));
- efree(*decoded);
- return FAILURE;
- }
-
- /* hex to long */
- {
- char *error = NULL;
- chunk_len = strtol(hex_len, &error, 16);
- if (error == hex_len) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING,
- "Invalid chunk size string: '%s'", hex_len);
- efree(*decoded);
- return FAILURE;
- }
- }
-
- memcpy(d_ptr, e_ptr += 2, chunk_len);
- d_ptr += chunk_len;
- e_ptr += chunk_len + 2;
- *decoded_len += chunk_len;
- }
-
- return SUCCESS;
-}
-/* }}} */
-
-/* {{{ STATUS http_split_response(zval *, zval *, zval *) */
-PHP_HTTP_API STATUS _http_split_response(zval *response, zval *headers, zval *body TSRMLS_DC)
-{
- char *b = NULL;
- size_t l = 0;
- STATUS status = http_split_response_ex(Z_STRVAL_P(response), Z_STRLEN_P(response), Z_ARRVAL_P(headers), &b, &l);
- ZVAL_STRINGL(body, b, l, 0);
- return status;
-}
-/* }}} */
-
-/* {{{ STATUS http_split_response(char *, size_t, HashTable *, char **, size_t *) */
-PHP_HTTP_API STATUS _http_split_response_ex(char *response, size_t response_len,
- HashTable *headers, char **body, size_t *body_len TSRMLS_DC)
-{
- char *header = response, *real_body = NULL;
-
- while (0 < (response_len - (response - header + 4))) {
- if ( (*response++ == '\r') &&
- (*response++ == '\n') &&
- (*response++ == '\r') &&
- (*response++ == '\n')) {
- real_body = response;
- break;
- }
- }
-
- if (real_body && (*body_len = (response_len - (real_body - header)))) {
- *body = ecalloc(1, *body_len + 1);
- memcpy(*body, real_body, *body_len);
- }
-
- return http_parse_headers_ex(header, real_body ? response_len - *body_len : response_len, headers, 1);
-}
-/* }}} */
-
-/* {{{ STATUS http_parse_headers(char *, size_t, HashTable *, zend_bool) */
-PHP_HTTP_API STATUS _http_parse_headers_ex(char *header, size_t header_len,
- HashTable *headers, zend_bool prettify TSRMLS_DC)
-{
- char *colon = NULL, *line = NULL, *begin = header;
- zval array;
-
- Z_ARRVAL(array) = headers;
-
- if (header_len < 2) {
- return FAILURE;
- }
-
- /* status code */
- if (!strncmp(header, "HTTP/1.", 7)) {
- char *end = strstr(header, HTTP_CRLF);
- add_assoc_stringl(&array, "Status",
- header + sizeof("HTTP/1.x ") - 1,
- end - (header + sizeof("HTTP/1.x ") - 1), 1);
- header = end + 2;
- }
-
- line = header;
-
- while (header_len >= (line - begin)) {
- int value_len = 0;
-
- switch (*line++)
- {
- case 0:
- --value_len; /* we don't have CR so value length is one char less */
- case '\n':
- if (colon && ((!(*line - 1)) || ((*line != ' ') && (*line != '\t')))) {
-
- /* skip empty key */
- if (header != colon) {
- char *key = estrndup(header, colon - header);
-
- if (prettify) {
- key = pretty_key(key, colon - header, 1, 1);
- }
-
- value_len += line - colon - 1;
-
- /* skip leading ws */
- while (isspace(*(++colon))) --value_len;
- /* skip trailing ws */
- while (isspace(colon[value_len - 1])) --value_len;
-
- if (value_len < 1) {
- /* hm, empty header? */
- add_assoc_stringl(&array, key, "", 0, 1);
- } else {
- add_assoc_stringl(&array, key, colon, value_len, 1);
- }
- efree(key);
- }
-
- colon = NULL;
- value_len = 0;
- header += line - header;
- }
- break;
-
- case ':':
- if (!colon) {
- colon = line - 1;
- }
- break;
- }
- }
- return SUCCESS;
-}
-/* }}} */
-
-/* {{{ void http_get_request_headers_ex(HashTable *, zend_bool) */
-PHP_HTTP_API void _http_get_request_headers_ex(HashTable *headers, zend_bool prettify TSRMLS_DC)
-{
- char *key = NULL;
- long idx = 0;
- zval array;
-
- Z_ARRVAL(array) = headers;
-
- FOREACH_HASH_KEY(HTTP_SERVER_VARS, key, idx) {
- if (key && !strncmp(key, "HTTP_", 5)) {
- zval **header;
-
- key += 5;
- if (prettify) {
- key = pretty_key(key, strlen(key), 1, 1);
- }
-
- zend_hash_get_current_data(HTTP_SERVER_VARS, (void **) &header);
- add_assoc_stringl(&array, key, Z_STRVAL_PP(header), Z_STRLEN_PP(header), 1);
- key = NULL;
- }
- }
-}
-/* }}} */
-
-/* {{{ STATUS http_urlencode_hash_ex(HashTable *, zend_bool, char *, size_t, char **, size_t *) */
-PHP_HTTP_API STATUS _http_urlencode_hash_ex(HashTable *hash, zend_bool override_argsep,
- char *pre_encoded_data, size_t pre_encoded_len,
- char **encoded_data, size_t *encoded_len TSRMLS_DC)
-{
- char *arg_sep;
- phpstr *qstr = phpstr_new();
-
- if (override_argsep || !strlen(arg_sep = INI_STR("arg_separator.output"))) {
- arg_sep = HTTP_URL_ARGSEP_DEFAULT;
- }
-
- if (pre_encoded_len && pre_encoded_data) {
- phpstr_append(qstr, pre_encoded_data, pre_encoded_len);
- }
-
- if (SUCCESS != http_urlencode_hash_implementation(hash, qstr, arg_sep)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't encode query data");
- phpstr_free(qstr);
- return FAILURE;
- }
-
- phpstr_data(qstr, encoded_data, encoded_len);
- phpstr_free(qstr);
-
- return SUCCESS;
-}
-/* }}} */
-
-/* {{{ STATUS http_auth_header(char *, char*) */
-PHP_HTTP_API STATUS _http_auth_header(const char *type, const char *realm TSRMLS_DC)
-{
- char realm_header[1024] = {0};
- snprintf(realm_header, 1023, "WWW-Authenticate: %s realm=\"%s\"", type, realm);
- return http_send_status_header(401, realm_header);
-}
-/* }}} */
-
-/* {{{ STATUS http_auth_credentials(char **, char **) */
-PHP_HTTP_API STATUS _http_auth_credentials(char **user, char **pass TSRMLS_DC)
-{
- if (strncmp(sapi_module.name, "isapi", 5)) {
- zval *zuser, *zpass;
-
- HTTP_GSC(zuser, "PHP_AUTH_USER", FAILURE);
- HTTP_GSC(zpass, "PHP_AUTH_PW", FAILURE);
-
- *user = estrndup(Z_STRVAL_P(zuser), Z_STRLEN_P(zuser));
- *pass = estrndup(Z_STRVAL_P(zpass), Z_STRLEN_P(zpass));
-
- return SUCCESS;
- } else {
- zval *zauth = NULL;
- HTTP_GSC(zauth, "HTTP_AUTHORIZATION", FAILURE);
- {
- char *decoded, *colon;
- int decoded_len;
- decoded = php_base64_decode(Z_STRVAL_P(zauth), Z_STRLEN_P(zauth),
- &decoded_len);
-
- if (colon = strchr(decoded + 6, ':')) {
- *user = estrndup(decoded + 6, colon - decoded - 6);
- *pass = estrndup(colon + 1, decoded + decoded_len - colon - 6 - 1);
-
- return SUCCESS;
- } else {
- return FAILURE;
- }
- }
- }
-}
-/* }}} */
-
-/* {{{ http_urlencode_hash_implementation
- Original Author: Sara Golemon <pollita@php.net> */
-PHP_HTTP_API STATUS _http_urlencode_hash_implementation_ex(
- HashTable *ht, phpstr *formstr, char *arg_sep,
- const char *num_prefix, int num_prefix_len,
- const char *key_prefix, int key_prefix_len,
- const char *key_suffix, int key_suffix_len,
- zval *type TSRMLS_DC)
-{
- char *key = NULL, *ekey, *newprefix, *p;
- int arg_sep_len, key_len, ekey_len, key_type, newprefix_len;
- ulong idx;
- zval **zdata = NULL, *copyzval;
-
- if (!ht || !formstr) {
- return FAILURE;
- }
-
- if (ht->nApplyCount > 0) {
- /* Prevent recursion */
- return SUCCESS;
- }
-
- if (!arg_sep || !strlen(arg_sep)) {
- arg_sep = HTTP_URL_ARGSEP_DEFAULT;
- }
- arg_sep_len = strlen(arg_sep);
-
- for (zend_hash_internal_pointer_reset(ht);
- (key_type = zend_hash_get_current_key_ex(ht, &key, &key_len, &idx, 0, NULL)) != HASH_KEY_NON_EXISTANT;
- zend_hash_move_forward(ht)
- ) {
- if (key_type == HASH_KEY_IS_STRING && key_len && key[key_len-1] == '\0') {
- /* We don't want that trailing NULL */
- key_len -= 1;
- }
-
-#ifdef ZEND_ENGINE_2
- /* handling for private & protected object properties */
- if (key && *key == '\0' && type != NULL) {
- char *tmp;
-
- zend_object *zobj = zend_objects_get_address(type TSRMLS_CC);
- if (zend_check_property_access(zobj, key TSRMLS_CC) != SUCCESS) {
- /* private or protected property access outside of the class */
- continue;
- }
- zend_unmangle_property_name(key, &tmp, &key);
- key_len = strlen(key);
- }
-#endif
-
- if (zend_hash_get_current_data_ex(ht, (void **)&zdata, NULL) == FAILURE || !zdata || !(*zdata)) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error traversing form data array.");
- return FAILURE;
- }
- if (Z_TYPE_PP(zdata) == IS_ARRAY || Z_TYPE_PP(zdata) == IS_OBJECT) {
- if (key_type == HASH_KEY_IS_STRING) {
- ekey = php_url_encode(key, key_len, &ekey_len);
- newprefix_len = key_suffix_len + ekey_len + key_prefix_len + 1;
- newprefix = emalloc(newprefix_len + 1);
- p = newprefix;
-
- if (key_prefix) {
- memcpy(p, key_prefix, key_prefix_len);
- p += key_prefix_len;
- }
-
- memcpy(p, ekey, ekey_len);
- p += ekey_len;
- efree(ekey);
-
- if (key_suffix) {
- memcpy(p, key_suffix, key_suffix_len);
- p += key_suffix_len;
- }
-
- *(p++) = '[';
- *p = '\0';
- } else {
- /* Is an integer key */
- ekey_len = spprintf(&ekey, 12, "%ld", idx);
- newprefix_len = key_prefix_len + num_prefix_len + ekey_len + key_suffix_len + 1;
- newprefix = emalloc(newprefix_len + 1);
- p = newprefix;
-
- if (key_prefix) {
- memcpy(p, key_prefix, key_prefix_len);
- p += key_prefix_len;
- }
-
- memcpy(p, num_prefix, num_prefix_len);
- p += num_prefix_len;
-
- memcpy(p, ekey, ekey_len);
- p += ekey_len;
- efree(ekey);
-
- if (key_suffix) {
- memcpy(p, key_suffix, key_suffix_len);
- p += key_suffix_len;
- }
- *(p++) = '[';
- *p = '\0';
- }
- ht->nApplyCount++;
- http_urlencode_hash_implementation_ex(HASH_OF(*zdata), formstr, arg_sep,
- NULL, 0, newprefix, newprefix_len, "]", 1, (Z_TYPE_PP(zdata) == IS_OBJECT ? *zdata : NULL));
- ht->nApplyCount--;
- efree(newprefix);
- } else if (Z_TYPE_PP(zdata) == IS_NULL || Z_TYPE_PP(zdata) == IS_RESOURCE) {
- /* Skip these types */
- continue;
- } else {
- if (formstr->used) {
- phpstr_append(formstr, arg_sep, arg_sep_len);
- }
- /* Simple key=value */
- phpstr_append(formstr, key_prefix, key_prefix_len);
- if (key_type == HASH_KEY_IS_STRING) {
- ekey = php_url_encode(key, key_len, &ekey_len);
- phpstr_append(formstr, ekey, ekey_len);
- efree(ekey);
- } else {
- /* Numeric key */
- if (num_prefix) {
- phpstr_append(formstr, num_prefix, num_prefix_len);
- }
- ekey_len = spprintf(&ekey, 12, "%ld", idx);
- phpstr_append(formstr, ekey, ekey_len);
- efree(ekey);
- }
- phpstr_append(formstr, key_suffix, key_suffix_len);
- phpstr_appends(formstr, "=");
- switch (Z_TYPE_PP(zdata)) {
- case IS_STRING:
- ekey = php_url_encode(Z_STRVAL_PP(zdata), Z_STRLEN_PP(zdata), &ekey_len);
- break;
- case IS_LONG:
- case IS_BOOL:
- ekey_len = spprintf(&ekey, 12, "%ld", Z_LVAL_PP(zdata));
- break;
- case IS_DOUBLE:
- ekey_len = spprintf(&ekey, 48, "%.*G", (int) EG(precision), Z_DVAL_PP(zdata));
- break;
- default:
- /* fall back on convert to string */
- MAKE_STD_ZVAL(copyzval);
- *copyzval = **zdata;
- zval_copy_ctor(copyzval);
- convert_to_string_ex(©zval);
- ekey = php_url_encode(Z_STRVAL_P(copyzval), Z_STRLEN_P(copyzval), &ekey_len);
- zval_ptr_dtor(©zval);
- }
- phpstr_append(formstr, ekey, ekey_len);
- efree(ekey);
- }
- }
-
- return SUCCESS;
-}
-/* }}} */
-
-/* }}} public API */
-