Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[6.0] Optimize http response #5489

Merged
merged 1 commit into from
Sep 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 5 additions & 4 deletions ext-src/php_swoole_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -759,11 +759,12 @@ static sw_inline void sw_zend_update_property_null_ex(zend_class_entry *scope, z
zend_update_property_ex(scope, SW_Z8_OBJ_P(object), s, &tmp);
}

static sw_inline zval *sw_zend_read_property_ex(zend_class_entry *ce, zval *obj, zend_string *s, int silent) {
zval rv, *property = zend_read_property_ex(ce, SW_Z8_OBJ_P(obj), s, silent, &rv);
static sw_inline zval *sw_zend_read_property_ex(zend_class_entry *ce, zval *zobject, zend_string *name, int silent) {
zval *zv = zend_hash_find(&ce->properties_info, name);
zend_property_info *property_info = (zend_property_info *) Z_PTR_P(zv);
zval *property = OBJ_PROP(SW_Z8_OBJ_P(zobject), property_info->offset);
if (UNEXPECTED(property == &EG(uninitialized_zval))) {
sw_zend_update_property_null_ex(ce, obj, s);
return zend_read_property_ex(ce, SW_Z8_OBJ_P(obj), s, silent, &rv);
ZVAL_NULL(property);
}
return property;
}
Expand Down
84 changes: 38 additions & 46 deletions ext-src/swoole_http_response.cc
Original file line number Diff line number Diff line change
Expand Up @@ -257,80 +257,77 @@ static int parse_header_name(const char *key, size_t keylen) {
static void http_set_date_header(String *response) {
static struct {
time_t time;
size_t len;
char buf[64];
zend_string *date = nullptr;
} cache{};

time_t now = time(nullptr);
if (now != cache.time) {
char *date_str = php_swoole_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), now, 0);
cache.len = strlen(date_str);
memcpy(cache.buf, date_str, cache.len);
efree(date_str);
if (cache.date) {
zend_string_release(cache.date);
}

cache.time = now;
cache.date = php_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), now, 0);
}
response->append(ZEND_STRL("Date: "));
response->append(cache.buf, cache.len);
response->append(ZSTR_VAL(cache.date), ZSTR_LEN(cache.date));
response->append(ZEND_STRL("\r\n"));
}

