diff options
Diffstat (limited to 'examples/rest_pastebin')
| -rw-r--r-- | examples/rest_pastebin/README.md | 52 | ||||
| -rw-r--r-- | examples/rest_pastebin/priv/index.html | 22 | ||||
| -rw-r--r-- | examples/rest_pastebin/priv/index.txt | 7 | ||||
| -rw-r--r-- | examples/rest_pastebin/rebar.config | 4 | ||||
| -rw-r--r-- | examples/rest_pastebin/src/rest_pastebin.app.src | 15 | ||||
| -rw-r--r-- | examples/rest_pastebin/src/rest_pastebin.erl | 14 | ||||
| -rw-r--r-- | examples/rest_pastebin/src/rest_pastebin_app.erl | 25 | ||||
| -rw-r--r-- | examples/rest_pastebin/src/rest_pastebin_sup.erl | 23 | ||||
| -rw-r--r-- | examples/rest_pastebin/src/toppage_handler.erl | 132 | ||||
| -rwxr-xr-x | examples/rest_pastebin/start.sh | 6 | 
10 files changed, 300 insertions, 0 deletions
diff --git a/examples/rest_pastebin/README.md b/examples/rest_pastebin/README.md new file mode 100644 index 0000000..0e9d9b5 --- /dev/null +++ b/examples/rest_pastebin/README.md @@ -0,0 +1,52 @@ +Cowboy Rest Hello World +======================= + +To compile this example you need rebar in your PATH. + +Type the following command: +``` +$ rebar get-deps compile +``` + +You can then start the Erlang node with the following command: +``` +./start.sh +``` + +Then run any given command or point your browser to the indicated URL. + +Examples +-------- + +To upload something to the paste application, you can use curl like: +``` +<command> | curl -i --data-urlencode paste@- localhost:8080 +``` +or to upload my_file: +``` +curl -i --data-urlencode paste@my_file localhost:8080 +``` + +The URL of your data will be in the location header. Alternately, you can visit +http://localhost:8080 with your favorite web browser and submit your paste via +the form. + +Code that has been pasted can be highlighted with ?lang=<language> option if +you have [highlight](http://www.andre-simon.de/doku/highlight/en/highlight.html) +installed (although pygments or any other should work just fine). For example: +``` +curl -i --data-urlencode paste@priv/index.html localhost:8080 +curl <url from location header> +``` + +Will show the text of the html file. If your terminal supports color +sequences and highlight is installed: +``` +curl <url from location header>?lang=html +``` + +Will show a syntax highlighted version of the source file. If you open the +same URL in your web browser and your web browser tells cowboy that it prefers +html files, you will see the file highlighted with html/css markup. Firefox is +known to work. + diff --git a/examples/rest_pastebin/priv/index.html b/examples/rest_pastebin/priv/index.html new file mode 100644 index 0000000..1c7e2eb --- /dev/null +++ b/examples/rest_pastebin/priv/index.html @@ -0,0 +1,22 @@ +<!DOCTYPE html> +<html> +	<head> +		<title>Simple Pastebin</title> +	</head> +	<body> +		<h1>Simple Pastebin</h1> +		<p> +			You can paste your text into the text field to submit, or you can +			capture the output of a command with: +		</p> +		<code> +			<i>command</i> | curl -i --data-urlencode paste@- localhost:8080 +		</code> +		<form action="/" method="post"> +			<textarea cols="80" rows="15" name="paste"></textarea> +			<div> +				<button type="submit">Upload your code</button> +			</div> +		</form> +	</body> +</html> diff --git a/examples/rest_pastebin/priv/index.txt b/examples/rest_pastebin/priv/index.txt new file mode 100644 index 0000000..0135fb0 --- /dev/null +++ b/examples/rest_pastebin/priv/index.txt @@ -0,0 +1,7 @@ +Simple Pastebin +--------------- + +You can paste your text into the text field to submit, or you can capture the +output of a command with: + +<command> | curl -i --data-urlencode paste@- localhost:8080 diff --git a/examples/rest_pastebin/rebar.config b/examples/rest_pastebin/rebar.config new file mode 100644 index 0000000..6ad3062 --- /dev/null +++ b/examples/rest_pastebin/rebar.config @@ -0,0 +1,4 @@ +{deps, [ +	{cowboy, ".*", +		{git, "git://github.com/extend/cowboy.git", "master"}} +]}. diff --git a/examples/rest_pastebin/src/rest_pastebin.app.src b/examples/rest_pastebin/src/rest_pastebin.app.src new file mode 100644 index 0000000..7701ebe --- /dev/null +++ b/examples/rest_pastebin/src/rest_pastebin.app.src @@ -0,0 +1,15 @@ +%% Feel free to use, reuse and abuse the code in this file. + +{application, rest_pastebin, [ +	{description, "Cowboy REST Pastebin example inspired by sprunge."}, +	{vsn, "1"}, +	{modules, []}, +	{registered, []}, +	{applications, [ +		kernel, +		stdlib, +		cowboy +	]}, +	{mod, {rest_pastebin_app, []}}, +	{env, []} +]}. diff --git a/examples/rest_pastebin/src/rest_pastebin.erl b/examples/rest_pastebin/src/rest_pastebin.erl new file mode 100644 index 0000000..cf03a71 --- /dev/null +++ b/examples/rest_pastebin/src/rest_pastebin.erl @@ -0,0 +1,14 @@ +%% Feel free to use, reuse and abuse the code in this file. + +-module(rest_pastebin). + +%% API. +-export([start/0]). + +%% API. + +start() -> +	ok = application:start(crypto), +	ok = application:start(ranch), +	ok = application:start(cowboy), +	ok = application:start(rest_pastebin). diff --git a/examples/rest_pastebin/src/rest_pastebin_app.erl b/examples/rest_pastebin/src/rest_pastebin_app.erl new file mode 100644 index 0000000..10ba4c5 --- /dev/null +++ b/examples/rest_pastebin/src/rest_pastebin_app.erl @@ -0,0 +1,25 @@ +%% Feel free to use, reuse and abuse the code in this file. + +%% @private +-module(rest_pastebin_app). +-behaviour(application). + +%% API. +-export([start/2]). +-export([stop/1]). + +%% API. + +start(_Type, _Args) -> +	Dispatch = cowboy_router:compile([ +		{'_', [ +			{"/[:paste_id]", toppage_handler, []} +		]} +	]), +	{ok, _} = cowboy:start_http(http, 100, [{port, 8080}], [ +		{env, [{dispatch, Dispatch}]} +	]), +	rest_pastebin_sup:start_link(). + +stop(_State) -> +	ok. diff --git a/examples/rest_pastebin/src/rest_pastebin_sup.erl b/examples/rest_pastebin/src/rest_pastebin_sup.erl new file mode 100644 index 0000000..b5f08d7 --- /dev/null +++ b/examples/rest_pastebin/src/rest_pastebin_sup.erl @@ -0,0 +1,23 @@ +%% Feel free to use, reuse and abuse the code in this file. + +%% @private +-module(rest_pastebin_sup). +-behaviour(supervisor). + +%% API. +-export([start_link/0]). + +%% supervisor. +-export([init/1]). + +%% API. + +-spec start_link() -> {ok, pid()}. +start_link() -> +	supervisor:start_link({local, ?MODULE}, ?MODULE, []). + +%% supervisor. + +init([]) -> +	Procs = [], +	{ok, {{one_for_one, 10, 10}, Procs}}. diff --git a/examples/rest_pastebin/src/toppage_handler.erl b/examples/rest_pastebin/src/toppage_handler.erl new file mode 100644 index 0000000..758e11d --- /dev/null +++ b/examples/rest_pastebin/src/toppage_handler.erl @@ -0,0 +1,132 @@ +%% Feel free to use, reuse and abuse the code in this file. + +%% @doc Pastebin handler. +-module(toppage_handler). + +%% REST Callbacks +-export([init/3]). +-export([allowed_methods/2]). +-export([content_types_provided/2]). +-export([content_types_accepted/2]). +-export([resource_exists/2]). +-export([post_is_create/2]). +-export([create_path/2]). + +%% Callback Callbacks +-export([create_paste/2]). +-export([paste_html/2]). +-export([paste_text/2]). + +init(_Transport, _Req, []) -> +	% For the random number generator: +	{X, Y, Z} = now(), +	random:seed(X, Y, Z), +	{upgrade, protocol, cowboy_rest}. + +allowed_methods(Req, State) -> +	{[<<"GET">>, <<"POST">>], Req, State}. + +content_types_provided(Req, State) -> +	{[ +		{{<<"text">>, <<"plain">>, []}, paste_text}, +		{{<<"text">>, <<"html">>, []}, paste_html} +	], Req, State}. + +content_types_accepted(Req, State) -> +	{[{{<<"application">>, <<"x-www-form-urlencoded">>, []}, create_paste}], +		Req, State}. + +resource_exists(Req, _State) -> +	case cowboy_req:binding(paste_id, Req) of +		{undefined, Req2} -> +			{true, Req2, index}; +		{PasteID, Req2} -> +			case valid_path(PasteID) and file_exists(PasteID) of +				true -> {true, Req2, PasteID}; +				false -> {false, Req2, PasteID} +			end +	end. + +post_is_create(Req, State) -> +	{true, Req, State}. + +create_path(Req, State) -> +	{<<$/, (new_paste_id())/binary>>, Req, State}. + +create_paste(Req, State) -> +	{<<$/, PasteID/binary>>, Req2} = cowboy_req:meta(put_path, Req), +	{ok, [{<<"paste">>, Paste}], Req3} = cowboy_req:body_qs(Req2), +	ok = file:write_file(full_path(PasteID), Paste), +	{true, Req3, State}. + +paste_html(Req, index) -> +	{read_file("index.html"), Req, index}; +paste_html(Req, Paste) -> +	{Style, Req2} = cowboy_req:qs_val(<<"lang">>, Req, plain), +	{format_html(Paste, Style), Req2, Paste}. + +paste_text(Req, index) -> +	{read_file("index.txt"), Req, index}; +paste_text(Req, Paste) -> +	{Style, Req2} = cowboy_req:qs_val(<<"lang">>, Req, plain), +	{format_text(Paste, Style), Req2, Paste}. + +% Private + +read_file(Name) -> +	{ok, Binary} = file:read_file(full_path(Name)), +	Binary. + +full_path(Name) -> +	{ok, Cwd} = file:get_cwd(), +	filename:join([Cwd, "priv", Name]). + +file_exists(Name) -> +	case file:read_file_info(full_path(Name)) of +		{ok, _Info} -> true; +		{error, _Reason} -> false +	end. + +valid_path(<<>>) -> true; +valid_path(<<$., _T/binary>>) -> false; +valid_path(<<_Char, T/binary>>) -> valid_path(T). + +new_paste_id() -> +	Initial = random:uniform(62) - 1, +	new_paste_id(<<Initial>>, 7). +new_paste_id(Bin, 0) -> +	Chars = <<"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890">>, +	<< <<(binary_part(Chars, B, 1))/binary>> || <<B>> <= Bin >>; +new_paste_id(Bin, Rem) -> +	Next = random:uniform(62) - 1, +	new_paste_id(<<Bin/binary, Next>>, Rem - 1). + +format_html(Paste, plain) -> +	Text = escape_html_chars(read_file(Paste)), +	<<"<!DOCTYPE html><html>", +	"<head><title>paste</title></head>", +	"<body><pre><code>", Text/binary, "</code></pre></body></html>\n">>; +format_html(Paste, Lang) -> +	highlight(full_path(Paste), Lang, "html"). + +format_text(Paste, plain) -> +	read_file(Paste); +format_text(Paste, Lang) -> +	highlight(full_path(Paste), Lang, "ansi"). + +highlight(Path, Lang, Type) -> +	Path1 = binary_to_list(Path), +	Lang1 = binary_to_list(Lang), +	os:cmd(["highlight --syntax=", Lang1, +		" --doc-title=paste ", +		" --out-format=", Type, +		" --include-style ", Path1]). + +% Escape some HTML characters that might make a fuss +escape_html_chars(Bin) -> +	<< <<(escape_html_char(B))/binary>> || <<B>> <= Bin >>. + +escape_html_char($<) -> <<"<">>; +escape_html_char($>) -> <<">">>; +escape_html_char($&) -> <<"&">>; +escape_html_char(C) -> <<C>>. diff --git a/examples/rest_pastebin/start.sh b/examples/rest_pastebin/start.sh new file mode 100755 index 0000000..24f5709 --- /dev/null +++ b/examples/rest_pastebin/start.sh @@ -0,0 +1,6 @@ +#!/bin/sh +erl -pa ebin deps/*/ebin -s rest_pastebin \ +	-eval "io:format(\"Upload: echo foo | curl -i --data-urlencode paste@- localhost:8080~n\")." \ +	-eval "io:format(\"Get: curl <value of the location header>~n\")." \ +	-eval "io:format(\"Get with highlighting: curl <location>?lang=<language>~n\")." \ +	-eval "io:format(\"To get html, point your browser to http://localhost:8080.~n\")."  | 
