我正在在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),
当我阅读有关gen_tcp
的Erlang文档时,更具体地说是recv
方法,我找到了描述HttpPacket
的页面。
页面上的语法清楚地表明,HttpPacket
中的Path
,在这种情况下,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中使用curl
和RESTClient
,它们都使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).
您可以使用一个简单的具有网络功能的客户端,例如NetCat(我的系统上的/usr/bin/nc
)来发送您喜欢的任何形式的请求。例如,以下连接到在localhost
端口8000上侦听的Web服务器,并在路径为URL的情况下发送GET
请求(请注意$
表示Shell提示):
$ nc localhost 8000
GET http://stackoverflow.com HTTP/1.1
$
nc
程序从其标准输入中读取。请确保在GET
线后两次击中输入,以正确指示HTTP标头的末端。这将导致服务器上的gen_tcp:recv
调用:
{absoluteURI,http,"stackoverflow.com",undefined,"/"}
同样,以下将返回gen_tcp:recv
的路径,而不是{abs_path, ...}
元组,而是"../foo"
:
$ nc localhost 8000
GET ../foo HTTP/1.1
$
您可以在文本文件中轻松设置这样的测试变化,并使用stdin重定向将其馈送到nc
中。