Poking Around Joe Armstrong’s Simple Web Server – Part 2 December 30, 2008

Let’s see what more we can learn about Joe Armstong’s Simple Web Server by poking around the second layer, http_driver.erl.

In our previous post we learned that web_server:server/1 passes web_server:server/2 as a function down to level 2, e.g. http_driver:start/3. It also instantiates the Port variable in http_driver:start/3 and passes in an integer, 15.

server(Port) ->

S = self(),

process_flag(trap_exit, true),

http_driver:start(Port, fun(Client) -> server(Client, S) end, 15),

loop().

Thus web_server:server/2 gets called somewhere in the depths of http_driver.erl or maybe even in tcp_driver.erl.

When called, web_server/server/2 listens for a Request variable. When a request is received, it calls web_server:generate_response/1. generate_response/1 looks for a file name in the Request tuple and, if found, returns file type and content to the Response variable in web_server:server/2. server/2, in turn sends the response back to the client.

server(Client, Master) ->

receive

{Client, closed} ->

true;

{Client, Request} ->

Response = generate_response(Request),

Client ! {self(), Response},

server(Client, Master)

after 5000 ->

true

end.

What’s not clear so far is just when and how web_server:server/2 gets called. Seems we have to dig down into level 2, http_driver.erl, to find the answer.

Here goes:

http_driver.erl

First thing we note is that http_driver.erl exports three functions: start/3, classify/1, and header/1.

-export([start/3]).

-export([classify/1, header/1]).

Good. http_driver:start/3 is just where we wanted to start excavating.

start/3

start(Port, Fun, Max) ->

spawn(fun() -> server(Port, Fun, Max) end).

http_driver:start/3 spawns a new process running http_driver:server/3.

server/3

server(Port, Fun, Max) ->

tcp_server:start_raw_server(Port,

fun(Socket) -> input_handler(Socket, Fun) end,

Max,

0).

Recall that the function web_server:server/2 was passed into http_driver:start/3 with two parameters: the variables Client and S. The value of Client is still mysterious at this point. The value of S, however, is the PID of the master web server process.

What do you want to bet that the value of Client ends up being the PID of the client process? Seems that we’ll need to move down to level 3, tcp_server.erl, however, to check it out. Be patient. We’ll get there.

Based on the Max variable in the http_driver:server/3, I’m guessing that integer 15 passed down in web_server:server/1 is the maximum number of connections. Comments in the source at this point would definitely help us out.

It looks, however, like we’re setting up a process in tcp_server with a port number, a function to handle input, a variable to hold the master web server process, a variable that holds the maximum number of connections (just a guess), and a yet mysterious integer 0. Once again, we’ll need to dig down into level 3, tcp_server.erl, to confirm.

The input function, http_driver:input_handler/2, takes two parameters: the variable Socket, and a second function, in this case, our old friend web_server:server/2, now packing the variables Client and S where S is the PID of master web server process.

So what happens when http_driver:input_handler/2 gets called?

input_handler/2

input_handler(Socket, Fun) ->

%% When we get spawned we spawn an

%% additional process to handle the input

S = self(),

Server = spawn_link(fun() -> Fun(S) end),

process_flag(trap_exit, true),

relay(Socket, Server, {header, []}).

Whoa!

We spawn another process. And if my eyes aren’t deceiving me, it’s web_server:server/1. But, boy, am I confused! I definitely need big-time guru help here. Is Fun(S) truly web_server:server/1? I thought server/1 took a port address as a parameter. But here it looks like it’s taking a PID. How can this be?

You know what? It’s now 1:48 am and I’m totally whacked. I’m going to pick this up in the later am when my mind is more rested.

Meanwhile, I’ll post our exploration to date in hope that some guru angel will fly by in the night and leave a comment behind to set us back on the right track.

Night all.