Skip to content
Browse files

""

git-svn-id: https://erlyaws.svn.sourceforge.net/svnroot/erlyaws/trunk/yaws@20 9fbdc01b-0d2c-0410-bfb7-fb27d70d8b52
  • Loading branch information...
1 parent f021eb3 commit f448988a71e752eeeec4777ff6dab7aaef41af59 @klacke committed
Showing with 297 additions and 188 deletions.
  1. +1 −1 ebin/yaws.app
  2. +1 −1 scripts/yaws.conf.template
  3. +54 −4 src/yaws_api.erl
  4. +12 −11 src/yaws_server.erl
  5. +0 −2 www/END
  6. +14 −66 www/EXHEAD
  7. +3 −37 www/HEAD
  8. +19 −17 www/TOPTAB
  9. +31 −0 www/cookies.yaws
  10. +1 −1 www/examples.yaws
  11. +22 −13 www/form.yaws
  12. +3 −2 www/index.yaws
  13. +61 −10 www/post.yaws
  14. +22 −0 www/setcookie.yaws
  15. +4 −9 www/simple.yaws
  16. +6 −3 www/stats.yaws
  17. +38 −0 www/stil.css
  18. +5 −11 www/todo.yaws
View
2 ebin/yaws.app
@@ -1,6 +1,6 @@
{application,yaws,
[{description,"yaws WWW server"},
- {vsn,"0.2"},
+ {vsn,"0.21"},
{modules,[yaws, yaws_app, yaws_config, yaws_server, yaws_sup, yaws_api, yaws_log, yaws_ls, yaws_debug]},
{registered, []},
{mod,{yaws_app,[]}},
View
2 scripts/yaws.conf.template
@@ -4,7 +4,7 @@
# first we have a set of globals
-logdir = /var/yaws/www
+logdir = /var/log/yaws
ebin_dir = %yawsdir%/examples/ebin
include_dir = %yawsdir%/examples/include
keepalive_timeout = 15000
View
58 src/yaws_api.erl
@@ -24,6 +24,9 @@
%% Content-type: multipart/form-data; boundary=-------------------7cd1d6371ec
%% which is used for file upload
+parse_post_data(Bin) ->
+ parse_post_data(Bin, ['ALLSTRINGS']).
+
parse_post_data(Bin, Spec) ->
do_parse_spec(Bin, Spec, nokey, [], key).
@@ -34,9 +37,9 @@ parse_post_data(Bin, Spec) ->
%% float
%% string
%% ip
-%% onoff
%% binary
-
+%% checkbox
+%% 'ALLSTRINGS'
%% special value ['ALLSTRINGS'] can be used in order to denote that
%% the remainder of the args are all strings
@@ -84,15 +87,18 @@ tail_spec(['ALLSTRINGS']) ->
tail_spec(L) ->
L.
+coerce_type(_, []) ->
+ undefined;
coerce_type(int, Str) ->
list_to_integer(lists:reverse(Str));
coerce_type(float, Str) ->
list_to_float(lists:reverse(Str));
coerce_type(string, Str) ->
lists:reverse(Str);
-coerce_type(onoff, "no") ->
+coerce_type(checkbox, "no") ->
on;
-coerce_type(onoff, "ffo") ->
+coerce_type(checkbox, Str) ->
+ io:format("XX ~s~n", [Str]),
off;
coerce_type(ip, Str) ->
exit(nyi_ip);
@@ -181,3 +187,47 @@ fl([Fmt, Arg | Tail]) ->
[f(Fmt, Arg) | fl(Tail)];
fl([]) ->
[].
+
+
+
+%% htmlize ( <xmp> doesn't seem to work with opera )
+%% FIXME add all the html weirdo chars here
+htmlize(<<Char, Tail/binary>>) ->
+ case htmlize_char(Char) of
+ Char ->
+ <<Char, (htmlize(Tail))/binary>>;
+ Bin ->
+ <<Bin/binary, (htmlize(Tail))/binary>>
+ end;
+htmlize(<<>>) ->
+ <<>>.
+
+htmlize_char($>) ->
+ <<"&gt;">>;
+htmlize_char($<) ->
+ <<"&lt;">>;
+htmlize_char($\n) ->
+ <<"<br>">>;
+htmlize_char(X) ->
+ X.
+
+
+
+secs() ->
+ {MS, S, _} = now(),
+ (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) ->
+ exit(nyi).
+
+
+
View
23 src/yaws_server.erl
@@ -41,10 +41,13 @@ start_link() ->
status() ->
gen_server:call(?MODULE, status).
-stats() ->
- S = status(),
+stats() ->
+ {S, Time} = status(),
{GC, Srvs, _} = S,
- flatmap(
+ Diff = calendar:time_difference(Time, calendar:local_time()),
+ G = fun(L) -> lists:reverse(lists:keysort(2, L)) end,
+
+ R= flatmap(
fun({Pid, SCS}) ->
map(
fun(SC) ->
@@ -53,9 +56,10 @@ stats() ->
L = ets:match(E, {{urlc_total, '$1'}, '$2'}),
{SC#sconf.servername,
flatten(yaws:fmt_ip(SC#sconf.listen)),
- lists:keysort(2,map(fun(P) -> list_to_tuple(P) end, L))}
+ G(map(fun(P) -> list_to_tuple(P) end, L))}
end, SCS)
- end, Srvs).
+ end, Srvs),
+ {Diff, R}.
@@ -67,6 +71,7 @@ stats() ->
%% {stop, Reason}
%%----------------------------------------------------------------------
init([]) ->
+ put(start_time, calendar:local_time()), %% for uptime
case yaws_config:load() of
{ok, Gconf, Sconfs} ->
erase(logdir),
@@ -125,7 +130,7 @@ init2(Gconf, Sconfs) ->
%% {stop, Reason, State} (terminate/2 is called)
%%----------------------------------------------------------------------
handle_call(status, From, State) ->
- Reply = State,
+ Reply = {State, get(start_time)},
{reply, Reply, State};
handle_call(mnum, From, {GC, Group, Mnum}) ->
{reply, Mnum+1, {GC, Group, Mnum+1}}.
@@ -162,10 +167,6 @@ terminate(Reason, State) ->
ok.
-
-
-
-
%% One server per IP we listen to
gserv(GC, Group0) ->
?TC([{record, GC, gconf}]),
@@ -327,7 +328,7 @@ maybe_access_log(CliSock, SC, Req) ->
?TC([{record, SC, sconf}]),
case SC#sconf.access_log of
true ->
- {ok, {Ip, Port}} = inet:sockname(CliSock),
+ {ok, {Ip, Port}} = inet:peername(CliSock),
Status = case erase(status_code) of
undefined -> "-";
I -> integer_to_list(I)
View
2 www/END
@@ -1,5 +1,3 @@
<hr>
<IMG SRC="/icons/yaws_pb.gif" >
-</td>
-</table>
</html>
View
80 www/EXHEAD
@@ -1,68 +1,16 @@
-<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
-<HTML>
-<HEAD>
- <meta name="keywords" content="Yaws">
+<IMG SRC="/icons/yaws_head.gif" WIDTH="600" ALT="YAWS">
+<br><br>
+
+<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="simple.yaws">Simple</a></td>
+ <td> <A HREF="form.yaws">Forms</a> </td>
+ <td> <A HREF="redirect.yaws">Redirect</a> </td>
+ <td> <A HREF="cookies.yaws">Cookies</a> </td>
+ <td> <A HREF="pcookie.yaws">Persistant Cookies</a> </td>
+</tr>
+</table>
+<hr>
- <TITLE>HYBER.ORG</TITLE>
-
-<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-
-<STYLE TYPE="text/css">
- BODY {
- background: #C6C6B5;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- color: black;
- }
-
-#menu {
- background: #B6B6A5;
-}
-
- div.links {
- background: green;
- }
-
- H1, H2, H3, H4, H5 {
- text-decoration: none;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- font-weight: bold;
- font-variant: small-caps
- }
- I { font-family: Times, Verdana, Arial, Helvetica, sans-serif;}
- P { text-decoration: none;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- font-weight: normal;
- }
- UL { margin-left: -2em }
-
- A { text-decoration: none;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- font-weight: normal;
- }
- A:visited { font-style: oblique; color: #600000;}
- A:link { color: #0000f0 } /* unvisited link */
- A:active { color: lime } /* active links */
-
-</STYLE>
-
-</HEAD>
-<BODY BGCOLOR="#C6C6B5" text="#333333">
-
-<IMG SRC="/icons/yaws_head.gif" width=400 ALT="YAWS">
-
-<table border="0" cellpadding="5" cellspacing="0" height="100%">
-<tr>
- <td valign=top BGCOLOR="#B6B6A5">
- <IMG SRC="spacer.gif" width=1 height=74 ALT=""><p></p>
- <A HREF="index.yaws">- Top Page</a><br><hr>
- <A HREF="simple.yaws">-Simple example</a><br><hr>
- <A HREF="forms.yaws">--A forms POST</a><br><hr>
- <A HREF="redirect.yaws">-Redirect</a><br><hr>
- <A HREF="cookies.yaws">-Cookie session</a><br><hr>
- <A HREF="pcookie.yaws">-Persistant cookies</a><br><hr>
- <A HREF="externalcode.yaws">-Using External code </a><br><hr>
- <A HREF="mnesiacluster.yaws">-Using Mnesia DBMS to keep cookie state in a cluster </a><br><hr>
- </td>
-
- <td valign=right width=75%>
View
40 www/HEAD
@@ -8,43 +8,9 @@
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
-<STYLE TYPE="text/css">
- BODY {
- background: #C6C6B5;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- color: black;
- }
-
-#menu {
- background: #B6B6A5;
-}
-
- div.links {
- background: green;
- }
-
- H1, H2, H3, H4, H5 {
- text-decoration: none;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- font-weight: bold;
- font-variant: small-caps
- }
- I { font-family: Times, Verdana, Arial, Helvetica, sans-serif;}
- P { text-decoration: none;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- font-weight: normal;
- }
- UL { margin-left: -2em }
-
- A { text-decoration: none;
- font-family: Verdana, Arial, Helvetica, sans-serif;
- font-weight: normal;
- }
- A:visited { font-style: oblique; color: #600000;}
- A:link { color: #0000f0 } /* unvisited link */
- A:active { color: lime } /* active links */
-
-</STYLE>
+
+<link rel="stylesheet" type="text/css" href="stil.css">
+
</HEAD>
<BODY BGCOLOR="#C6C6B5" text="#333333">
View
36 www/TOPTAB
@@ -1,20 +1,22 @@
-<IMG SRC="/icons/yaws_head.gif" WIDTH=400 ALT="YAWS">
+<IMG SRC="/icons/yaws_head.gif" WIDTH="600" ALT="YAWS">
+<br><br>
-<table border="0" cellpadding="5" cellspacing="0" height="100%">
-<tr>
- <td valign=top width=25% BGCOLOR="#B6B6A5">
- <IMG SRC="spacer.gif" width=1 height=74 ALT=""><p></p>
- <A HREF="index.yaws">- Top Page</a><br><hr>
- <A HREF="configuration.yaws">-Configuring and Building Yaws</a><br><hr>
- <A HREF="dynamic.yaws">-Generating dynamic content</a><br><hr>
- <A HREF="running.yaws">-Running yaws</a><br><hr>
- <A HREF="examples.yaws">-Examples</a><br><hr>
- <A HREF="features.yaws">-Features</a><br><hr>
- <A HREF="todo.yaws">-TODO list </a><br><hr>
- <A HREF="motivation.yaws">-Motivation </a><br><hr>
- <A HREF="download">-Download </a><br><hr>
- <A HREF="contacts.yaws">-Contacts </a><br><hr>
- </td>
+<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="configuration.yaws">Config</a></td>
+ <td> <A HREF="dynamic.yaws">Dynamic content</a> </td>
+ <td> <A HREF="running.yaws">Running yaws</a> </td>
+ <td> <A HREF="history.yaws">History</a> </td>
+</tr>
- <td valign=right width=75%>
+<tr border="1">
+ <td> <A HREF="examples.yaws">Examples</a> </td>
+ <td> <A HREF="todo.yaws">TODO list </a> </td>
+ <td> <A HREF="motivation.yaws">Motivation </a> </td>
+ <td> <A HREF="download">Download </a> </td>
+</tr>
+
+</table>
+<hr>
View
31 www/cookies.yaws
@@ -0,0 +1,31 @@
+<erl>
+out(A) -> yaws_api:ssi(A#arg.docroot, ["/HEAD", "/EXHEAD"]).
+</erl>
+
+
+
+<h1>Yaws and Cookies</h1>
+<p>
+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
+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.
+
+<p>
+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
+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>
View
2 www/examples.yaws
@@ -1,5 +1,5 @@
<erl>
-out(A) -> file:read_file([A#arg.docroot, "/EXHEAD"]).
+out(A) -> yaws_api:ssi(A#arg.docroot, ["/HEAD", "/EXHEAD"]).
</erl>
View
35 www/form.yaws
@@ -7,30 +7,39 @@
<body>
+<h2>POST example </h2>
+
+<p>This is a simple example where we get to fill in
+a series of fields and POST the data by hitting the Submit button
+at the end.
+<p>
+The action is set to the yaws file <tt>/post.yaws </tt> which
+gets POSTed data in its <tt>ARG#arg.clidata</tt> field.
+
+
<form METHOD=POST
- ACTION="http://localhost:8080/post.yaws"
+ ACTION="/post.yaws"
-Please help us to improve the World Wide Web by filling in
-the following questionaire:
+This is a serious poll.
- <p>Your organization? <input NAME="org" TYPE=text SIZE="48">
+ <p>Your favourite programming language? <input NAME="lang" TYPE=text SIZE="48">
-<p>Commercial? <input NAME="commerce" TYPE=checkbox>
+<p>Imperative ? <input NAME="imperative" TYPE=checkbox>
-How many users? <input NAME="users" TYPE=int>
+How many tabs to you indent? <input NAME="tabs" TYPE=int>
-<p>Which browsers do you use?
+<p>Which OS do you use?
<ol>
-<li>Cello <input NAME="browsers" TYPE=checkbox VALUE="cello">
-<li>Lynx <input NAME="browsers" TYPE=checkbox VALUE="lynx">
-<li>X Mosaic <input NAME="browsers" TYPE=checkbox VALUE="mosaic">
-<li>Others <input NAME="others" SIZE=40>q
+<li>Windows 95 pro ultra <input NAME="os1" TYPE=checkbox VALUE="w95">
+<li>Windows XP beta cracked <input NAME="os2" TYPE=checkbox VALUE="xpbeta">
+<li>Windows <input NAME="os3" TYPE=checkbox VALUE="windows">
+<li>Other<input NAME="other" SIZE=40>
</ol>
-A contact point for your site: <input NAME="contact" SIZE="42">
+Your email <input NAME="contact" SIZE="42">
-<p>Many thanks on behalf of the WWW central support team.
+<p>Many thanks on behalf of the Windows central support team.
<p><input TYPE=submit> <input TYPE=reset>
View
5 www/index.yaws
@@ -64,8 +64,9 @@ an <a href="http://www.erlang.org">Erlang</a> system, then do:
<pre>
# export CVS_RSH=ssh
-# cvs -d:pserver:anonymous@cvs.erlyaws.sourceforge.net:/cvsroot/erlyaws login
-# cvs -z3 -d:pserver:anonymous@cvs.erlyaws.sourceforge.net:/cvsroot/erlyaws co .
+# export CVSROOT=:pserver:anonymous@cvs.erlyaws.sourceforge.net:/cvsroot/erlyaws
+# cvs login
+# cvs -z3 co .
# cd yaws; make; make install
</pre>
View
71 www/post.yaws
@@ -1,7 +1,7 @@
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<HTML>
<HEAD>
- <meta name="keywords" content="HYBER dot ORG">
+ <meta name="keywords" content="post">
<TITLE>Top EE page</TITLE>
@@ -16,25 +16,76 @@
<H1> post.yaws </H1>
-<p> Pre ee code
+<p> This is the <tt>post.yaws</tt>. This yaws file gets invoked with client data.
+This is the data that is submitted from the forms page <a href="/form.yaws">form.yaws</a>.
+<p>POST data is naturally organized as a <tt>{Key, Value}</tt> list. A call to
+the function <tt>yaws_api:parse_post_data(A#arg.clidata)</tt> will parse the
+POSTed data.
+
+<pre>
+out(A) ->
+ L = f("&lt;pre>~n clidata: ~p~n &lt;/pre>",
+ [yaws_api:parse_post_data(A#arg.clidata)]),
+ {ok,L}.
+</pre>
+
+<p>Will produce the following output:
<erl>
+out(A) ->
+ L = f("<pre>~n clidata: ~p~n </pre>",
+ [yaws_api:parse_post_data(A#arg.clidata)]),
+ {ok,L}.
+</erl>
+
+<p>Above, we got all the <tt>Value</tt> arguments as strings, however
+it is also possible to let the parser coerce data types of the posted data.
+
+<p>In this specific case we know the expected type of the arguments posted from
+the form. If <a href="form.yaws">back</a> back to the forms page, we can see that
+the arguments are
+<ol>
+<li> string (the "lang" field)
+<li> checkbox (the "imperative" field)
+<li> integer (the "tabs" field)
+<li> checkbox (the "os1" field)
+<li> checkbox (the "os2" field)
+<li> checkbox (the "os3" field)
+<li> string (the "other" field)
+<li> string (the "contact" field)
+</ol>
+<p>Since we know the types we expect in the form, we can indicate that to
+the <tt>parse_post_data/2</tt> function as in the following code:
+
+
+<pre>
out(A) ->
- Spec = ['ALLSTRINGS'],
- L = io_lib:format(
- "~n<xmp>~n Yes here we go ~nARG=~p ~n~n"
- "Client data is:~p~n"
- "</xmp>",
- [A, yaws_api:parse_post_data(A#arg.clidata, Spec)]),
-
- {ok, L}.
+ Spec = [string, checkbox, integer,
+ checkbox, checkbox, checkbox,
+ string, string],
+ L = f("&lt;pre>~n clidata: ~p~n &lt;/pre>",
+ [yaws_api:parse_post_data(A#arg.clidata, Spec)]),
+ {ok,L}.
+</pre>
+
+<p>
+This will produce the following output:
+<erl>
+out(A) ->
+ Spec = [string, checkbox, int,
+ checkbox, checkbox, checkbox,
+ string, string],
+ L = f("~n<pre>~n clidata: ~p~n </pre>",
+ [yaws_api:parse_post_data(A#arg.clidata, Spec)]),
+ {ok,L}.
</erl>
+
</HTML>
View
22 www/setcookie.yaws
@@ -0,0 +1,22 @@
+<erl>
+
+session(A, Visits) ->
+ receive
+ {From, tick} ->
+ N = calendar:local_time(),
+ From ! {self(), [N|Visits]},
+ session(A, [N|Visits])
+ after 30000 -> %% keep state for 30 secs only
+ exit(normal)
+ end.
+
+someheaders(A) ->
+ H=A#arg.headers,
+ case H#headers.cookie of
+ undefined ->
+ Now = calendar:local_time(),
+ P = spawn(fun() -> session(A, [Now]) end),
+ yaws_api:setcookie(pid_to_list(P), "/");
+ PidStr ->
+
+
View
13 www/simple.yaws
@@ -15,7 +15,8 @@ HTML code.
<erl>
out(A) ->
{ok, B} = file:read_file([A#arg.docroot, "/simple_ex1.yaws"]),
- {ok, ["<xmp> \n", B, "</xmp\n>"]}.
+ B2 = yaws_api:htmlize(B),
+ {ok, ["<pre> \n", B2, "</pre>\n"]}.
</erl>
<br>
@@ -32,7 +33,8 @@ HTML code.
<erl>
out(A) ->
{ok, B} = file:read_file([A#arg.docroot, "/simple_ex2.yaws"]),
- {ok, ["<xmp> \n", B, "</xmp\n>"]}.
+ B2 = yaws_api:htmlize(B),
+ {ok, ["<pre> \n", B2, "</pre>\n"]}.
</erl>
The file has one very simple function which just returns a tuple
@@ -42,11 +44,4 @@ The String will be substituted into the delivered HTML data instead of the
Erlang code.
-
-
-
-
-
-
-
</html>
View
9 www/stats.yaws
@@ -9,13 +9,16 @@ out(A) ->
<erl>
out(A) ->
- L = yaws_server:stats(),
- H = "<html> \n ",
+ {UpTime, L} = yaws_server:stats(),
+ {Days, {Hours, Minutes, Secs}} = UpTime,
+ H = f("<html> ~n <h4>Uptime: ~w Days, ~w Hours, ~w Minutes </h4> ~n",
+ [Days, Hours, Minutes]),
+
T =lists:map(
fun({Host,IP,Hits}) ->
L1= f("<hr><h3> stats for ~p at ~p </h3>~n",
[Host,IP]),
- T = "<table border-4 > \n"
+ T = "<table border=\"2\" > \n"
"<TR> <TH>URL</TH> <TH>Number of hits</TH> </TR>",
L2=lists:map(
fun({Url, Hits}) ->
View
38 www/stil.css
@@ -0,0 +1,38 @@
+
+<STYLE TYPE="text/css">
+ BODY {
+ background: #C6C6B5;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ color: black;
+ }
+
+#menu {
+ background: #B6B6A5;
+}
+
+ div.links {
+ background: green;
+ }
+
+ H1, H2, H3, H4, H5 {
+ text-decoration: none;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-weight: bold;
+ font-variant: small-caps
+ }
+ I { font-family: Times, Verdana, Arial, Helvetica, sans-serif;}
+ P { text-decoration: none;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+ }
+
+ A { text-decoration: none;
+ font-family: Verdana, Arial, Helvetica, sans-serif;
+ font-weight: normal;
+ }
+ A:visited { font-style: oblique; color: #600000;}
+ A:link { color: #0000f0 } /* unvisited link */
+ A:active { color: lime } /* active links */
+ A:hover { background: #edb }
+
+</STYLE>
View
16 www/todo.yaws
@@ -1,4 +1,3 @@
-
<erl>
out(A) ->
@@ -7,28 +6,21 @@ out(A) ->
</erl>
-<H2>TODO</h2>
+<H2>TODO</H2>
<ul>
-<li> ssl
-<li> virtual hosting (done Thu Feb 7 20:23:23 CET 2002)
-<li> handle the If-..... headers
+<li> ssl
+<li> handle the If-..... headers
<li> generate Etag for static content
-<li> directory listings (done, {2002,2,5})
<li> handle Range header
<li> TRACE, PUT, OPTIONS ......
<li> optimize with some precalculated headers
<li> documentation in the www directory
-<li> cache pages in memory, cache filedescriptors (done Feb 12, didn't help much)
-<li> cache headers ... (done Feb 7)
-<li> remove all filename:join .... calls, they suck (done Feb 6)
<li> error codes
<li> more functions in yaws_api redirect(), push() ....
<li> lots of examples
-<li> do something with URL parameters ala http://a.b.com/foo?a=1
-and pass them down to the yaws code in the arg structure (done Feb 6)
<li> make stop and control functions to ctl and HUP the daemon
<li> maybe do .htaccess
<li> do something cool, maybe a streaming audio app
@@ -38,6 +30,8 @@ and pass them down to the yaws code in the arg structure (done Feb 6)
<li> HTTP trailer support
<li> a cool statistics yaws page that talks to the server
<li> man pages for yaws as well as yaws.conf
+<li> ~user public_html syntax
+<li> #fragments in URLs
</ul>

0 comments on commit f448988

Please sign in to comment.
Something went wrong with that request. Please try again.