1

我正在用 Erlang 编写接受 HTTP 请求的代码。我有如下所示的工作代码。

我遇到的问题是我不确定gen_tcp:recv.

我创建了一个监听套接字并使用接受套接字

{ok, ListenSock}=gen_tcp:listen(Port, [list,{active, false},{packet,http}])
{ok, Sock}=gen_tcp:accept(ListenSock),

我接受 GET 请求(或任何其他请求)

{ok, {http_request, Method, Path, Version}} = gen_tcp:recv(Sock, 0),
handle_get(Sock, Path);

然后,要获取 url 参数(CGI 参数,例如?foo=1&bar=2),我必须匹配Path一个结构{abs_path, RelativePath}

handle_get(Sock, ReqPath) ->
    {abs_path, RelPath} = ReqPath,
    Parameters = string:substr(RelPath, string:str(RelPath, "?") + 1),

当我阅读 Erlang 的文档时gen_tcp,更具体地说,recv我找到了描述HttpPacket.

页面上的语法清楚地表明Pathin HttpPacket,在这种情况下是HttpRequest类型,可以有多种类型HttpUri

HttpRequest = {http_request, HttpMethod, HttpUri, HttpVersion}
HttpUri = '*'
        | {absoluteURI,
           http | https,
           Host :: HttpString,
           Port :: inet:port_number() | undefined,
           Path :: HttpString}
        | {scheme, Scheme :: HttpString, HttpString}
        | {abs_path, HttpString}
        | HttpString

我知道我必须支持每一种可能的情况,但我不确定。我也想知道如何测试这些案例。我曾尝试在 Firefox 中使用curlandRESTClient并且它们都gen_tcp:recv返回abs_path

所以要明确一点,如何确定请求是否成立{abs_path, HttpString}{scheme, Scheme :: HttpString, HttpString}或者{absoluteURI,...}我是否需要支持所有这些?

完整列表

start(Port)->
    {ok, ListenSock}=gen_tcp:listen(Port, [list,{active, false},{packet,http}]),
    loop(ListenSock).


loop(ListenSock) -> 
    {ok, Sock}=gen_tcp:accept(ListenSock),
    spawn(?MODULE, handle_request, [Sock]),
    loop(ListenSock).

%% Takes a TCP socket and receives 
%% http://erlang.org/doc/man/erlang.html#decode_packet-3
handle_request(Sock) ->
    {ok, {http_request, Method, Path, _Version}} = gen_tcp:recv(Sock, 0),

    case (Method) of
        'GET' ->
            handle_get(Sock, Path);
        _ -> 
            send_unsupported_error(Sock)
    end.

handle_get(Sock, ReqPath) ->
    {abs_path, RelPath} = ReqPath,
    Parameters = string:substr(RelPath, string:str(RelPath, "?") + 1),
    %% Debugging
    ParsedParms = httpd:parse_query(Parameters),
    io:fwrite("Full Path: ~p~nParameters: ~p~n", [RelPath, ParsedParms]),
    %% End Debugging
    send_accept(Sock).
4

1 回答 1

1

您可以使用简单的支持网络的客户端,例如 netcat(/usr/bin/nc在我的系统上)来发送您喜欢的任何形式的请求。例如,以下内容连接到侦听localhost端口 8000 的 Web 服务器并发送GET路径为 URL 的请求(注意$表示 shell 提示符):

$ nc localhost 8000
GET http://stackoverflow.com HTTP/1.1

$

nc程序从其标准输入读取。请务必在该行之后按两次 EnterGET以正确指示 HTTP 标头的结尾。这导致gen_tcp:recv服务器上的调用返回:

{absoluteURI,http,"stackoverflow.com",undefined,"/"}

同样,以下将返回一个gen_tcp:recv不是{abs_path, ...}元组的路径,而只是"../foo"

$ nc localhost 8000
GET ../foo HTTP/1.1

$

您可以轻松地在文本文件中设置类似的测试变体,并nc使用标准输入重定向将它们输入。

于 2015-05-14T13:32:44.770 回答