Skip to content

Commit 74cce1a

Browse files
committed
optimize response
1 parent b21b8d9 commit 74cce1a

File tree

3 files changed

+104
-124
lines changed

3 files changed

+104
-124
lines changed

ext-src/php_swoole_private.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -720,11 +720,12 @@ static sw_inline void sw_zend_update_property_null_ex(zend_class_entry *scope, z
720720
zend_update_property_ex(scope, SW_Z8_OBJ_P(object), s, &tmp);
721721
}
722722

723-
static sw_inline zval *sw_zend_read_property_ex(zend_class_entry *ce, zval *obj, zend_string *s, int silent) {
724-
zval rv, *property = zend_read_property_ex(ce, SW_Z8_OBJ_P(obj), s, silent, &rv);
723+
static sw_inline zval *sw_zend_read_property_ex(zend_class_entry *ce, zval *zobject, zend_string *name, int silent) {
724+
zval *zv = zend_hash_find(&ce->properties_info, name);
725+
zend_property_info *property_info = (zend_property_info *) Z_PTR_P(zv);
726+
zval *property = OBJ_PROP(SW_Z8_OBJ_P(zobject), property_info->offset);
725727
if (UNEXPECTED(property == &EG(uninitialized_zval))) {
726-
sw_zend_update_property_null_ex(ce, obj, s);
727-
return zend_read_property_ex(ce, SW_Z8_OBJ_P(obj), s, silent, &rv);
728+
ZVAL_NULL(property);
728729
}
729730
return property;
730731
}

ext-src/swoole_http_response.cc

Lines changed: 96 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -293,80 +293,87 @@ static int parse_header_name(const char *key, size_t keylen) {
293293
static void http_set_date_header(String *response) {
294294
static struct {
295295
time_t time;
296-
size_t len;
297-
char buf[64];
296+
zend_string *date = nullptr;
298297
} cache{};
299298

300299
time_t now = time(nullptr);
301300
if (now != cache.time) {
302-
char *date_str = php_swoole_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), now, 0);
303-
cache.len = strlen(date_str);
304-
memcpy(cache.buf, date_str, cache.len);
305-
efree(date_str);
301+
if (cache.date) {
302+
zend_string_release(cache.date);
303+
}
304+
306305
cache.time = now;
306+
cache.date = php_format_date((char *) ZEND_STRL(SW_HTTP_DATE_FORMAT), now, 0);
307307
}
308308
response->append(ZEND_STRL("Date: "));
309-
response->append(cache.buf, cache.len);
309+
response->append(ZSTR_VAL(cache.date), ZSTR_LEN(cache.date));
310310
response->append(ZEND_STRL("\r\n"));
311311
}
312312

