@@ -111,6 +111,25 @@ wait_headers({headers_complete, Parser}, Client, Status, Headers) ->
111
111
[hackney , Client # client .host , response_time ],
112
112
ResponseTime ),
113
113
HeadersList = hackney_headers_new :to_list (Headers ),
114
+ CE = case proplists :get_value (compress , Client # client .options , false ) of
115
+ true ->
116
+ case hackney_headers_new :get_value (<<" content-encoding" >>, Headers , nil ) of
117
+ nil -> nil ;
118
+ C ->
119
+ Z = zlib :open (),
120
+ % % inflateInit2 (https://www.zlib.net/manual.html#Advanced)
121
+ WindowBits = 15 + if C == <<" gzip" >> -> 16 ; true -> 0 end ,
122
+ ok = zlib :inflateInit (Z , WindowBits ),
123
+ ok = case erlang :function_exported (zlib , safeInflate , 2 ) of
124
+ % % OTP-20.0.5 and later
125
+ true -> ok ;
126
+ % % OTP-18.0 and later
127
+ false -> zlib :setBufSize (Z , 512 * 1024 )
128
+ end ,
129
+ {zlib ,Z }
130
+ end ;
131
+ false -> nil
132
+ end ,
114
133
TE = hackney_headers_new :get_value (<<" transfer-encoding" >>, Headers , nil ),
115
134
CLen = case hackney_headers_new :lookup (" content-length" , Headers ) of
116
135
[] -> undefined ;
@@ -122,6 +141,7 @@ wait_headers({headers_complete, Parser}, Client, Status, Headers) ->
122
141
end ,
123
142
Client2 = Client # client {parser = Parser ,
124
143
headers = Headers ,
144
+ ce = CE ,
125
145
te = TE ,
126
146
clen = CLen },
127
147
{ok , Status , HeadersList , Client2 }.
@@ -147,17 +167,64 @@ stream_body(Client=#client{parser=Parser, clen=CLen, te=TE}) ->
147
167
stream_body (Data , # client {parser = Parser }= Client ) ->
148
168
stream_body1 (hackney_http :execute (Parser , Data ), Client ).
149
169
150
- stream_body1 ({more , Parser , Buffer }, Client ) ->
170
+ stream_body1 ({ok , Data , Parser }, Client = # client {ce = {zlib ,Z }}) ->
171
+ stream_body2 (case stream_body_zlib (Z , Data ) of
172
+ <<>> -> {more , Parser , <<>>};
173
+ D when is_binary (D ) -> {ok , D , Parser };
174
+ E -> {error ,E }
175
+ end , Client );
176
+ stream_body1 ({done , _Rest }, Client = # client {ce = {zlib ,_Z }}) ->
177
+ stream_body1 (done , Client );
178
+ stream_body1 (done , Client = # client {ce = {zlib ,Z }, parser = Parser }) ->
179
+ stream_body2 (case stream_body_zlib (Z , <<>>) of
180
+ done -> done ;
181
+ D when is_binary (D ), size (D ) > 0 -> {ok , D , Parser };
182
+ E -> {error ,E }
183
+ end , Client );
184
+ stream_body1 (Result , Client ) ->
185
+ stream_body2 (Result , Client ).
186
+
187
+ stream_body_zlib (Z , Data ) ->
188
+ case erlang :function_exported (zlib , safeInflate , 2 ) of
189
+ true ->
190
+ % % OTP-20.0.5 and later
191
+ case zlib :safeInflate (Z , Data ) of
192
+ {continue , []} when Data == <<>> ->
193
+ data_error ;
194
+ {finished , []} when Data == <<>> ->
195
+ case (catch zlib :inflateEnd (Z )) of
196
+ ok -> done ;
197
+ _ -> data_error
198
+ end ;
199
+ {_ , Output } ->
200
+ iolist_to_binary (Output )
201
+ end ;
202
+ false ->
203
+ % % OTP-18.0 and later
204
+ case zlib :inflateChunk (Z , Data ) of
205
+ [] when Data == <<>> ->
206
+ case (catch zlib :inflateEnd (Z )) of
207
+ ok -> done ;
208
+ _ -> data_error
209
+ end ;
210
+ {more , Decompressed } ->
211
+ iolist_to_binary (Decompressed );
212
+ Decompressed ->
213
+ iolist_to_binary (Decompressed )
214
+ end
215
+ end .
216
+
217
+ stream_body2 ({more , Parser , Buffer }, Client ) ->
151
218
stream_body_recv (Buffer , Client # client {parser = Parser });
152
- stream_body1 ({ok , Data , Parser }, Client ) ->
219
+ stream_body2 ({ok , Data , Parser }, Client ) ->
153
220
{ok , Data , Client # client {parser = Parser }};
154
- stream_body1 ({done , Rest }, Client ) ->
221
+ stream_body2 ({done , Rest }, Client ) ->
155
222
Client2 = end_stream_body (Rest , Client ),
156
223
{done , Client2 };
157
- stream_body1 (done , Client ) ->
224
+ stream_body2 (done , Client ) ->
158
225
Client2 = end_stream_body (<<>>, Client ),
159
226
{done , Client2 };
160
- stream_body1 (Error , _Client ) ->
227
+ stream_body2 (Error , _Client ) ->
161
228
Error .
162
229
163
230
@@ -277,6 +344,9 @@ skip_body(Client) ->
277
344
{error , Reason } -> {error , Reason }
278
345
end .
279
346
347
+ end_stream_body (Rest , Client = # client {ce = {zlib ,Z }}) ->
348
+ catch zlib :close (Z ),
349
+ end_stream_body (Rest , Client # client {ce = nil });
280
350
end_stream_body (Rest , Client0 ) ->
281
351
Client = Client0 # client {response_state = done ,
282
352
body_state = done ,
0 commit comments