|
|
|
@ -171,6 +171,9 @@ typedef struct php_cli_server_client { |
|
|
|
char *current_header_name; |
|
|
|
size_t current_header_name_len; |
|
|
|
unsigned int current_header_name_allocated:1; |
|
|
|
char *current_header_value; |
|
|
|
size_t current_header_value_len; |
|
|
|
enum { HEADER_NONE=0, HEADER_FIELD, HEADER_VALUE } last_header_element; |
|
|
|
size_t post_read_offset; |
|
|
|
php_cli_server_request request; |
|
|
|
unsigned int content_sender_initialized:1; |
|
|
|
@ -1469,7 +1472,7 @@ static void normalize_vpath(char **retval, size_t *retval_len, const char *vpath |
|
|
|
#ifdef PHP_WIN32 |
|
|
|
{ |
|
|
|
char *p = decoded_vpath; |
|
|
|
|
|
|
|
|
|
|
|
do { |
|
|
|
if (*p == '\\') { |
|
|
|
*p = '/'; |
|
|
|
@ -1572,50 +1575,100 @@ static int php_cli_server_client_read_request_on_fragment(php_http_parser *parse |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length) |
|
|
|
static void php_cli_server_client_save_header(php_cli_server_client *client) |
|
|
|
{ |
|
|
|
php_cli_server_client *client = parser->data; |
|
|
|
/* strip off the colon */ |
|
|
|
zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1); |
|
|
|
char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len); |
|
|
|
zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, client->current_header_value); |
|
|
|
zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, client->current_header_value); |
|
|
|
efree(lc_header_name); |
|
|
|
zend_string_release(orig_header_name); |
|
|
|
|
|
|
|
if (client->current_header_name_allocated) { |
|
|
|
pefree(client->current_header_name, 1); |
|
|
|
client->current_header_name_allocated = 0; |
|
|
|
} |
|
|
|
client->current_header_name = (char *)at; |
|
|
|
client->current_header_name_len = length; |
|
|
|
return 0; |
|
|
|
client->current_header_name = NULL; |
|
|
|
client->current_header_name_len = 0; |
|
|
|
client->current_header_value = NULL; |
|
|
|
client->current_header_value_len = 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length) |
|
|
|
static int php_cli_server_client_read_request_on_header_field(php_http_parser *parser, const char *at, size_t length) |
|
|
|
{ |
|
|
|
php_cli_server_client *client = parser->data; |
|
|
|
char *value = pestrndup(at, length, 1); |
|
|
|
if (!value) { |
|
|
|
return 1; |
|
|
|
} |
|
|
|
{ |
|
|
|
/* strip off the colon */ |
|
|
|
zend_string *orig_header_name = zend_string_init(client->current_header_name, client->current_header_name_len, 1); |
|
|
|
char *lc_header_name = zend_str_tolower_dup(client->current_header_name, client->current_header_name_len); |
|
|
|
zend_hash_str_add_ptr(&client->request.headers, lc_header_name, client->current_header_name_len, value); |
|
|
|
zend_hash_add_ptr(&client->request.headers_original_case, orig_header_name, value); |
|
|
|
efree(lc_header_name); |
|
|
|
zend_string_release(orig_header_name); |
|
|
|
switch (client->last_header_element) { |
|
|
|
case HEADER_VALUE: |
|
|
|
php_cli_server_client_save_header(client); |
|
|
|
/* break missing intentionally */ |
|
|
|
case HEADER_NONE: |
|
|
|
client->current_header_name = (char *)at; |
|
|
|
client->current_header_name_len = length; |
|
|
|
break; |
|
|
|
case HEADER_FIELD: |
|
|
|
if (client->current_header_name_allocated) { |
|
|
|
size_t new_length = client->current_header_name_len + length; |
|
|
|
client->current_header_name = perealloc(client->current_header_name, new_length + 1, 1); |
|
|
|
memcpy(client->current_header_name + client->current_header_name_len, at, length); |
|
|
|
client->current_header_name_len = new_length; |
|
|
|
} else { |
|
|
|
size_t new_length = client->current_header_name_len + length; |
|
|
|
char* field = pemalloc(new_length + 1, 1); |
|
|
|
memcpy(field, client->current_header_name, client->current_header_name_len); |
|
|
|
memcpy(field + client->current_header_name_len, at, length); |
|
|
|
client->current_header_name = field; |
|
|
|
client->current_header_name_len = new_length; |
|
|
|
client->current_header_name_allocated = 1; |
|
|
|
} |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
if (client->current_header_name_allocated) { |
|
|
|
pefree(client->current_header_name, 1); |
|
|
|
client->current_header_name_allocated = 0; |
|
|
|
client->last_header_element = HEADER_FIELD; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int php_cli_server_client_read_request_on_header_value(php_http_parser *parser, const char *at, size_t length) |
|
|
|
{ |
|
|
|
php_cli_server_client *client = parser->data; |
|
|
|
switch (client->last_header_element) { |
|
|
|
case HEADER_FIELD: |
|
|
|
client->current_header_value = pestrndup(at, length, 1); |
|
|
|
client->current_header_value_len = length; |
|
|
|
break; |
|
|
|
case HEADER_VALUE: |
|
|
|
{ |
|
|
|
size_t new_length = client->current_header_value_len + length; |
|
|
|
client->current_header_value = perealloc(client->current_header_value, new_length + 1, 1); |
|
|
|
memcpy(client->current_header_value + client->current_header_value_len, at, length); |
|
|
|
client->current_header_value_len = new_length; |
|
|
|
} |
|
|
|
break; |
|
|
|
case HEADER_NONE: |
|
|
|
// can't happen |
|
|
|
assert(0); |
|
|
|
break; |
|
|
|
} |
|
|
|
client->last_header_element = HEADER_VALUE; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static int php_cli_server_client_read_request_on_headers_complete(php_http_parser *parser) |
|
|
|
{ |
|
|
|
php_cli_server_client *client = parser->data; |
|
|
|
if (client->current_header_name_allocated) { |
|
|
|
pefree(client->current_header_name, 1); |
|
|
|
client->current_header_name_allocated = 0; |
|
|
|
switch (client->last_header_element) { |
|
|
|
case HEADER_NONE: |
|
|
|
break; |
|
|
|
case HEADER_FIELD: |
|
|
|
client->current_header_value = pemalloc(1, 1); |
|
|
|
*client->current_header_value = '\0'; |
|
|
|
client->current_header_value_len = 0; |
|
|
|
/* break missing intentionally */ |
|
|
|
case HEADER_VALUE: |
|
|
|
php_cli_server_client_save_header(client); |
|
|
|
break; |
|
|
|
} |
|
|
|
client->current_header_name = NULL; |
|
|
|
client->last_header_element = HEADER_NONE; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
@ -1791,9 +1844,14 @@ static int php_cli_server_client_ctor(php_cli_server_client *client, php_cli_ser |
|
|
|
} |
|
|
|
php_http_parser_init(&client->parser, PHP_HTTP_REQUEST); |
|
|
|
client->request_read = 0; |
|
|
|
|
|
|
|
client->last_header_element = HEADER_NONE; |
|
|
|
client->current_header_name = NULL; |
|
|
|
client->current_header_name_len = 0; |
|
|
|
client->current_header_name_allocated = 0; |
|
|
|
client->current_header_value = NULL; |
|
|
|
client->current_header_value_len = 0; |
|
|
|
|
|
|
|
client->post_read_offset = 0; |
|
|
|
if (FAILURE == php_cli_server_request_ctor(&client->request)) { |
|
|
|
return FAILURE; |
|
|
|
|