Пример #1
0
php_http_url_t *php_http_url_from_struct(HashTable *ht)
{
	zval **e;
	php_http_buffer_t buf;

	php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
	php_http_buffer_account(&buf, sizeof(php_http_url_t));
	memset(buf.data, 0, buf.used);

	if (SUCCESS == zend_hash_find(ht, "scheme", sizeof("scheme"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->scheme = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "user", sizeof("user"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->user = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "pass", sizeof("pass"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->pass = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "host", sizeof("host"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->host = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "port", sizeof("port"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_LONG, *e);
		url(buf)->port = (unsigned short) Z_LVAL_P(cpy);
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "path", sizeof("path"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->path = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "query", sizeof("query"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->query = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}
	if (SUCCESS == zend_hash_find(ht, "fragment", sizeof("fragment"), (void *) &e)) {
		zval *cpy = php_http_ztyp(IS_STRING, *e);
		url(buf)->fragment = &buf.data[buf.used];
		url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL_P(cpy), Z_STRLEN_P(cpy) + 1));
		zval_ptr_dtor(&cpy);
	}

	return url(buf);
}
php_http_message_parser_state_t php_http_message_parser_parse_stream(php_http_message_parser_t *parser, php_http_buffer_t *buf, php_stream *s, unsigned flags, php_http_message_t **message)
{
	php_http_message_parser_state_t state = PHP_HTTP_MESSAGE_PARSER_STATE_START;

	if (!buf->data) {
		php_http_buffer_resize_ex(buf, 0x1000, 1, 0);
	}
	while (1) {
		size_t justread = 0;
#if DBG_PARSER
		fprintf(stderr, "#SP: %s (f:%u)\n", php_http_message_parser_state_name(state), flags);
#endif
		/* resize if needed */
		if (buf->free < 0x1000) {
			php_http_buffer_resize_ex(buf, 0x1000, 1, 0);
		}
		switch (state) {
			case PHP_HTTP_MESSAGE_PARSER_STATE_START:
			case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER:
			case PHP_HTTP_MESSAGE_PARSER_STATE_HEADER_DONE:
				/* read line */
				php_stream_get_line(s, buf->data + buf->used, buf->free, &justread);
				/* if we fail reading a whole line, try a single char */
				if (!justread) {
					int c = php_stream_getc(s);

					if (c != EOF) {
						char s[1] = {c};
						justread = php_http_buffer_append(buf, s, 1);
					}
				}
				php_http_buffer_account(buf, justread);
				break;

			case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DUMB:
				/* read all */
				justread = php_stream_read(s, buf->data + buf->used, buf->free);
				php_http_buffer_account(buf, justread);
				break;

			case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_LENGTH:
				/* read body_length */
				justread = php_stream_read(s, buf->data + buf->used, MIN(buf->free, parser->body_length));
				php_http_buffer_account(buf, justread);
				break;

			case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_CHUNKED:
				/* duh, this is very naive */
				if (parser->body_length) {
					justread = php_stream_read(s, buf->data + buf->used, MIN(parser->body_length, buf->free));

					php_http_buffer_account(buf, justread);

					parser->body_length -= justread;
				} else {
					php_http_buffer_resize(buf, 24);
					php_stream_get_line(s, buf->data, buf->free, &justread);
					php_http_buffer_account(buf, justread);

					parser->body_length = strtoul(buf->data + buf->used - justread, NULL, 16);
				}
				break;

			case PHP_HTTP_MESSAGE_PARSER_STATE_BODY:
			case PHP_HTTP_MESSAGE_PARSER_STATE_BODY_DONE:
			case PHP_HTTP_MESSAGE_PARSER_STATE_UPDATE_CL:
				/* should not occur */
				abort();
				break;

			case PHP_HTTP_MESSAGE_PARSER_STATE_DONE:
			case PHP_HTTP_MESSAGE_PARSER_STATE_FAILURE:
				return php_http_message_parser_state_is(parser);
		}

		if (justread) {
			state = php_http_message_parser_parse(parser, buf, flags, message);
		} else if (php_stream_eof(s)) {
			return php_http_message_parser_parse(parser, buf, flags | PHP_HTTP_MESSAGE_PARSER_CLEANUP, message);
		} else {
			return state;
		}
	}

	return PHP_HTTP_MESSAGE_PARSER_STATE_DONE;
}
Пример #3
0
static php_http_url_t *php_http_url_from_env(TSRMLS_D)
{
	zval *https, *zhost, *zport;
	long port;
	php_http_buffer_t buf;

	php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
	php_http_buffer_account(&buf, sizeof(php_http_url_t));
	memset(buf.data, 0, buf.used);

	/* scheme */
	url(buf)->scheme = &buf.data[buf.used];
	https = php_http_env_get_server_var(ZEND_STRL("HTTPS"), 1 TSRMLS_CC);
	if (https && !strcasecmp(Z_STRVAL_P(https), "ON")) {
		php_http_buffer_append(&buf, "https", sizeof("https"));
	} else {
		php_http_buffer_append(&buf, "http", sizeof("http"));
	}

	/* host */
	url(buf)->host = &buf.data[buf.used];
	if ((((zhost = php_http_env_get_server_var(ZEND_STRL("HTTP_HOST"), 1 TSRMLS_CC)) ||
			(zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_NAME"), 1 TSRMLS_CC)) ||
			(zhost = php_http_env_get_server_var(ZEND_STRL("SERVER_ADDR"), 1 TSRMLS_CC)))) && Z_STRLEN_P(zhost)) {
		size_t stop_at = strspn(Z_STRVAL_P(zhost), "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-.");

		php_http_buffer_append(&buf, Z_STRVAL_P(zhost), stop_at);
		php_http_buffer_append(&buf, "", 1);
	} else {
		char *host_str = localhostname();

		php_http_buffer_append(&buf, host_str, strlen(host_str) + 1);
		efree(host_str);
	}

	/* port */
	zport = php_http_env_get_server_var(ZEND_STRL("SERVER_PORT"), 1 TSRMLS_CC);
	if (zport && IS_LONG == is_numeric_string(Z_STRVAL_P(zport), Z_STRLEN_P(zport), &port, NULL, 0)) {
		url(buf)->port = port;
	}

	/* path */
	if (SG(request_info).request_uri && SG(request_info).request_uri[0]) {
		const char *q = strchr(SG(request_info).request_uri, '?');

		url(buf)->path = &buf.data[buf.used];

		if (q) {
			php_http_buffer_append(&buf, SG(request_info).request_uri, q - SG(request_info).request_uri);
			php_http_buffer_append(&buf, "", 1);
		} else {
			php_http_buffer_append(&buf, SG(request_info).request_uri, strlen(SG(request_info).request_uri) + 1);
		}
	}

	/* query */
	if (SG(request_info).query_string && SG(request_info).query_string[0]) {
		url(buf)->query = &buf.data[buf.used];
		php_http_buffer_append(&buf, SG(request_info).query_string, strlen(SG(request_info).query_string) + 1);
	}

	return url(buf);
}
Пример #4
0
php_http_url_t *php_http_url_mod(const php_http_url_t *old_url, const php_http_url_t *new_url, unsigned flags TSRMLS_DC)
{
	php_http_url_t *tmp_url = NULL;
	php_http_buffer_t buf;

	php_http_buffer_init_ex(&buf, MAX(PHP_HTTP_BUFFER_DEFAULT_SIZE, sizeof(php_http_url_t)<<2), PHP_HTTP_BUFFER_INIT_PREALLOC);
	php_http_buffer_account(&buf, sizeof(php_http_url_t));
	memset(buf.data, 0, buf.used);

	/* set from env if requested */
	if (flags & PHP_HTTP_URL_FROM_ENV) {
		php_http_url_t *env_url = php_http_url_from_env(TSRMLS_C);

		old_url = tmp_url = php_http_url_mod(env_url, old_url, flags ^ PHP_HTTP_URL_FROM_ENV TSRMLS_CC);
		php_http_url_free(&env_url);
	}

	url_copy(scheme);

	if (!(flags & PHP_HTTP_URL_STRIP_USER)) {
		url_copy(user);
	}

	if (!(flags & PHP_HTTP_URL_STRIP_PASS)) {
		url_copy(pass);
	}
	
	url_copy(host);
	
	if (!(flags & PHP_HTTP_URL_STRIP_PORT)) {
		url(buf)->port = url_isset(new_url, port) ? new_url->port : ((old_url) ? old_url->port : 0);
	}

	if (!(flags & PHP_HTTP_URL_STRIP_PATH)) {
		if ((flags & PHP_HTTP_URL_JOIN_PATH) && url_isset(old_url, path) && url_isset(new_url, path) && *new_url->path != '/') {
			size_t old_path_len = strlen(old_url->path), new_path_len = strlen(new_url->path);
			char *path = ecalloc(1, old_path_len + new_path_len + 1 + 1);
			
			strcat(path, old_url->path);
			if (path[old_path_len - 1] != '/') {
				php_dirname(path, old_path_len);
				strcat(path, "/");
			}
			strcat(path, new_url->path);
			
			url(buf)->path = &buf.data[buf.used];
			if (path[0] != '/') {
				url_append(&buf, php_http_buffer_append(&buf, "/", 1));
			}
			url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1));
			efree(path);
		} else {
			const char *path = NULL;

			if (url_isset(new_url, path)) {
				path = new_url->path;
			} else if (url_isset(old_url, path)) {
				path = old_url->path;
			}

			if (path) {
				url(buf)->path = &buf.data[buf.used];

				url_append(&buf, php_http_buffer_append(&buf, path, strlen(path) + 1));
			}


		}
	}

	if (!(flags & PHP_HTTP_URL_STRIP_QUERY)) {
		if ((flags & PHP_HTTP_URL_JOIN_QUERY) && url_isset(new_url, query) && url_isset(old_url, query)) {
			zval qarr, qstr;
			
			INIT_PZVAL(&qstr);
			INIT_PZVAL(&qarr);
			array_init(&qarr);
			
			ZVAL_STRING(&qstr, old_url->query, 0);
			php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC);
			ZVAL_STRING(&qstr, new_url->query, 0);
			php_http_querystring_update(&qarr, &qstr, NULL TSRMLS_CC);
			
			ZVAL_NULL(&qstr);
			php_http_querystring_update(&qarr, NULL, &qstr TSRMLS_CC);

			url(buf)->query = &buf.data[buf.used];
			url_append(&buf, php_http_buffer_append(&buf, Z_STRVAL(qstr), Z_STRLEN(qstr) + 1));

			zval_dtor(&qstr);
			zval_dtor(&qarr);
		} else {
			url_copy(query);
		}
	}

	if (!(flags & PHP_HTTP_URL_STRIP_FRAGMENT)) {
		url_copy(fragment);
	}
	
	/* done with copy & combine & strip */

	if (flags & PHP_HTTP_URL_FROM_ENV) {
		/* free old_url we tainted above */
		php_http_url_free(&tmp_url);
	}

	/* replace directory references if path is not a single slash */
	if ((flags & PHP_HTTP_URL_SANITIZE_PATH)
	&&	url(buf)->path[0] && url(buf)->path[1]) {
		char *ptr, *end = url(buf)->path + strlen(url(buf)->path) + 1;
			
		for (ptr = strchr(url(buf)->path, '/'); ptr; ptr = strchr(ptr, '/')) {
			switch (ptr[1]) {
				case '/':
					memmove(&ptr[1], &ptr[2], end - &ptr[2]);
					break;
					
				case '.':
					switch (ptr[2]) {
						case '\0':
							ptr[1] = '\0';
							break;

						case '/':
							memmove(&ptr[1], &ptr[3], end - &ptr[3]);
							break;

						case '.':
							if (ptr[3] == '/') {
								char *pos = &ptr[4];
								while (ptr != url(buf)->path) {
									if (*--ptr == '/') {
										break;
									}
								}
								memmove(&ptr[1], pos, end - pos);
								break;
							} else if (!ptr[3]) {
								/* .. at the end */
								ptr[1] = '\0';
							}
							/* no break */

						default:
							/* something else */
							++ptr;
							break;
					}
					break;

				default:
					++ptr;
					break;
			}
		}
	}
	/* unset default ports */
	if (url(buf)->port) {
		if (	((url(buf)->port == 80) && url(buf)->scheme && !strcmp(url(buf)->scheme, "http"))
			||	((url(buf)->port ==443) && url(buf)->scheme && !strcmp(url(buf)->scheme, "https"))
		) {
			url(buf)->port = 0;
		}
	}
	
	return url(buf);
}