206
229
%% but we do not want that so errors will be handled by the process
207
230
%% sending an init_error message to itself.
208
231
%%--------------------------------------------------------------------
209
init([Request, Options, ProfileName]) ->
232
init([Options, ProfileName]) ->
233
?hcrv("init - starting", [{options, Options}, {profile, ProfileName}]),
210
234
process_flag(trap_exit, true),
212
235
handle_verbose(Options#options.verbose),
213
Address = handle_proxy(Request#request.address, Options#options.proxy),
215
case {Address /= Request#request.address, Request#request.scheme} of
217
Error = https_through_proxy_is_not_currently_supported,
218
self() ! {init_error,
219
Error, httpc_response:error(Request, Error)},
220
{ok, #state{request = Request, options = Options,
221
status = ssl_tunnel}};
222
%% This is what we should do if and when ssl supports
223
%% "socket upgrading"
224
%%send_ssl_tunnel_request(Address, Request,
225
%% #state{options = Options,
226
%% status = ssl_tunnel});
228
send_first_request(Address, Request,
229
#state{options = Options,
230
profile_name = ProfileName})
232
gen_server:enter_loop(?MODULE, [], State).
236
State = #state{status = undefined,
238
profile_name = ProfileName},
239
?hcrd("init - started", []),
234
243
%%--------------------------------------------------------------------
235
244
%% Function: handle_call(Request, From, State) -> {reply, Reply, State} |
240
249
%% {stop, Reason, State} (terminate/2 is called)
241
250
%% Description: Handling call messages
242
251
%%--------------------------------------------------------------------
243
handle_call(Request, _, State = #state{session = Session =
244
#tcp_session{socket = Socket,
248
profile_name = ProfileName}) ->
249
Address = handle_proxy(Request#request.address, Options#options.proxy),
254
%% This is the first request, the reason the proc was started
255
handle_call({connect_and_send, #request{address = Address0,
256
scheme = Scheme} = Request},
258
#state{options = #options{proxy = Proxy},
260
session = undefined} = State) ->
261
?hcrv("connect and send", [{address0, Address0}, {proxy, Proxy}]),
262
Address = handle_proxy(Address0, Proxy),
264
((Address =/= Address0) andalso (Scheme =:= https)) ->
265
%% This is what we should do if and when ssl supports
266
%% "socket upgrading"
267
%%send_ssl_tunnel_request(Address, Request,
268
%% #state{options = Options,
269
%% status = ssl_tunnel});
270
Reason = {failed_connecting,
271
https_through_proxy_is_not_currently_supported},
272
%% Send a reply to the original caller
273
ErrorResponse = httpc_response:error(Request, Reason),
274
httpc_response:send(Request#request.from, ErrorResponse),
275
%% Reply to the manager
276
ErrorReply = {error, Reason},
277
{stop, normal, ErrorReply, State};
279
case connect_and_send_first_request(Address, Request, State) of
281
{reply, ok, NewState};
282
{stop, Error, NewState} ->
283
{stop, Error, Error, NewState}
287
handle_call(#request{address = Addr} = Request, _,
288
#state{status = Status,
289
session = #tcp_session{socket = Socket,
290
type = pipeline} = Session,
292
options = #options{proxy = Proxy} = _Options,
293
profile_name = ProfileName} = State)
294
when Status =/= undefined ->
296
?hcrv("new request on a pipeline session",
298
{profile, ProfileName},
302
Address = handle_proxy(Addr, Proxy),
251
304
case httpc_request:send(Address, Request, Socket) of
307
?hcrd("request sent", []),
253
309
%% Activate the request time out for the new request
254
NewState = activate_request_timeout(State#state{request =
257
ClientClose = httpc_request:is_client_closing(
258
Request#request.headers),
311
activate_request_timeout(State#state{request = Request}),
314
httpc_request:is_client_closing(Request#request.headers),
259
316
case State#state.request of
260
#request{} -> %% Old request no yet finished
317
#request{} -> %% Old request not yet finished
318
?hcrd("old request still not finished", []),
261
319
%% Make sure to use the new value of timers in state
262
NewTimers = NewState#state.timers,
320
NewTimers = NewState#state.timers,
263
321
NewPipeline = queue:in(Request, State#state.pipeline),
265
323
Session#tcp_session{queue_length =
266
324
%% Queue + current
267
325
queue:len(NewPipeline) + 1,
268
326
client_close = ClientClose},
269
327
httpc_manager:insert_session(NewSession, ProfileName),
328
?hcrd("session updated", []),
270
329
{reply, ok, State#state{pipeline = NewPipeline,
271
session = NewSession,
272
timers = NewTimers}};
330
session = NewSession,
331
timers = NewTimers}};
274
%% Note: tcp-message reciving has already been
333
%% Note: tcp-message receiving has already been
275
334
%% activated by handle_pipeline/2.
335
?hcrd("no current request", []),
276
336
cancel_timer(Timers#timers.queue_timer,
281
341
httpc_manager:insert_session(NewSession, ProfileName),
283
343
(Request#request.settings)#http_options.relaxed,
285
NewState#state{request = Request,
286
session = NewSession,
287
mfa = {httpc_response, parse,
288
[State#state.max_header_size,
291
Timers#timers{queue_timer =
344
MFA = {httpc_response, parse,
345
[State#state.max_header_size, Relaxed]},
346
NewTimers = Timers#timers{queue_timer = undefined},
347
?hcrd("session created", []),
348
{reply, ok, NewState#state{request = Request,
349
session = NewSession,
294
353
{error, Reason} ->
354
?hcri("failed sending request", [{reason, Reason}]),
295
355
{reply, {pipeline_failed, Reason}, State}
298
handle_call(Request, _, #state{session = Session =
299
#tcp_session{type = keep_alive,
303
profile_name = ProfileName} = State) ->
305
ClientClose = httpc_request:is_client_closing(Request#request.headers),
358
handle_call(#request{address = Addr} = Request, _,
359
#state{status = Status,
360
session = #tcp_session{socket = Socket,
361
type = keep_alive} = Session,
363
options = #options{proxy = Proxy} = _Options,
364
profile_name = ProfileName} = State)
365
when Status =/= undefined ->
307
Address = handle_proxy(Request#request.address,
308
Options#options.proxy),
367
?hcrv("new request on a keep-alive session",
369
{profile, ProfileName},
372
Address = handle_proxy(Addr, Proxy),
309
373
case httpc_request:send(Address, Request, Socket) of
376
?hcrd("request sent", []),
378
%% Activate the request time out for the new request
312
activate_request_timeout(State#state{request =
380
activate_request_timeout(State#state{request = Request}),
383
httpc_request:is_client_closing(Request#request.headers),
315
385
case State#state.request of
316
386
#request{} -> %% Old request not yet finished
317
387
%% Make sure to use the new value of timers in state
318
NewTimers = NewState#state.timers,
388
?hcrd("old request still not finished", []),
389
NewTimers = NewState#state.timers,
319
390
NewKeepAlive = queue:in(Request, State#state.keep_alive),
321
392
Session#tcp_session{queue_length =
322
393
%% Queue + current
323
394
queue:len(NewKeepAlive) + 1,
324
395
client_close = ClientClose},
325
396
httpc_manager:insert_session(NewSession, ProfileName),
397
?hcrd("session updated", []),
326
398
{reply, ok, State#state{keep_alive = NewKeepAlive,
327
session = NewSession,
328
timers = NewTimers}};
399
session = NewSession,
400
timers = NewTimers}};
330
402
%% Note: tcp-message reciving has already been
331
403
%% activated by handle_pipeline/2.
404
?hcrd("no current request", []),
332
405
cancel_timer(Timers#timers.queue_timer,
367
447
%% handle_keep_alive_queue/2 on the other hand will just skip the
368
448
%% request as if it was never issued as in this case the request will
369
449
%% not have been sent.
370
handle_cast({cancel, RequestId}, State = #state{request = Request =
371
#request{id = RequestId},
372
profile_name = ProfileName}) ->
450
handle_cast({cancel, RequestId},
451
#state{request = #request{id = RequestId} = Request,
452
profile_name = ProfileName,
453
canceled = Canceled} = State) ->
454
?hcrv("cancel current request", [{request_id, RequestId},
455
{profile, ProfileName},
456
{canceled, Canceled}]),
373
457
httpc_manager:request_canceled(RequestId, ProfileName),
458
?hcrv("canceled", []),
375
State#state{canceled = [RequestId | State#state.canceled],
376
request = Request#request{from = answer_sent}}};
377
handle_cast({cancel, RequestId}, State = #state{profile_name = ProfileName}) ->
460
State#state{canceled = [RequestId | Canceled],
461
request = Request#request{from = answer_sent}}};
462
handle_cast({cancel, RequestId},
463
#state{profile_name = ProfileName,
464
canceled = Canceled} = State) ->
465
?hcrv("cancel", [{request_id, RequestId},
466
{profile, ProfileName},
467
{canceled, Canceled}]),
378
468
httpc_manager:request_canceled(RequestId, ProfileName),
379
{noreply, State#state{canceled = [RequestId | State#state.canceled]}};
469
?hcrv("canceled", []),
470
{noreply, State#state{canceled = [RequestId | Canceled]}};
380
472
handle_cast(stream_next, #state{session = Session} = State) ->
381
http_transport:setopts(socket_type(Session#tcp_session.scheme),
382
Session#tcp_session.socket, [{active, once}]),
473
activate_once(Session),
383
474
{noreply, State#state{once = once}}.
399
490
(Proto =:= ssl) orelse
400
491
(Proto =:= httpc_handler) ->
402
?hcri("received data", [{proto, Proto}, {data, Data}, {mfa, MFA}, {method, Method}, {stream, Stream}, {session, Session}, {status_line, StatusLine}]),
493
?hcri("received data", [{proto, Proto},
495
{function, Function},
499
{status_line, StatusLine}]),
405
502
try Module:Function([Data | Args]) of
407
?hcrd("data processed - ok", [{result, Result}]),
504
?hcrd("data processed - ok", []),
408
505
handle_http_msg(Result, State);
409
506
{_, whole_body, _} when Method =:= head ->
410
507
?hcrd("data processed - whole body", []),
411
508
handle_response(State#state{body = <<>>});
412
509
{Module, whole_body, [Body, Length]} ->
413
?hcrd("data processed - whole body", [{module, Module}, {body, Body}, {length, Length}]),
510
?hcrd("data processed - whole body", [{length, Length}]),
414
511
{_, Code, _} = StatusLine,
415
512
{NewBody, NewRequest} = stream(Body, Request, Code),
416
513
%% When we stream we will not keep the already
417
514
%% streamed data, that would be a waste of memory.
418
NewLength = case Stream of
425
523
NewState = next_body_chunk(State),
427
{noreply, NewState#state{mfa = {Module, whole_body,
428
[NewBody, NewLength]},
524
NewMFA = {Module, whole_body, [NewBody, NewLength]},
525
{noreply, NewState#state{mfa = NewMFA,
429
526
request = NewRequest}};
431
?hcrd("data processed", [{new_mfa, NewMFA}]),
432
http_transport:setopts(socket_type(Session#tcp_session.scheme),
433
Session#tcp_session.socket,
528
?hcrd("data processed - new mfa", []),
529
activate_once(Session),
435
530
{noreply, State#state{mfa = NewMFA}}
438
ClientErrMsg = httpc_response:error(Request,
439
{could_not_parse_as_http,
441
NewState = answer_request(Request, ClientErrMsg, State),
533
?hcrd("data processing exit", [{exit, _Exit}]),
534
ClientReason = {could_not_parse_as_http, Data},
535
ClientErrMsg = httpc_response:error(Request, ClientReason),
536
NewState = answer_request(Request, ClientErrMsg, State),
442
537
{stop, normal, NewState};
444
ClientErrMsg = httpc_response:error(Request,
445
{could_not_parse_as_http,
447
NewState = answer_request(Request, ClientErrMsg, State),
539
?hcrd("data processing error", [{error, _Error}]),
540
ClientReason = {could_not_parse_as_http, Data},
541
ClientErrMsg = httpc_response:error(Request, ClientReason),
542
NewState = answer_request(Request, ClientErrMsg, State),
448
543
{stop, normal, NewState}
451
?hcri("data processed", [{result, FinalResult}]),
546
?hcri("data processed", []),
455
550
handle_info({Proto, Socket, Data},
460
555
status_line = StatusLine,
461
556
profile_name = Profile} = State)
462
557
when (Proto =:= tcp) orelse
513
609
handle_info({timeout, RequestId},
514
610
#state{request = #request{id = RequestId} = Request,
515
611
canceled = Canceled} = State) ->
612
?hcri("timeout of current request", [{id, RequestId}]),
516
613
httpc_response:send(Request#request.from,
517
httpc_response:error(Request,timeout)),
614
httpc_response:error(Request, timeout)),
615
?hcrv("response (timeout) sent - now terminate", []),
519
617
State#state{request = Request#request{from = answer_sent},
520
618
canceled = [RequestId | Canceled]}};
522
620
handle_info({timeout, RequestId}, #state{canceled = Canceled} = State) ->
621
?hcri("timeout", [{id, RequestId}]),
524
623
fun(#request{id = Id, from = From} = Request) when Id =:= RequestId ->
624
?hcrv("found request", [{id, Id}, {from, From}]),
525
625
%% Notify the owner
526
626
Response = httpc_response:error(Request, timeout),
527
627
httpc_response:send(From, Response),
628
?hcrv("response (timeout) sent", []),
528
629
[Request#request{from = answer_sent}];
532
633
case State#state.status of
635
?hcrd("pipeline", []),
534
636
Pipeline = queue:filter(Filter, State#state.pipeline),
535
637
{noreply, State#state{canceled = [RequestId | Canceled],
536
638
pipeline = Pipeline}};
640
?hcrd("keep_alive", []),
538
641
KeepAlive = queue:filter(Filter, State#state.keep_alive),
539
642
{noreply, State#state{canceled = [RequestId | Canceled],
540
643
keep_alive = KeepAlive}}
728
846
http_transport:connect(SocketType, ToAddress, Opts3, Timeout)
732
send_first_request(Address, Request, #state{options = Options} = State) ->
849
connect_and_send_first_request(Address,
850
#request{settings = Settings,
852
address = OrigAddress,
853
scheme = Scheme} = Request,
854
#state{options = Options} = State) ->
857
[{address, Address}, {request, Request}, {options, Options}]),
733
859
SocketType = socket_type(Request),
734
ConnTimeout = (Request#request.settings)#http_options.connect_timeout,
736
[{address, Address}, {request, Request}, {options, Options}]),
860
ConnTimeout = Settings#http_options.connect_timeout,
737
861
case connect(SocketType, Address, Options, ConnTimeout) of
739
?hcri("connected - now send first request", [{socket, Socket}]),
863
?hcrd("connected - now send first request", [{socket, Socket}]),
740
864
case httpc_request:send(Address, Request, Socket) of
742
?hcri("first request sent", []),
866
?hcrd("first request sent", []),
744
httpc_request:is_client_closing(
745
Request#request.headers),
868
httpc_request:is_client_closing(Headers),
746
869
SessionType = httpc_manager:session_type(Options),
748
#tcp_session{id = {Request#request.address, self()},
749
scheme = Request#request.scheme,
871
#tcp_session{id = {OrigAddress, self()},
751
874
client_close = ClientClose,
753
TmpState = State#state{request = Request,
755
mfa = init_mfa(Request, State),
757
init_status_line(Request),
761
http_transport:setopts(SocketType,
762
Socket, [{active, once}]),
877
State#state{request = Request,
879
mfa = init_mfa(Request, State),
880
status_line = init_status_line(Request),
884
?hcrt("activate socket", []),
885
activate_once(Session),
763
886
NewState = activate_request_timeout(TmpState),
767
%% Commented out in wait of ssl support to avoid
769
%%case State#state.status of
770
%% new -> % Called from init/1
771
self() ! {init_error, error_sending,
772
httpc_response:error(Request, Reason)},
773
{ok, State#state{request = Request,
775
#tcp_session{socket = Socket}}}
776
%%ssl_tunnel -> % Not called from init/1
778
%% answer_request(Request,
779
%%httpc_response:error(Request,
782
%% {stop, normal, NewState}
890
?hcrv("failed sending request", [{reason, Reason}]),
891
Error = {error, {send_failed,
892
httpc_response:error(Request, Reason)}},
893
{stop, Error, State#state{request = Request}}
787
%% Commented out in wait of ssl support to avoid
789
%% case State#state.status of
790
%% new -> % Called from init/1
791
self() ! {init_error, error_connecting,
792
httpc_response:error(Request, Reason)},
793
{ok, State#state{request = Request}}
794
%% ssl_tunnel -> % Not called from init/1
796
%% answer_request(Request,
797
%% httpc_response:error(Request,
800
%% {stop, normal, NewState}
897
?hcri("connect failed", [{reason, Reason}]),
898
Error = {error, {connect_failed,
899
httpc_response:error(Request, Reason)}},
900
{stop, Error, State#state{request = Request}}
904
handler_info(#state{request = Request,
906
status_line = _StatusLine,
908
keep_alive = KeepAlive,
910
canceled = _Canceled,
912
timers = _Timers} = _State) ->
914
?hcrt("handler info", [{request, Request},
916
{pipeline, Pipeline},
917
{keep_alive, KeepAlive},
920
%% Info about the current request
926
started = ReqStarted} ->
927
[{id, Id}, {started, ReqStarted}]
930
?hcrt("handler info", [{request_info, RequestInfo}]),
932
%% Info about the current session/socket
933
SessionType = Session#tcp_session.type,
934
QueueLen = case Session#tcp_session.type of
940
Socket = Session#tcp_session.socket,
941
Scheme = Session#tcp_session.scheme,
942
SocketType = socket_type(Scheme),
944
?hcrt("handler info", [{session_type, SessionType},
945
{queue_length, QueueLen},
947
{socket_type, SocketType},
950
SocketOpts = http_transport:getopts(SocketType, Socket),
951
SocketStats = http_transport:getstat(SocketType, Socket),
953
Remote = http_transport:peername(SocketType, Socket),
954
Local = http_transport:sockname(SocketType, Socket),
956
?hcrt("handler info", [{remote, Remote},
958
{socket_opts, SocketOpts},
959
{socket_stats, SocketStats}]),
961
SocketInfo = [{remote, Remote},
963
{socket_opts, SocketOpts},
964
{socket_stats, SocketStats}],
967
[{type, SessionType},
968
{queue_length, QueueLen},
970
{socket_info, SocketInfo}],
973
{current_request, RequestInfo},
974
{session, SessionInfo}].
804
978
handle_http_msg({Version, StatusCode, ReasonPharse, Headers, Body},
805
979
State = #state{request = Request}) ->
806
?hcrt("handle_http_msg", [{body, Body}]),
980
?hcrt("handle_http_msg", [{headers, Headers}]),
807
981
case Headers#http_response_h.'content-type' of
808
982
"multipart/byteranges" ++ _Param ->
809
exit(not_yet_implemented);
983
exit({not_yet_implemented, multypart_byteranges});
811
StatusLine = {Version, StatusCode, ReasonPharse},
985
StatusLine = {Version, StatusCode, ReasonPharse},
812
986
{ok, NewRequest} = start_stream(StatusLine, Headers, Request),
813
987
handle_http_body(Body,
814
988
State#state{request = NewRequest,
815
989
status_line = StatusLine,
816
990
headers = Headers})
818
handle_http_msg({ChunkedHeaders, Body},
819
State = #state{headers = Headers}) ->
820
?hcrt("handle_http_msg", [{chunked_headers, ChunkedHeaders}, {body, Body}]),
992
handle_http_msg({ChunkedHeaders, Body}, #state{headers = Headers} = State) ->
993
?hcrt("handle_http_msg",
994
[{chunked_headers, ChunkedHeaders}, {headers, Headers}]),
821
995
NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders),
822
996
handle_response(State#state{headers = NewHeaders, body = Body});
823
handle_http_msg(Body, State = #state{status_line = {_,Code, _}}) ->
824
?hcrt("handle_http_msg", [{body, Body}, {code, Code}]),
825
{NewBody, NewRequest}= stream(Body, State#state.request, Code),
997
handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
998
?hcrt("handle_http_msg", [{code, Code}]),
999
{NewBody, NewRequest} = stream(Body, State#state.request, Code),
826
1000
handle_response(State#state{body = NewBody, request = NewRequest}).
828
1002
handle_http_body(<<>>, State = #state{status_line = {_,304, _}}) ->
896
%%% Normaly I do not comment out code, I throw it away. But this might
897
%%% actually be used on day if ssl is improved.
898
%% handle_response(State = #state{status = ssl_tunnel,
899
%% request = Request,
900
%% options = Options,
901
%% session = #tcp_session{socket = Socket,
903
%% status_line = {_, 200, _}}) ->
904
%% %%% Insert code for upgrading the socket if and when ssl supports this.
905
%% Address = handle_proxy(Request#request.address, Options#options.proxy),
906
%% send_first_request(Address, Request, State);
907
%% handle_response(State = #state{status = ssl_tunnel,
908
%% request = Request}) ->
909
%% NewState = answer_request(Request,
910
%% httpc_response:error(Request,
911
%% ssl_proxy_tunnel_failed),
913
%% {stop, normal, NewState};
915
handle_response(State = #state{status = new}) ->
916
handle_response(try_to_enable_pipeline_or_keep_alive(State));
918
handle_response(State =
919
#state{request = Request,
1077
handle_response(#state{status = new} = State) ->
1078
?hcrd("handle response - status = new", []),
1079
handle_response(try_to_enable_pipeline_or_keep_alive(State));
1081
handle_response(#state{request = Request,
920
1082
status = Status,
921
1083
session = Session,
922
1084
status_line = StatusLine,
923
1085
headers = Headers,
925
1087
options = Options,
926
profile_name = ProfileName}) when Status =/= new ->
927
?hcrt("handle response", [{status, Status}, {session, Session}, {status_line, StatusLine}, {profile_name, ProfileName}]),
1088
profile_name = ProfileName} = State)
1089
when Status =/= new ->
1091
?hcrd("handle response", [{profile, ProfileName},
1095
{status_line, StatusLine}]),
928
1097
handle_cookies(Headers, Request, Options, ProfileName),
929
1098
case httpc_response:result({StatusLine, Headers, Body}, Request) of
1101
?hcrd("handle response - continue", []),
932
1102
%% Send request body
933
1103
{_, RequestBody} = Request#request.content,
934
1104
http_transport:send(socket_type(Session#tcp_session.scheme),
935
1105
Session#tcp_session.socket,
937
1107
%% Wait for next response
938
http_transport:setopts(socket_type(Session#tcp_session.scheme),
939
Session#tcp_session.socket,
1108
activate_once(Session),
941
1109
Relaxed = (Request#request.settings)#http_options.relaxed,
943
State#state{mfa = {httpc_response, parse,
944
[State#state.max_header_size,
946
status_line = undefined,
1110
MFA = {httpc_response, parse,
1111
[State#state.max_header_size, Relaxed]},
1112
{noreply, State#state{mfa = MFA,
1113
status_line = undefined,
1114
headers = undefined,
950
1117
%% Ignore unexpected 100-continue response and receive the
951
1118
%% actual response that the server will send right away.
952
1119
{ignore, Data} ->
1120
?hcrd("handle response - ignore", [{data, Data}]),
953
1121
Relaxed = (Request#request.settings)#http_options.relaxed,
954
NewState = State#state{mfa =
955
{httpc_response, parse,
956
[State#state.max_header_size,
1122
MFA = {httpc_response, parse,
1123
[State#state.max_header_size, Relaxed]},
1124
NewState = State#state{mfa = MFA,
958
1125
status_line = undefined,
1126
headers = undefined,
961
1128
handle_info({httpc_handler, dummy, Data}, NewState);
962
1130
%% On a redirect or retry the current request becomes
963
1131
%% obsolete and the manager will create a new request
964
1132
%% with the same id as the current.
965
1133
{redirect, NewRequest, Data} ->
966
?hcrt("handle response - redirect", [{new_request, NewRequest}, {data, Data}]),
1134
?hcrt("handle response - redirect",
1135
[{new_request, NewRequest}, {data, Data}]),
967
1136
ok = httpc_manager:redirect_request(NewRequest, ProfileName),
968
1137
handle_queue(State#state{request = undefined}, Data);
969
1138
{retry, TimeNewRequest, Data} ->
970
?hcrt("handle response - retry", [{time_new_request, TimeNewRequest}, {data, Data}]),
1139
?hcrt("handle response - retry",
1140
[{time_new_request, TimeNewRequest}, {data, Data}]),
971
1141
ok = httpc_manager:retry_request(TimeNewRequest, ProfileName),
972
1142
handle_queue(State#state{request = undefined}, Data);
973
1143
{ok, Msg, Data} ->
974
?hcrt("handle response - result ok", [{msg, Msg}, {data, Data}]),
1144
?hcrd("handle response - ok", []),
975
1145
end_stream(StatusLine, Request),
976
1146
NewState = answer_request(Request, Msg, State),
977
1147
handle_queue(NewState, Data);
979
?hcrt("handle response - result stop", [{msg, Msg}]),
1149
?hcrd("handle response - stop", [{msg, Msg}]),
980
1150
end_stream(StatusLine, Request),
981
1151
NewState = answer_request(Request, Msg, State),
982
1152
{stop, normal, NewState}
991
1161
handle_cookies(Headers, Request, #options{cookies = enabled}, ProfileName) ->
992
1162
{Host, _ } = Request#request.address,
993
Cookies = http_cookie:cookies(Headers#http_response_h.other,
1163
Cookies = httpc_cookie:cookies(Headers#http_response_h.other,
994
1164
Request#request.path, Host),
995
1165
httpc_manager:store_cookies(Cookies, Request#request.address,
998
1168
%% This request could not be pipelined or used as sequential keept alive
1000
handle_queue(State = #state{status = close}, _) ->
1170
handle_queue(#state{status = close} = State, _) ->
1001
1171
{stop, normal, State};
1003
handle_queue(State = #state{status = keep_alive}, Data) ->
1173
handle_queue(#state{status = keep_alive} = State, Data) ->
1004
1174
handle_keep_alive_queue(State, Data);
1006
handle_queue(State = #state{status = pipeline}, Data) ->
1176
handle_queue(#state{status = pipeline} = State, Data) ->
1007
1177
handle_pipeline(State, Data).
1009
handle_pipeline(State =
1010
#state{status = pipeline, session = Session,
1179
handle_pipeline(#state{status = pipeline,
1011
1181
profile_name = ProfileName,
1012
options = #options{pipeline_timeout = TimeOut}},
1182
options = #options{pipeline_timeout = TimeOut}} =
1186
?hcrd("handle pipeline", [{profile, ProfileName},
1188
{timeout, TimeOut}]),
1014
1190
case queue:out(State#state.pipeline) of
1192
?hcrd("epmty pipeline queue", []),
1016
1194
%% The server may choose too teminate an idle pipeline
1017
1195
%% in this case we want to receive the close message
1018
1196
%% at once and not when trying to pipeline the next
1020
http_transport:setopts(socket_type(Session#tcp_session.scheme),
1021
Session#tcp_session.socket,
1198
activate_once(Session),
1023
1200
%% If a pipeline that has been idle for some time is not
1024
1201
%% closed by the server, the client may want to close it.
1025
NewState = activate_queue_timeout(TimeOut, State),
1202
NewState = activate_queue_timeout(TimeOut, State),
1026
1203
NewSession = Session#tcp_session{queue_length = 0},
1027
1204
httpc_manager:insert_session(NewSession, ProfileName),
1028
1205
%% Note mfa will be initilized when a new request
1031
NewState#state{request = undefined,
1208
NewState#state{request = undefined,
1033
1210
status_line = undefined,
1034
headers = undefined,
1211
headers = undefined,
1038
1213
{{value, NextRequest}, Pipeline} ->
1039
1214
case lists:member(NextRequest#request.id,
1040
1215
State#state.canceled) of
1217
?hcrv("next request had been cancelled", []),
1042
1218
%% See comment for handle_cast({cancel, RequestId})
1044
1220
State#state{request =
1045
1221
NextRequest#request{from = answer_sent}}};
1223
?hcrv("next request", [{request, NextRequest}]),
1048
1225
Session#tcp_session{queue_length =
1049
1226
%% Queue + current