Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

""

git-svn-id: https://erlyaws.svn.sourceforge.net/svnroot/erlyaws/trunk/yaws@22 9fbdc01b-0d2c-0410-bfb7-fb27d70d8b52
  • Loading branch information...
commit d69e4d84ba4022e70c20324670d220b9788b8df7 1 parent 0f3d5ec
@klacke authored
View
11 Makefile
@@ -26,5 +26,12 @@ touch:
release:
. vsn.mk; \
CVS_RSH=ssh; \
- cvs tag yaws-$$(YAWS_VSN) . ;\
-
+ Y=`echo $$(YAWS_VSN) | sed 's/./-/g'` ;\
+ cvs tag yaws-$$(Y) . ;\
+ [ -d tmp ] && rm -rf tmp ; \
+ (cd ..; cvs export -d tmp .; cd tmp; mv yaws yaws-$$(YAWS_VSN); \
+ tar cfz yaws-$$(YAWS_VSN).tar.gz yaws-$$(YAWS_VSN) \;
+ mv yaws-$$(YAWS_VSN) .. )
+
+
+
View
2  ebin/yaws.app
@@ -1,7 +1,7 @@
{application,yaws,
[{description,"yaws WWW server"},
{vsn,"0.21"},
- {modules,[yaws, yaws_app, yaws_config, yaws_server, yaws_sup, yaws_api, yaws_log, yaws_ls, yaws_debug]},
+ {modules,[yaws, yaws_app, yaws_config, yaws_server, yaws_sup, yaws_api, yaws_log, yaws_ls, yaws_debug, yaws_compile]},
{registered, []},
{mod,{yaws_app,[]}},
{env, []},
View
4 include/yaws_api.hrl
@@ -10,7 +10,7 @@
-record(arg, {
clisock, %% the socket leading to the peer client
- h, %% headers
+ headers, %% headers
req, %% request
clidata, %% The client data (as a binary in POST requests)
querydata, %% Was the URL on the form of ....?query (GET reqs)
@@ -18,8 +18,6 @@
}).
-
-
-record(http_request, {method,
path,
View
3  src/Makefile
@@ -16,7 +16,8 @@ MODULES=yaws \
yaws_api \
yaws_log \
yaws_ls \
- yaws_debug
+ yaws_debug \
+ yaws_compile
EBIN_FILES=$(MODULES:%=../ebin/%.$(EMULATOR)) ../ebin/yaws.app
View
2  src/yaws.erl
@@ -313,6 +313,8 @@ mk_list([X|Rest]) ->
universal_time_as_string() ->
time_to_string(calendar:universal_time(), "GMT").
+
+
time_to_string( {{Year, Month, Day}, {Hour, Min, Sec}}, Zone) ->
io_lib:format("~s, ~s ~s ~w ~s:~s:~s ~s",
[day(Year, Month, Day),
View
4 src/yaws.hrl
@@ -13,14 +13,14 @@
-record(gconf,{file,
yaws_dir,
logdir,
- ebin_dir,
+ ebin_dir = [],
keepalive_timeout = 15000,
max_num_cached_files = 400,
max_num_cached_bytes = 1000000, %% 1 MEG
max_size_cached_file = 8000,
default_type = "text/html",
timeout = 2000,
- include_dir,
+ include_dir = [],
yaws %% FIXME add version here
}). %% a list of lists of #confs
%% one list of #conf's per listen ip
View
88 src/yaws_api.erl
@@ -176,6 +176,16 @@ ssi(DocRoot, Files) ->
{ok, L}.
+%% include pre
+pre_ssi_files(DocRoot, Files) ->
+ {ok, L} = ssi(DocRoot, Files),
+ pre_ssi_string(L).
+
+pre_ssi_string(Str) ->
+ {ok, << "<br><br>\n<div class=\"box\"> \n <pre>\n",
+ (htmlize(list_to_binary(Str)))/binary,
+ "\n</pre>\n</div>\n<br>\n\n">>}.
+
%% convenience
@@ -190,8 +200,7 @@ fl([]) ->
-%% htmlize ( <xmp> doesn't seem to work with opera )
-%% FIXME add all the html weirdo chars here
+%% htmlize
htmlize(<<Char, Tail/binary>>) ->
case htmlize_char(Char) of
Char ->
@@ -206,8 +215,8 @@ htmlize_char($>) ->
<<"&gt;">>;
htmlize_char($<) ->
<<"&lt;">>;
-htmlize_char($\n) ->
- <<"<br>">>;
+htmlize_char($&) ->
+ <<"&amp;">>;
htmlize_char(X) ->
X.
@@ -218,16 +227,69 @@ secs() ->
(MS * 1000000) + S.
-setcookie(Name) ->
- setcookie(Name, "/", secs() + 3600, [], []).
-setcookie(Name, Path) ->
- setcookie(Name, Path, secs() + 3600, [], []).
-setcookie(Name, Path, Expire) ->
- setcookie(Name, Path, Expire, [], []).
-setcookie(Name, Path, Expire, Domain) ->
- setcookie(Name, Path, Expire, Domain,[]).
-setcookie(Name, Path, Expire, Domain, Secure) ->
+
+
+
+setcookie(Name, Value) ->
+ {ok, f("Set-Cookie: ~s=~s;\r\n", [Name, Value])}.
+
+setcookie(Name, Value, Path) ->
+ {ok, f("Set-Cookie: ~s=~s; path=~s\r\n", [Name, Value, Path])}.
+
+setcookie(Name, Value, Path, Expire) ->
+ setcookie(Name, Value, Path, Expire, [], []).
+
+setcookie(Name, Value, Path, Expire, Domain) ->
+ setcookie(Name, Value, Path, Expire, Domain,[]).
+
+setcookie(Name, Value, Path, Expire, Domain, Secure) ->
exit(nyi).
+
+
+%% This function can be passed the cookie we get in the Arg#arg.cookies
+%% to search for a specific cookie
+%% return [] if not found
+%% Str if found
+%% if serveral cookies with the same name are passed fron the browser,
+%% only the first match is returned
+
+
+find_cookie_val(Cookie, []) ->
+ [];
+find_cookie_val(Cookie, [FullCookie | FullCookieList]) ->
+ case find_cookie_val2(Cookie, FullCookie) of
+ [] ->
+ find_cookie_val(Cookie, FullCookieList);
+ Val ->
+ Val
+ end.
+
+find_cookie_val2(Cookie, FullCookie) ->
+ case lists:prefix(Cookie, FullCookie) of
+ false when FullCookie == [] ->
+ [];
+ false ->
+ find_cookie_val2(Cookie, tl(FullCookie));
+ true ->
+ case lists:dropwhile(fun(X) -> X /= $= end, FullCookie) of
+ [] ->
+ [];
+ List ->
+ find_cookie_val3(tl(List),[])
+ end
+ end.
+
+
+find_cookie_val3([], Ack) ->
+ lists:reverse(Ack);
+find_cookie_val3([$;|_], Ack) ->
+ lists:reverse(Ack);
+find_cookie_val3([H|T], Ack) ->
+ find_cookie_val3(T, [H|Ack]).
+
+
+
+
View
303 src/yaws_compile.erl
@@ -0,0 +1,303 @@
+%%%----------------------------------------------------------------------
+%%% File : yaws_compile.erl
+%%% Author : Claes Wikstrom <klacke@hyber.org>
+%%% Purpose :
+%%% Created : 20 Feb 2002 by Claes Wikstrom <klacke@hyber.org>
+%%%----------------------------------------------------------------------
+
+-module(yaws_compile).
+-author('klacke@hyber.org').
+
+-compile(export_all).
+-include("yaws.hrl").
+
+
+
+%% tada !!
+%% returns a CodeSpec which is:
+%% a list {data, NumChars} |
+%% {mod, LineNo, YawsFile, NumSkipChars, Mod, Func} |
+%% {error, NumSkipChars, E}}
+
+% each erlang fragment inside <erl> .... </erl> is compiled into
+% its own module
+
+
+-record(comp, {
+ gc, %% global conf
+ sc, %% server conf
+ startline = 0,
+ modnum = 1,
+ infile,
+ infd,
+ outfile,
+ outfd}).
+
+
+
+comp_opts(GC) ->
+ I = lists:map(fun(Dir) -> {i, Dir} end, GC#gconf.include_dir),
+ YawsDir = {i, "/home/klacke/yaws/include"},
+ I2 = [YawsDir | I],
+ Opts = [binary, report_errors | I2],
+ ?Debug("Compile opts = ~p~n", [Opts]),
+ Opts.
+
+
+compile_file(File, GC, SC) ->
+ case file:open(File, [read]) of
+ {ok, Fd} ->
+ Spec = compile_file(#comp{infile = File,
+ infd = Fd, gc = GC, sc = SC},
+ 1,
+ io:get_line(Fd, ''), init, 0, []);
+ Err ->
+ yaws:elog("can't open ~s~n", [File]),
+ exit(normal)
+ end.
+
+compile_file(C, LineNo, eof, Mode, NumChars, Ack) ->
+ file:close(C#comp.infd),
+ {ok, lists:reverse([{data, NumChars} |Ack])};
+
+
+%% skip initial space
+compile_file(C, LineNo, Chars, init, NumChars, Ack) ->
+ case Chars -- [$\s, $\t, $\n, $\r] of
+ [] ->
+ compile_file(C, LineNo+1, line(C), init, NumChars, Ack);
+ _ ->
+ compile_file(C, LineNo, Chars, html, NumChars, Ack)
+ end;
+
+
+
+compile_file(C, LineNo, Chars = "<erl>" ++ Tail, html, NumChars, Ack) ->
+ ?Debug("start erl:~p",[LineNo]),
+ C2 = new_out_file(LineNo, C, C#comp.gc),
+ C3 = C2#comp{startline = LineNo},
+ L = length(Chars),
+ if
+ NumChars > 0 ->
+ compile_file(C3, LineNo+1, line(C) , erl,L,
+ [{data, NumChars} | Ack]);
+ true -> %% just ignore zero byte data segments
+ compile_file(C3, LineNo+1, line(C) , erl, L, Ack)
+ end;
+
+compile_file(C, LineNo, Chars = "</erl>" ++ Tail, erl, NumChars, Ack) ->
+ ?Debug("stop erl:~p",[LineNo]),
+ file:close(C#comp.outfd),
+ NumChars2 = NumChars + length(Chars),
+ case proc_compile_file(C#comp.outfile, comp_opts(C#comp.gc)) of
+ {ok, ModuleName, Binary} ->
+ case code:load_binary(ModuleName, C#comp.outfile, Binary) of
+ {module, ModuleName} ->
+ C2 = C#comp{modnum = C#comp.modnum+1},
+ L2 = check_exported(C, LineNo,NumChars2, ModuleName),
+ compile_file(C2, LineNo+1, line(C),html,0,L2++Ack);
+ Err ->
+ A2 = gen_err(C, LineNo, NumChars2,
+ ?F("Cannot load module ~p: ~p",
+ [ModuleName, Err])),
+ compile_file(C, LineNo+1, line(C),
+ html, 0, [A2|Ack])
+ end;
+ {error, Errors, Warnings} ->
+ %% FIXME remove outfile here ... keep while debuging
+ A2 = comp_err(C, LineNo, NumChars2, Errors),
+ compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack]);
+ {error, Str} ->
+ %% this is boring but does actually happen
+ %% in order to get proper user errors here we need to catch i/o
+ %% or hack compiler/parser
+ yaws:elog("Dynamic compile error in file ~s, line~w",
+ [C#comp.infile, LineNo]),
+ A2 = {error, NumChars2, ?F("<pre> Dynamic compile error in file "
+ " ~s line ~w~n~s </pre>",
+ [C#comp.infile, LineNo, Str])},
+ compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack])
+ end;
+
+compile_file(C, LineNo, Chars = "<pre>" ++ Tail, html, NumChars, Ack) ->
+ ?Debug("start pre:~p",[LineNo]),
+ compile_file(C, LineNo+1, line(C) , pre, NumChars + length(Chars), Ack);
+
+compile_file(C, LineNo, Chars = "</pre>" ++ Tail, pre, NumChars, Ack) ->
+ ?Debug("stop pre:~p",[LineNo]),
+ compile_file(C, LineNo+1, line(C) , html, NumChars + length(Chars), Ack);
+
+compile_file(C, LineNo, Chars, erl, NumChars, Ack) ->
+ io:format(C#comp.outfd, "~s", [Chars]),
+ compile_file(C, LineNo+1, line(C), erl, NumChars + length(Chars), Ack);
+
+compile_file(C, LineNo, Chars, html, NumChars, Ack) ->
+ compile_file(C, LineNo+1, line(C), html, NumChars + length(Chars), Ack);
+
+compile_file(C, LineNo, Chars, pre, NumChars, Ack) ->
+ compile_file(C, LineNo+1, line(C), pre, NumChars + length(Chars), Ack).
+
+
+
+
+
+check_exported(C, LineNo, NumChars, Mod) when C#comp.modnum == 1->
+ case {is_exported(some_headers, 1, Mod),
+ is_exported(all_headers, 1, Mod),
+ is_exported(out, 1, Mod)} of
+ {true, true, _} ->
+ [gen_err(C, LineNo, NumChars,
+ ?F("Cannot have both some and the all "
+ "headers",[]))];
+
+ %% someheaders
+ {true, false, true} ->
+ [{mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,some_headers},
+ {mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,out}];
+ {true, false, false} ->
+ [{mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,some_headers}];
+
+ %% allheaders
+ {false, true, true} ->
+ [{mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,all_headers},
+ {mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,out}];
+
+ {false, true, false} ->
+ [{mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,all_headers}];
+
+ {false, false, true} ->
+ [{mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,out}];
+ {false, false, false} ->
+ ?Debug("XX ~p~n", [C]),
+ [gen_err(C, LineNo, NumChars,
+ "neither out/1 , some_headers/1 nor "
+ "all_headers/1 is defined ")]
+
+
+ end;
+
+check_exported(C, LineNo, NumChars, Mod) ->
+ case is_exported(out, 1, Mod) of
+ true ->
+ [{mod, C#comp.startline, C#comp.infile,
+ NumChars,Mod,out}];
+ false ->
+ ?Debug("XX ~p~n", [C]),
+ [gen_err(C, LineNo, NumChars,
+ "out/1 is not defined ")]
+ end.
+
+
+
+
+line(C) ->
+ io:get_line(C#comp.infd, '').
+
+is_exported(Fun, A, Mod) ->
+ case (catch Mod:module_info()) of
+ List when list(List) ->
+ case lists:keysearch(exports, 1, List) of
+ {value, {exports, Exp}} ->
+ lists:member({Fun, A}, Exp);
+ _ ->
+ false
+ end;
+ _ ->
+ false
+ end.
+
+
+%% this will generate 9 lines
+new_out_file(Line, C, GC) ->
+ Mnum = gen_server:call(yaws_server, mnum),
+ Module = [$m | integer_to_list(Mnum)],
+ OutFile = "/tmp/yaws/" ++ Module ++ ".erl",
+ ?Debug("Writing outout file~s~n", [OutFile]),
+ {ok, Out} = file:open(OutFile, [write]),
+ ok = io:format(Out, "-module(~s).~n-compile(export_all).~n~n", [Module]),
+ io:format(Out, "%%~n%% code at line ~w from file ~s~n%%~n",
+ [Line, C#comp.infile]),
+
+ io:format(Out, "-import(yaws_api, [f/2, fl/1, parse_post_data/2]). ~n~n", []),
+ io:format(Out, '-include("~s/include/yaws_api.hrl").~n',
+ [GC#gconf.yaws_dir]),
+ C#comp{outfd = Out,
+ outfile = OutFile}.
+
+
+gen_err(C, LineNo, NumChars, Err) ->
+ S = io_lib:format("<p> Error in File ~s Erlang code beginning "
+ "at line ~w~n"
+ "Error is: ~p~n", [C#comp.infile, C#comp.startline,
+ Err]),
+ yaws:elog("~s~n", [S]),
+ {error, NumChars, S}.
+
+
+comp_err(C, LineNo, NumChars, Err) ->
+ case Err of
+ [{FileName, [ErrInfo|_]} |_] ->
+ {Line0, Mod, E}=ErrInfo,
+ Line = Line0 + C#comp.startline - 9,
+ ?Debug("XX ~p~n", [{LineNo, Line0}]),
+ Str = io_lib:format("~s:~w: ~s\n",
+ [C#comp.infile, Line,
+ apply(Mod, format_error, [E])]),
+ HtmlStr = ?F("~n<pre>~nDynamic compile error: ~s~n</pre>~n",
+ [Str]),
+ yaws:elog("Dynamic compiler err ~s", [Str]),
+ {error, NumChars, HtmlStr};
+ Other ->
+ yaws:elog("Dynamic compile error", []),
+ {error, NumChars, ?F("<pre> Compile error - "
+ "Other err ~p</pre>~n", [Err])}
+ end.
+
+
+%% due to compiler not producing proper error
+%% we NEED to catch all io produced by the compiler
+
+proc_compile_file(F, Opts) ->
+ G = group_leader(),
+ group_leader(self(), self()),
+ P = proc_lib:spawn(?MODULE, compiler_proc, [self(), F, Opts]),
+ Res = get_compiler_data(P, []),
+ group_leader(G, self()),
+ Res.
+
+compiler_proc(Top, F, Opts) ->
+ R = (catch compile:file(F, Opts)),
+ Top ! {self(), result, R}.
+
+
+get_compiler_data(P, Ack) ->
+ receive
+ {P, result, {ok, Mod, Bin}} ->
+ {ok, Mod, Bin};
+ {io_request, P1, P2, {put_chars, M, F, A}} ->
+ P1 ! {io_reply, P2, ok},
+ Str = apply(M, F, A),
+ get_compiler_data(P, [Str|Ack]);
+ {P, result, {error, Errors, Warnings}} ->
+ {error, Errors, Warnings};
+ {P, result, error} ->
+ S = lists:map(
+ fun(S) -> S ++ "\n" end, lists:reverse(Ack)),
+ {error, S}
+ end.
+
+
+
+
+
+
+
+
+
View
11 src/yaws_config.erl
@@ -16,7 +16,7 @@
%% where to look for yaws.conf
paths() ->
- ["/etc", os:getenv("HOME"), "."].
+ [os:getenv("HOME"), ".", "/etc"].
%% load the config
@@ -112,12 +112,11 @@ arrange([C1|Tail], {in, C0}, A, B) ->
-
make_default_gconf() ->
Y = yaws_dir(),
#gconf{yaws_dir = Y,
- ebin_dir = filename:join([Y, "examples/ebin"]),
- include_dir = filename:join([Y, "examples/include"]),
+ ebin_dir = [filename:join([Y, "examples/ebin"])],
+ include_dir = [filename:join([Y, "examples/include"])],
logdir = ".",
yaws = "Yaws 0.2"}.
@@ -168,7 +167,7 @@ fload(FD, globals, GC, C, Cs, Lno, Chars) ->
["ebin_dir", '=', Dir] ->
case is_dir(Dir) of
true ->
- fload(FD, globals, GC#gconf{ebin_dir = Dir},
+ fload(FD, globals, GC#gconf{ebin_dir = [Dir|GC#gconf.ebin_dir]},
C, Cs, Lno+1, Next);
false ->
{error, ?F("Expect directory at line ~w", [Lno])}
@@ -177,7 +176,7 @@ fload(FD, globals, GC, C, Cs, Lno, Chars) ->
["include_dir", '=', Dir] ->
case is_dir(Dir) of
true ->
- fload(FD, globals, GC#gconf{include_dir = Dir},
+ fload(FD, globals, GC#gconf{include_dir=[Dir|GC#gconf.include_dir]},
C, Cs, Lno+1, Next);
false ->
{error, ?F("Expect directory at line ~w", [Lno])}
View
265 src/yaws_server.erl
@@ -283,6 +283,7 @@ aloop(CliSock, GS, Num) ->
Sconf = pick_sconf(H, GS#gs.group),
?Debug("Sconf: ~p", [?format_record(Sconf, sconf)]),
?TC([{record, Sconf, sconf}]),
+ ?Debug("Headers = ~p~n", [?format_record(H, headers)]),
Res = apply(yaws_server, Req#http_request.method,
[CliSock, GS#gs.gconf, Sconf, Req, H]),
maybe_access_log(CliSock, Sconf, Req),
@@ -443,7 +444,7 @@ get_headers(CliSock, Req, GC, H) ->
make_arg(CliSock, Head, Req, GC, SC) ->
?TC([{record, GC, gconf}, {record, SC, sconf}]),
#arg{clisock = CliSock,
- h = Head,
+ headers = Head,
req = Req,
docroot = SC#sconf.docroot}.
@@ -507,7 +508,7 @@ do_yaws(CliSock, GC, SC, Req, H, ARG, UT) ->
deliver_dyn_file(CliSock, GC, SC, Req, H, Spec, ARG,UT);
Other ->
del_old_files(Other),
- {ok, Spec} = compile_file(UT#urltype.fullpath, GC, SC),
+ {ok, Spec} = yaws_compile:compile_file(UT#urltype.fullpath, GC, SC),
?Debug("Spec for file ~s is:~n~p~n",[UT#urltype.fullpath, Spec]),
ets:insert(SC#sconf.ets, {FileAtom, Mtime, Spec}),
deliver_dyn_file(CliSock, GC, SC, Req, H, Spec, ARG, UT)
@@ -543,7 +544,7 @@ get_client_data(CliSock, all, eof) ->
<<>>.
-do_dyn_headers(CliSock, GC, SC, Req, Head, [H|T], ARG) ->
+do_dyn_headers(CliSock, GC, SC, Bin, Fd, Req, Head, [H|T], ARG) ->
?TC([{record, GC, gconf}, {record, SC, sconf}]),
{DoClose, Chunked} = case Req#http_request.version of
{1, 0} -> {true, []};
@@ -553,36 +554,38 @@ do_dyn_headers(CliSock, GC, SC, Req, Head, [H|T], ARG) ->
{mod, LineNo, YawsFile, SkipChars, Mod, some_headers} ->
MimeType = "text/html",
OutH = make_dyn_headers(DoClose, MimeType),
+ {_, Bin2} = skip_data(Bin, Fd, SkipChars),
case (catch apply(Mod, some_headers, [ARG])) of
{ok, Out} ->
- {[make_200(),OutH, Chunked, Out, crnl()], T, DoClose};
+ {[make_200(),OutH, Chunked, Out, crnl()], T, DoClose, Bin2};
close ->
exit(normal);
Err ->
{[make_200(), OutH, crnl(),
- ?F("<p> yaws code ~w:~w(~p) crashed:"
- " ~n~p~n",
- [Mod, some_headers, [Head], Err])], T, DoClose}
+ ?F("<p> ~n<xmp>yaws code ~w:~w(~p) crashed:"
+ " ~n~p~n</xmp>~n",
+ [Mod, some_headers, [Head], Err])], T, DoClose, Bin2}
end;
{mod, LineNo, YawsFile, SkipChars, Mod, all_headers} ->
+ {_, Bin2} = skip_data(Bin, Fd, SkipChars),
case (catch apply(Mod, all_headers, [ARG])) of
{ok, StatusCode, Out} when integer(StatusCode) ->
put(status_code, StatusCode),
- {[Out, crnl()], T, DoClose};
+ {[Out, crnl()], T, DoClose, Bin2};
close ->
exit(normal);
Err ->
MimeType = "text/html",
OutH = make_dyn_headers(DoClose, MimeType),
{[make_200(), OutH, crnl(),
- ?F("<p> yaws code ~w:~w(~p) crashed:"
+ ?F("<p> yaws code ~w:~w(~p) crashed or returned bad value:"
" ~n~p~n",
- [Mod, all_headers, [Head], Err])], T, DoClose}
+ [Mod, all_headers, [Head], Err])], T, DoClose, Bin2}
end;
_ ->
MimeType = "text/html",
OutH = make_dyn_headers(DoClose, MimeType),
- {[make_200(),OutH, Chunked, crnl()], [H|T], DoClose}
+ {[make_200(),OutH, Chunked, crnl()], [H|T], DoClose, Bin}
end.
@@ -593,10 +596,11 @@ deliver_dyn_file(CliSock, GC, SC, Req, Head, Specs, ARG, UT) ->
?TC([{record, GC, gconf}, {record, SC, sconf}]),
Fd = ut_open(UT),
Bin = ut_read(Fd),
- {S2, Tail, DoClose} = do_dyn_headers(CliSock,GC, SC,Req,Head,Specs,ARG),
+ {S2, Tail, DoClose, Bin2} = do_dyn_headers(CliSock,GC, SC,Bin,Fd,
+ Req,Head,Specs,ARG),
+ ?Debug("TAIL =~p~n", [Tail]),
safe_send(true, CliSock, S2),
- deliver_dyn_file(CliSock, GC, SC, Req, Head, UT,
- DoClose, Bin, Fd, Specs, ARG).
+ deliver_dyn_file(CliSock, GC, SC, Req, Head, UT, DoClose, Bin2, Fd, Tail, ARG).
@@ -1075,242 +1079,15 @@ flush(Sock, Sz) ->
-%% tada !!
-%% returns a CodeSpec which is:
-%% a list {data, NumChars} |
-%% {mod, LineNo, YawsFile, NumSkipChars, Mod, Func} |
-%% {error, NumSkipChars, E}}
-
-% each erlang fragment inside <erl> .... </erl> is compiled into
-% its own module
-
-
--record(comp, {
- gc, %% global conf
- sc, %% server conf
- startline = 0,
- modnum = 1,
- infile,
- infd,
- outfile,
- outfd}).
-
-
-comp_opts(GC) ->
- I = lists:map(fun(Dir) -> {i, Dir} end, GC#gconf.include_dir),
- YawsDir = {i, "/home/klacke/yaws/include"},
- I2 = [YawsDir | I],
- Opts = [binary, report_errors | I2],
- ?Debug("Compile opts = ~p~n", [Opts]),
- Opts.
-
-
-compile_file(File, GC, SC) ->
- case file:open(File, [read]) of
- {ok, Fd} ->
- Spec = compile_file(#comp{infile = File,
- infd = Fd, gc = GC, sc = SC},
- 1,
- io:get_line(Fd, ''), html, 0, []);
- Err ->
- yaws:elog("can't open ~s~n", [File]),
- exit(normal)
- end.
-
-compile_file(C, LineNo, eof, Mode, NumChars, Ack) ->
- file:close(C#comp.infd),
- {ok, lists:reverse([{data, NumChars} |Ack])};
-
-compile_file(C, LineNo, Chars = "<erl>" ++ Tail, html, NumChars, Ack) ->
- ?Debug("start erl:~p",[LineNo]),
- C2 = new_out_file(LineNo, C, C#comp.gc),
- C3 = C2#comp{startline = LineNo},
- L = length(Chars),
- if
- NumChars > 0 ->
- compile_file(C3, LineNo+1, line(C) , erl,L,
- [{data, NumChars} | Ack]);
- true -> %% just ignore zero byte data segments
- compile_file(C3, LineNo+1, line(C) , erl, L, Ack)
- end;
-
-compile_file(C, LineNo, Chars = "</erl>" ++ Tail, erl, NumChars, Ack) ->
- ?Debug("stop erl:~p",[LineNo]),
- file:close(C#comp.outfd),
- NumChars2 = NumChars + length(Chars),
- case compile:file(C#comp.outfile, comp_opts(C#comp.gc)) of
- {ok, ModuleName, Binary} ->
- case code:load_binary(ModuleName, C#comp.outfile, Binary) of
- {module, ModuleName} ->
- C2 = C#comp{modnum = C#comp.modnum+1},
- L2 = check_exported(C2, LineNo,NumChars2, ModuleName),
- compile_file(C, LineNo+1, line(C),html,0,L2++Ack);
- Err ->
- A2 = gen_err(C, LineNo, NumChars2,
- ?F("Cannot load module ~p: ~p",
- [ModuleName, Err])),
- compile_file(C, LineNo+1, line(C),
- html, 0, [A2|Ack])
- end;
- {error, Errors, Warnings} ->
- %% FIXME remove outfile here ... keep while debuging
- A2 = comp_err(C, LineNo, NumChars2, Errors),
- compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack]);
- error ->
- %% this is boring but does actually happen
- %% in order to get proper user errors here we need to catch i/o
- %% or hack compiler/parser
- yaws:elog("Dynamic compile error in file ~s, line~w",
- [C#comp.infile, LineNo]),
- A2 = {error, NumChars2, ?F("<xmp> Dynamic compile error in file "
- " ~s line ~w </xmp>",
- [C#comp.infile, LineNo])},
- compile_file(C, LineNo+1, line(C), html, 0, [A2|Ack])
- end;
-
-compile_file(C, LineNo, Chars = "<xmp>" ++ Tail, html, NumChars, Ack) ->
- ?Debug("start xmp:~p",[LineNo]),
- compile_file(C, LineNo+1, line(C) , xmp, NumChars + length(Chars), Ack);
-
-compile_file(C, LineNo, Chars = "</xmp>" ++ Tail, xmp, NumChars, Ack) ->
- ?Debug("stop xmp:~p",[LineNo]),
- compile_file(C, LineNo+1, line(C) , html, NumChars + length(Chars), Ack);
-
-compile_file(C, LineNo, Chars, erl, NumChars, Ack) ->
- io:format(C#comp.outfd, "~s", [Chars]),
- compile_file(C, LineNo+1, line(C), erl, NumChars + length(Chars), Ack);
-
-compile_file(C, LineNo, Chars, html, NumChars, Ack) ->
- compile_file(C, LineNo+1, line(C), html, NumChars + length(Chars), Ack);
-
-compile_file(C, LineNo, Chars, xmp, NumChars, Ack) ->
- compile_file(C, LineNo+1, line(C), xmp, NumChars + length(Chars), Ack).
-
-
-
-
-
-check_exported(C, LineNo, NumChars, Mod) when C#comp.modnum == 1->
- case {is_exported(some_headers, 1, Mod),
- is_exported(all_headers, 1, Mod),
- is_exported(all_out, 1, Mod)} of
- {true, true, _} ->
- [gen_err(C, LineNo, NumChars,
- ?F("Cannot have both some and the all "
- "headers",[]))];
-
- %% someheaders
- {true, false, true} ->
- [{mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,some_headers},
- {mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,out}];
- {true, false, false} ->
- [{mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,some_headers}];
-
- %% allheaders
- {false, true, true} ->
- [{mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,all_headers},
- {mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,out}];
-
- {false, true, false} ->
- [{mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,all_headers}];
-
- {false, false, true} ->
- [{mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,out}]
-
-
- end;
-check_exported(C, LineNo, NumChars, Mod) ->
- case is_exported(out, 1, Mod) of
- true ->
- [{mod, C#comp.startline, C#comp.infile,
- NumChars,Mod,out}];
- false ->
- [gen_err(C, LineNo, NumChars,
- "out/1 is not defined ")]
- end.
-
-
-
-
-line(C) ->
- io:get_line(C#comp.infd, '').
-
-is_exported(Fun, A, Mod) ->
- case (catch Mod:module_info()) of
- List when list(List) ->
- case lists:keysearch(exports, 1, List) of
- {value, {exports, Exp}} ->
- lists:member({Fun, A}, Exp);
- _ ->
- false
- end;
- _ ->
- false
- end.
-
-
-%% this will generate 9 lines
-new_out_file(Line, C, GC) ->
- Mnum = gen_server:call(?MODULE, mnum),
- Module = [$m | integer_to_list(Mnum)],
- OutFile = "/tmp/yaws/" ++ Module ++ ".erl",
- ?Debug("Writing outout file~s~n", [OutFile]),
- {ok, Out} = file:open(OutFile, [write]),
- ok = io:format(Out, "-module(~s).~n-compile(export_all).~n~n", [Module]),
- io:format(Out, "%%~n%% code at line ~w from file ~s~n%%~n",
- [Line, C#comp.infile]),
-
- io:format(Out, "-import(yaws_api, [f/2, fl/1, parse_post_data/2]). ~n~n", []),
- io:format(Out, '-include("~s/include/yaws_api.hrl").~n',
- [GC#gconf.yaws_dir]),
- C#comp{outfd = Out,
- outfile = OutFile}.
+tcp_send(S, Data) ->
+ ?Debug("SEND: ~s", [binary_to_list(to_binary(Data))]),
+ ok = gen_tcp:send(S, Data).
mtime(F) ->
F#file_info.mtime.
-gen_err(C, LineNo, NumChars, Err) ->
- S = io_lib:format("<p> Error in File ~s Erlang code beginning "
- "at line ~w~n"
- "Error is: ~p~n", [C#comp.infile, C#comp.startline,
- Err]),
- yaws:elog("~s~n", [S]),
- {error, NumChars, S}.
-
-
-comp_err(C, LineNo, NumChars, Err) ->
- case Err of
- [{FileName, [ErrInfo|_]} |_] ->
- {Line0, Mod, E}=ErrInfo,
- Line = Line0 + C#comp.startline - 9,
- ?Debug("XX ~p~n", [{LineNo, Line0}]),
- Str = io_lib:format("~s:~w: ~s\n",
- [C#comp.infile, Line,
- apply(Mod, format_error, [E])]),
- HtmlStr = ?F("~n<pre>~nDynamic compile error: ~s~n</pre>~n",
- [Str]),
- yaws:elog("Dynamic compiler err ~s", [Str]),
- {error, NumChars, HtmlStr};
- Other ->
- yaws:elog("Dynamic compile error", []),
- {error, NumChars, ?F("<pre> Compile error - "
- "Other err ~p</pre>~n", [Err])}
- end.
-
-tcp_send(S, Data) ->
- ?Debug("SEND: ~s", [binary_to_list(to_binary(Data))]),
- ok = gen_tcp:send(S, Data).
-
-
not_found_body(Url, GC, SC) ->
View
2  www/EXHEAD
@@ -3,7 +3,7 @@
<table bgcolor="#B6b6a5" border="2" cellpadding="5" cellspacing="0" width="100%">
<tr border="2">
- <td> <A HREF="index.yaws">- Top Page</a> </td>
+ <td> <A HREF="index.yaws">Top Page</a> </td>
<td> <A HREF="simple.yaws">Simple</a></td>
<td> <A HREF="form.yaws">Forms</a> </td>
<td> <A HREF="redirect.yaws">Redirect</a> </td>
View
22 www/HEAD
@@ -1,17 +1,9 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<HTML>
-<HEAD>
- <meta name="keywords" content="Yaws">
-
-
- <TITLE>Yaws</TITLE>
-
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-
-
-<link rel="stylesheet" type="text/css" href="stil.css">
-
-
-</HEAD>
-<BODY BGCOLOR="#C6C6B5" text="#333333">
+<html>
+<head>
+ <meta name="keywords" content="Yaws">
+ <title>Yaws</title>
+ <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+ <link rel="stylesheet" type="text/css" href="stil.css">
+</head>
View
1  www/TOPTAB
@@ -16,6 +16,7 @@
<td> <A HREF="todo.yaws">TODO list </a> </td>
<td> <A HREF="motivation.yaws">Motivation </a> </td>
<td> <A HREF="download">Download </a> </td>
+ <td> <A HREF="api.yaws">Yaws API </a> </td>
</tr>
</table>
View
111 www/api.yaws
@@ -0,0 +1,111 @@
+
+<erl>
+
+out(A) ->
+ yaws_api:ssi(A#arg.docroot, ["/HEAD", "/TOPTAB"]).
+
+</erl>
+
+<H1>Yaws API</H2>
+
+Here we describe the API avalable to Yaws applications.
+First and foremost, the entire regular erlang API is available, this
+include mnesia ans all other erlang applications that are part of the
+regular erlang system.
+<p>
+Here we describe the functions available in the module
+<code>yaws_api</code>. We divide the API functions into four distinct
+groups.
+<ol>
+<li> Functions that are only callable from the <code>all_headers/1</code>
+function. The all_headers/1 function is must generate all HTTP headers as well
+as the HTTP status code line. For example, a function which does a HTTP
+redirect is such a function.
+<li> Functions that are only callable inside the <code>some_headers/1</code>
+function.
+<li>Functions that are only callable inside the <code>out/1</code> function.
+<li> Functions that are callable evrywhere.
+</ol>
+
+
+<h2>Functions callable from all_headers/1</h2>
+<hr><h3> <code>redirect(Location)</code></h3>
+Issue a HTTP redirect to <code>Location</code>
+
+
+<h2>Functions callable from some_headers/1</h2>
+<hr><h3> <code>setcookie(Name, Value, [Path, [Expire, [Domain, Secure]]])</code></h3>
+Sets a cookie. Usage examples avilable in <a href="cookie.yaws">cookie.yaws</a>
+
+
+
+
+<h2>Functions callable from out/1</h2>
+<hr>
+<h3> <code>pre_ssi_files(DocRoot, Files)</code></h3>
+This function will perform a server side include on the files in
+<code>Files</code>. The data will be transformed so that all
+&lt;, &gt;, &amp; cahracters are htmlized. This useful for including
+code snippets in the yaws code.
+
+
+<hr>
+<hr><h3> <code>pre_ssi_string(String)</code></h3>
+Same as above, but for an explicit string
+
+
+
+
+<h2>Functions callable from anywhere </h2>
+
+<hr><h3><code>htmlize(Binary)</code></h3>
+Transform data so that all
+&lt;, &gt;, &amp; characters and line breaks are htmlized.
+
+<hr><h3><code>f(Fmt, Args)</code></h3>
+This function is automatically included in all yaws code. It is just
+a shortcut for: <code>io_lib:format(Fmt, Args)
+
+
+<hr><h3><code>f([Fmt, Args .......])</code></h3>
+This function is automatically included in all yaws code. It will
+apply io_lib:format to a conscutive list of Fmt and Args arguments.
+
+
+<hr><h3><code>ssi([File1, File2 ...])</code></h3>
+Server side include, the files will be included as is into the
+document.
+
+
+
+<hr>
+<h3> <tt> parse_post_data(Bin, Spec) </tt> </h2>
+
+<p>
+When data is POSTed to a yaws page,
+this function can be used to parse the
+data in a convenient way. Data which is posted from a form is naturally
+arranged as a list of {key,value} pairs.
+<p> Similarly, when data is fed to a yaws page in the URL as a query part,
+the query can be parsed by this function.
+
+<p>We can see examples of the usage of this function in the files
+<a href="form.yaws">form.yaws</a> which feeds the POST data to the file
+<a href="post.yaws">post.yaws</a>. The file post.yaws will call this function
+to parse the data POSTed from the previous page.
+
+
+
+
+<hr>
+<h3><code> code_to_phrase(Code) </code></h2>
+<p>Makes a mapping from HTTP status codes to HTTP status code phrases.
+
+
+
+
+
+
+<erl>
+out(A) -> yaws_api:ssi(A#arg.docroot, ["/END"]).
+</erl>
View
30 www/cookies.yaws
@@ -9,23 +9,39 @@ out(A) -> yaws_api:ssi(A#arg.docroot, ["/HEAD", "/EXHEAD"]).
Cookies are the means in HTTP to assign data to a session. A HTTP session
typically consists of many (and sometimes concurrent) TCP connections from the
client to the web server. The first time a client arrives to our webserver, we
-issue the HTTP header <tt>SetCookie: someval</tt>. The browser will then in
-subsequent connections to the same server pass this value "someval" in its
-client side <tt>Cookie: someval</tt> header. We can thereby assign state to a
+issue the HTTP header <tt>Set-Cookie: var=someval</tt>. The browser will then in
+subsequent connections to the same server pass this cookie "var=someval" in its
+client side <tt>Cookie: var=someval</tt> header. We can thereby assign state to a
session, either through data actualy encoded into the cookie value itself, or by
associating server side session data to the cookie.
<p>
+
Let's do an example where we set a simple cookie, and create a specific erlang process
-which is then responsible for that session. The cookie value will be a string encoding of
-the pid handling the session.
+which is then responsible for that session.
+The cookie value will be a string encoding of the pid handling the session.
<p>
-The yaws code in <a href="setcookie.yaws">setcookie.yaws</a> sets the cookie in the browser.
+The yaws code in
+<a href="setcookie.yaws">setcookie.yaws</a> sets the cookie in the browser.
-<p>And the yaws code in <a href="readcookie.yaws">readcookie.yaws</a> will read the cookie
+<p>And the yaws code in <a href="readcookie.yaws">readcookie.yaws</a>
+will read the cookie
and report some uninteresting session data.
A correct definition of cookies can be found at Netscapes
<a href="http://www.netscape.com/newsref/std/cookie_spec.html">cookie spec</a>
+
+
+<p>The code to set the cookie looks like:
+
+<erl>
+out(A) -> yaws_api:pre_ssi_files(A#arg.docroot, ["setcookie.yaws"]).
+</erl>
+
+
+
+
+</html>
+
View
81 www/dynamic.yaws
@@ -11,25 +11,31 @@ out(A) ->
Yaws have verry nice support for generating dynamic content on the fly.
We use embedded erlang code to generate the content. The Erlang code
-is separated from the HTML code by <pre><erl></pre> and <tt></erl></tt>
+is separated from the HTML code by <tt> &lt;erl> </tt> and <tt> &lt;/erl> </tt>
markers. For example:
-<xmp>
+<erl>
+out(A) ->
-<html>
-<h1>Foobar</h1>
+L = "
+ <html>
+ <h1>Foobar</h1>
-<erl>
+ <erl>
-out(Arg) ->
- {ok, "Funky Shit"}.
+ out(Arg) ->
+ {ok, \"Funky Shit\"}.
-</erl>
+ </erl>
+
+ <h1>Baz</h1>
+ </html>
-<h1>Baz</h1>
-</html>
+",
+
+yaws_api:pre_ssi_string(L).
+</erl>
-</xmp>
@@ -51,13 +57,12 @@ The <tt>out/1</tt> function is supplied with a record argument. The
definition of that record is automatically included in the embedded erlang code
and the record definition is:
-
-<xmp>
-
+<erl>
+out(A) -> yaws_api:pre_ssi_string("
-record(arg, {
clisock, %% the socket leading to the peer client
- h, %% headers
- req, %% request
+ headers, %% #headers{} record
+ req, %% #http_request{} record
clidata, %% The client data (as a binary in POST requests)
querydata, %% Was the URL on the form of ....?query (GET reqs)
docroot %% where's the data
@@ -87,7 +92,8 @@ and the record definition is:
keep_alive,
content_length}).
-</xmp>
+").
+</erl>
@@ -108,47 +114,6 @@ The usage of these functions is better
described in the <a href="examples.yaws">Examples</a> section.
-
-<h2>The yaws_api module</h2>
-
-The yaws_api module contains a number of utility functions which
-is available to the erlang code embedded in the HTML documents.
-Naturally, all the normal functions in the erlang libraries are available,
-but the yaws_api module, contains functions that ease the development of
-code that generates dynamic HTML content.
-We have:
-
-<br>
-
-<ul>
-<li> <tt> parse_post_data(Bin, Spec) </tt> <br>
-When data is POSTed to a yaws page, this function can be used to parse the
-data in a convenient way. Data which is posted from a form is naturally
-arranged as a list of key,value pairs.
-<p> Similarly, when data is fed to a yaws page in the URL as a query part,
-the query can be parsed by this function. <br>
-
-
-<li> <tt> code_to_phrase(Code) </tt> <br>
-Makes a mapping from HTTP status codes to HTTP status code phrases. <br>
-
-
-<li> <tt> ssi(DocRoot, FileList) </tt>
-Server side include. <br>
-
-
-<li> <tt> redirect(Url) </tt> <br>
-This function must be called in the first chunk of erlang coe in a yaws file.
-Furthermore, it must be called from the <tt>all_headers/1</tt> function.
-It will generate a redirect responce to the client.
-<br>
-
-
-
-</ul>
-
-
-
<erl>
out(A) -> yaws_api:ssi(A#arg.docroot, ["/END"]).
</erl>
View
8 www/examples.yaws
@@ -4,16 +4,20 @@ out(A) -> yaws_api:ssi(A#arg.docroot, ["/HEAD", "/EXHEAD"]).
<h1>Yaws Examples</h1>
-<br>
+<p>
Here we try to show the power of yaws by means of a series of examples.
Many of the pages inside this documentation, use embedded erlang code
merely as a means to include files into the HTML documentation. Yaws can
be used to do much more which is shown by the examples.
-<br>
+<p>
It can be used to generate any dynamic content, and also, combining Yaws with
the Erlang DBMS Mnesia, we can easily connect persitant data to a Cookie.
+<p>
+In all of the examples we will utilize the yaws api functions defined in the
+module <tt>yaws_api</tt>. The documentation for the API module is
+<a href="api.yaws">here</a>
<erl>
out(A) -> yaws_api:ssi(A#arg.docroot, ["/END"]).
View
5 www/history.yaws
@@ -11,6 +11,11 @@ out(A) ->
<table border="2">
+
+<tr><td> Feb 26, 2002 Cought I/O from the erlang compiler when compiling.
+The compiler will (wrongly) produce some errors plainly to the tty.
+The RightThing would be to fix that, but .....
+<tr><td> Feb 22, 2002 yaws_api:set_cookie + examples </td></tr>
<tr><td> Feb 14, 2002 redid HTML tables for top docs </td></tr>
<tr><td> Feb 13, 2002 released first version to the net 0.20 </td></tr>
<tr><td> Feb 12, 2002 cached pages in RAM (ets tables) </td></tr>
View
9 www/index.yaws
@@ -60,15 +60,16 @@ The SourceForge www page is <a href="http://sourceforge.net/projects/erlyaws/">h
<p>To cvs check out the latest source first install
an <a href="http://www.erlang.org">Erlang</a> system, then do:
-
-<pre>
-
+<erl>
+out(A) -> pre_ssi_string("
# export CVS_RSH=ssh
# export CVSROOT=:pserver:anonymous@cvs.erlyaws.sourceforge.net:/cvsroot/erlyaws
# cvs login
# cvs -z3 co .
# cd yaws; make; make install
-</pre>
+"
+</erl>
+
Will checkout the bleeding edge source, build it and install it at
127.0.0.1:80 with the docroot set to the local documentation.
View
33 www/pcookie.yaws
@@ -0,0 +1,33 @@
+<erl>
+out(A) -> yaws_api:ssi(A#arg.docroot, ["/HEAD", "/EXHEAD"]).
+</erl>
+
+
+
+<h1>Persistant Cookies</h1>
+<p>
+We saw in the first <a href="cookies.yaws">cookie</a> example, how we
+assigned a special erlang process to handle each session.
+The cookie has an expiry date, and the correct thing would be to let the
+handling process live as long as the cookie is valid. This is not a good option.
+A better option is to store cookie in a persistant storage. This can be an
+ets table or a dets table. If we choose an ets table, the cookies will disappear
+when the yaws server is restarded, whereas if we choose a dets table,
+the cookies will survive daemon restarts. What to choose depends on the
+type of cookie information we have.
+
+<p>
+The yaws code in
+<a href="setpcookie.yaws">setpcookie.yaws</a> sets the cookie in the browser.
+
+<p>And the yaws code in <a href="readpcookie.yaws">readpcookie.yaws</a>
+will read the cookie
+
+<p>
+Let's show some code. To set the cookie we we have:
+
+
+
+
+</html>
+
View
63 www/readcookie.yaws
@@ -0,0 +1,63 @@
+<html>
+
+<h2> Read cookie </h2>
+
+<erl>
+out(A) ->
+ H=A#arg.headers,
+ C = H#headers.cookie,
+ io:format("Cookie =~p~n", [C]),
+ L=case C of
+ [] ->
+ f("<p> No cookie set from the browser, need to "
+ "visit <a href=\"/setcookie.yaws\">setcookie.yaws</a> "
+ "to set the cookie first ~n", []);
+ [Cookie| Cs] ->
+ case string:tokens(Cookie, [$=]) of
+ ["foobar", PidStr] ->
+ Pid = list_to_pid(PidStr),
+ Pid ! {self(), tick},
+ receive
+ {Pid, VisitList} ->
+ f("<p> Yes, I read your cookie "
+ "You have vistited this page ~w times "
+ "they were ~n<ol> ~n~s </ol>~n "
+
+ "Reloading this page will show the session state ",
+
+ [length(VisitList),
+ lists:map(fun(D) ->
+ Ds = yaws:time_to_string(D, "GMT"),
+ f("<li> ~s~n", [Ds]) end,
+ VisitList)
+ ])
+ after 500 ->
+ f("<p> You had a cookie, but the pid handling your sess "
+ "timedout ...",[])
+ end;
+ Other ->
+ f("<p> Noooo weirdo cookie here ~p~n", [C])
+ end
+ end,
+ {ok, L}.
+
+</erl>
+
+
+<p>
+The code to read the cookie, is simple, we get the cookie passed to the yaws
+code in the #arg structure which is the argument supplied to the out/1 function.
+The code is:
+<erl>
+out(A) ->
+ yaws_api:pre_ssi_files(A#arg.docroot, ["readcookie.yaws"]).
+</erl>
+
+
+
+
+</html>
+
+
+
+
View
55 www/readpcookie.yaws
@@ -0,0 +1,55 @@
+<html>
+
+<h2> Read persitant cookie </h2>
+
+<erl>
+
+to_integer(S) ->
+ list_to_integer(string:strip(S, both)).
+
+out(A) ->
+ H=A#arg.headers,
+ C = H#headers.cookie,
+ io:format("Cookie =~p~n", [C]),
+ L=case C of
+ [] ->
+ f("<p> No cookie set from the browser, need to "
+ "visit <a href=\"/setpcookie.yaws\">setpcookie.yaws</a> "
+ "to set the cookie first ~n", []);
+ [Cookie| Cs] ->
+ case string:tokens(Cookie, [$=]) of
+ ["pfoobar", Num] ->
+ case ets:lookup(pcookies, {cookie,to_integer(Num)}) of
+ [{{cookie, Num}, Data}] ->
+ f("<p> Yes, I read your cookie "
+ "Your persistant info is ~p: ~n", [Data]);
+ [] ->
+ f("<p> You had a cookie,but the data is gone",[])
+ end;
+ Other ->
+ f("<p> Noooo weirdo cookie here ~p~n", [C])
+ end
+ end,
+ {ok, L}.
+
+</erl>
+
+
+<p>
+The code to read the cookie, is simple, we get the cookie passed to the yaws
+code in the #arg structure which is the argument supplied to the out/1 function.
+The code is:
+<erl>
+out(A) ->
+ yaws_api:pre_ssi_files(A#arg.docroot, ["readpcookie.yaws"]).
+</erl>
+
+
+</html>
+
+
+
+
+
+
+
View
52 www/setcookie.yaws
@@ -1,3 +1,4 @@
+
<erl>
session(A, Visits) ->
@@ -6,17 +7,52 @@ session(A, Visits) ->
N = calendar:local_time(),
From ! {self(), [N|Visits]},
session(A, [N|Visits])
- after 30000 -> %% keep state for 30 secs only
+ after 60000 -> %% keep state for 60 secs only
exit(normal)
end.
-someheaders(A) ->
- H=A#arg.headers,
- case H#headers.cookie of
- undefined ->
+
+some_headers(A) ->
+ H = A#arg.headers,
+ C = H#headers.cookie,
+ case C of
+ [Cookie|_] ->
+ case string:tokens(Cookie, [$=]) of
+ ["foobar", PidStr] ->
+ Pid = list_to_pid(PidStr),
+ case process_info(Pid, messages) of
+ undefined ->
+ Now = calendar:local_time(),
+ P = spawn(fun() -> session(A, [Now]) end),
+ yaws_api:setcookie("foobar", pid_to_list(P), "/");
+ _ ->
+ ok
+ end;
+ _ ->
+ ignore
+ end;
+ [] ->
Now = calendar:local_time(),
P = spawn(fun() -> session(A, [Now]) end),
- yaws_api:setcookie(pid_to_list(P), "/");
- PidStr ->
-
+ yaws_api:setcookie("foobar", pid_to_list(P), "/")
+ end.
+
+</erl>
+
+<html>
+
+
+<h2> set cookie </h2>
+
+<p>This is the page that set the cookie in the browser.
+<a href="/readcookie.yaws">readcookie.yaws</a> will read the cookie and
+report persitant information as long as the browser session exists.
+
+<p> it will set the cookie <tt>foobar = &lt;x,y,z&gt;; </tt> where the
+x,y,z string is the textual representation of an actual erlang pid
+which will be responsible for this session.
+
+</html>
+
+
View
73 www/setpcookie.yaws
@@ -0,0 +1,73 @@
+
+<erl>
+
+ensure_pcookie_server() ->
+ case whereis(pcookie_server) of
+ undefined ->
+ proc_lib:start(?MODULE, pserv, []);
+ _ ->
+ ok
+ end.
+
+pserv() ->
+ catch begin
+ register(pcookie_server, self()),
+ T = ets:new(pcookies, [set, public, named_table]),
+ ets:insert(T, {counter, 0})
+ end,
+ proc_lib:init_ack(ok),
+ pserv_loop().
+
+pserv_loop() ->
+ receive
+ X ->
+ pserv_loop()
+ end.
+
+setcookie(A) ->
+ Num = ets:update_counter(pcookies, counter, 1),
+ Data = {(A#arg.headers)#headers.user_agent, calendar:local_time(),
+ inet:peername(A#arg.clisock)},
+ ets:insert(pcookies, {{cookie, Num}, Data}),
+ yaws_api:setcookie("pfoobar", integer_to_list(Num), "/").
+
+
+
+some_headers(A) ->
+ ensure_pcookie_server(),
+ H = A#arg.headers,
+ C = H#headers.cookie,
+ case C of
+ [Cookie|_] ->
+ case string:tokens(Cookie, [$=]) of
+ ["pfoobar", NumStr] ->
+ Num = list_to_integer(NumStr),
+ %% cookie allready set
+ case ets:lookup(pcookies, {c, Num}) of
+ [{cookie, Data}] ->
+ ok; %% cookie already set
+ [] ->
+ setcookie(A)
+ end;
+ _ ->
+ setcookie(A)
+ end;
+ _ ->
+ setcookie(A)
+ end.
+
+</erl>
+
+<html>
+
+
+<h2> Set persistant cookie </h2>
+
+<p>This is the page that set a persistant cookie in the browser.
+<a href="/readpcookie.yaws">readpcookie.yaws</a> will read the cookie and
+report persitant information.
+
+</html>
+
+
+
View
19 www/simple.yaws
@@ -1,7 +1,11 @@
<erl>
-out(A) -> file:read_file([A#arg.docroot, "/EXHEAD"]).
+
+out(A) ->
+ yaws_api:ssi(A#arg.docroot, ["/HEAD", "/EXHEAD"]).
+
</erl>
+
<h2>Hello world</h2>
The absoluteley most simple example is a HTML file which doesn't contain
@@ -13,10 +17,7 @@ HTML code.
<br>
<erl>
-out(A) ->
- {ok, B} = file:read_file([A#arg.docroot, "/simple_ex1.yaws"]),
- B2 = yaws_api:htmlize(B),
- {ok, ["<pre> \n", B2, "</pre>\n"]}.
+out(A) -> yaws_api:pre_ssi_files(A#arg.docroot, ["/simple_ex1.yaws"]).
</erl>
<br>
@@ -29,14 +30,12 @@ the data from the file will be delivered untouched.
The file <a href="simple_ex2.yaws">simple_ex2.yaws</a> contains the following
HTML code.
-<br>
+
<erl>
-out(A) ->
- {ok, B} = file:read_file([A#arg.docroot, "/simple_ex2.yaws"]),
- B2 = yaws_api:htmlize(B),
- {ok, ["<pre> \n", B2, "</pre>\n"]}.
+out(A) -> yaws_api:pre_ssi_files(A#arg.docroot, ["/simple_ex2.yaws"]).
</erl>
+
The file has one very simple function which just returns a tuple
<tt>{ok, String} </tt>
<br>
View
13 www/stil.css
@@ -1,6 +1,6 @@
-<STYLE TYPE="text/css">
- BODY {
+<style TYPE="text/css">
+ body {
background: #C6C6B5;
font-family: Verdana, Arial, Helvetica, sans-serif;
color: black;
@@ -14,7 +14,12 @@
background: green;
}
- H1, H2, H3, H4, H5 {
+ div.box { border: solid; border-width: thin; width: 100%;
+ background: rgb(235, 245, 230) }
+
+
+
+ H1, H2, H4, H5 {
text-decoration: none;
font-family: Verdana, Arial, Helvetica, sans-serif;
font-weight: bold;
@@ -35,4 +40,4 @@
A:active { color: lime } /* active links */
A:hover { background: #edb }
-</STYLE>
+</style>
Please sign in to comment.
Something went wrong with that request. Please try again.