static PHP_METHOD(swoole_server_port, set) { zval *zset = NULL; HashTable *vht; zval *v; if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "z", &zset) == FAILURE) { return; } php_swoole_array_separate(zset); vht = Z_ARRVAL_P(zset); swListenPort *port = swoole_get_object(getThis()); swoole_server_port_property *property = swoole_get_property(getThis(), 0); if (port == NULL || property == NULL) { swoole_php_fatal_error(E_ERROR, "Please use the swoole_server->listen method."); return; } property->setting = zset; //backlog if (php_swoole_array_get_value(vht, "backlog", v)) { convert_to_long(v); port->backlog = (int) Z_LVAL_P(v); } if (php_swoole_array_get_value(vht, "socket_buffer_size", v)) { convert_to_long(v); port->socket_buffer_size = (int) Z_LVAL_P(v); if (port->socket_buffer_size <= 0 || port->socket_buffer_size > SW_MAX_INT) { port->socket_buffer_size = SW_MAX_INT; } } if (php_swoole_array_get_value(vht, "buffer_high_watermark", v)) { convert_to_long(v); port->buffer_high_watermark = (int) Z_LVAL_P(v); } if (php_swoole_array_get_value(vht, "buffer_low_watermark", v)) { convert_to_long(v); port->buffer_low_watermark = (int) Z_LVAL_P(v); } //tcp_nodelay if (php_swoole_array_get_value(vht, "open_tcp_nodelay", v)) { convert_to_boolean(v); port->open_tcp_nodelay = Z_BVAL_P(v); } //tcp_defer_accept if (php_swoole_array_get_value(vht, "tcp_defer_accept", v)) { convert_to_long(v); port->tcp_defer_accept = (uint8_t) Z_LVAL_P(v); } //tcp_keepalive if (php_swoole_array_get_value(vht, "open_tcp_keepalive", v)) { convert_to_boolean(v); port->open_tcp_keepalive = Z_BVAL_P(v); } //buffer: eof check if (php_swoole_array_get_value(vht, "open_eof_check", v)) { convert_to_boolean(v); port->open_eof_check = Z_BVAL_P(v); } //buffer: split package with eof if (php_swoole_array_get_value(vht, "open_eof_split", v)) { convert_to_boolean(v); port->protocol.split_by_eof = Z_BVAL_P(v); if (port->protocol.split_by_eof) { port->open_eof_check = 1; } } //package eof if (php_swoole_array_get_value(vht, "package_eof", v)) { convert_to_string(v); port->protocol.package_eof_len = Z_STRLEN_P(v); if (port->protocol.package_eof_len > SW_DATA_EOF_MAXLEN) { swoole_php_fatal_error(E_ERROR, "pacakge_eof max length is %d", SW_DATA_EOF_MAXLEN); RETURN_FALSE; } bzero(port->protocol.package_eof, SW_DATA_EOF_MAXLEN); memcpy(port->protocol.package_eof, Z_STRVAL_P(v), Z_STRLEN_P(v)); } //http_protocol if (php_swoole_array_get_value(vht, "open_http_protocol", v)) { convert_to_boolean(v); port->open_http_protocol = Z_BVAL_P(v); } //websocket protocol if (php_swoole_array_get_value(vht, "open_websocket_protocol", v)) { convert_to_boolean(v); port->open_websocket_protocol = Z_BVAL_P(v); } if (php_swoole_array_get_value(vht, "websocket_subprotocol", v)) { convert_to_string(v); port->websocket_subprotocol = strdup(Z_STRVAL_P(v)); port->websocket_subprotocol_length = Z_STRLEN_P(v); } #ifdef SW_USE_HTTP2 //http2 protocol if (php_swoole_array_get_value(vht, "open_http2_protocol", v)) { convert_to_boolean(v); port->open_http2_protocol = Z_BVAL_P(v); } #endif //buffer: mqtt protocol if (php_swoole_array_get_value(vht, "open_mqtt_protocol", v)) { convert_to_boolean(v); port->open_mqtt_protocol = Z_BVAL_P(v); } //redis protocol if (php_swoole_array_get_value(vht, "open_redis_protocol", v)) { convert_to_boolean(v); port->open_redis_protocol = Z_BVAL_P(v); } //tcp_keepidle if (php_swoole_array_get_value(vht, "tcp_keepidle", v)) { convert_to_long(v); port->tcp_keepidle = (uint16_t) Z_LVAL_P(v); } //tcp_keepinterval if (php_swoole_array_get_value(vht, "tcp_keepinterval", v)) { convert_to_long(v); port->tcp_keepinterval = (uint16_t) Z_LVAL_P(v); } //tcp_keepcount if (sw_zend_hash_find(vht, ZEND_STRS("tcp_keepcount"), (void **) &v) == SUCCESS) { convert_to_long(v); port->tcp_keepcount = (uint16_t) Z_LVAL_P(v); } //open length check if (php_swoole_array_get_value(vht, "open_length_check", v)) { convert_to_boolean(v); port->open_length_check = Z_BVAL_P(v); } //package length size if (php_swoole_array_get_value(vht, "package_length_type", v)) { convert_to_string(v); port->protocol.package_length_type = Z_STRVAL_P(v)[0]; port->protocol.package_length_size = swoole_type_size(port->protocol.package_length_type); if (port->protocol.package_length_size == 0) { swoole_php_fatal_error(E_ERROR, "unknow package_length_type, see pack(). Link: http://php.net/pack"); RETURN_FALSE; } } //c/c++ function if (php_swoole_array_get_value(vht, "package_length_func", v)) { convert_to_string(v); swProtocol_length_function func = swModule_get_global_function(Z_STRVAL_P(v), Z_STRLEN_P(v)); if (func == NULL) { swoole_php_fatal_error(E_ERROR, "extension module function '%s' is undefined.", Z_STRVAL_P(v)); return; } port->protocol.get_package_length = func; port->protocol.package_length_size = 0; port->protocol.package_length_type = '\0'; port->protocol.package_length_offset = SW_BUFFER_SIZE; } //package length offset if (php_swoole_array_get_value(vht, "package_length_offset", v)) { convert_to_long(v); port->protocol.package_length_offset = (int) Z_LVAL_P(v); } //package body start if (php_swoole_array_get_value(vht, "package_body_offset", v) || php_swoole_array_get_value(vht, "package_body_start", v)) { convert_to_long(v); port->protocol.package_body_offset = (int) Z_LVAL_P(v); } /** * package max length */ if (php_swoole_array_get_value(vht, "package_max_length", v)) { convert_to_long(v); port->protocol.package_max_length = (int) Z_LVAL_P(v); } #ifdef SW_USE_OPENSSL if (port->ssl) { if (php_swoole_array_get_value(vht, "ssl_cert_file", v)) { convert_to_string(v); if (access(Z_STRVAL_P(v), R_OK) < 0) { swoole_php_fatal_error(E_ERROR, "ssl cert file[%s] not found.", Z_STRVAL_P(v)); return; } port->ssl_cert_file = strdup(Z_STRVAL_P(v)); port->open_ssl_encrypt = 1; } if (php_swoole_array_get_value(vht, "ssl_key_file", v)) { convert_to_string(v); if (access(Z_STRVAL_P(v), R_OK) < 0) { swoole_php_fatal_error(E_ERROR, "ssl key file[%s] not found.", Z_STRVAL_P(v)); return; } port->ssl_key_file = strdup(Z_STRVAL_P(v)); } if (php_swoole_array_get_value(vht, "ssl_method", v)) { convert_to_long(v); port->ssl_method = (int) Z_LVAL_P(v); } //verify client cert if (php_swoole_array_get_value(vht, "ssl_client_cert_file", v)) { convert_to_string(v); if (access(Z_STRVAL_P(v), R_OK) < 0) { swoole_php_fatal_error(E_ERROR, "ssl cert file[%s] not found.", port->ssl_cert_file); return; } port->ssl_client_cert_file = strdup(Z_STRVAL_P(v)); } if (php_swoole_array_get_value(vht, "ssl_verify_depth", v)) { convert_to_long(v); port->ssl_verify_depth = (int) Z_LVAL_P(v); } if (php_swoole_array_get_value(vht, "ssl_prefer_server_ciphers", v)) { convert_to_boolean(v); port->ssl_config.prefer_server_ciphers = Z_BVAL_P(v); } // if (sw_zend_hash_find(vht, ZEND_STRS("ssl_session_tickets"), (void **) &v) == SUCCESS) // { // convert_to_boolean(v); // port->ssl_config.session_tickets = Z_BVAL_P(v); // } // if (sw_zend_hash_find(vht, ZEND_STRS("ssl_stapling"), (void **) &v) == SUCCESS) // { // convert_to_boolean(v); // port->ssl_config.stapling = Z_BVAL_P(v); // } // if (sw_zend_hash_find(vht, ZEND_STRS("ssl_stapling_verify"), (void **) &v) == SUCCESS) // { // convert_to_boolean(v); // port->ssl_config.stapling_verify = Z_BVAL_P(v); // } if (php_swoole_array_get_value(vht, "ssl_ciphers", v)) { convert_to_string(v); port->ssl_config.ciphers = strdup(Z_STRVAL_P(v)); } if (php_swoole_array_get_value(vht, "ssl_ecdh_curve", v)) { convert_to_string(v); port->ssl_config.ecdh_curve = strdup(Z_STRVAL_P(v)); } // if (sw_zend_hash_find(vht, ZEND_STRS("ssl_session_cache"), (void **) &v) == SUCCESS) // { // convert_to_string(v); // port->ssl_config.session_cache = strdup(Z_STRVAL_P(v)); // } if (swPort_enable_ssl_encrypt(port) < 0) { swoole_php_fatal_error(E_ERROR, "swPort_enable_ssl_encrypt() failed."); RETURN_FALSE; } } #endif zend_update_property(swoole_server_port_class_entry_ptr, getThis(), ZEND_STRL("setting"), zset TSRMLS_CC); }
php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, char *path, char *mode, int options, char **opened_path, php_stream_context *context, int redirect_max, int header_init STREAMS_DC TSRMLS_DC) { php_stream *stream = NULL; php_url *resource = NULL; int use_ssl; int use_proxy = 0; char *scratch = NULL; char *tmp = NULL; char *ua_str = NULL; zval **ua_zval = NULL, **tmpzval = NULL; int scratch_len = 0; int body = 0; char location[HTTP_HEADER_BLOCK_SIZE]; zval *response_header = NULL; int reqok = 0; char *http_header_line = NULL; char tmp_line[128]; size_t chunk_size = 0, file_size = 0; int eol_detect = 0; char *transport_string, *errstr = NULL; int transport_len, have_header = 0, request_fulluri = 0; char *protocol_version = NULL; int protocol_version_len = 3; /* Default: "1.0" */ struct timeval timeout; char *user_headers = NULL; tmp_line[0] = '\0'; if (redirect_max < 1) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Redirection limit reached, aborting"); return NULL; } resource = php_url_parse(path); if (resource == NULL) { return NULL; } if (strncasecmp(resource->scheme, "http", sizeof("http")) && strncasecmp(resource->scheme, "https", sizeof("https"))) { if (!context || php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == FAILURE || Z_TYPE_PP(tmpzval) != IS_STRING || Z_STRLEN_PP(tmpzval) <= 0) { php_url_free(resource); return php_stream_open_wrapper_ex(path, mode, REPORT_ERRORS, NULL, context); } /* Called from a non-http wrapper with http proxying requested (i.e. ftp) */ request_fulluri = 1; use_ssl = 0; use_proxy = 1; transport_len = Z_STRLEN_PP(tmpzval); transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval)); } else { /* Normal http request (possibly with proxy) */ if (strpbrk(mode, "awx+")) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP wrapper does not support writeable connections"); php_url_free(resource); return NULL; } use_ssl = resource->scheme && (strlen(resource->scheme) > 4) && resource->scheme[4] == 's'; /* choose default ports */ if (use_ssl && resource->port == 0) resource->port = 443; else if (resource->port == 0) resource->port = 80; if (context && php_stream_context_get_option(context, wrapper->wops->label, "proxy", &tmpzval) == SUCCESS && Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) { use_proxy = 1; transport_len = Z_STRLEN_PP(tmpzval); transport_string = estrndup(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval)); } else { transport_len = spprintf(&transport_string, 0, "%s://%s:%d", use_ssl ? "ssl" : "tcp", resource->host, resource->port); } } if (context && php_stream_context_get_option(context, wrapper->wops->label, "timeout", &tmpzval) == SUCCESS) { SEPARATE_ZVAL(tmpzval); convert_to_double_ex(tmpzval); timeout.tv_sec = (time_t) Z_DVAL_PP(tmpzval); timeout.tv_usec = (size_t) ((Z_DVAL_PP(tmpzval) - timeout.tv_sec) * 1000000); } else { timeout.tv_sec = FG(default_socket_timeout); timeout.tv_usec = 0; } stream = php_stream_xport_create(transport_string, transport_len, options, STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT, NULL, &timeout, context, &errstr, NULL); if (stream) { php_stream_set_option(stream, PHP_STREAM_OPTION_READ_TIMEOUT, 0, &timeout); } if (errstr) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "%s", errstr); efree(errstr); errstr = NULL; } efree(transport_string); if (stream && use_proxy && use_ssl) { smart_str header = {0}; smart_str_appendl(&header, "CONNECT ", sizeof("CONNECT ")-1); smart_str_appends(&header, resource->host); smart_str_appendc(&header, ':'); smart_str_append_unsigned(&header, resource->port); smart_str_appendl(&header, " HTTP/1.0\r\n\r\n", sizeof(" HTTP/1.0\r\n\r\n")-1); if (php_stream_write(stream, header.c, header.len) != header.len) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; } smart_str_free(&header); if (stream) { char header_line[HTTP_HEADER_BLOCK_SIZE]; /* get response header */ while (php_stream_gets(stream, header_line, HTTP_HEADER_BLOCK_SIZE-1) != NULL) { if (header_line[0] == '\n' || header_line[0] == '\r' || header_line[0] == '\0') { break; } } } /* enable SSL transport layer */ if (stream) { if (php_stream_xport_crypto_setup(stream, STREAM_CRYPTO_METHOD_SSLv23_CLIENT, NULL TSRMLS_CC) < 0 || php_stream_xport_crypto_enable(stream, 1 TSRMLS_CC) < 0) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Cannot connect to HTTPS server through proxy"); php_stream_close(stream); stream = NULL; } } } if (stream == NULL) goto out; /* avoid buffering issues while reading header */ if (options & STREAM_WILL_CAST) chunk_size = php_stream_set_chunk_size(stream, 1); /* avoid problems with auto-detecting when reading the headers -> the headers * are always in canonical \r\n format */ eol_detect = stream->flags & (PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC); stream->flags &= ~(PHP_STREAM_FLAG_DETECT_EOL | PHP_STREAM_FLAG_EOL_MAC); php_stream_context_set(stream, context); php_stream_notify_info(context, PHP_STREAM_NOTIFY_CONNECT, NULL, 0); if (header_init && context && php_stream_context_get_option(context, "http", "max_redirects", &tmpzval) == SUCCESS) { SEPARATE_ZVAL(tmpzval); convert_to_long_ex(tmpzval); redirect_max = Z_LVAL_PP(tmpzval); } if (context && php_stream_context_get_option(context, "http", "method", &tmpzval) == SUCCESS) { if (Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) { scratch_len = strlen(path) + 29 + Z_STRLEN_PP(tmpzval); scratch = emalloc(scratch_len); strlcpy(scratch, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval) + 1); strcat(scratch, " "); } } if (context && php_stream_context_get_option(context, "http", "protocol_version", &tmpzval) == SUCCESS) { SEPARATE_ZVAL(tmpzval); convert_to_double_ex(tmpzval); protocol_version_len = spprintf(&protocol_version, 0, "%.1F", Z_DVAL_PP(tmpzval)); } if (!scratch) { scratch_len = strlen(path) + 29 + protocol_version_len; scratch = emalloc(scratch_len); strcpy(scratch, "GET "); } /* Should we send the entire path in the request line, default to no. */ if (!request_fulluri && context && php_stream_context_get_option(context, "http", "request_fulluri", &tmpzval) == SUCCESS) { zval tmp = **tmpzval; zval_copy_ctor(&tmp); convert_to_boolean(&tmp); request_fulluri = Z_BVAL(tmp) ? 1 : 0; zval_dtor(&tmp); } if (request_fulluri) { /* Ask for everything */ strcat(scratch, path); } else { /* Send the traditional /path/to/file?query_string */ /* file */ if (resource->path && *resource->path) { strlcat(scratch, resource->path, scratch_len); } else { strlcat(scratch, "/", scratch_len); } /* query string */ if (resource->query) { strlcat(scratch, "?", scratch_len); strlcat(scratch, resource->query, scratch_len); } } /* protocol version we are speaking */ if (protocol_version) { strlcat(scratch, " HTTP/", scratch_len); strlcat(scratch, protocol_version, scratch_len); strlcat(scratch, "\r\n", scratch_len); efree(protocol_version); protocol_version = NULL; } else { strlcat(scratch, " HTTP/1.0\r\n", scratch_len); } /* send it */ php_stream_write(stream, scratch, strlen(scratch)); if (context && php_stream_context_get_option(context, "http", "header", &tmpzval) == SUCCESS && Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval)) { /* Remove newlines and spaces from start and end, php_trim will estrndup() */ tmp = php_trim(Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval), NULL, 0, NULL, 3 TSRMLS_CC); if (strlen(tmp) > 0) { if (!header_init) { /* Remove post headers for redirects */ int l = strlen(tmp); char *s, *s2, *tmp_c = estrdup(tmp); php_strtolower(tmp_c, l); if ((s = strstr(tmp_c, "content-length:"))) { if ((s2 = memchr(s, '\n', tmp_c + l - s))) { int b = tmp_c + l - 1 - s2; memmove(tmp, tmp + (s2 + 1 - tmp_c), b); memmove(tmp_c, s2 + 1, b); } else { tmp[s - tmp_c] = *s = '\0'; } l = strlen(tmp_c); } if ((s = strstr(tmp_c, "content-type:"))) { if ((s2 = memchr(s, '\n', tmp_c + l - s))) { memmove(tmp, tmp + (s2 + 1 - tmp_c), tmp_c + l - 1 - s2); } else { tmp[s - tmp_c] = '\0'; } } efree(tmp_c); tmp_c = php_trim(tmp, strlen(tmp), NULL, 0, NULL, 3 TSRMLS_CC); efree(tmp); tmp = tmp_c; } user_headers = estrdup(tmp); /* Make lowercase for easy comparison against 'standard' headers */ php_strtolower(tmp, strlen(tmp)); if (strstr(tmp, "user-agent:")) { have_header |= HTTP_HEADER_USER_AGENT; } if (strstr(tmp, "host:")) { have_header |= HTTP_HEADER_HOST; } if (strstr(tmp, "from:")) { have_header |= HTTP_HEADER_FROM; } if (strstr(tmp, "authorization:")) { have_header |= HTTP_HEADER_AUTH; } if (strstr(tmp, "content-length:")) { have_header |= HTTP_HEADER_CONTENT_LENGTH; } if (strstr(tmp, "content-type:")) { have_header |= HTTP_HEADER_TYPE; } } efree(tmp); } /* auth header if it was specified */ if (((have_header & HTTP_HEADER_AUTH) == 0) && resource->user && resource->pass) { /* decode the strings first */ php_url_decode(resource->user, strlen(resource->user)); php_url_decode(resource->pass, strlen(resource->pass)); /* scratch is large enough, since it was made large enough for the whole URL */ strcpy(scratch, resource->user); strcat(scratch, ":"); strcat(scratch, resource->pass); tmp = php_base64_encode((unsigned char*)scratch, strlen(scratch), NULL); if (snprintf(scratch, scratch_len, "Authorization: Basic %s\r\n", tmp) > 0) { php_stream_write(stream, scratch, strlen(scratch)); php_stream_notify_info(context, PHP_STREAM_NOTIFY_AUTH_REQUIRED, NULL, 0); } efree(tmp); tmp = NULL; } /* if the user has configured who they are, send a From: line */ if (((have_header & HTTP_HEADER_FROM) == 0) && cfg_get_string("from", &tmp) == SUCCESS) { if (snprintf(scratch, scratch_len, "From: %s\r\n", tmp) > 0) php_stream_write(stream, scratch, strlen(scratch)); } /* Send Host: header so name-based virtual hosts work */ if ((have_header & HTTP_HEADER_HOST) == 0) { if ((use_ssl && resource->port != 443 && resource->port != 0) || (!use_ssl && resource->port != 80 && resource->port != 0)) { if (snprintf(scratch, scratch_len, "Host: %s:%i\r\n", resource->host, resource->port) > 0) php_stream_write(stream, scratch, strlen(scratch)); } else { if (snprintf(scratch, scratch_len, "Host: %s\r\n", resource->host) > 0) { php_stream_write(stream, scratch, strlen(scratch)); } } } if (context && php_stream_context_get_option(context, "http", "user_agent", &ua_zval) == SUCCESS && Z_TYPE_PP(ua_zval) == IS_STRING) { ua_str = Z_STRVAL_PP(ua_zval); } else if (FG(user_agent)) { ua_str = FG(user_agent); } if (((have_header & HTTP_HEADER_USER_AGENT) == 0) && ua_str) { #define _UA_HEADER "User-Agent: %s\r\n" char *ua; size_t ua_len; ua_len = sizeof(_UA_HEADER) + strlen(ua_str); /* ensure the header is only sent if user_agent is not blank */ if (ua_len > sizeof(_UA_HEADER)) { ua = emalloc(ua_len + 1); if ((ua_len = slprintf(ua, ua_len, _UA_HEADER, ua_str)) > 0) { ua[ua_len] = 0; php_stream_write(stream, ua, ua_len); } else { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot construct User-agent header"); } if (ua) { efree(ua); } } } if (user_headers) { /* A bit weird, but some servers require that Content-Length be sent prior to Content-Type for POST * see bug #44603 for details. Since Content-Type maybe part of user's headers we need to do this check first. */ if ( header_init && context && !(have_header & HTTP_HEADER_CONTENT_LENGTH) && php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS && Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0 ) { scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval)); php_stream_write(stream, scratch, scratch_len); have_header |= HTTP_HEADER_CONTENT_LENGTH; } php_stream_write(stream, user_headers, strlen(user_headers)); php_stream_write(stream, "\r\n", sizeof("\r\n")-1); efree(user_headers); } /* Request content, such as for POST requests */ if (header_init && context && php_stream_context_get_option(context, "http", "content", &tmpzval) == SUCCESS && Z_TYPE_PP(tmpzval) == IS_STRING && Z_STRLEN_PP(tmpzval) > 0) { if (!(have_header & HTTP_HEADER_CONTENT_LENGTH)) { scratch_len = slprintf(scratch, scratch_len, "Content-Length: %d\r\n", Z_STRLEN_PP(tmpzval)); php_stream_write(stream, scratch, scratch_len); } if (!(have_header & HTTP_HEADER_TYPE)) { php_stream_write(stream, "Content-Type: application/x-www-form-urlencoded\r\n", sizeof("Content-Type: application/x-www-form-urlencoded\r\n") - 1); php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Content-type not specified assuming application/x-www-form-urlencoded"); } php_stream_write(stream, "\r\n", sizeof("\r\n")-1); php_stream_write(stream, Z_STRVAL_PP(tmpzval), Z_STRLEN_PP(tmpzval)); php_stream_write(stream, "\r\n\r\n", sizeof("\r\n\r\n")-1); } else { php_stream_write(stream, "\r\n", sizeof("\r\n")-1); } location[0] = '\0'; if (header_init) { zval *tmp; MAKE_STD_ZVAL(tmp); array_init(tmp); ZEND_SET_SYMBOL(EG(active_symbol_table), "http_response_header", tmp); } { zval **rh; zend_hash_find(EG(active_symbol_table), "http_response_header", sizeof("http_response_header"), (void **) &rh); response_header = *rh; } if (!php_stream_eof(stream)) { size_t tmp_line_len; /* get response header */ if (php_stream_get_line(stream, tmp_line, sizeof(tmp_line) - 1, &tmp_line_len) != NULL) { zval *http_response; int response_code; if (tmp_line_len > 9) { response_code = atoi(tmp_line + 9); } else { response_code = 0; } /* when we request only the header, don't fail even on error codes */ if (options & STREAM_ONLY_GET_HEADERS) { reqok = 1; } switch(response_code) { case 200: case 206: /* partial content */ case 302: case 303: case 301: reqok = 1; break; case 403: php_stream_notify_error(context, PHP_STREAM_NOTIFY_AUTH_RESULT, tmp_line, response_code); break; default: /* safety net in the event tmp_line == NULL */ if (!tmp_line_len) { tmp_line[0] = '\0'; } php_stream_notify_error(context, PHP_STREAM_NOTIFY_FAILURE, tmp_line, response_code); } if (tmp_line[tmp_line_len - 1] == '\n') { --tmp_line_len; if (tmp_line[tmp_line_len - 1] == '\r') { --tmp_line_len; } } MAKE_STD_ZVAL(http_response); ZVAL_STRINGL(http_response, tmp_line, tmp_line_len, 1); zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_response, sizeof(zval *), NULL); } } else { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "HTTP request failed, unexpected end of socket!"); goto out; } /* read past HTTP headers */ http_header_line = emalloc(HTTP_HEADER_BLOCK_SIZE); while (!body && !php_stream_eof(stream)) { size_t http_header_line_length; if (php_stream_get_line(stream, http_header_line, HTTP_HEADER_BLOCK_SIZE, &http_header_line_length) && *http_header_line != '\n' && *http_header_line != '\r') { char *e = http_header_line + http_header_line_length - 1; while (*e == '\n' || *e == '\r') { e--; } http_header_line_length = e - http_header_line + 1; http_header_line[http_header_line_length] = '\0'; if (!strncasecmp(http_header_line, "Location: ", 10)) { strlcpy(location, http_header_line + 10, sizeof(location)); } else if (!strncasecmp(http_header_line, "Content-Type: ", 14)) { php_stream_notify_info(context, PHP_STREAM_NOTIFY_MIME_TYPE_IS, http_header_line + 14, 0); } else if (!strncasecmp(http_header_line, "Content-Length: ", 16)) { file_size = atoi(http_header_line + 16); php_stream_notify_file_size(context, file_size, http_header_line, 0); } if (http_header_line[0] == '\0') { body = 1; } else { zval *http_header; MAKE_STD_ZVAL(http_header); ZVAL_STRINGL(http_header, http_header_line, http_header_line_length, 1); zend_hash_next_index_insert(Z_ARRVAL_P(response_header), &http_header, sizeof(zval *), NULL); } } else { break; } } if (!reqok || location[0] != '\0') { if (options & STREAM_ONLY_GET_HEADERS && redirect_max <= 1) { goto out; } if (location[0] != '\0') php_stream_notify_info(context, PHP_STREAM_NOTIFY_REDIRECTED, location, 0); php_stream_close(stream); stream = NULL; if (location[0] != '\0') { char new_path[HTTP_HEADER_BLOCK_SIZE]; char loc_path[HTTP_HEADER_BLOCK_SIZE]; *new_path='\0'; if (strlen(location)<8 || (strncasecmp(location, "http://", sizeof("http://")-1) && strncasecmp(location, "https://", sizeof("https://")-1) && strncasecmp(location, "ftp://", sizeof("ftp://")-1) && strncasecmp(location, "ftps://", sizeof("ftps://")-1))) { if (*location != '/') { if (*(location+1) != '\0' && resource->path) { char *s = strrchr(resource->path, '/'); if (!s) { s = resource->path; if (!s[0]) { efree(s); s = resource->path = estrdup("/"); } else { *s = '/'; } } s[1] = '\0'; if (resource->path && *(resource->path) == '/' && *(resource->path + 1) == '\0') { snprintf(loc_path, sizeof(loc_path) - 1, "%s%s", resource->path, location); } else { snprintf(loc_path, sizeof(loc_path) - 1, "%s/%s", resource->path, location); } } else { snprintf(loc_path, sizeof(loc_path) - 1, "/%s", location); } } else { strlcpy(loc_path, location, sizeof(loc_path)); } if ((use_ssl && resource->port != 443) || (!use_ssl && resource->port != 80)) { snprintf(new_path, sizeof(new_path) - 1, "%s://%s:%d%s", resource->scheme, resource->host, resource->port, loc_path); } else { snprintf(new_path, sizeof(new_path) - 1, "%s://%s%s", resource->scheme, resource->host, loc_path); } } else { strlcpy(new_path, location, sizeof(new_path)); } php_url_free(resource); /* check for invalid redirection URLs */ if ((resource = php_url_parse(new_path)) == NULL) { php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path); goto out; } #define CHECK_FOR_CNTRL_CHARS(val) { \ if (val) { \ unsigned char *s, *e; \ int l; \ l = php_url_decode(val, strlen(val)); \ s = val; e = s + l; \ while (s < e) { \ if (iscntrl(*s)) { \ php_stream_wrapper_log_error(wrapper, options TSRMLS_CC, "Invalid redirect URL! %s", new_path); \ goto out; \ } \ s++; \ } \ } \ } \ /* check for control characters in login, password & path */ if (strncasecmp(new_path, "http://", sizeof("http://") - 1) || strncasecmp(new_path, "https://", sizeof("https://") - 1)) { CHECK_FOR_CNTRL_CHARS(resource->user) CHECK_FOR_CNTRL_CHARS(resource->pass) CHECK_FOR_CNTRL_CHARS(resource->path) } stream = php_stream_url_wrap_http_ex(wrapper, new_path, mode, options, opened_path, context, --redirect_max, 0 STREAMS_CC TSRMLS_CC); } else {
PHP_METHOD(JsonPath, find) { char *path; #if PHP_MAJOR_VERSION < 7 int path_len; #else size_t path_len; #endif zval *z_array; HashTable *arr; if (zend_parse_parameters(ZEND_NUM_ARGS()TSRMLS_CC, "as", &z_array, &path, &path_len) == FAILURE) { return; } array_init(return_value); lex_token lex_tok[PARSE_BUF_LEN]; char lex_tok_values[PARSE_BUF_LEN][PARSE_BUF_LEN]; int lex_tok_count = 0; char *p = path; char buffer[PARSE_BUF_LEN]; lex_token *ptr = lex_tok; lex_error err; while ((*ptr = scan(&p, buffer, sizeof(buffer), &err)) != LEX_NOT_FOUND) { switch (*ptr) { case LEX_NODE: case LEX_LITERAL: strcpy(lex_tok_values[lex_tok_count], buffer); break; case LEX_ERR: snprintf(err.msg, sizeof(err.msg), "%s at position %d", err.msg, (err.pos - path)); zend_throw_exception(spl_ce_RuntimeException, err.msg, 0 TSRMLS_CC); return; default: lex_tok_values[lex_tok_count][0] = '\0'; break; } ptr++; lex_tok_count++; } operator tok[100]; int tok_count = 0; int *int_ptr = &tok_count; parse_error p_err; if (!build_parse_tree(lex_tok, lex_tok_values, lex_tok_count, tok, int_ptr, &p_err)) { zend_throw_exception(spl_ce_RuntimeException, p_err.msg, 0 TSRMLS_CC); } operator * tok_ptr_start; operator * tok_ptr_end; tok_ptr_start = &tok[0]; tok_ptr_end = &tok[tok_count - 1]; iterate(z_array, tok_ptr_start, tok_ptr_end, return_value TSRMLS_CC); operator * fr = tok_ptr_start; while (fr <= tok_ptr_end) { if (fr->filter_type == FLTR_EXPR) { efree((void *)fr->expressions); } fr++; } if (zend_hash_num_elements(HASH_OF(return_value)) == 0) { convert_to_boolean(return_value); RETURN_FALSE; } return; }