[Erlang Programming Book] Exercise 15-2: A Simple HTTP Proxy

156 views
Skip to first unread message

Yoshi

unread,
May 4, 2010, 8:28:52 PM5/4/10
to Erlang Programming
Hello,

I tried following code(sorry for long code), and got many errors.
For example,
1) when I tried to show the page that has a lot of pictures, not all
pictures are shown.
2) sometimes connect methods is being sent, and I don't know how to
deal with it.

I would appreciate any suggestion.



-module(hp).
-compile([export_all]).

start() ->
inets:start(),
{ok, ListenSock} = gen_tcp:listen(1500, [{packet, http},
{reuseaddr, true},{active,false}]),
wait_connect(ListenSock).

wait_connect(ListenSock) ->
spawn(?MODULE, wait_connect, [ListenSock]),
{ok, Sock} = gen_tcp:accept(ListenSock),
Data = loop(Sock,[]),
{Method,Url,_} = process_header(Data),
case Method of
error ->
io:format("*** ERROR:no http_request in header~n"),
NewMethod = bogus,
gen_tcp:close(Sock),
exit(url_error);
'HEAD' -> NewMethod = head;
'GET' -> NewMethod = get;
'PUT' -> NewMethod = put;
'POST' -> NewMethod = post;
'TRACE' -> NewMethod = trace;
'OPTIONS' -> NewMethod = options;
'DELETE' -> NewMethod = delete;
Other ->
io:format("*** ERROR method unsupported:[~p]~n", [Other]),
NewMethod = other,
gen_tcp:send(Sock, <<"HTTP/1.1 501 Not Implemented.\r
\n">>),
gen_tcp:close(Sock),
exit(bad_method)
end,
io:format("=== Request from client ===~n"),
io:format(" URL:[~p]~n", [Url]),
io:format("===========================~n"),

case http:request(NewMethod, {Url, []}, [], []) of
{error, Reason} ->
io:format("*** Error:http request [~p]\n", Reason);

{ok, {{Version, ResCode, ReasonPhrase}, Headers, Body}} ->
RetHead = make_header(Version, ResCode, ReasonPhrase,
Headers),
case gen_tcp:send(Sock, list_to_binary(RetHead++Body)) of
ok -> ok;
{error, Reason} -> Reason
end
end,
gen_tcp:close(Sock).


loop(Sock, Acc) ->
case gen_tcp:recv(Sock, 0) of
{ok, http_eoh} ->
io:format("HTTP End of Header received.~n"),
lists:reverse(Acc);
{ok, Data} ->
io:format("~p~n", [Data]),
loop(Sock, [Data|Acc]);
{error, Reason} ->
io:format("ERROR:[~p]~n",[Reason]),
loop(Sock, Acc)
end.

process_header(HttpHead) ->
case lists:keyfind('http_request',1,HttpHead) of
false -> {error, no_get, {-1,-1}};
{_,Method,{_,Scheme,HostName,_,DataPath},Ver} ->
{Method, atom_to_list(Scheme) ++ "://" ++ HostName ++
DataPath, Ver};
{_,Method,{Scheme,HostName,_Port},Ver} -> % in case of CONNECT
etc
{Method, atom_to_list(Scheme) ++ "://" ++ HostName, Ver}
end.

make_header(Version, ResCode, ReasonPhrase, Headers) ->
FirstLine = "HTTP/" ++
Version ++ " " ++
integer_to_list(ResCode) ++ " " ++
ReasonPhrase ++ "\r\n",
FirstLine ++ concat_headers(Headers) ++ "\r\n".

concat_headers(Headers) ->
lists:concat([Title ++ ": " ++ Contents ++ "\r\n" || {Title,
Contents} <- Headers]).

--
Yoshi

--
Erlang Programming Website:
http://www.erlangprogramming.org/
Reply all
Reply to author
Forward
0 new messages