[erlang-questions] try catch scope

25 views
Skip to first unread message

Wes James

unread,
Jun 29, 2010, 5:21:12 PM6/29/10
to erlang-q...@erlang.org
What is the scope of try/catch.

I changed the code:

has_query(A) ->
case length(yaws_api:parse_query(A)) of
0 -> false;
_ -> true
end.
to this

has_query(A) ->
try
case length(yaws_api:parse_query(A)) of
0 -> false;
_ -> true
end
catch
_ -> false
end.


because if a user puts in an invalid character in the URL it crashes
parse_query and I want the app to continue without erroring out in the
browser.

Is this because of the level of the error?

For instance if you have the url http://localhost/app?var1=foo1%var2=foo2

in parse_query it tries to do a list_to_integer of "va" with var2
based on how it parses the args list and you can't do that since "va"
doesn't produce a valid integer. Would the try need to be at the
level of the list_to_integer call?

thx,

-wes

________________________________________________________________
erlang-questions (at) erlang.org mailing list.
See http://www.erlang.org/faq.html
To unsubscribe; mailto:erlang-questio...@erlang.org

Sergey Samokhin

unread,
Jun 29, 2010, 5:46:07 PM6/29/10
to Wes James, erlang-q...@erlang.org
> has_query(A) ->
>        try
>                case length(yaws_api:parse_query(A)) of
>                        0  -> false;
>                        _ -> true
>                end
>        catch
>                _ -> false
>        end.

For this function to catch exceptions of all possible types (error,
exit and throw) you need to use "_:_" pattern instead of just "_"
(which will catch only 'throw' exceptions):

has_query(A) ->
try
case length(yaws_api:parse_query(A)) of
0 -> false;
_ -> true
end
catch

_:_ -> false % <----- Here "_" has been replaced by "_:_"
end.

--
Sergey Samokhin

Jesper Louis Andersen

unread,
Jun 29, 2010, 5:53:04 PM6/29/10
to Wes James, erlang-q...@erlang.org
On Tue, Jun 29, 2010 at 11:21 PM, Wes James <comp...@gmail.com> wrote:
> What is the scope of try/catch.
> has_query(A) ->
>        try
>                case length(yaws_api:parse_query(A)) of

[...]

> because if a user puts in an invalid character in the URL it crashes
> parse_query and I want the app to continue without erroring out in the
> browser.
>
> Is this because of the level of the error?

Yes (is my guess), see
http://www.erlang.org/doc/reference_manual/expressions.html#id2276021
on the try..catch construction. Since you omit the class, it is
defaulted to 'throw'. I would personally regard that as an error in
the interface of parse_query. My solution would be something akin to

safe_parse_query(A) ->
try
Q = yaws_api:parse_query(A),
{ok, Q}
catch
error:_ -> no_parse % You should really narrow down the class and
the error Reason to the right type here. I may be wrong.
end.

which transforms the function into a variant which is safer:

has_query(A) ->
case yaws_api:parse_query(A) of
no_parse -> false;
{ok, Q} when length(Q) == 0 -> false;
{ok, Q} -> true
end.

alternatively, no_parse can be an empty list, if you so want.

(Caveat: I only wrote the code and did not test it).

--
J.

Wes James

unread,
Jun 29, 2010, 6:17:02 PM6/29/10
to erlang-q...@erlang.org
Thank you Sergey and Jesper for your responses. I went back and looked at:

http://www.erlang.org/doc/reference_manual/expressions.html#id2275780
and
http://www.erlang.org/doc/reference_manual/errors.html

to see how _:_ works. There is no mention of this on these pages. Is
_:_ the same as {_,_}? Is there a doc on what _:_ is?

thx, again,

-wes

Robert Virding

unread,
Jun 29, 2010, 7:35:45 PM6/29/10
to Wes James, erlang-q...@erlang.org
No _:_ is *NOT* the same as {_,_}. It is a special pattern which can
only be used in the catch part of a try. There you can give
[Class1:]ExceptionPattern1 as a pattern to match which class of
exception to match and also which exception. Writing _:_ here means
that you match all classes and all exceptions, i.e. you catch
everything.

Calling throw an exception is not really correct in my opinion as it
doesn't really signify an error but is a non-local return. At least
that is how it was intended to be used. Try might actually be too
powerful.

Robert

Magnus Henoch

unread,
Jun 30, 2010, 7:53:30 AM6/30/10
to erlang-q...@erlang.org
Wes James <comp...@gmail.com> writes:

> has_query(A) ->
> case length(yaws_api:parse_query(A)) of
> 0 -> false;
> _ -> true
> end.

A separate note about the code: you should avoid "case length(Foo)" when
possible, since length/1 needs to traverse the entire list. Just
comparing the result to the empty list is probably faster:

case yaws_api:parse_query(A) of
[] -> false;
_ -> true
end.

And this can be simplified further:

yaws_api:parse_query(A) /= [].

(There is a difference between my two examples and yours: your code will
crash with badarg if the result is not a proper list, while mine will
just return false.)

--
Magnus Henoch, mag...@erlang-solutions.com
Erlang Solutions
http://www.erlang-solutions.com/

Wes James

unread,
Jun 30, 2010, 9:33:39 AM6/30/10
to erlang-q...@erlang.org
Mangus,

Thanks! This is much better!

has_query(A) ->
try
yaws_api:parse_query(A) /= []


catch
_:_ -> false

end.

-wes

Raimo Niskanen

unread,
Jun 30, 2010, 10:17:31 AM6/30/10
to Wes James, erlang-q...@erlang.org
On Wed, Jun 30, 2010 at 07:33:39AM -0600, Wes James wrote:
> Mangus,
>
> Thanks! This is much better!
>
> has_query(A) ->
> try
> yaws_api:parse_query(A) /= []
> catch
> _:_ -> false
> end.
>
> -wes

This might be even clearer (separating the right and wrong cases):

has_query(A) ->
try yaws_api:parse_query(A) of
[] -> false;
_ -> true % Were you supposed to return true for this case?
catch
error:_ -> false % Only cathes runtime errors, not exit/1.
end.

--

/ Raimo Niskanen, Erlang/OTP, Ericsson AB

Wes James

unread,
Jun 30, 2010, 6:43:31 PM6/30/10
to erlang-q...@erlang.org
On Wed, Jun 30, 2010 at 8:17 AM, Raimo Niskanen
<raimo+erlan...@erix.ericsson.se> wrote:
> On Wed, Jun 30, 2010 at 07:33:39AM -0600, Wes James wrote:
>> Mangus,
>>
>> Thanks! This is much better!
>>
>> has_query(A) ->
>>       try
>>               yaws_api:parse_query(A) /= []
>>       catch
>>               _:_ -> false
>>       end.
>>
>> -wes
>
> This might be even clearer (separating the right and wrong cases):
>
> has_query(A) ->
>    try yaws_api:parse_query(A) of
>        [] -> false;
>        _ -> true % Were you supposed to return true for this case?
>    catch
>        error:_ -> false % Only cathes runtime errors, not exit/1.
>    end.
>


Thanks. This works too. Bottom line, is I want to show the default
search page even if the parse_query call throws an error. Maybe
someone is trying to insert bad chars or such in to the URL to try to
reveal something or even hack the system, etc.

thx,

-wes

Reply all
Reply to author
Forward
0 new messages