ninenines / cowboy

Small, fast, modern HTTP server for Erlang/OTP.
https://ninenines.eu
ISC License
7.26k stars 1.16k forks source link

Constraints error: badarity #1358

Closed 7stud closed 5 years ago

7stud commented 5 years ago

I'm using cowboy 2.6.1:

Makefile:

PROJECT = hello_erlang
PROJECT_DESCRIPTION = New project
PROJECT_VERSION = 0.1.0

DEPS = cowboy
#dep_cowboy_commit = master
dep_cowboy_commit = 2.6.1

DEP_PLUGINS = cowboy

include erlang.mk

Here's the error:

=ERROR REPORT==== 19-Feb-2019::13:52:35 ===
Ranch listener my_http_listener, connection process <0.415.0>, stream 1 had its request process  
 <0.416.0> exit with reason {badarity,{#Fun<hello_erlang_app.0.73248188>,[2]}} and stacktrace   
[{cowboy_constraints,apply_constraint,2,[{file,"src/cowboy_constraints.erl"},{line,50}]},   
 {cowboy_constraints,validate_list,3,[{file,"src/cowboy_constraints.erl"},{line,35}]},    
{cowboy_router,check_constraints,2,[{file,"src/cowboy_router.erl"},{line,282}]}, 
 {cowboy_router,match_path,4,[{file,"src/cowboy_router.erl"},{line,261}]},{cowboy_router,execute,2,
[{file,"src/cowboy_router.erl"},{line,163}]},{cowboy_stream_h,execute,3,
[{file,"src/cowboy_stream_h.erl"},{line,178}]},{cowboy_stream_h,proc_lib_hack,3,
[{file,"src/cowboy_stream_h.erl"},{line,163}]},{proc_lib,init_p_do_apply,3,[{file,"proc_lib.erl"},{line,247}]}]

Here's my route:

hello_erlang_app.erl:

-module(hello_erlang_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).
-export([positive_fun/2]).

positive_fun(forward, Value) when Value > 0 -> 
    {ok, Value};
positive_fun(forward, _) ->
    {error, not_positive}.
%positive_fun(format_error, {not_positive, Value}) ->
%   io_lib:format("The value ~p is not an integer.", [Value]).

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [

               { "/get/:id", 
                 [  { id, [int, fun positive_fun/2] } ],
                 id_handler, 
                 []
               } ,

               {"/[...]", no_matching_route_handler, []}

        ]}
    ]),

    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch} }
    ),

    hello_erlang_sup:start_link().

stop(_State) ->
    ok.

The url I entered in my browser:

http://localhost:8080/get/2

id_handler.erl:

-module(id_handler).
-behavior(cowboy_handler).
-export([init/2]).

init(Req0, State) -> %State comes from last argument of route
    Id = cowboy_req:binding(id, Req0),
    Reply = io_lib:format("Hello Erlang~nId=~w~n", [Id]),

    Req = cowboy_req:reply(200,
        #{<<"content-type">> => <<"text/plain">>},
        Reply,
        Req0),

    {ok, Req, State}.

no_matching_router_handler.erl:

-module(no_matching_route_handler).
-behavior(cowboy_handler).

-export([init/2]).

init(Req0, State) -> %State comes from last argument of route
    Req = cowboy_req:reply(404,
        #{<<"content-type">> => <<"text/plain">>},
        <<"[ME] 404. Whoops! (No matching route!)">>,
        Req0),
    {ok, Req, State}.

If I change the arity of the constraint function to 1:

-module(hello_erlang_app).
-behaviour(application).

-export([start/2]).
-export([stop/1]).
-export([positive_fun/1]).

positive_fun(Value) ->   %% <<<====== HERE
    Value > 0.

start(_Type, _Args) ->
    Dispatch = cowboy_router:compile([
        {'_', [

               { "/get/:id", 
                 [  { id, [int, fun positive_fun/1] } ],
                 id_handler, 
                 []
               }, 

               {"/[...]", no_matching_route_handler, []}

        ]}
    ]),

    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch} }
    ),

    hello_erlang_sup:start_link().

stop(_State) ->
    ok.

....then everything works as expected:

1) When I enter the url http://localhost:8080/get/4 in my browser, I see the response:

Hello Erlang
Id=4

2) When I enter the url http://localhost:8080/get/-10 in my browser, I see the response:

