inets httpd cgi script: почему я получаю ошибку "Нет такого файла или каталога"?

Когда я пытаюсь запросить скрипт cgi с httpd-сервера inets, я получаю эту ошибку:

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 документам:

CGI Properties - Требуется mod_cgi

{script_alias, {Alias, RealName}}
Псевдоним = string() и RealName = string(). Поведение аналогично псевдониму свойства, за исключением того, что он также помечает целевой каталог как содержащий CGI-сценарии. URL-адреса с путем, начинающимся с псевдонима, сопоставляются со сценариями, начинающимися с RealName, например:

{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

Почему я получаю в два раза cgi-bin компонент в моем запросе URL?

1 ответ

Решение

Если я использую полный путь к каталогу cgi-bin сервера в script_alias вариант, то я могу успешно запросить скрипт 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 сделать cgi-запрос к серверу httpd:

-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.

Кажется, что-то не так с реализацией cgi в httpd, так как я не могу сделать запрос cgi post, содержащий данные json. Сценарий cgi должен прочитать тело запроса, чтобы получить необработанную строку, и я попытался сделать это с обоими сценариями perl cgi, $str = $q->param('POSTDATA'); и скрипт Python CGI, my_dict = json.load(sys.stdin) и я не могу получить тело запроса с сервера httpd.

Другие вопросы по тегам