Persistent Cookies

We saw in the first cookie 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 restarted, 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.

The yaws code in setpcookie.yaws sets the cookie in the browser.

And the yaws code in readpcookie.yaws will read the cookie

Let's show some code. To set the cookie we we have:




<erl>
-export([pserv/0]).

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:set_cookie("pfoobar",integer_to_list(Num),
                        [{path,"/"}]).



out(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>


<erl>


out(A) -> {ssi, "TAB.inc", [],[]}.
</erl>

<div id="entry">





<h2> Set persistent cookie </h2>

<p>This is the page that set a persistent cookie in
the browser.
<a href="readpcookie.yaws">readpcookie.yaws</a> will
read the cookie and report persistent information.



</div>


<erl>
out(A) -> {ssi, "END2",[],[]}.
</erl>



And to read the cookie, we have the following code:



<html>

<h2> Read persistent cookie </h2>

<erl>

to_integer(S) ->
    list_to_integer(string:strip(S, both)).

out(A) ->
    H=A#arg.headers,
    C = H#headers.cookie,
    L=case yaws_api:find_cookie_val("pfoobar", 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 </p>~n", []);
          NumStr ->
              Num = to_integer(NumStr),
              case ets:lookup(pcookies, {cookie,Num}) of
                  [{{cookie, Num}, Data}] ->
                      f("<p> Yes, I read your cookie:it is ~p~n "
                        "Your persistent info is ~n"
                        "<pre>~n~p~n</pre> </p>~n", [NumStr, Data]);
                  [] ->
                      f("<p> You had a cookie,but the data is gone </p>",[])
              end
      end,
    {html, 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:</p>

<erl>
out(A) ->
    {ok, B} = file:read_file(A#arg.docroot ++ "/readpcookie.yaws"),
       {ehtml,
        {'div', [{class, "box"}],
        {pre,[], B}}}.
</erl>


</html>









Valid XHTML 1.0!