[ME] 404. Whoops! (No matching route!)

I don't get it??! The Constraint docs only show constraint functions with arity 2, for example:

PositiveFun = fun
    (_, V) when V > 0 ->
        {ok, V};
    (_, _) ->
        {error, not_positive}
end,
{my_value, [int, PositiveFun]}.

And the Constraint docs say:

Custom constraints are specified as a fun. This fun takes two arguments. The first argument indicates the operation to be performed, and the second is the value.

Also, how do you modify the value, e.g. by adding 1 to it, rather than matching or not matching the route like my postive_fun/1 does? I searched through the source code for the built in int constraint function to see how it was implemented, but I was unable to find it.

Startup info:

~/erlang_programs/cowboy_apps/hello_erlang$ make run
erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
 GEN    rebar.config
 DEPEND hello_erlang.d
erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
 ERLC   id_handler.erl
 APP    hello_erlang
===> Starting relx build process ...
===> Resolving OTP Applications from directories:
          /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/ebin
          /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps
          /Users/7stud/.asdf/installs/erlang/20.3/lib
          /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps
          /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel
===> Resolved hello_erlang_release-1
===> rendering builtin_hook_status hook to "/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/bin/hooks/builtin/status"
===> Including Erts from /Users/7stud/.asdf/installs/erlang/20.3
===> release successfully created!
===> tarball /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/hello_erlang_release-1.tar.gz successfully created!
Exec: /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/erts-9.3/bin/erlexec -boot /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/releases/1/hello_erlang_release -mode embedded -boot_var ERTS_LIB_DIR /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/lib -config /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/releases/1/sys.config -args_file /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/releases/1/vm.args -pa -- console
Root: /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release
heart_beat_kill_pid = 25238
Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]

