1616
1717#include "php_swoole.h"
1818#include "thirdparty/php_http_parser.h"
19+
1920#include "ext/standard/basic_functions.h"
2021#include "ext/standard/php_http.h"
2122#include "ext/standard/base64.h"
23+
2224#include "websocket.h"
2325
26+ #ifdef SW_HAVE_ZLIB
27+ #include <zlib.h>
28+ #endif
29+
2430#ifdef SW_ASYNC_HTTPCLIENT
2531
32+ extern swString * swoole_zlib_buffer ;
33+
2634static swString * http_client_buffer ;
2735
2836enum http_client_state
@@ -42,8 +50,6 @@ typedef struct
4250 zval * request_header ;
4351 zval * request_body ;
4452 char * request_method ;
45- zval * response_header ;
46- zval * response_body ;
4753
4854} http_client_callback ;
4955
@@ -59,15 +65,16 @@ typedef struct
5965
6066 char * tmp_header_field_name ;
6167 zend_size_t tmp_header_field_name_len ;
62-
63- char * body ;
6468
6569 php_http_parser parser ;
70+
6671 swString * buffer ;
72+ swString * body ;
6773
6874 int state : 8 ; //0 wait 1 ready 2 busy
6975 int keep_alive :1 ; //0 no 1 keep
7076 int upgrade :1 ;
77+ int gzip : 1 ;
7178
7279} http_client ;
7380
@@ -218,6 +225,20 @@ static int http_client_execute(zval *zobject, char *uri, zend_size_t uri_len, zv
218225 return SW_ERR ;
219226 }
220227
228+ if (http -> body == NULL )
229+ {
230+ http -> body = swString_new (SW_HTTP_RESPONSE_INIT_SIZE );
231+ if (http -> body == NULL )
232+ {
233+ swoole_php_fatal_error (E_ERROR , "[1] swString_new(%d) failed." , SW_HTTP_RESPONSE_INIT_SIZE );
234+ return SW_ERR ;
235+ }
236+ }
237+ else
238+ {
239+ swString_clear (http -> body );
240+ }
241+
221242 http -> uri = estrdup (uri );
222243 http -> uri_len = uri_len ;
223244
@@ -247,7 +268,13 @@ static int http_client_execute(zval *zobject, char *uri, zend_size_t uri_len, zv
247268 return SW_ERR ;
248269 }
249270
271+ #if PHP_MAJOR_VERSION >= 7
272+ cli -> object = (zval * ) emalloc (sizeof (zval ));
273+ ZVAL_DUP (cli -> object , zobject );
274+ #else
250275 cli -> object = zobject ;
276+ #endif
277+
251278 cli -> reactor_fdtype = PHP_SWOOLE_FD_STREAM_CLIENT ;
252279 cli -> onReceive = http_client_onReceive ;
253280 cli -> onConnect = http_client_onConnect ;
@@ -271,6 +298,14 @@ void swoole_http_client_init(int module_number TSRMLS_DC)
271298 {
272299 swoole_php_fatal_error (E_ERROR , "[1] swString_new(%d) failed." , SW_HTTP_RESPONSE_INIT_SIZE );
273300 }
301+
302+ #ifdef SW_HAVE_ZLIB
303+ swoole_zlib_buffer = swString_new (2048 );
304+ if (!swoole_zlib_buffer )
305+ {
306+ swoole_php_fatal_error (E_ERROR , "[2] swString_new(%d) failed." , SW_HTTP_RESPONSE_INIT_SIZE );
307+ }
308+ #endif
274309}
275310
276311/**
@@ -629,6 +664,7 @@ static int http_client_send_http_request(zval *zobject TSRMLS_DC)
629664 uint32_t keylen ;
630665 int keytype ;
631666 zval * value ;
667+
632668 if (send_header && Z_TYPE_P (send_header ) == IS_ARRAY )
633669 {
634670 SW_HASHTABLE_FOREACH_START2 (Z_ARRVAL_P (send_header ), key , keylen , keytype , value )
@@ -658,6 +694,13 @@ static int http_client_send_http_request(zval *zobject TSRMLS_DC)
658694 http_client_swString_append_headers (http_client_buffer , ZEND_STRL ("Host" ), ZEND_STRL ("keep-alive" ));
659695 }
660696
697+ #ifdef SW_HAVE_ZLIB
698+ if (sw_zend_hash_find (Z_ARRVAL_P (send_header ), ZEND_STRS ("Accept-Encoding" ), (void * * ) & value ) == FAILURE )
699+ {
700+ http_client_swString_append_headers (http_client_buffer , ZEND_STRL ("Accept-Encoding" ), ZEND_STRL ("gzip" ));
701+ }
702+ #endif
703+
661704 if (post_data )
662705 {
663706 char post_len_str [16 ];
@@ -822,15 +865,10 @@ static PHP_METHOD(swoole_http_client, __construct)
822865 swoole_set_object (getThis (), NULL );
823866
824867 zval * headers ;
825- SW_MAKE_STD_ZVAL (headers );
868+ SW_ALLOC_INIT_ZVAL (headers );
826869 array_init (headers );
827870 zend_update_property (swoole_http_client_class_entry_ptr , getThis (), ZEND_STRL ("headers" ), headers TSRMLS_CC );
828871
829- zval * body ;
830- SW_MAKE_STD_ZVAL (body );
831- SW_ZVAL_STRING (body , "" , 1 );
832- zend_update_property (swoole_http_client_class_entry_ptr , getThis (), ZEND_STRL ("body" ), body TSRMLS_CC );
833-
834872 http_client_callback * hcc ;
835873 hcc = (http_client_callback * ) emalloc (sizeof (http_client_callback ));
836874 bzero (hcc , sizeof (http_client_callback ));
@@ -847,7 +885,7 @@ static PHP_METHOD(swoole_http_client, __destruct)
847885 http_client_set_cb (getThis (), ZEND_STRL ("finish" ), NULL TSRMLS_CC );
848886 http_client_set_cb (getThis (), ZEND_STRL ("close" ), NULL TSRMLS_CC );
849887 http_client_set_cb (getThis (), ZEND_STRL ("error" ), NULL TSRMLS_CC );
850-
888+
851889 http_client_callback * hcc = swoole_get_property (getThis (), 0 );
852890
853891 if (hcc -> request_header )
@@ -867,7 +905,7 @@ static PHP_METHOD(swoole_http_client, __destruct)
867905 }
868906 efree (hcc );
869907 swoole_set_property (getThis (), 0 , NULL );
870-
908+
871909 //printf("zim_swoole_http_client___destruct()\n");
872910 http_client * http = swoole_get_object (getThis ());
873911 if (http )
@@ -1014,30 +1052,84 @@ static int http_client_parser_on_header_value(php_http_parser *parser, const cha
10141052 {
10151053 http -> upgrade = 1 ;
10161054 }
1055+ #ifdef SW_HAVE_ZLIB
1056+ else if (strcasecmp (header_name , "Content - Encoding ") == 0 && strncasecmp (at , "gzip ", length ) == 0 )
1057+ {
1058+ http -> gzip = 1 ;
1059+ }
1060+ #endif
10171061 efree (header_name );
10181062 return 0 ;
10191063}
10201064
1065+ static int http_response_uncompress (char * body , int length )
1066+ {
1067+ z_stream stream ;
1068+ memset (& stream , 0 , sizeof (stream ));
1069+
1070+ if (Z_OK != inflateInit2 (& stream , MAX_WBITS + 16 ))
1071+ {
1072+ swWarn ("inflateInit2() failed." );
1073+ return SW_ERR ;
1074+ }
1075+
1076+ int status = 0 ;
1077+
1078+ stream .avail_in = length ;
1079+ stream .next_in = (Bytef * ) body ;
1080+
1081+ swString_clear (swoole_zlib_buffer );
1082+
1083+ #if 0
1084+ printf (SW_START_LINE "\nstatus=%d\tavail_in=%ld,\tavail_out=%ld,\ttotal_in=%ld,\ttotal_out=%ld\n" , status , stream .avail_in , stream .avail_out ,
1085+ stream .total_in , stream .total_out );
1086+ #endif
1087+
1088+ while (1 )
1089+ {
1090+ stream .avail_out = swoole_zlib_buffer -> size - stream .total_out ;
1091+ stream .next_out = (Bytef * ) (swoole_zlib_buffer -> str + stream .total_out );
1092+
1093+ status = inflate (& stream , Z_SYNC_FLUSH );
1094+
1095+ #if 0
1096+ printf ("status=%d\tavail_in=%ld,\tavail_out=%ld,\ttotal_in=%ld,\ttotal_out=%ld\n" , status , stream .avail_in , stream .avail_out ,
1097+ stream .total_in , stream .total_out );
1098+ #endif
1099+
1100+ if (status == Z_STREAM_END )
1101+ {
1102+ swoole_zlib_buffer -> length = stream .total_out ;
1103+ inflateEnd (& stream );
1104+ return SW_OK ;
1105+ }
1106+ else if (status == Z_OK )
1107+ {
1108+ if (stream .total_out >= swoole_zlib_buffer -> size )
1109+ {
1110+ swString_extend (swoole_zlib_buffer , swoole_zlib_buffer -> size * 2 );
1111+ }
1112+ }
1113+ else
1114+ {
1115+ inflateEnd (& stream );
1116+ return SW_ERR ;
1117+ }
1118+ }
1119+ return SW_ERR ;
1120+ }
1121+
10211122static int http_client_parser_on_body (php_http_parser * parser , const char * at , size_t length )
10221123{
10231124#if PHP_MAJOR_VERSION < 7
10241125 TSRMLS_FETCH_FROM_CTX (sw_thread_ctx ? sw_thread_ctx : NULL);
10251126#endif
10261127
10271128 http_client * http = (http_client * ) parser -> data ;
1028- zval * zobject = (zval * ) http -> cli -> object ;
1029-
1030- zval * body = sw_zend_read_property (swoole_http_client_class_entry_ptr , zobject , ZEND_STRL ("body" ), 0 TSRMLS_CC );
1031- zval * tmp ;
1032- SW_MAKE_STD_ZVAL (tmp );
1033- SW_ZVAL_STRINGL (tmp , at , length , 1 );
1034- #if PHP_MAJOR_VERSION < 7
1035- add_string_to_string (body , body , tmp );
1036- #else
1037- concat_function (body , body , tmp );
1038- #endif
1039- sw_zval_ptr_dtor (& tmp );
1040-
1129+ if (swString_append_ptr (http -> body , (char * )at , length ) < 0 )
1130+ {
1131+ return -1 ;
1132+ }
10411133 return 0 ;
10421134}
10431135
@@ -1064,6 +1156,20 @@ static int http_client_parser_on_message_complete(php_http_parser *parser)
10641156 zval * * args [1 ];
10651157 args [0 ] = & zobject ;
10661158
1159+ if (http -> gzip )
1160+ {
1161+ if (http_response_uncompress (http -> body -> str , http -> body -> length ) == SW_ERR )
1162+ {
1163+ swWarn ("error" );
1164+ return 0 ;
1165+ }
1166+ zend_update_property_stringl (swoole_http_client_class_entry_ptr , zobject , ZEND_STRL ("body" ), swoole_zlib_buffer -> str , swoole_zlib_buffer -> length TSRMLS_CC );
1167+ }
1168+ else
1169+ {
1170+ zend_update_property_stringl (swoole_http_client_class_entry_ptr , zobject , ZEND_STRL ("body" ), http -> body -> str , http -> body -> length TSRMLS_CC );
1171+ }
1172+
10671173 if (zcallback == NULL || ZVAL_IS_NULL (zcallback ))
10681174 {
10691175 swoole_php_fatal_error (E_WARNING , "swoole_http_client object have not receive callback." );
0 commit comments