/examples/https/https_store.erl
Erlang | 146 lines | 100 code | 14 blank | 32 comment | 0 complexity | 521193db19fe9785003a035b1505f91e MD5 | raw file
Possible License(s): MIT
- %% 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).