=PROGRESS REPORT==== 19-Feb-2019::13:59:32 ===
          supervisor: {local,sasl_safe_sup}
             started: [{pid,<0.402.0>},
                       {id,alarm_handler},
                       {mfargs,{alarm_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 19-Feb-2019::13:59:32 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.401.0>},
                       {id,sasl_safe_sup},
                       {mfargs,
                           {supervisor,start_link,
                               [{local,sasl_safe_sup},sasl,safe]}},
                       {restart_type,permanent},
                       {shutdown,infinity},
                       {child_type,supervisor}]

=PROGRESS REPORT==== 19-Feb-2019::13:59:32 ===
          supervisor: {local,sasl_sup}
             started: [{pid,<0.403.0>},
                       {id,release_handler},
                       {mfargs,{release_handler,start_link,[]}},
                       {restart_type,permanent},
                       {shutdown,2000},
                       {child_type,worker}]

=PROGRESS REPORT==== 19-Feb-2019::13:59:32 ===
         application: sasl
          started_at: 'hello_erlang@127.0.0.1'

=PROGRESS REPORT==== 19-Feb-2019::13:59:32 ===
          supervisor: {local,runtime_tools_sup}
             started: [{pid,<0.409.0>},
                       {id,ttb_autostart},
                       {mfargs,{ttb_autostart,start_link,[]}},
                       {restart_type,temporary},
                       {shutdown,3000},
                       {child_type,worker}]

=PROGRESS REPORT==== 19-Feb-2019::13:59:32 ===
         application: runtime_tools
          started_at: 'hello_erlang@127.0.0.1'
Eshell V9.3  (abort with ^G)
(hello_erlang@127.0.0.1)1> 
essen commented 5 years ago

The stacktrace doesn't make sense, it seems like you could have a different cowboy_constraints module version than the one in 2.6.1 interfering. Perhaps you have something in ERL_LIBS that use Cowboy and it picks up the module from there?

7stud commented 5 years ago

The stacktrace doesn't make sense, it seems like you could have a different cowboy_constraints module version than the one in 2.6.1 interfering. Perhaps you have something in ERL_LIBS that use Cowboy and it picks up the module from there?

Thanks for taking a look.

All my environment variables are shown below. Here is what I have for ERL_LIBS:

"ERL_LIBS=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps:/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps"

The first directory doesn't exist:

~/erlang_programs/cowboy_apps/hello_erlang$ cd /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps
-bash: cd: /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps: No such file or directory

~/erlang_programs/cowboy_apps/hello_erlang$

Edit: Well, if I do the same thing in the cowboy shell, this is what I get:

(hello_erlang@127.0.0.1)1> cd("/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps").
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release
ok
(hello_erlang@127.0.0.1)2> ls().
bin                               erl_crash.dump                    
erts-8.2                          erts-9.3                          
hello_erlang_release-1.tar.gz     lib                               
log                               releases                          

ok

And, then:

(hello_erlang@127.0.0.1)3> cd("lib").
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/lib
ok

(hello_erlang@127.0.0.1)4> ls().
asn1-4.0.4               asn1-5.0.5               cowboy-2.0.0-pre.9       
cowlib-2.0.0-pre.1       crypto-3.7.2             crypto-4.2.1             
hello_erlang-0.1.0       kernel-5.1.1             kernel-5.4.3             
public_key-1.3           public_key-1.5.2         ranch-1.4.0              
runtime_tools-1.11       runtime_tools-1.12.5     sasl-3.0.2               
sasl-3.1.1               ssl-8.1                  ssl-8.2.4                
stdlib-3.2               stdlib-3.4.4             
ok

The cowboy version listed there is: cowboy-2.0.0-pre.9. But, there is also a cowboy directory (without a version) in the other directory shown in ERL_LIBS:

(hello_erlang@127.0.0.1)10> cd("/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps").    /Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps
ok
(hello_erlang@127.0.0.1)11> ls().
cowboy     cowlib     gun        ranch      
ok
(hello_erlang@127.0.0.1)12> cd(cowboy).
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps/cowboy
ok
(hello_erlang@127.0.0.1)13> ls().
.git                      .gitattributes            .gitignore                
CHANGELOG.md              CONTRIBUTING.asciidoc     LICENSE                   
README.asciidoc           cowboy.d                  doc                       
ebin                      erlang.mk                 examples                  
makefile                  makefile.bak              plugins.mk                
rebar.config              src                       test                      

ok
(hello_erlang@127.0.0.1)14> cd(src).
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps/cowboy/src
ok
(hello_erlang@127.0.0.1)15> ls().
cowboy.erl                  cowboy_app.erl              
cowboy_bstr.erl             cowboy_clear.erl            
cowboy_clock.erl            cowboy_compress_h.erl       
cowboy_constraints.erl      cowboy_handler.erl          
cowboy_http.erl             cowboy_http2.erl            
cowboy_iolists.erl          cowboy_loop.erl             
cowboy_middleware.erl       cowboy_req.erl              
cowboy_rest.erl             cowboy_router.erl           
cowboy_static.erl           cowboy_stream.erl           
cowboy_stream_h.erl         cowboy_sub_protocol.erl     
cowboy_sup.erl              cowboy_tls.erl              
cowboy_websocket.erl        
ok

(hello_erlang@127.0.0.1)17> os:cmd("cat cowboy.erl").
"%% Copyright (c) 2011-2017, Loïc Hoguin <essen@ninenines.eu>\n%%\n%% Permission to use, copy, modify, and/or distribute this software for any\n%% purpose with or without fee is hereby granted, provided that the above\n%% copyright notice and this permission notice appear in all copies.\n%%\n%% THE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\n%% WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\n%% MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR\n%% ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\n%% WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN\n%% ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF\n%% OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.\n\n-module(cowboy).\n\n-export([start_clear/3]).\n-export([start_tls/3]).\n-export([stop_listener/1]).\n-export([set_env/3]).\n\n%% @todo Detailed opts.\n-type opts() :: map().\n-export_type([opts/0]).\n\n-type fields() :: [atom()\n\t| {atom(), cowboy_constraints:constraint() | [cowboy_constraints:constraint()]}\n\t| {atom(), cowboy_constraints:constraint() | [cowboy_constraints:constraint()], any()}].\n-export_type([fields/0]).\n\n-type http_headers() :: #{binary() => iodata()}.\n-export_type([http_headers/0]).\n\n-type http_status() :: non_neg_integer() | binary().\n-export_type([http_status/0]).\n\n-type http_version() :: 'HTTP/2' | 'HTTP/1.1' | 'HTTP/1.0'.\n-export_type([http_version/0]).\n\n-spec start_clear(ranch:ref(), ranch_tcp:opts(), opts())\n\t-> {ok, pid()} | {error, any()}.\nstart_clear(Ref, TransOpts0, ProtoOpts0) ->\n\t{TransOpts, ConnectionType} = ensure_connection_type(TransOpts0),\n\tProtoOpts = ProtoOpts0#{connection_type => ConnectionType},\n\tranch:start_listener(Ref, ranch_tcp, TransOpts, cowboy_clear, ProtoOpts).\n\n-spec start_tls(ranch:ref(), ranch_ssl:opts(), opts())\n\t-> {ok, pid()} | {error, any()}.\nstart_tls(Ref, TransOpts0, ProtoOpts0) ->\n\t{TransOpts1, ConnectionType} = ensure_connection_type(TransOpts0),\n\tTransOpts = [\n\t\t{next_protocols_advertised, [<<\"h2\">>, <<\"http/1.1\">>]},\n\t\t{alpn_preferred_protocols, [<<\"h2\">>, <<\"http/1.1\">>]}\n\t|TransOpts1],\n\tProtoOpts = ProtoOpts0#{connection_type => ConnectionType},\n\tranch:start_listener(Ref, ranch_ssl, TransOpts, cowboy_tls, ProtoOpts).\n\nensure_connection_type(TransOpts) ->\n\tcase proplists:get_value(connection_type, TransOpts) of\n\t\tundefined -> {[{connection_type, supervisor}|TransOpts], supervisor};\n\t\tConnectionType -> {TransOpts, ConnectionType}\n\tend.\n\n-spec stop_listener(ranch:ref()) -> ok | {error, not_found}.\nstop_listener(Ref) ->\n\tranch:stop_listener(Ref).\n\n-spec set_env(ranch:ref(), atom(), any()) -> ok.\nset_env(Ref, Name, Value) ->\n\tOpts = ranch:get_protocol_options(Ref),\n\t{_, Env} = maps:find(env, Opts),\n\tOpts2 = maps:put(env, maps:put(Name, Value, Env), Opts),\n\tok = ranch:set_protocol_options(Ref, Opts2).\n"
(hello_erlang@127.0.0.1)18> 

What do I do to make my app use the correct cowboy version?? I though that is what the Makefile was for.

All environment variables:

(hello_erlang@127.0.0.1)1> SeparateLines = fun F([]) -> ok;                                 
(hello_erlang@127.0.0.1)1>                     F([H|T]) -> io:format("~p~n", [H]), F(T) end.
#Fun<erl_eval.30.99386804>
(hello_erlang@127.0.0.1)2> SeparateLines(lists:sort(os:getenv())).   

"ANDROID_SDK=/Users/7stud/Library/Android/sdk"
"APPS_DIR=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps"
"ASDF_DIR=/Users/7stud/.asdf"
"Apple_PubSub_Socket_Render=/private/tmp/com.apple.launchd.A8dplSuI7k/Render"
"BINDIR=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/erts-9.3/bin"
"DEPS_DIR=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps"
"DIALYZER_PLT=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/.hello_erlang.plt"
"EMU=beam"
"ERLANG_MK_FILENAME=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/erlang.mk"
"ERLANG_MK_TMP=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/.erlang.mk"
"ERL_AFLAGS=-kernel shell_history enabled"
"ERL_LIBS=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/apps:/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps"
"GEM_HOME=/Users/7stud/.rvm/gems/ruby-2.4.0"
"GEM_PATH=/Users/7stud/.rvm/gems/ruby-2.4.0:/Users/7stud/.rvm/gems/ruby-2.4.0@global"
"GOPATH=/Users/7stud/go_programs"
"HOME=/Users/7stud"
"IGNORE_DEPS="
"IRBRC=/Users/7stud/.rvm/rubies/ruby-2.4.0/.irbrc"
"JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.8.0_40.jdk/Contents/Home"
"LANG=en_US.UTF-8"
"LD_LIBRARY_PATH=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/erts-9.3/lib:"
"LOGNAME=7stud"
"MAKEFLAGS="
"MAKELEVEL=1"
"MANPATH=/opt/local/share/man:/Users/7stud/perl5/perlbrew/perls/perl-5.20.2/man:/Users/7stud/.nvm/versions/node/v11.2.0/share/man:/usr/local/share/man:/Library/Frameworks/Python.framework/Versions/2.7/share/man:/Library/Frameworks/Python.framework/Versions/3.4/share/man:/usr/share/man:/usr/local/MacGPG2/share/man:/usr/local/git/share/man:/Applications/Xcode.app/Contents/Developer/usr/share/man:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/share/man"
"MFLAGS="
"MY_RUBY_HOME=/Users/7stud/.rvm/rubies/ruby-2.4.0"
"NAME=hello_erlang@127.0.0.1"
"NO_AUTOPATCH="
"NVM_BIN=/Users/7stud/.nvm/versions/node/v11.2.0/bin"
"NVM_CD_FLAGS="
"NVM_DIR=/Users/7stud/.nvm"
"NVM_IOJS_ORG_MIRROR=https://iojs.org/dist"
"NVM_NODEJS_ORG_MIRROR=https://nodejs.org/dist"
"NVM_PATH=/Users/7stud/.nvm/versions/node/v11.2.0/lib/node"
"OLDPWD=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang"
"PATH=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/erts-9.3/bin:/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release/bin:/Users/7stud/.rvm/gems/ruby-2.4.0/bin:/Users/7stud/.rvm/gems/ruby-2.4.0@global/bin:/Users/7stud/.rvm/rubies/ruby-2.4.0/bin:/Users/7stud/Library/Android/sdk/platform-tools:/Users/7stud/.asdf/shims:/Users/7stud/.asdf/bin:/Applications/Postgres.app/Contents/Versions/10/bin:/opt/local/bin:/opt/local/sbin:/Library/Frameworks/Python.framework/Versions/3.6/bin:/Users/7stud/.evm/erlang_versions/otp_src_20.2/bin:/usr/local/mysql/bin:/usr/local/bin/mongodb-osx-x86_64-3.0.7/bin:/Users/7stud/.local/bin:/Users/7stud/perl5/perlbrew/bin:/Users/7stud/perl5/perlbrew/perls/perl-5.20.2/bin:/Users/7stud/.nvm/versions/node/v11.2.0/bin:/usr/local/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/Library/Frameworks/Python.framework/Versions/3.4/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/go/bin:/usr/local/MacGPG2/bin:/Applications/Wireshark.app/Contents/MacOS:/usr/local/git/bin:/usr/local/go/bin://Users/7stud/go_programs/bin:/Applications/Rakudo/bin:/Applications/Rakudo/share/perl6/site/bin:/Users/7stud/flutter_apps/flutter/bin:/Users/7stud/.rvm/bin"
"PERLBREW_BASHRC_VERSION=0.73"
"PERLBREW_HOME=/Users/7stud/.perlbrew"
"PERLBREW_MANPATH=/Users/7stud/perl5/perlbrew/perls/perl-5.20.2/man"
"PERLBREW_PATH=/Users/7stud/perl5/perlbrew/bin:/Users/7stud/perl5/perlbrew/perls/perl-5.20.2/bin" 
"PERLBREW_PERL=perl-5.20.2"
"PERLBREW_ROOT=/Users/7stud/perl5/perlbrew"
"PERLBREW_VERSION=0.73"
"PLATFORM=darwin"
"PROGNAME=hello_erlang_release/bin/hello_erlang_release"
"PROJECT_HOME=/Users/7stud/django_projects"
"PWD=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release"
"REBAR_DEPS_DIR=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps"
"REL_NAME=hello_erlang_release"
"ROOTDIR=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/_rel/hello_erlang_release"
"RUBY_VERSION=ruby-2.4.0"
"SECURITYSESSIONID=186a7"
"SHELL=/bin/bash"
"SHLVL=1"
"SSH_AUTH_SOCK=/private/tmp/com.apple.launchd.j3fk5KvbKB/Listeners"
"TERM=xterm-256color"
"TERM_PROGRAM=Apple_Terminal"
"TERM_PROGRAM_VERSION=404"
"TERM_SESSION_ID=BBE0A4AF-DBCE-44CE-A52B-7133971D3D6E"
"TMPDIR=/var/folders/th/8j21gcbs5757m9q728jrlvxw0000gn/T/"
"USER=7stud"
"VIRTUALENVWRAPPER_HOOK_DIR=/Users/7stud/.virtualenvs"
"VIRTUALENVWRAPPER_PROJECT_FILENAME=.project"
"VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python3.4"
"VIRTUALENVWRAPPER_SCRIPT=/Library/Frameworks/Python.framework/Versions/3.4/bin/virtualenvwrapper.sh"
"WORKON_HOME=/Users/7stud/.virtualenvs"
"XPC_FLAGS=0x0"
"XPC_SERVICE_NAME=0"
"XREFR=/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/xrefr"
"__CF_USER_TEXT_ENCODING=0x1F5:0x0:0x0"
"_compat_rebar_config={deps, [\n{cowboy,\".*\",{git,\"https://github.com/ninenines/cowboy\",\"2.6.1\"}}\n]}.\n{erl_opts, [debug_info,warn_export_vars,warn_shadow_vars,warn_obsolete_guard]}."
"_system_arch=x86_64"
"_system_name=OSX"
"_system_type=Darwin"
"_system_version=10.13"
"rvm_bin_path=/Users/7stud/.rvm/bin"
"rvm_path=/Users/7stud/.rvm"
"rvm_prefix=/Users/7stud"
"rvm_version=1.27.0 (latest)"
ok
(hello_erlang@127.0.0.1)3> 
essen commented 5 years ago
(hello_erlang@127.0.0.1)4> ls().
asn1-4.0.4               asn1-5.0.5               cowboy-2.0.0-pre.9

This says that your release has Cowboy 2.0.0-pre.9.

(hello_erlang@127.0.0.1)14> cd(src).
/Users/7stud/erlang_programs/cowboy_apps/hello_erlang/deps/cowboy/src
ok
(hello_erlang@127.0.0.1)15> ls().

And this confirms it as well.

I do not know what is happening but it's not the right Cowboy version being picked up.

Try this and see if that fixes it, and if not please paste the complete output:

make erlang-mk
make distclean
make
7stud commented 5 years ago

Thanks again!

Try this and see if that fixes it, and if not please paste the complete output:

make erlang-mk
make distclean
make

Yep, that worked, i.e. the arity 2 constraint function gives me the expected output. While I was waiting for a response from you, I started a new project, and the arity 2 constraint function worked in the new project. I think my problem was that I originally created the hello_erlang cowboy app a year ago(?), and this week I changed the Makefile to use cowboy 2.6.1, and then I was running $ make run, which doesn't do the make step ??

I searched around, and I don't understand how $make erlang-mk works. It appears to have downloaded something from github and then created the file erlang.mk:

/erlang_programs/cowboy_apps/hello_erlang$ make erlang-mk
erlang.mk:26: Please upgrade to GNU Make 4 or later: https://erlang.mk/guide/installation.html
git clone https://github.com/ninenines/erlang.mk .erlang.mk.build
Cloning into '.erlang.mk.build'...

but I can ask on stackoverflow about that.

One last question, if I may, the cowboy constraint docs give this example for the built in int constraint function:

Finally, the format_error operation takes an error returned by any other operation and returns a formatted human-readable error message.

int(format_error, {not_an_integer, Value}) ->
  io_lib:format("The value ~p is not an integer.", [Value]).

When I add a format_error clause to my positive_fun():

positive_fun(forward, Value) when Value > 0-> 
    {ok, Value};
positive_fun(forward, _) ->
    {error, not_positive};
positive_fun(format_error, {not_positive, Value}) ->
    io_lib:format("The value ~p is not an integer.", [Value]).

I see no difference in the response in my browser:

1) For the url http://localhost:8080/get/2, I see:

Hello Erlang
Id=2

2) For the url http://localhost:8080/get/-10, I see:

[ME] 404. Whoops! (No matching route!)

The docs say:

Finally, the format_error operation takes an error returned by any other operation and returns a formatted human-readable error message.

Where does that string get returned to?

Thanks.

essen commented 5 years ago

First, when you change a dependency's version, Erlang.mk will not automatically update to that version. Updating automatically is not always what one wants so the solution might be to have a separate command for updating deps.

The format_error is not used during routing, it's used when matching query string or cookies. Constraints are for more than routing! :-)

7stud commented 5 years ago

First, when you change a dependency's version, Erlang.mk will not automatically update to that version. Updating automatically is not always what one wants so the solution might be to have a separate command for updating deps.

The format_error is not used during routing, it's used when matching query string or cookies. Constraints are for more than routing! :-)

Thanks essen! I really appreciate the help!

essen commented 5 years ago

Think we're done here, closing, thanks!