My blog

My new book is published

Jun 1, 22:05

My new book on WebRTC just became available on Amazon:

WebRTC Blueprints

An error occurred while loading or saving gnome-terminal

Nov 8, 2013, 16:12

...nautilus, whatever

If you see this message, you can try to do this:

chmod 700 /tmp/gconfd-username/

You should also restart the machine or X server or VNC server (in case if you're working via VNC).

p.s. you need to replace 'username' in this command with your actual username

Emacs trump stucks if remote shell is ZSH

Apr 16, 2013, 15:31

How to get Emacs + Trump to work with ZSH as default shell?

Just out the following line into ~/.zshrc

[[ $TERM == "dumb" ]] && unsetopt zle && PS1='$ '

Mac OS X: app is damaged and cannot be opened

Mar 21, 2013, 1:12

Just downloaded «English Grammar in Use Extra» application, tried to install it and got this funny message: « is damaged and cannot be opened»

How to fix that?

  1. Go to 'System Preferences...' -> 'Security & Privacy' -> Tab 'General'
  2. Then click on the lock at the bottom of the window, enter your password.
  3. Now you can change 'Allow applications downloaded from:' option — set it to 'Anywhere'

Handling HTTP sessions in Cowboy

Feb 25, 2013, 18:13

How to implement session mechanism using Cowboy HTTP server?

It could be not obvious, because Cowboy still has no detailed documentation. Here we will made a simple session handling implementation.

I suppose you know already how to make simple 'Hello world'-like website using Cowboy. So, I provide just code snippets instead of complete source code.

OK. Cowboy has request- and response-handler mechanisms. First of all, we need to tell to Cowboy that we want to use a session handler.

{ok, _} = cowboy:start_http(http, 100, [{port, Port}], [
                  {env, [{dispatch, Dispatch}]},
                  {max_keepalive, 50},
                  {onrequest, fun handler_session:on_request/1},
                  {timeout, 500}

Take a look at fun handler_session:on_request/1 construction — this is our session handler code.

Next, we need to actually implement our session handler.

-export([on_request/1, get_session/1, set_session/1, drop_session/1]).

on_request(Req) ->
    {Path, Req1} = cowboy_req:path(Req),
    {SESSID, Req2} = get_session(Req1),
    case SESSID of
        undefined ->
            Req4 = session_no(Req2, Path);
        _ ->
            PEER = session_db:get(SESSID),
            case PEER of
                undefined ->
                    case Path of
                        <<"/logoff">> ->
                            Req4 = Req2;
                        _ ->
                            Req3 = cowboy_req:set_resp_header(<<"Location">>,<<"/logoff">>,Req2),
                            {ok, Req4} = cowboy_req:reply(302, [], "", Req3)
                _ ->
                    Req4 = session_yes(Req2, Path)

session_no(Req, Path) ->
    case lists:member(Path,[<<"/main">>,<<"/logoff">>]) of
        true ->
            Req1 = cowboy_req:set_resp_header(<<"Location">>,<<"">>,Req),
            {ok, Req2} = cowboy_req:reply(302, [], "", Req1);
        _ ->
            Req2 = Req

session_yes(Req, Path) ->
    case lists:member(Path,[<<"/login">>, <<"/registration">>, <<"/">>]) of
        true ->
            Req1 = cowboy_req:set_resp_header(<<"Location">>,<<"/main">>,Req),
            {ok, Req2} = cowboy_req:reply(302, [], "", Req1);
        _ ->
            Req2 = Req

get_session(Req) ->
    {SID, Req1} = cowboy_req:cookie(<<"SESSON_ID">>, Req),
    {SID, Req1}.

set_session(Req) ->
    SID = generate_session(),
    Req1 = cowboy_req:set_resp_cookie(<<"SESSION_ID">>,SID,[{path, <<"/">>}],Req),
    {Req1, SID}.

drop_session(Req) ->
    Req2 = cowboy_req:set_resp_header(<<"Set-Cookie">>,<<"SESSION_ID=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/">>, Req),

generate_session() ->
    Now = {_, _, Micro} = now(),
    Nowish = calendar:now_to_universal_time(Now),
    Nowsecs = calendar:datetime_to_gregorian_seconds(Nowish),
    Then = calendar:datetime_to_gregorian_seconds({{1970, 1, 1}, {0, 0, 0}}),
    Prefix = io_lib:format(&quot;~14.16.0b&quot;, [(Nowsecs - Then) * 1000000 + Micro]),
    list_to_binary(Prefix ++ to_hex(crypto:rand_bytes(9))).

to_hex([]) ->
to_hex(Bin) when is_binary(Bin) ->
to_hex([H|T]) ->
    [to_digit(H div 16), to_digit(H rem 16) | to_hex(T)].

to_digit(N) when N < 10 -> $0 + N;
to_digit(N) -> $a + N-10.

The logic is pretty simple. We get URL path from Cowboy, get session value from request.   Then we check whether we already have such session value stored in our database, using session_db:get() construction (not showed here — you can implement some simple functionality to store and select session values from/into any database you like most).

If there is no session in the request, we allow user to get to any URI except '/main' and '/logoff' (assuming that '/main' is our protected area, and '/logoff' is just no sense if you're not logged in yet).

If there is a session in request but we didn't found it in our DB, we redirect user to '/logoff' URI — to drop the wrong session and let user login again.

If there is a session in the request AND we found it in our DB, we allow user to get at any URI. Except that in case if user tried to reach '/login', '/', or '/registration' we redirect it at '/main'.

Session generating functions used the same as in previous article How to Create UUID Or Session ID

So, now any HTTP request will be processed by our session handler. Sure, you should also implement simple '/login' handler. It should parse simple HTML form, when login was successful — generate session, set it in HTTP response and store it in DB.

Ctrl + ↓ Earlier