@@ -293,80 +293,87 @@ static int parse_header_name(const char *key, size_t keylen) {
293
293
static void http_set_date_header (String *response) {
294
294
static struct {
295
295
time_t time;
296
- size_t len;
297
- char buf[64 ];
296
+ zend_string *date = nullptr ;
298
297
} cache{};
299
298
300
299
time_t now = time (nullptr );
301
300
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
+
306
305
cache.time = now;
306
+ cache.date = php_format_date ((char *) ZEND_STRL (SW_HTTP_DATE_FORMAT), now, 0 );
307
307
}
308
308
response->append (ZEND_STRL (" Date: " ));
309
- response->append (cache.buf , cache.len );
309
+ response->append (ZSTR_VAL ( cache.date ), ZSTR_LEN ( cache.date ) );
310
310
response->append (ZEND_STRL (" \r\n " ));
311
311
}
312
312
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))) {
315
316
return ;
316
317
}
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
+
317
336
zend::String str_value (value);
318
337
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 " ));
326
342
}
327
343
328
344
void HttpContext::build_header (String *http_buffer, const char *body, size_t length) {
329
345
assert (send_header_ == 0 );
330
346
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 ) {
341
350
http_buffer->append (response.status );
342
351
http_buffer->append (ZEND_STRL (" " ));
343
352
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));
345
356
}
357
+ http_buffer->append (ZEND_STRL (" \r\n " ));
346
358
359
+ // http headers
347
360
uint32_t header_flags = 0x0 ;
348
-
349
- /* *
350
- * http header
351
- */
352
361
zval *zheader =
353
362
sw_zend_read_property_ex (swoole_http_response_ce, response.zobject , SW_ZSTR_KNOWN (SW_ZEND_STR_HEADER), 0 );
354
363
if (ZVAL_IS_ARRAY (zheader)) {
364
+ #ifdef SW_HAVE_COMPRESSION
365
+ zend_string *content_type = nullptr ;
366
+ #endif
355
367
zval *zvalue;
356
368
zend_string *string_key;
357
369
zend_ulong num_key;
358
370
359
- #ifdef SW_HAVE_COMPRESSION
360
- zend_string *content_type = nullptr ;
361
- #endif
362
371
ZEND_HASH_FOREACH_KEY_VAL (Z_ARRVAL_P (zheader), num_key, string_key, zvalue) {
363
372
if (!string_key) {
364
373
string_key = zend_long_to_str (num_key);
365
- } else {
366
- zend_string_addref (string_key);
367
374
}
368
- zend::String key (string_key, false );
369
375
int key_header = parse_header_name (ZSTR_VAL (string_key), ZSTR_LEN (string_key));
376
+
370
377
if (key_header > 0 ) {
371
378
#ifdef SW_HAVE_COMPRESSION
372
379
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
392
399
" You have set 'Transfer-Encoding', 'Content-Length' will be ignored" );
393
400
continue ;
394
401
}
395
- header_flags |= key_header;
402
+
396
403
if (ZVAL_IS_STRING (zvalue) && Z_STRLEN_P (zvalue) == 0 ) {
397
404
continue ;
398
405
}
406
+ header_flags |= key_header;
399
407
}
400
408
if (ZVAL_IS_ARRAY (zvalue)) {
401
409
zval *zvalue_2;
402
410
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 );
404
412
}
405
413
SW_HASHTABLE_FOREACH_END ();
406
414
} 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 );
408
416
}
409
417
}
410
418
ZEND_HASH_FOREACH_END ();
@@ -421,15 +429,13 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
421
429
#endif
422
430
}
423
431
424
- /* *
425
- * http cookies
426
- */
432
+ // http cookies
427
433
zval *zcookie =
428
434
sw_zend_read_property_ex (swoole_http_response_ce, response.zobject , SW_ZSTR_KNOWN (SW_ZEND_STR_COOKIE), 0 );
429
435
if (ZVAL_IS_ARRAY (zcookie)) {
430
436
zval *zvalue;
431
437
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)) ) {
433
439
continue ;
434
440
}
435
441
http_buffer->append (ZEND_STRL (" Set-Cookie: " ));
@@ -442,6 +448,7 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
442
448
if (!(header_flags & HTTP_HEADER_SERVER)) {
443
449
http_buffer->append (ZEND_STRL (" Server: " SW_HTTP_SERVER_SOFTWARE " \r\n " ));
444
450
}
451
+
445
452
if (!(header_flags & HTTP_HEADER_DATE)) {
446
453
http_set_date_header (http_buffer);
447
454
}
@@ -482,9 +489,8 @@ void HttpContext::build_header(String *http_buffer, const char *body, size_t len
482
489
if (!(header_flags & HTTP_HEADER_CONTENT_LENGTH)) {
483
490
http_buffer->append (ZEND_STRL (" Content-Length: " ));
484
491
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));
488
494
http_buffer->append (ZEND_STRL (" \r\n " ));
489
495
}
490
496
}
@@ -754,16 +760,8 @@ bool HttpContext::send_file(const char *file, uint32_t l_file, off_t offset, siz
754
760
}
755
761
756
762
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 ;
767
765
768
766
if (send_chunked) {
769
767
if (send_trailer_) {
@@ -773,86 +771,64 @@ void HttpContext::end(zval *zdata, zval *return_value) {
773
771
send_trailer (return_value);
774
772
send_trailer_ = 0 ;
775
773
} else {
776
- if (!send (this , ZEND_STRL (" 0 \r\n\r\n " ))) {
774
+ if (!send (this , ZEND_STRL (SW_HTTP_CHUNK_EOF ))) {
777
775
RETURN_FALSE;
778
776
}
779
777
}
780
778
send_chunked = 0 ;
781
- } else {
782
- String *http_buffer = get_write_buffer ();
783
- http_buffer->clear ();
779
+ return ;
780
+ }
784
781
785
782
#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 );
808
800
}
809
801
}
802
+ websocket_compression = accept_websocket_compression;
803
+ if (conn) {
804
+ conn->websocket_compression = accept_websocket_compression;
805
+ }
806
+ }
810
807
#endif
811
808
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);
816
812
817
- if (http_body. length > 0 ) {
813
+ if (length > 0 ) {
818
814
#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 ;
846
818
}
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 ;
851
822
RETURN_FALSE;
852
823
}
853
824
}
854
825
855
- _skip_copy:
826
+ if (!send (this , http_buffer->str , http_buffer->length )) {
827
+ end_ = 1 ;
828
+ close (this );
829
+ RETURN_FALSE;
830
+ }
831
+
856
832
if (upgrade && !co_socket) {
857
833
Server *serv = (Server *) private_data;
858
834
Connection *conn = serv->get_connection_verify (fd);
0 commit comments