【问题标题】:inets httpd cgi script: Why am I getting a "No such file or directory" error?inets httpd cgi 脚本:为什么我收到“没有这样的文件或目录”错误?
【发布时间】:2018-03-08 17:41:43
【问题描述】:

当我尝试从 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 服务器 proplist_file:

[
  {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_cgi

{script_alias, {Alias, RealName}}
别名 = string() 和实名 = 细绳()。具有与属性别名相同的行为,除了它们 还将目标目录标记为包含 CGI 脚本。带有 以 Alias 开头的路径映射到以 Alias 开头的脚本 实名,例如:

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

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

还有:

{server_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

为什么我的请求 url 中出现了双倍的 cgi-bin 组件?

【问题讨论】:

    标签: erlang inets


    【解决方案1】:

    如果我在script_alias 选项中使用服务器的cgi-bin 目录的完整路径,那么我可以成功请求cgi 脚本。我无法获得工作的相对路径。这是对我有用的 httpd 服务器配置:

    server.conf:

    [
      {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 script 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";
    

    file1.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 发布请求。 cgi 脚本必须读取请求的主体以获取原始字符串,我尝试使用 perl cgi 脚本 $str = $q-&gt;param('POSTDATA'); 和 python cgi 脚本 my_dict = json.load(sys.stdin) 来做到这一点,但我无法获得来自 httpd 服务器的请求正文。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-29
      • 2019-05-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-31
      相关资源
      最近更新 更多