Posts Tagged ‘erlang’

Nitrogen module auto-reloading

Saturday, June 20th, 2009

This is a really simple tip, but it was handy for me, and it could be helpful for someone else, too.

While playing around with Nitrogen, which is a great project by the way (more in a later blog post, I guarantee it), I noticed that I had to restart the server to re-load modules as I changed them (or I could manually, reload them, I know, I know..).

Since I was using Mochiweb as my backend, and I’m used to the development version of Mochiweb auto-reloading modules as you recompile, I wanted the same functionality here.

Turns out it’s as simple as changing the default start.sh from

#!/bin/sh
cd `dirname $0`
 
echo Starting Nitrogen.
erl \
	-name nitrogen@localhost \
	-pa ./ebin -pa ./include \
	-s make all \
	-eval "application:start(appname)"

to this

#!/bin/sh
cd `dirname $0`
 
echo Starting Nitrogen.
erl \
	-name nitrogen@localhost \
	-pa ./ebin -pa ./include \
	-s make all \
	-s reloader \
	-eval "application:start(appname)"

… and bam, modules now reload as you recompile them.

Untiny that url!

Saturday, April 11th, 2009

There has been some talk about and arguments against and responses to issues about using rev=”cononical” for referencing shorter URLs instead of the automated use of TinyURL when posting to sites like Twitter.

I must say that I agree with Ben Ramsey (see “arguments agains” above) in suggesting we use rel=”alternate shorter” instead.

I also like the idea that Chris Shiflett had of using a HTTP header and a HEAD request to make it so you neither have to retrieve the entire requested page nor parse any HTML. I’d stick with Ben’s suggestion, however, and make the header something like “X-Alternate-Shorter:”, rather than “X-Rev-Canonical”. What’s the harm in calling it something that actually makes sense?

The idea of using HTTP HEAD requests to solve the problem inspired me to come up with a more immediate solution to one of the problems introduced by using url shortening services: uncertainty about where a URL leads.

This problem can be solved on the client side, which requires no work on the part of Twitter (meaning this is more likely to be put into use sooner).

Since most URL shortening services use an HTTP redirect to do their job, all it takes is a HEAD request to the tiny URL in question, and then a look at whatever “Location:” header is returned to see what the real URL is. In fact, you don’t even really need to do a HEAD request in most cases, since most URL shortening services don’t return any body, since they are just redirecting you anyway.

Read on for more information and implementations of an untinyurl function in various languages.

(more…)

First steps to an Erlang OpenID consumer

Wednesday, January 21st, 2009

I’m working on a little project in Erlang and I wanted to use only OpenID for my authentication. It turns out there is currently no Erlang OpenID consumer library (or if there is, I couldn’t find it).

So I’ve started writing my own. So far I’ve got the first necessary step complete: HTML-based discovery.

I’m starting with version 1.1, simply because it is shorter and requires less (I don’t want to implement the XRI or Yadis protocols just yet).

It turns out that mochiweb comes with an HTML parser, so I used that, since I’m using mochiweb for my application. The parsed HTML comes back as a series of nested tuples of the format {<<”tag”>>, Attributes, Children}, where “tag” is the tagname (the root will be <<”html”>>, for example), Attributes is a proplist of that tag’s attributes, and Children is a list of more tuples of the same format and/or binaries with the contents of text nodes. Everything is represented as binaries, so I use those directly rather than converting between strings and binaries.

Here’s the code which finds the link tags with rel=”openid.server” and rel=”openid.delegate” (if it is there):

get_openid_server(Identifier) ->
    NormalizedIdentifier = normalize_identifier(Identifier),
    case http:request(NormalizedIdentifier) of
        {ok, {_Status, _Headers, Body}} ->
            HtmlTokens = mochiweb_html:parse(Body),
            find_openid_tags(HtmlTokens);
        _ ->
            {error, http_error}
    end.
 
normalize_identifier(Ident = "http://" ++ _Rest) ->
    Ident;
normalize_identifier(Ident) ->
    "http://" ++ Ident.
 
find_openid_tags(HtmlTokens) ->
    case find_tag(<<"head">>, [HtmlTokens]) of
        {<<"head">>, _Attrs, Children, _Rest} ->
            case find_tag_with_attr(<<"link">>, {<<"rel">>, <<"openid.server">>}, Children) of
                not_found ->
                    {error, openid_server_not_found};
                ServerAttrs ->
                    Server = proplists:get_value(<<"href">>, ServerAttrs),
                    case find_tag_with_attr(<<"link">>, {<<"rel">>, <<"openid.delegate">>}, Children) of
                        not_found ->
                            [{server, Server}];
                        DelegateAttrs ->
                            Delegate = proplists:get_value(<<"href">>, DelegateAttrs),
                            [{server, Server}, {delegate, Delegate}]
                    end
            end;
        not_found ->
            {error, no_head_tag}
    end.
 
find_tag(_TagName, []) ->
    not_found;
find_tag(TagName, [{TagName, Attributes, Children} | Rest]) ->
    {TagName, Attributes, Children, Rest};
find_tag(TagName, [{_OtherTag, _Attributes, Children} | Rest]) ->
    find_tag(TagName, Children ++ Rest);
find_tag(TagName, [_Other | Rest]) ->
    find_tag(TagName, Rest).
 
find_tag_with_attr(_TagName, {_AttrKey, _AttrVal}, []) ->
    not_found;
find_tag_with_attr(TagName, Attr = {AttrKey, AttrVal}, Tags) ->
    case find_tag(TagName, Tags) of
        not_found ->
            not_found;
        {TagName, Attributes, Children, Rest} ->
            case proplists:get_value(AttrKey, Attributes) of
                AttrVal ->
                    Attributes;
                _ -> 
                    find_tag_with_attr(TagName, Attr, Children ++ Rest) 
            end
    end.

(the <PIPE>s above should be “|”s and the <SEMI>s should be “;”s. Not sure why the syntax highlighter is doing that to them…

Assuming the above code is put into a module called “openid”, you get the following:

1> openid:get_openid_server("blog.paulbonser.com")
[{server,<<"http://www.livejournal.com/openid/server.bml">>},
 {delegate,<<"http://misterpib.livejournal.com/">>}]
2>

As I said, this is the first step. Hopefully I’ll have some time very soon to get on with the next couple of steps, and then I’ll be done.