summaryrefslogtreecommitdiff
path: root/deps/mochiweb/examples
diff options
context:
space:
mode:
authorMicah Anderson <micah@leap.se>2014-01-15 18:13:16 +0000
committerdrebs <drebs@leap.se>2014-01-17 08:48:11 -0200
commit510c6d763fba74f95ae8f894408c3658bcef4f83 (patch)
treed4dd0930b902cb1e5d46bea621ec83f801ea8ed6 /deps/mochiweb/examples
parent8bd863936ead4243f58fb99e11d1221e1af0a71e (diff)
embed dependencies that were previously pulled in by git during rebar build
Diffstat (limited to 'deps/mochiweb/examples')
-rw-r--r--deps/mochiweb/examples/https/https_store.erl146
-rw-r--r--deps/mochiweb/examples/https/server_cert.pem19
-rw-r--r--deps/mochiweb/examples/https/server_key.pem27
-rw-r--r--deps/mochiweb/examples/keepalive/keepalive.erl81
4 files changed, 273 insertions, 0 deletions
diff --git a/deps/mochiweb/examples/https/https_store.erl b/deps/mochiweb/examples/https/https_store.erl
new file mode 100644
index 00000000..959cc00c
--- /dev/null
+++ b/deps/mochiweb/examples/https/https_store.erl
@@ -0,0 +1,146 @@
+
+%% Trivial web storage app. It's available over both HTTP (port 8442)
+%% and HTTPS (port 8443). You use a PUT to store items, a GET to
+%% retrieve them and DELETE to delete them. The HTTP POST method is
+%% invalid for this application. Example (using HTTPS transport):
+%%
+%% $ curl -k --verbose https://localhost:8443/flintstones
+%% ...
+%% 404 Not Found
+%% ...
+%% $ echo -e "Fred\nWilma\nBarney" |
+%% curl -k --verbose https://localhost:8443/flintstones \
+%% -X PUT -H "Content-Type: text/plain" --data-binary @-
+%% ...
+%% 201 Created
+%% ...
+%% $ curl -k --verbose https://localhost:8443/flintstones
+%% ...
+%% Fred
+%% Wilma
+%% Barney
+%% ...
+%% $ curl -k --verbose https://localhost:8443/flintstones -X DELETE
+%% ...
+%% 200 OK
+%% ...
+%% $ curl -k --verbose https://localhost:8443/flintstones
+%% ...
+%% 404 Not Found
+%% ...
+%%
+%% All submitted data is stored in memory (in an ets table). Could be
+%% useful for ad-hoc testing.
+
+-module(https_store).
+
+-export([start/0,
+ stop/0,
+ dispatch/1,
+ loop/1
+ ]).
+
+-define(HTTP_OPTS, [
+ {loop, {?MODULE, dispatch}},
+ {port, 8442},
+ {name, http_8442}
+ ]).
+
+-define(HTTPS_OPTS, [
+ {loop, {?MODULE, dispatch}},
+ {port, 8443},
+ {name, https_8443},
+ {ssl, true},
+ {ssl_opts, [
+ {certfile, "server_cert.pem"},
+ {keyfile, "server_key.pem"}]}
+ ]).
+
+-record(sd, {http, https}).
+-record(resource, {type, data}).
+
+start() ->
+ {ok, Http} = mochiweb_http:start(?HTTP_OPTS),
+ {ok, Https} = mochiweb_http:start(?HTTPS_OPTS),
+ SD = #sd{http=Http, https=Https},
+ Pid = spawn_link(fun() ->
+ ets:new(?MODULE, [named_table]),
+ loop(SD)
+ end),
+ register(http_store, Pid),
+ ok.
+
+stop() ->
+ http_store ! stop,
+ ok.
+
+dispatch(Req) ->
+ case Req:get(method) of
+ 'GET' ->
+ get_resource(Req);
+ 'PUT' ->
+ put_resource(Req);
+ 'DELETE' ->
+ delete_resource(Req);
+ _ ->
+ Headers = [{"Allow", "GET,PUT,DELETE"}],
+ Req:respond({405, Headers, "405 Method Not Allowed\r\n"})
+ end.
+
+get_resource(Req) ->
+ Path = Req:get(path),
+ case ets:lookup(?MODULE, Path) of
+ [{Path, #resource{type=Type, data=Data}}] ->
+ Req:ok({Type, Data});
+ [] ->
+ Req:respond({404, [], "404 Not Found\r\n"})
+ end.
+
+put_resource(Req) ->
+ ContentType = case Req:get_header_value("Content-Type") of
+ undefined ->
+ "application/octet-stream";
+ S ->
+ S
+ end,
+ Resource = #resource{type=ContentType, data=Req:recv_body()},
+ http_store ! {self(), {put, Req:get(path), Resource}},
+ Pid = whereis(http_store),
+ receive
+ {Pid, created} ->
+ Req:respond({201, [], "201 Created\r\n"});
+ {Pid, updated} ->
+ Req:respond({200, [], "200 OK\r\n"})
+ end.
+
+delete_resource(Req) ->
+ http_store ! {self(), {delete, Req:get(path)}},
+ Pid = whereis(http_store),
+ receive
+ {Pid, ok} ->
+ Req:respond({200, [], "200 OK\r\n"})
+ end.
+
+loop(#sd{http=Http, https=Https} = SD) ->
+ receive
+ stop ->
+ ok = mochiweb_http:stop(Http),
+ ok = mochiweb_http:stop(Https),
+ exit(normal);
+ {From, {put, Key, Val}} ->
+ Exists = ets:member(?MODULE, Key),
+ ets:insert(?MODULE, {Key, Val}),
+ case Exists of
+ true ->
+ From ! {self(), updated};
+ false ->
+ From ! {self(), created}
+ end;
+ {From, {delete, Key}} ->
+ ets:delete(?MODULE, Key),
+ From ! {self(), ok};
+ _ ->
+ ignore
+ end,
+ ?MODULE:loop(SD).
+
diff --git a/deps/mochiweb/examples/https/server_cert.pem b/deps/mochiweb/examples/https/server_cert.pem
new file mode 100644
index 00000000..f84ccca7
--- /dev/null
+++ b/deps/mochiweb/examples/https/server_cert.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAgigAwIBAgIJAJLkNZzERPIUMA0GCSqGSIb3DQEBBQUAMBQxEjAQBgNV
+BAMTCWxvY2FsaG9zdDAeFw0xMDAzMTgxOTM5MThaFw0yMDAzMTUxOTM5MThaMBQx
+EjAQBgNVBAMTCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
+ggEBAJeUCOZxbmtngF4S5lXckjSDLc+8C+XjMBYBPyy5eKdJY20AQ1s9/hhp3ulI
+8pAvl+xVo4wQ+iBSvOzcy248Q+Xi6+zjceF7UNRgoYPgtJjKhdwcHV3mvFFrS/fp
+9ggoAChaJQWDO1OCfUgTWXImhkw+vcDR11OVMAJ/h73dqzJPI9mfq44PTTHfYtgr
+v4LAQAOlhXIAa2B+a6PlF6sqDqJaW5jLTcERjsBwnRhUGi7JevQzkejujX/vdA+N
+jRBjKH/KLU5h3Q7wUchvIez0PXWVTCnZjpA9aR4m7YV05nKQfxtGd71czYDYk+j8
+hd005jetT4ir7JkAWValBybJVksCAwEAAaN1MHMwHQYDVR0OBBYEFJl9s51SnjJt
+V/wgKWqV5Q6jnv1ZMEQGA1UdIwQ9MDuAFJl9s51SnjJtV/wgKWqV5Q6jnv1ZoRik
+FjAUMRIwEAYDVQQDEwlsb2NhbGhvc3SCCQCS5DWcxETyFDAMBgNVHRMEBTADAQH/
+MA0GCSqGSIb3DQEBBQUAA4IBAQB2ldLeLCc+lxK5i0EZquLamMBJwDIjGpT0JMP9
+b4XQOK2JABIu54BQIZhwcjk3FDJz/uOW5vm8k1kYni8FCjNZAaRZzCUfiUYTbTKL
+Rq9LuIAODyP2dnTqyKaQOOJHvrx9MRZ3XVecXPS0Tib4aO57vCaAbIkmhtYpTWmw
+e3t8CAIDVtgvjR6Se0a1JA4LktR7hBu22tDImvCSJn1nVAaHpani6iPBPPdMuMsP
+TBoeQfj8VpqBUjCStqJGa8ytjDFX73YaxV2mgrtGwPNme1x3YNRR11yTu7tksyMO
+GrmgxNriqYRchBhNEf72AKF0LR1ByKwfbDB9rIsV00HtCgOp
+-----END CERTIFICATE-----
diff --git a/deps/mochiweb/examples/https/server_key.pem b/deps/mochiweb/examples/https/server_key.pem
new file mode 100644
index 00000000..69bbf823
--- /dev/null
+++ b/deps/mochiweb/examples/https/server_key.pem
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpAIBAAKCAQEAl5QI5nFua2eAXhLmVdySNIMtz7wL5eMwFgE/LLl4p0ljbQBD
+Wz3+GGne6UjykC+X7FWjjBD6IFK87NzLbjxD5eLr7ONx4XtQ1GChg+C0mMqF3Bwd
+Xea8UWtL9+n2CCgAKFolBYM7U4J9SBNZciaGTD69wNHXU5UwAn+Hvd2rMk8j2Z+r
+jg9NMd9i2Cu/gsBAA6WFcgBrYH5ro+UXqyoOolpbmMtNwRGOwHCdGFQaLsl69DOR
+6O6Nf+90D42NEGMof8otTmHdDvBRyG8h7PQ9dZVMKdmOkD1pHibthXTmcpB/G0Z3
+vVzNgNiT6PyF3TTmN61PiKvsmQBZVqUHJslWSwIDAQABAoIBACI8Ky5xHDFh9RpK
+Rn/KC7OUlTpADKflgizWJ0Cgu2F9L9mkn5HyFHvLHa+u7CootbWJOiEejH/UcBtH
+WyMQtX0snYCpdkUpJv5wvMoebGu+AjHOn8tfm9T/2O6rhwgckLyMb6QpGbMo28b1
+p9QiY17BJPZx7qJQJcHKsAvwDwSThlb7MFmWf42LYWlzybpeYQvwpd+UY4I0WXLu
+/dqJIS9Npq+5Y5vbo2kAEAssb2hSCvhCfHmwFdKmBzlvgOn4qxgZ1iHQgfKI6Z3Y
+J0573ZgOVTuacn+lewtdg5AaHFcl/zIYEr9SNqRoPNGbPliuv6k6N2EYcufWL5lR
+sCmmmHECgYEAxm+7OpepGr++K3+O1e1MUhD7vSPkKJrCzNtUxbOi2NWj3FFUSPRU
+adWhuxvUnZgTcgM1+KuQ0fB2VmxXe9IDcrSFS7PKFGtd2kMs/5mBw4UgDZkOQh+q
+kDiBEV3HYYJWRq0w3NQ/9Iy1jxxdENHtGmG9aqamHxNtuO608wGW2S8CgYEAw4yG
+ZyAic0Q/U9V2OHI0MLxLCzuQz17C2wRT1+hBywNZuil5YeTuIt2I46jro6mJmWI2
+fH4S/geSZzg2RNOIZ28+aK79ab2jWBmMnvFCvaru+odAuser4N9pfAlHZvY0pT+S
+1zYX3f44ygiio+oosabLC5nWI0zB2gG8pwaJlaUCgYEAgr7poRB+ZlaCCY0RYtjo
+mYYBKD02vp5BzdKSB3V1zeLuBWM84pjB6b3Nw0fyDig+X7fH3uHEGN+USRs3hSj6
+BqD01s1OT6fyfbYXNw5A1r+nP+5h26Wbr0zblcKxdQj4qbbBZC8hOJNhqTqqA0Qe
+MmzF7jiBaiZV/Cyj4x1f9BcCgYEAhjL6SeuTuOctTqs/5pz5lDikh6DpUGcH8qaV
+o6aRAHHcMhYkZzpk8yh1uUdD7516APmVyvn6rrsjjhLVq4ZAJjwB6HWvE9JBN0TR
+bILF+sREHUqU8Zn2Ku0nxyfXCKIOnxlx/J/y4TaGYqBqfXNFWiXNUrjQbIlQv/xR
+K48g/MECgYBZdQlYbMSDmfPCC5cxkdjrkmAl0EgV051PWAi4wR+hLxIMRjHBvAk7
+IweobkFvT4TICulgroLkYcSa5eOZGxB/DHqcQCbWj3reFV0VpzmTDoFKG54sqBRl
+vVntGt0pfA40fF17VoS7riAdHF53ippTtsovHEsg5tq5NrBl5uKm2g==
+-----END RSA PRIVATE KEY-----
diff --git a/deps/mochiweb/examples/keepalive/keepalive.erl b/deps/mochiweb/examples/keepalive/keepalive.erl
new file mode 100644
index 00000000..965a17eb
--- /dev/null
+++ b/deps/mochiweb/examples/keepalive/keepalive.erl
@@ -0,0 +1,81 @@
+-module(keepalive).
+
+%% your web app can push data to clients using a technique called comet long
+%% polling. browsers make a request and your server waits to send a
+%% response until data is available. see wikipedia for a better explanation:
+%% http://en.wikipedia.org/wiki/Comet_(programming)#Ajax_with_long_polling
+%%
+%% since the majority of your http handlers will be idle at any given moment,
+%% you might consider making them hibernate while they wait for more data from
+%% another process. however, since the execution stack is discarded when a
+%% process hibernates, the handler would usually terminate after your response
+%% code runs. this means http keep alives wouldn't work; the handler process
+%% would terminate after each response and close its socket rather than
+%% returning to the big @mochiweb_http@ loop and processing another request.
+%%
+%% however, if mochiweb exposes a continuation that encapsulates the return to
+%% the top of the big loop in @mochiweb_http@, we can call that after the
+%% response. if you do that then control flow returns to the proper place,
+%% and keep alives work like they would if you hadn't hibernated.
+
+-export([ start/1, loop/1
+ ]).
+
+%% internal export (so hibernate can reach it)
+-export([ resume/3
+ ]).
+
+-define(LOOP, {?MODULE, loop}).
+
+start(Options = [{port, _Port}]) ->
+ mochiweb_http:start([{name, ?MODULE}, {loop, ?LOOP} | Options]).
+
+loop(Req) ->
+ Path = Req:get(path),
+ case string:tokens(Path, "/") of
+ ["longpoll" | RestOfPath] ->
+ %% the "reentry" is a continuation -- what @mochiweb_http@
+ %% needs to do to start its loop back at the top
+ Reentry = mochiweb_http:reentry(?LOOP),
+
+ %% here we could send a message to some other process and hope
+ %% to get an interesting message back after a while. for
+ %% simplicity let's just send ourselves a message after a few
+ %% seconds
+ erlang:send_after(2000, self(), "honk honk"),
+
+ %% since we expect to wait for a long time before getting a
+ %% reply, let's hibernate. memory usage will be minimized, so
+ %% we won't be wasting memory just sitting in a @receive@
+ proc_lib:hibernate(?MODULE, resume, [Req, RestOfPath, Reentry]),
+
+ %% we'll never reach this point, and this function @loop/1@
+ %% won't ever return control to @mochiweb_http@. luckily
+ %% @resume/3@ will take care of that.
+ io:format("not gonna happen~n", []);
+
+ _ ->
+ ok(Req, io_lib:format("some other page: ~p", [Path]))
+ end,
+
+ io:format("restarting loop normally in ~p~n", [Path]),
+ ok.
+
+%% this is the function that's called when a message arrives.
+resume(Req, RestOfPath, Reentry) ->
+ receive
+ Msg ->
+ Text = io_lib:format("wake up message: ~p~nrest of path: ~p", [Msg, RestOfPath]),
+ ok(Req, Text)
+ end,
+
+ %% if we didn't call @Reentry@ here then the function would finish and the
+ %% process would exit. calling @Reentry@ takes care of returning control
+ %% to @mochiweb_http@
+ io:format("reentering loop via continuation in ~p~n", [Req:get(path)]),
+ Reentry(Req).
+
+ok(Req, Response) ->
+ Req:ok({_ContentType = "text/plain",
+ _Headers = [],
+ Response}).