From 0b423eb28756e88895ecb7dcf7cbf71d7cbf1571 Mon Sep 17 00:00:00 2001 From: Alexey Shchepin Date: Wed, 7 Mar 2012 16:19:59 +0200 Subject: [PATCH] Don't ignore Length parameter in tls:recv --- src/tls/tls.erl | 33 ++++++++++++++----------- src/tls/tls_drv.c | 13 ++++++++-- src/web/ejabberd_http.erl | 52 +++++++++++++++------------------------ 3 files changed, 50 insertions(+), 48 deletions(-) diff --git a/src/tls/tls.erl b/src/tls/tls.erl index dfb9d2306..e4184a09a 100644 --- a/src/tls/tls.erl +++ b/src/tls/tls.erl @@ -32,7 +32,7 @@ -export([start/0, start_link/0, tcp_to_tls/2, tls_to_tcp/1, send/2, - recv/2, recv/3, recv_data/2, + recv/2, recv/3, setopts/2, sockname/1, peername/1, controlling_process/2, @@ -160,29 +160,34 @@ tls_to_tcp(#tlssock{tcpsock = TCPSocket, tlsport = Port}) -> recv(Socket, Length) -> recv(Socket, Length, infinity). -recv(#tlssock{tcpsock = TCPSocket} = TLSSock, - _Length, Timeout) -> - %% The Length argument cannot be used for gen_tcp:recv/3, because the - %% compressed size does not equal the desired uncompressed one. - case gen_tcp:recv(TCPSocket, 0, Timeout) of - {ok, Packet} -> - recv_data(TLSSock, Packet); - {error, _Reason} = Error -> - Error +recv(#tlssock{tcpsock = TCPSocket, tlsport = Port} = TLSSock, + Length, Timeout) -> + case port_control(Port, ?GET_DECRYPTED_INPUT, <>) of + <<0>> -> + case gen_tcp:recv(TCPSocket, 0, Timeout) of + {ok, Packet} -> + recv_data(TLSSock, Packet, Length); + {error, _Reason} = Error -> + Error + end; + <<0, In/binary>> -> + {ok, In}; + <<1, Error/binary>> -> + {error, binary_to_list(Error)} end. -recv_data(TLSSock, Packet) -> - case catch recv_data1(TLSSock, Packet) of +recv_data(TLSSock, Packet, Length) -> + case catch recv_data1(TLSSock, Packet, Length) of {'EXIT', Reason} -> {error, Reason}; Res -> Res end. -recv_data1(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet) -> +recv_data1(#tlssock{tcpsock = TCPSocket, tlsport = Port}, Packet, Length) -> case port_control(Port, ?SET_ENCRYPTED_INPUT, Packet) of <<0>> -> - case port_control(Port, ?GET_DECRYPTED_INPUT, []) of + case port_control(Port, ?GET_DECRYPTED_INPUT, <>) of <<0, In/binary>> -> case port_control(Port, ?GET_ENCRYPTED_OUTPUT, []) of <<0, Out/binary>> -> diff --git a/src/tls/tls_drv.c b/src/tls/tls_drv.c index 40295d7a3..60a51174d 100644 --- a/src/tls/tls_drv.c +++ b/src/tls/tls_drv.c @@ -434,13 +434,22 @@ static ErlDrvSSizeT tls_drv_control(ErlDrvData handle, "SSL_do_handshake failed"); } if (SSL_is_init_finished(d->ssl)) { + size_t req_size = 0; + if (len == 4) + { + req_size = + (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + } size = BUF_SIZE + 1; rlen = 1; b = driver_alloc_binary(size); b->orig_bytes[0] = 0; - while ((res = SSL_read(d->ssl, - b->orig_bytes + rlen, BUF_SIZE)) > 0) + while ((req_size == 0 || rlen < req_size + 1) && + (res = SSL_read(d->ssl, + b->orig_bytes + rlen, + (req_size == 0 || req_size + 1 >= size) ? + size - rlen : req_size + 1 - rlen)) > 0) { //printf("%d bytes of decrypted data read from state machine\r\n",res); rlen += res; diff --git a/src/web/ejabberd_http.erl b/src/web/ejabberd_http.erl index aff928f72..fab09782a 100644 --- a/src/web/ejabberd_http.erl +++ b/src/web/ejabberd_http.erl @@ -192,38 +192,30 @@ receive_headers(State) -> _ -> case Data of {ok, Binary} -> - process_requests(State, binary_to_list(Binary)); + {Request, Trail} = parse_request( + State, + State#state.trail ++ binary_to_list(Binary)), + State1 = State#state{trail = Trail}, + NewState = lists:foldl( + fun(D, S) -> + case S#state.end_of_request of + true -> + S; + _ -> + process_header(S, D) + end + end, State1, Request), + case NewState#state.end_of_request of + true -> + ok; + _ -> + receive_headers(NewState) + end; _ -> ok end end. -process_requests(State, Data) -> - {Request, Trail} = parse_request( - State, - State#state.trail ++ Data), - State1 = State#state{trail = Trail}, - NewState = lists:foldl( - fun(D, S) -> - case S#state.end_of_request of - true -> - S; - _ -> - process_header(S, D) - end - end, State1, Request), - case State1#state.trail of - [] -> - case NewState#state.end_of_request of - true -> - ok; - _ -> - receive_headers(NewState) - end; - _ -> - process_requests(State1, "") - end. - process_header(State, Data) -> SockMod = State#state.sockmod, Socket = State#state.socket, @@ -599,11 +591,7 @@ recv_data(_State, 0, Acc) -> recv_data(State, Len, Acc) -> case State#state.trail of [] -> - Len2 = case State#state.sockmod of - gen_tcp -> Len; - _ -> 0 - end, - case (State#state.sockmod):recv(State#state.socket, Len2, 300000) of + case (State#state.sockmod):recv(State#state.socket, Len, 300000) of {ok, Data} -> recv_data(State, Len - size(Data), [Acc | [Data]]); _ ->