二郎 gen_tcp:recv http_request abs_path
Erlang gen_tcp:recv http_request abs_path
我正在用接受 HTTP 请求的 Erlang 编写代码。我有如下所示的工作代码。
我遇到的问题是我不确定 gen_tcp:recv
的 returned 结果。
我创建了一个侦听套接字并使用
接受套接字
{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
方法,我发现了 the page describing HttpPacket
.
页面上的语法清楚地表明Path
在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 中使用 curl
和 RESTClient
,它们都使 gen_tcp:recv
return 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).
您可以使用一个简单的 network-capable 客户端,例如 netcat(在我的系统上是 /usr/bin/nc
)来发送您喜欢的任何形式的请求。例如,以下连接到侦听 localhost
端口 8000 的 Web 服务器并发送 GET
请求,其中路径为 URL(注意 $
表示 shell提示):
$ nc localhost 8000
GET http://whosebug.com HTTP/1.1
$
nc
程序从其标准输入读取。请务必在 GET
行后按两次 Enter 以正确指示 HTTP headers 的结尾。这导致服务器上的 gen_tcp:recv
调用 returning:
{absoluteURI,http,"whosebug.com",undefined,"/"}
类似地,以下将 return 来自 gen_tcp:recv
的路径不是 {abs_path, ...}
元组,而只是 "../foo"
:
$ nc localhost 8000
GET ../foo HTTP/1.1
$
您可以轻松地在文本文件中设置测试变体,并使用标准输入重定向将它们输入 nc
。
我正在用接受 HTTP 请求的 Erlang 编写代码。我有如下所示的工作代码。
我遇到的问题是我不确定 gen_tcp:recv
的 returned 结果。
我创建了一个侦听套接字并使用
接受套接字{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
方法,我发现了 the page describing HttpPacket
.
页面上的语法清楚地表明Path
在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 中使用 curl
和 RESTClient
,它们都使 gen_tcp:recv
return 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).
您可以使用一个简单的 network-capable 客户端,例如 netcat(在我的系统上是 /usr/bin/nc
)来发送您喜欢的任何形式的请求。例如,以下连接到侦听 localhost
端口 8000 的 Web 服务器并发送 GET
请求,其中路径为 URL(注意 $
表示 shell提示):
$ nc localhost 8000
GET http://whosebug.com HTTP/1.1
$
nc
程序从其标准输入读取。请务必在 GET
行后按两次 Enter 以正确指示 HTTP headers 的结尾。这导致服务器上的 gen_tcp:recv
调用 returning:
{absoluteURI,http,"whosebug.com",undefined,"/"}
类似地,以下将 return 来自 gen_tcp:recv
的路径不是 {abs_path, ...}
元组,而只是 "../foo"
:
$ nc localhost 8000
GET ../foo HTTP/1.1
$
您可以轻松地在文本文件中设置测试变体,并使用标准输入重定向将它们输入 nc
。