Error reports in Erlang
Question
I've taken the cowboy example code and brooken it.
The code for the default request handler looked like this:
-module(default_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({_Any, http}, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
{ok, Req2} = cowboy_http_req:reply(200, [], <<"Hello world!">>, Req),
{ok, Req2, State}.
terminate(_Req, _State) ->
ok.
its straight forward, but I wanted to make return files so I changed it to:
-module(default_handler).
-behaviour(cowboy_http_handler).
-export([init/3, handle/2, terminate/2]).
init({_Any, http}, Req, []) ->
{ok, Req, undefined}.
handle(Req, State) ->
try
{Path, Req1} = cowboy_http_req:path(Req),
{ok, File} = file:read_file(Path),
cowboy_http_req:reply(200, [], File, Req1)
of
{ok, Req2} ->
{ok, Req2, State}
catch
_ ->
{ok, Req3} = cowboy_http_req:reply(200, [], <<"Hello world!">>, Req),
{ok, Req3, State}
end.
terminate(_Req, _State) ->
ok.
The try-catch thing should handle the fact that there might not be a file, but it does not. Why is that?
When I try to fetch a file that is not there I get a large error report in the console, can anyone tell me why?
=ERROR REPORT==== 15-Jun-2012::14:24:54 ===
** Handler default_handler terminating in handle/2
for the reason error:{badmatch,{error,badarg}}
** Options were []
** Handler state was undefined
** Request was [{socket,#Port<0.1515>},
{transport,cowboy_tcp_transport},
{connection,keepalive},
{pid,<0.1175.0>},
{method,'GET'},
{version,{1,1}},
{peer,undefined},
{host,[<<"localhost">>]},
{host_info,undefined},
{raw_host,<<"localhost">>},
{port,8080},
{path,[<<"favicon.ico">>]},
{path_info,undefined},
{raw_path,<<"/favicon.ico">>},
{qs_vals,undefined},
{raw_qs,<<>>},
{bindings,[]},
{headers,
[{'Accept-Charset',<<"ISO-8859-1,utf-8;q=0.7,*;q=0.3">>},
{'Accept-Language',<<"en-US,en;q=0.8">>},
{'Accept-Encoding',<<"gzip,deflate,sdch">>},
{'User-Agent',
<<"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/535.19 (KHTML, like Gecko) Ubuntu/10.10 Chromium/18.0.1025.151 Chrome/18.0.1025.151 Safari/535.19">>},
{'Accept',<<"*/*">>},
{'Connection',<<"keep-alive">>},
{'Host',<<"localhost">>}]},
{p_headers,[{'Connection',[<<"keep-alive">>]}]},
{cookies,undefined},
{meta,[]},
{body_state,waiting},
{buffer,<<>>},
{resp_state,waiting},
{resp_headers,[]},
{resp_body,<<>>},
{onresponse,undefined},
{urldecode,{#Fun<cowboy_http.urldecode.2>,crash}}]
** Stacktrace: [{default_handler,handle,2,
[{file,"src/default_handler.erl"},{line,13}]},
{cowboy_http_protocol,handler_handle,3,
[{file,"src/cowboy_http_protocol.erl"},
{line,298}]}]
Solution
This line:
{Path, Req1} = cowboy_http_req:path(Req),
Actually returns a list of binaries, like [<<"path">>,<<"path2">>] instead of something like "/path/path2" which should be what you're actually looking for.
So, to form the filesystem path:
{Path, Req1} = cowboy_http_req:path(Req),
FsPath = lists:foldl(
fun(PathComponent, Acc) ->
string:join([Acc, erlang:binary_to_list(PathComponent)], "/")
end,
"",
Path
),
{ok, File} = file:read_file(FsPath),
(The badarg error you're getting is because the argument to file:read_file/1 is not a string (a list) but a list of binaries, which is not the expected argument.
And the catch needs a _:_ clause, just like Harald answer states.
Cheers.
OTHER TIPS
probably because of how it evaluates the catch clause, see http://www.erlang.org/doc/reference_manual/expressions.html#try
If an exception occurs during evaluation of Exprs but there is no matching ExceptionPattern of the right Class with a true guard sequence, the exception is passed on as if Exprs had not been enclosed in a try expression.
You need to specify an error class (error, throw or exit) if not looking for the default, which is throw.
try Exprs of
Pattern1 [when GuardSeq1] ->
Body1;
...;
PatternN [when GuardSeqN] ->
BodyN
catch
[Class1:]ExceptionPattern1 [when ExceptionGuardSeq1] ->
ExceptionBody1;
...;
[ClassN:]ExceptionPatternN [when ExceptionGuardSeqN] ->
ExceptionBodyN
a catch-all-errors would be written as
catch
_:_ ->
notice how you specify both class and ExpressionPattern as "don't care".
Hope this helps because I only 'dabbled' in erlang until now. :)