313-
static void add_custom_header(String *response, const char *key, size_t l_key, zval *value) {
314-
if (ZVAL_IS_NULL(value)) {
313+
static void add_custom_header(String *http_buffer, const char *key, size_t l_key, zval *value, int key_header) {
314+
if (ZVAL_IS_NULL(value) || swoole_http_has_crlf(key, l_key) ||
315+
swoole_http_has_crlf(Z_STRVAL_P(value), Z_STRLEN_P(value))) {
315316
return;
316317
}
318+
319+
if (key_header == HTTP_HEADER_CONTENT_TYPE && ZVAL_IS_STRING(value)) {
320+
if (SW_STRCASEEQ(Z_STRVAL_P(value), Z_STRLEN_P(value), SW_HTTP_APPLICATION_JSON)) {
321+
http_buffer->append(SW_STRL("Content-Type: " SW_HTTP_APPLICATION_JSON "\r\n"));
322+
return;
323+
}
324+
325+
if (SW_STRCASEEQ(Z_STRVAL_P(value), Z_STRLEN_P(value), SW_HTTP_DEFAULT_CONTENT_TYPE)) {
326+
http_buffer->append(SW_STRL("Content-Type: " SW_HTTP_DEFAULT_CONTENT_TYPE "\r\n"));
327+
return;
328+
}
329+
330+
if (SW_STRCASEEQ(Z_STRVAL_P(value), Z_STRLEN_P(value), SW_HTTP_TEXT_PLAIN)) {
331+
http_buffer->append(SW_STRL("Content-Type: " SW_HTTP_TEXT_PLAIN "\r\n"));
332+
return;
333+
}
334+
}
335+
317336
zend::String str_value(value);
318337
str_value.rtrim();
319-
if (swoole_http_has_crlf(str_value.val(), str_value.len())) {
320-
return;
321-
}
322-
response->append(key, l_key);
323-
response->append(SW_STRL(": "));
324-
response->append(str_value.val(), str_value.len());
325-
response->append(SW_STRL("\r\n"));
338+
http_buffer->append(key, l_key);
339+
http_buffer->append(SW_STRL(": "));
340+
http_buffer->append(str_value.val(), str_value.len());
341+
http_buffer->append(SW_STRL("\r\n"));
326342
}
327343

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

331-
/**
332-
* http status line
333-
*/
334-
if (!response.reason) {
335-
const char *status = HttpServer::get_status_message(response.status);
336-
http_buffer->append(ZEND_STRL("HTTP/1.1 "));
337-
http_buffer->append((char *) status, strlen(status));
338-
http_buffer->append(ZEND_STRL("\r\n"));
339-
} else {
340-
http_buffer->append(ZEND_STRL("HTTP/1.1 "));
347+
// http status line
348+
http_buffer->append(ZEND_STRL("HTTP/1.1 "));
349+
if (response.reason) {
341350
http_buffer->append(response.status);
342351
http_buffer->append(ZEND_STRL(" "));
343352
http_buffer->append(response.reason, strlen(response.reason));
344-
http_buffer->append(ZEND_STRL("\r\n"));
353+
} else {
354+
const char *status = HttpServer::get_status_message(response.status);
355+
http_buffer->append((char *) status, strlen(status));
345356
}
357+
http_buffer->append(ZEND_STRL("\r\n"));
346358

359+
// http headers
347360
uint32_t header_flags = 0x0;
348-
349-
/**
350-
* http header
351-
*/
352361
zval *zheader =
353362
sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_HEADER), 0);
354363
if (ZVAL_IS_ARRAY(zheader)) {
364+
#ifdef SW_HAVE_COMPRESSION
365+
zend_string *content_type = nullptr;
366+
#endif
355367
zval *zvalue;
356368
zend_string *string_key;
357369
zend_ulong num_key;
358370

359-
#ifdef SW_HAVE_COMPRESSION
360-
zend_string *content_type = nullptr;
361-
#endif
362371
ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(zheader), num_key, string_key, zvalue) {
363372
if (!string_key) {
364373
string_key = zend_long_to_str(num_key);
365-
} else {
366-
zend_string_addref(string_key);
367374
}
368-
zend::String key(string_key, false);
369375
int key_header = parse_header_name(ZSTR_VAL(string_key), ZSTR_LEN(string_key));
376+
370377
if (key_header > 0) {
371378
#ifdef SW_HAVE_COMPRESSION
372379
if (key_header == HTTP_HEADER_CONTENT_TYPE && accept_compression && compression_types) {
@@ -392,19 +399,20 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
392399
"You have set 'Transfer-Encoding', 'Content-Length' will be ignored");
393400
continue;
394401
}
395-
header_flags |= key_header;
402+
396403
if (ZVAL_IS_STRING(zvalue) && Z_STRLEN_P(zvalue) == 0) {
397404
continue;
398405
}
406+
header_flags |= key_header;
399407
}
400408
if (ZVAL_IS_ARRAY(zvalue)) {
401409
zval *zvalue_2;
402410
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(zvalue), zvalue_2) {
403-
add_custom_header(http_buffer, ZSTR_VAL(string_key), ZSTR_LEN(string_key), zvalue_2);
411+
add_custom_header(http_buffer, ZSTR_VAL(string_key), ZSTR_LEN(string_key), zvalue_2, key_header);
404412
}
405413
SW_HASHTABLE_FOREACH_END();
406414
} else {
407-
add_custom_header(http_buffer, ZSTR_VAL(string_key), ZSTR_LEN(string_key), zvalue);
415+
add_custom_header(http_buffer, ZSTR_VAL(string_key), ZSTR_LEN(string_key), zvalue, key_header);
408416
}
409417
}
410418
ZEND_HASH_FOREACH_END();
@@ -421,15 +429,13 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
421429
#endif
422430
}
423431

