代码之家  ›  专栏  ›  技术社区  ›  7stud

inets httpd cgi脚本:为什么会出现“没有这样的文件或目录”错误?

  •  0
  • 7stud  · 技术社区  · 7 年前

    当我尝试从inets httpd服务器请求cgi脚本时,出现以下错误:

    sh: /Users/7stud/erlang_programs/inets_proj/cgi-bin/cgi-bin/1.pl: 
    No such file or directory
    

    我注意到路径的cgi bin组件加倍了。我的cgi脚本实际位于:

    /Users/7stud/erlang_programs/inets_proj/cgi-bin/1.pl
    

    这是我的httpd server proplist\u文件:

    [
      {modules, [
            mod_alias,
            mod_cgi
      ]},
      { bind_address, "localhost"}, 
      {port,0},
      {server_name,"httpd_test"},
      {server_root,"."},
      {document_root,"./htdocs"},
      {script_alias, {"/cgi-bin/", "./cgi-bin/"} }
    ].
    

    根据 httpd docs :

    CGI属性 -需要mod\u cgi

    {script\u alias,{alias,RealName}}
    别名=string()和RealName= 字符串()。与属性别名具有相同的行为,只是 还将目标目录标记为包含CGI脚本。带有 以别名开头的路径映射到以开头的脚本 RealName,例如:

    {script_alias, {"/cgi-bin/", "/web/cgi-bin/"}}
    

    访问 http://your.server.org/cgi-bin/foo 将导致服务器 运行脚本 /web/cgi-bin/foo .

    以及:

    {server\u root,path()}
    定义服务器的主目录,其中 可以存储日志文件等。 其他中指定的相对路径 属性引用此目录。

    更多信息:

    5> httpd:info(S).
    [{mime_types,[{"htm","text/html"},{"html","text/html"}]},
     {server_name,"httpd_test"},
     {script_alias,{"/cgi-bin/","./cgi-bin/"}},
     {bind_address,{127,0,0,1}},
     {modules,[mod_actions,mod_alias,mod_cgi,mod_get,mod_head,
               mod_log]},
     {server_root,"."},
     {port,59641},
     {document_root,"./htdocs"}]
    
    6> pwd().
    /Users/7stud/erlang_programs/inets_proj
    ok
    
    7> ls().
    cgi-bin         cl.beam         cl.erl          htdocs          
    s.beam          s.erl           server.conf     
    ok
    

    为什么我要加倍 cgi-bin 我的请求url中的组件?

    1 回复  |  直到 7 年前
        1
  •  0
  •   7stud    7 年前

    如果我在 script_alias 选项,则可以成功请求cgi脚本。我找不到一条相对的工作道路。这是适用于我的httpd服务器配置:

    服务器形态:

    [
      {modules, [
        mod_alias,
        mod_actions,
        mod_cgi,
        mod_get
      ]},
      {bind_address, "localhost"}, 
      {port,0},
      {server_name,"httpd_test"},
      {server_root,"/Users/7stud/erlang_programs/inets_proj"},
      {document_root,"./htdocs"},
      {script_alias, {"/cgi-bin/", "/Users/7stud/erlang_programs/inets_proj/cgi-bin/"} }
    ].
    

    目录结构:

    $ tree inets_proj
    inets_proj
    ├── cgi-bin
    │   └── 1.pl
    ├── cl.beam
    ├── cl.erl
    ├── htdocs
    │   └── file1.txt
    ├── s.beam
    ├── s.erl
    └── server.conf
    

    s、 erl:

    -module(s).
    -compile(export_all).
    
    ensure_inets_start() ->
        case inets:start() of
            ok -> ok;
            {error,{already_started,inets}} -> ok
        end.
    
    %After start(), need to lookup the port with:
    %      3> httpd:info(Server)
    
    start() ->
        ok = s:ensure_inets_start(),
    
        {ok, Server} = inets:start(httpd, 
            [{proplist_file, "./server.conf"}]
        ),
        Server.
    
    
    stop(Server) ->
        ok = inets:stop(httpd, Server).
    

    cgi脚本1。pl(确保文件具有可执行权限!):

    #!/usr/bin/env perl
    
    use strict;
    use warnings;
    use 5.020;
    use autodie;
    use Data::Dumper;
    
    print "Content-type: text/html\n\n";
    print "Hello, Perl.\n";
    

    文件1.txt:

    Hello, world!
    

    在外壳中:

    $ erl
    Erlang/OTP 19 [erts-8.2] [source] [64-bit] [smp:4:4] [async-threads:10] [hipe] [kernel-poll:false]
    
    Eshell V8.2  (abort with ^G)
    
    1> c(s).
    {ok,s}
    
    2> S = s:start().
    <0.79.0>
    
    3> httpd:info(S).
    [{mime_types,[{"htm","text/html"},{"html","text/html"}]},
     {server_name,"httpd_test"},
     {script_alias,{"/cgi-bin/",
                    "/Users/7stud/erlang_programs/inets_proj/cgi-bin/"}},
     {bind_address,{127,0,0,1}},
     {modules,[mod_alias,mod_actions,mod_cgi,mod_get]},
     {server_root,"/Users/7stud/erlang_programs/inets_proj"},
     {port,54344},
     {document_root,"./htdocs"}]
    
    4> 
    

    在终端窗口中:

    ~$ curl -v "http://localhost:54344/cgi-bin/1.pl"
    *   Trying 127.0.0.1...
    * TCP_NODELAY set
    * Connected to localhost (127.0.0.1) port 54344 (#0)
    > GET /cgi-bin/1.pl HTTP/1.1
    > Host: localhost:54344
    > User-Agent: curl/7.58.0
    > Accept: */*
    > 
    < HTTP/1.1 200 OK
    < Date: Wed, 28 Feb 2018 03:18:05 GMT
    < Server: inets/6.3.4
    < Transfer-Encoding: chunked
    < Content-Type: text/html
    < 
    Hello, Perl.
    * Connection #0 to host localhost left intact
    
    
    ~$ curl -v "http://localhost:54344/file1.txt"
    *   Trying 127.0.0.1...
    * TCP_NODELAY set
    * Connected to localhost (127.0.0.1) port 54344 (#0)
    > GET /file1.txt HTTP/1.1
    > Host: localhost:54344
    > User-Agent: curl/7.58.0
    > Accept: */*
    > 
    < HTTP/1.1 200 OK
    < Date: Wed, 28 Feb 2018 03:18:56 GMT
    < Server: inets/6.3.4
    < Content-Type: text/plain
    < Etag: nCZT0114
    < Content-Length: 14
    < Last-Modified: Mon, 26 Feb 2018 02:51:52 GMT
    < 
    Hello, world!
    * Connection #0 to host localhost left intact
    $
    

    尽管文档中提到必须使用主机语法作为 httpd:info() --而不是你指定的 {bind_address, "localhost"} --我可以使用 localhost 在请求中。

    下面是一个使用 httpc 要向httpd服务器发出cgi post请求,请执行以下操作:

    -module(cl).
    -compile(export_all).
    
    ensure_inets_start() ->
        case inets:start() of
            ok -> ok;
            {error,{already_started,inets}} -> ok
        end.
    
    start() ->
        ensure_inets_start().
    
    %%   Need "http://" at start of url:
    %%
    %%   cl:myget("http://localhost:62049/file1.txt")
    %%
    %%   Need to look up port with httpd:info(Server)
    
    myget(Url) ->
        {ok, ReqRef} = 
            httpc:request(get, {Url, []}, [], [{sync, false}]),
    
        receive
            {http, {ReqRef, Result}} ->
                Result
        after 2000 ->
            my_error
        end.
    
    stop() ->
        inets:stop().
    
    url(Port) ->
        "http://localhost:" ++ integer_to_list(Port) ++ "/cgi-bin/1.pl".
    
    mypost(Port) ->
        Url = url(Port),
        Headers = [],
        ContentType = "application/x-www-form-urlencoded",
        Body = "a=1&b=2",
    
        Request = {Url, Headers, ContentType, Body},
        HttpOptions = [],
        Options = [{sync, false}],
        {ok, ReqRef} = httpc:request(post, Request, HttpOptions, Options),
    
        receive
            {http, {ReqRef, Result}} ->
                Result;
            Other -> Other
        after 1000 ->
            my_error
        end.
    

    httpd的cgi实现似乎有问题,因为我无法发出包含json数据的cgi post请求。cgi脚本必须读取请求的正文才能获得原始字符串,我已经用perl cgi脚本和, $str = $q->param('POSTDATA'); 和python cgi脚本, my_dict = json.load(sys.stdin) 我无法从httpd服务器获取请求的正文。