static void add_custom_header(String *response, const char *key, size_t l_key, zval *value) {
static void add_custom_header(String *http_buffer, const char *key, size_t l_key, zval *value) {
if (ZVAL_IS_NULL(value)) {
return;
}

zend::String str_value(value);
str_value.rtrim();
if (swoole_http_has_crlf(str_value.val(), str_value.len())) {
return;
}
response->append(key, l_key);
response->append(SW_STRL(": "));
response->append(str_value.val(), str_value.len());
response->append(SW_STRL("\r\n"));

http_buffer->append(key, l_key);
http_buffer->append(SW_STRL(": "));
http_buffer->append(str_value.val(), str_value.len());
http_buffer->append(SW_STRL("\r\n"));
}

void HttpContext::build_header(String *http_buffer, const char *body, size_t length) {
assert(send_header_ == 0);

/**
* http status line
*/
if (!response.reason) {
const char *status = HttpServer::get_status_message(response.status);
http_buffer->append(ZEND_STRL("HTTP/1.1 "));
http_buffer->append((char *) status, strlen(status));
http_buffer->append(ZEND_STRL("\r\n"));
} else {
http_buffer->append(ZEND_STRL("HTTP/1.1 "));
// http status line
http_buffer->append(ZEND_STRL("HTTP/1.1 "));
if (response.reason) {
http_buffer->append(response.status);
http_buffer->append(ZEND_STRL(" "));
http_buffer->append(response.reason, strlen(response.reason));
http_buffer->append(ZEND_STRL("\r\n"));
} else {
const char *status = HttpServer::get_status_message(response.status);
http_buffer->append((char *) status, strlen(status));
}
http_buffer->append(ZEND_STRL("\r\n"));

// http headers
uint32_t header_flags = 0x0;

/**
* http header
*/
zval *zheader =
sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_HEADER), 0);
if (ZVAL_IS_ARRAY(zheader)) {
#ifdef SW_HAVE_COMPRESSION
zend_string *content_type = nullptr;
#endif
zval *zvalue;
zend_string *string_key;
zend_ulong num_key;

#ifdef SW_HAVE_COMPRESSION
zend_string *content_type = nullptr;
#endif
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zheader), num_key, string_key, zvalue) {
if (!string_key) {
string_key = zend_long_to_str(num_key);
} else {
zend_string_addref(string_key);
}
zend::String key(string_key, false);

int key_header = parse_header_name(ZSTR_VAL(string_key), ZSTR_LEN(string_key));

if (key_header > 0) {
#ifdef SW_HAVE_COMPRESSION
if (key_header == HTTP_HEADER_CONTENT_TYPE && accept_compression && compression_types) {
Expand All @@ -356,6 +353,7 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
"You have set 'Transfer-Encoding', 'Content-Length' will be ignored");
continue;
}

header_flags |= key_header;
if (ZVAL_IS_STRING(zvalue) && Z_STRLEN_P(zvalue) == 0) {
continue;
Expand Down Expand Up @@ -385,15 +383,13 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
#endif
}

/**
* http cookies
*/
// http cookies
zval *zcookie =
sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE), 0);
if (ZVAL_IS_ARRAY(zcookie)) {
zval *zvalue;
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(zcookie), zvalue) {
if (Z_TYPE_P(zvalue) != IS_STRING) {
if (Z_TYPE_P(zvalue) != IS_STRING || swoole_http_has_crlf(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue))) {
continue;
}
http_buffer->append(ZEND_STRL("Set-Cookie: "));
Expand All @@ -406,6 +402,7 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
if (!(header_flags & HTTP_HEADER_SERVER)) {
http_buffer->append(ZEND_STRL("Server: " SW_HTTP_SERVER_SOFTWARE "\r\n"));
}

if (!(header_flags & HTTP_HEADER_DATE)) {
http_set_date_header(http_buffer);
}
Expand Down Expand Up @@ -446,9 +443,9 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
if (!(header_flags & HTTP_HEADER_CONTENT_LENGTH)) {
http_buffer->append(ZEND_STRL("Content-Length: "));

char content_length2[128];
int convert_result = swoole_itoa(content_length2, length);
http_buffer->append(content_length2, convert_result);
char result[128];
int convert_result = swoole_itoa(result, length);
http_buffer->append(result, convert_result);
http_buffer->append(ZEND_STRL("\r\n"));
}
}
Expand Down Expand Up @@ -731,26 +728,21 @@ void HttpContext::write(zval *zdata, zval *return_value) {
}
}

struct {
char *str;
size_t length;
} http_body;
size_t length = php_swoole_get_send_data(zdata, &http_body.str);
char *data = nullptr;
size_t length = php_swoole_get_send_data(zdata, &data);

if (length == 0) {
php_swoole_error_ex(E_WARNING, SW_ERROR_NO_PAYLOAD, "the data sent must not be empty");
RETURN_FALSE;
} else {
http_body.length = length;
}

http_buffer->clear();
char *hex_string = swoole_dec2hex(http_body.length, 16);
char *hex_string = swoole_dec2hex(length, 16);
int hex_len = strlen(hex_string);
//"%.*s\r\n%.*s\r\n", hex_len, hex_string, body.length, body.str
http_buffer->append(hex_string, hex_len);
http_buffer->append(ZEND_STRL("\r\n"));
http_buffer->append(http_body.str, http_body.length);
http_buffer->append(data, length);
http_buffer->append(ZEND_STRL("\r\n"));
sw_free(hex_string);

Expand Down
1 change: 1 addition & 0 deletions include/swoole_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
#define SW_HTTP_UPLOAD_FILE "Swoole-Upload-File"
#define SW_HTTP_CHUNK_EOF "0\r\n\r\n"
#define SW_HTTP_DEFAULT_CONTENT_TYPE "text/html"
#define SW_HTTP_MAX_APPEND_DATA 16384

// #define SW_HTTP_100_CONTINUE
#define SW_HTTP_100_CONTINUE_PACKET "HTTP/1.1 100 Continue\r\n\r\n"
Expand Down
Loading