424-
/**
425-
* http cookies
426-
*/
432+
// http cookies
427433
zval *zcookie =
428434
sw_zend_read_property_ex(swoole_http_response_ce, response.zobject, SW_ZSTR_KNOWN(SW_ZEND_STR_COOKIE), 0);
429435
if (ZVAL_IS_ARRAY(zcookie)) {
430436
zval *zvalue;
431437
SW_HASHTABLE_FOREACH_START(Z_ARRVAL_P(zcookie), zvalue) {
432-
if (Z_TYPE_P(zvalue) != IS_STRING) {
438+
if (Z_TYPE_P(zvalue) != IS_STRING || swoole_http_has_crlf(Z_STRVAL_P(zvalue), Z_STRLEN_P(zvalue))) {
433439
continue;
434440
}
435441
http_buffer->append(ZEND_STRL("Set-Cookie: "));
@@ -442,6 +448,7 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
442448
if (!(header_flags & HTTP_HEADER_SERVER)) {
443449
http_buffer->append(ZEND_STRL("Server: " SW_HTTP_SERVER_SOFTWARE "\r\n"));
444450
}
451+
445452
if (!(header_flags & HTTP_HEADER_DATE)) {
446453
http_set_date_header(http_buffer);
447454
}
@@ -482,9 +489,8 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
482489
if (!(header_flags & HTTP_HEADER_CONTENT_LENGTH)) {
483490
http_buffer->append(ZEND_STRL("Content-Length: "));
484491

485-
char content_length2[128];
486-
int convert_result = swoole_itoa(content_length2, length);
487-
http_buffer->append(content_length2, convert_result);
492+
char result[128];
493+
http_buffer->append(result, swoole_itoa(result, length));
488494
http_buffer->append(ZEND_STRL("\r\n"));
489495
}
490496
}
@@ -754,16 +760,8 @@ bool HttpContext::send_file(const char *file, uint32_t l_file, off_t offset, siz
754760
}
755761

756762
void HttpContext::end(zval *zdata, zval *return_value) {
757-
struct {
758-
char *str;
759-
size_t length;
760-
} http_body;
761-
if (zdata) {
762-
http_body.length = php_swoole_get_send_data(zdata, &http_body.str);
763-
} else {
764-
http_body.length = 0;
765-
http_body.str = nullptr;
766-
}
763+
char *data = nullptr;
764+
size_t length = zdata ? php_swoole_get_send_data(zdata, &data) : 0;
767765

768766
if (send_chunked) {
769767
if (send_trailer_) {
@@ -773,86 +771,64 @@ void HttpContext::end(zval *zdata, zval *return_value) {
773771
send_trailer(return_value);
774772
send_trailer_ = 0;
775773
} else {
776-
if (!send(this, ZEND_STRL("0\r\n\r\n"))) {
774+
if (!send(this, ZEND_STRL(SW_HTTP_CHUNK_EOF))) {
777775
RETURN_FALSE;
778776
}
779777
}
780778
send_chunked = 0;
781-
} else {
782-
String *http_buffer = get_write_buffer();
783-
http_buffer->clear();
779+
return;
780+
}
784781

785782
#ifdef SW_HAVE_ZLIB
786-
if (upgrade) {
787-
Server *serv = nullptr;
788-
Connection *conn = nullptr;
789-
if (!co_socket) {
790-
serv = (Server *) private_data;
791-
conn = serv->get_connection_verify(fd);
792-
}
793-
bool enable_websocket_compression = co_socket ? websocket_compression : serv->websocket_compression;
794-
bool accept_websocket_compression = false;
795-
zval *pData;
796-
if (enable_websocket_compression && request.zobject &&
797-
(pData = zend_hash_str_find(Z_ARRVAL_P(request.zheader), ZEND_STRL("sec-websocket-extensions"))) &&
798-
Z_TYPE_P(pData) == IS_STRING) {
799-
std::string value(Z_STRVAL_P(pData), Z_STRLEN_P(pData));
800-
if (value.substr(0, value.find_first_of(';')) == "permessage-deflate") {
801-
accept_websocket_compression = true;
802-
set_header(ZEND_STRL("Sec-Websocket-Extensions"), ZEND_STRL(SW_WEBSOCKET_EXTENSION_DEFLATE), false);
803-
}
804-
}
805-
websocket_compression = accept_websocket_compression;
806-
if (conn) {
807-
conn->websocket_compression = accept_websocket_compression;
783+
if (upgrade) {
784+
Server *serv = nullptr;
785+
Connection *conn = nullptr;
786+
if (!co_socket) {
787+
serv = (Server *) private_data;
788+
conn = serv->get_connection_verify(fd);
789+
}
790+
bool enable_websocket_compression = co_socket ? websocket_compression : serv->websocket_compression;
791+
bool accept_websocket_compression = false;
792+
zval *pData;
793+
if (enable_websocket_compression && request.zobject &&
794+
(pData = zend_hash_str_find(Z_ARRVAL_P(request.zheader), ZEND_STRL("sec-websocket-extensions"))) &&
795+
Z_TYPE_P(pData) == IS_STRING) {
796+
std::string value(Z_STRVAL_P(pData), Z_STRLEN_P(pData));
797+
if (value.substr(0, value.find_first_of(';')) == "permessage-deflate") {
798+
accept_websocket_compression = true;
799+
set_header(ZEND_STRL("Sec-Websocket-Extensions"), ZEND_STRL(SW_WEBSOCKET_EXTENSION_DEFLATE), false);
808800
}
809801
}
802+
websocket_compression = accept_websocket_compression;
803+
if (conn) {
804+
conn->websocket_compression = accept_websocket_compression;
805+
}
806+
}
810807
#endif
811808

812-
build_header(http_buffer, http_body.str, http_body.length);
813-
814-
char *send_body_str;
815-
size_t send_body_len;
809+
String *http_buffer = get_write_buffer();
810+
http_buffer->clear();
811+
build_header(http_buffer, data, length);
816812

817-
if (http_body.length > 0) {
813+
if (length > 0) {
818814
#ifdef SW_HAVE_COMPRESSION
819-
if (content_compressed) {
820-
send_body_str = zlib_buffer->str;
821-
send_body_len = zlib_buffer->length;
822-
} else
823-
#endif
824-
{
825-
send_body_str = http_body.str;
826-
send_body_len = http_body.length;
827-
}
828-
// send twice to reduce memory copy
829-
if (send_body_len < swoole_pagesize()) {
830-
if (http_buffer->append(send_body_str, send_body_len) < 0) {
831-
send_header_ = 0;
832-
RETURN_FALSE;
833-
}
834-
} else {
835-
if (!send(this, http_buffer->str, http_buffer->length)) {
836-
send_header_ = 0;
837-
RETURN_FALSE;
838-
}
839-
if (!send(this, send_body_str, send_body_len)) {
840-
end_ = 1;
841-
close(this);
842-
RETURN_FALSE;
843-
}
844-
goto _skip_copy;
845-
}
815+
if (content_compressed) {
816+
data = zlib_buffer->str;
817+
length = zlib_buffer->length;
846818
}
847-
848-
if (!send(this, http_buffer->str, http_buffer->length)) {
849-
end_ = 1;
850-
close(this);
819+
#endif
820+
if (http_buffer->append(data, length) < 0) {
821+
send_header_ = 0;
851822
RETURN_FALSE;
852823
}
853824
}
854825

855-
_skip_copy:
826+
if (!send(this, http_buffer->str, http_buffer->length)) {
827+
end_ = 1;
828+
close(this);
829+
RETURN_FALSE;
830+
}
831+
856832
if (upgrade && !co_socket) {
857833
Server *serv = (Server *) private_data;
858834
Connection *conn = serv->get_connection_verify(fd);

include/swoole_config.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,9 @@
184184
#define SW_HTTP_UPLOAD_FILE "Swoole-Upload-File"
185185
#define SW_HTTP_CHUNK_EOF "0\r\n\r\n"
186186
#define SW_HTTP_DEFAULT_CONTENT_TYPE "text/html"
187+
#define SW_HTTP_CONTENT_TYPE_WITH_CHARSET "text/html; charset=utf-8"
188+
#define SW_HTTP_APPLICATION_JSON "application/json"
189+
#define SW_HTTP_TEXT_PLAIN "text/plain; charset=utf-8"
187190

188191
// #define SW_HTTP_100_CONTINUE
189192
#define SW_HTTP_100_CONTINUE_PACKET "HTTP/1.1 100 Continue\r\n\r\n"

0 commit comments

Comments
 (0)