You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by da...@apache.org on 2014/02/05 00:44:47 UTC

[34/44] Remove src/mochiweb

http://git-wip-us.apache.org/repos/asf/couchdb/blob/acf8eaff/src/mochiweb/src/mochiweb_socket_server.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb/src/mochiweb_socket_server.erl b/src/mochiweb/src/mochiweb_socket_server.erl
deleted file mode 100644
index ff0d8f3..0000000
--- a/src/mochiweb/src/mochiweb_socket_server.erl
+++ /dev/null
@@ -1,364 +0,0 @@
-%% @author Bob Ippolito <bo...@mochimedia.com>
-%% @copyright 2007 Mochi Media, Inc.
-
-%% @doc MochiWeb socket server.
-
--module(mochiweb_socket_server).
--author('bob@mochimedia.com').
--behaviour(gen_server).
-
--include("internal.hrl").
-
--export([start/1, stop/1]).
--export([init/1, handle_call/3, handle_cast/2, terminate/2, code_change/3,
-         handle_info/2]).
--export([get/2, set/3]).
-
--record(mochiweb_socket_server,
-        {port,
-         loop,
-         name=undefined,
-         %% NOTE: This is currently ignored.
-         max=2048,
-         ip=any,
-         listen=null,
-         nodelay=false,
-         backlog=128,
-         active_sockets=0,
-         acceptor_pool_size=16,
-         ssl=false,
-         ssl_opts=[{ssl_imp, new}],
-         acceptor_pool=sets:new(),
-         profile_fun=undefined}).
-
--define(is_old_state(State), not is_record(State, mochiweb_socket_server)).
-
-start(State=#mochiweb_socket_server{}) ->
-    start_server(State);
-start(Options) ->
-    start(parse_options(Options)).
-
-get(Name, Property) ->
-    gen_server:call(Name, {get, Property}).
-
-set(Name, profile_fun, Fun) ->
-    gen_server:cast(Name, {set, profile_fun, Fun});
-set(Name, Property, _Value) ->
-    error_logger:info_msg("?MODULE:set for ~p with ~p not implemented~n",
-                          [Name, Property]).
-
-stop(Name) when is_atom(Name) ->
-    gen_server:cast(Name, stop);
-stop(Pid) when is_pid(Pid) ->
-    gen_server:cast(Pid, stop);
-stop({local, Name}) ->
-    stop(Name);
-stop({global, Name}) ->
-    stop(Name);
-stop(Options) ->
-    State = parse_options(Options),
-    stop(State#mochiweb_socket_server.name).
-
-%% Internal API
-
-parse_options(Options) ->
-    parse_options(Options, #mochiweb_socket_server{}).
-
-parse_options([], State) ->
-    State;
-parse_options([{name, L} | Rest], State) when is_list(L) ->
-    Name = {local, list_to_atom(L)},
-    parse_options(Rest, State#mochiweb_socket_server{name=Name});
-parse_options([{name, A} | Rest], State) when A =:= undefined ->
-    parse_options(Rest, State#mochiweb_socket_server{name=A});
-parse_options([{name, A} | Rest], State) when is_atom(A) ->
-    Name = {local, A},
-    parse_options(Rest, State#mochiweb_socket_server{name=Name});
-parse_options([{name, Name} | Rest], State) ->
-    parse_options(Rest, State#mochiweb_socket_server{name=Name});
-parse_options([{port, L} | Rest], State) when is_list(L) ->
-    Port = list_to_integer(L),
-    parse_options(Rest, State#mochiweb_socket_server{port=Port});
-parse_options([{port, Port} | Rest], State) ->
-    parse_options(Rest, State#mochiweb_socket_server{port=Port});
-parse_options([{ip, Ip} | Rest], State) ->
-    ParsedIp = case Ip of
-                   any ->
-                       any;
-                   Ip when is_tuple(Ip) ->
-                       Ip;
-                   Ip when is_list(Ip) ->
-                       {ok, IpTuple} = inet_parse:address(Ip),
-                       IpTuple
-               end,
-    parse_options(Rest, State#mochiweb_socket_server{ip=ParsedIp});
-parse_options([{loop, Loop} | Rest], State) ->
-    parse_options(Rest, State#mochiweb_socket_server{loop=Loop});
-parse_options([{backlog, Backlog} | Rest], State) ->
-    parse_options(Rest, State#mochiweb_socket_server{backlog=Backlog});
-parse_options([{nodelay, NoDelay} | Rest], State) ->
-    parse_options(Rest, State#mochiweb_socket_server{nodelay=NoDelay});
-parse_options([{acceptor_pool_size, Max} | Rest], State) ->
-    MaxInt = ensure_int(Max),
-    parse_options(Rest,
-                  State#mochiweb_socket_server{acceptor_pool_size=MaxInt});
-parse_options([{max, Max} | Rest], State) ->
-    error_logger:info_report([{warning, "TODO: max is currently unsupported"},
-                              {max, Max}]),
-    MaxInt = ensure_int(Max),
-    parse_options(Rest, State#mochiweb_socket_server{max=MaxInt});
-parse_options([{ssl, Ssl} | Rest], State) when is_boolean(Ssl) ->
-    parse_options(Rest, State#mochiweb_socket_server{ssl=Ssl});
-parse_options([{ssl_opts, SslOpts} | Rest], State) when is_list(SslOpts) ->
-    SslOpts1 = [{ssl_imp, new} | proplists:delete(ssl_imp, SslOpts)],
-    parse_options(Rest, State#mochiweb_socket_server{ssl_opts=SslOpts1});
-parse_options([{profile_fun, ProfileFun} | Rest], State) when is_function(ProfileFun) ->
-    parse_options(Rest, State#mochiweb_socket_server{profile_fun=ProfileFun}).
-
-
-start_server(State=#mochiweb_socket_server{ssl=Ssl, name=Name}) ->
-    case Ssl of
-        true ->
-            application:start(crypto),
-            application:start(public_key),
-            application:start(ssl);
-        false ->
-            void
-    end,
-    case Name of
-        undefined ->
-            gen_server:start_link(?MODULE, State, []);
-        _ ->
-            gen_server:start_link(Name, ?MODULE, State, [])
-    end.
-
-ensure_int(N) when is_integer(N) ->
-    N;
-ensure_int(S) when is_list(S) ->
-    list_to_integer(S).
-
-ipv6_supported() ->
-    case (catch inet:getaddr("localhost", inet6)) of
-        {ok, _Addr} ->
-            true;
-        {error, _} ->
-            false
-    end.
-
-init(State=#mochiweb_socket_server{ip=Ip, port=Port, backlog=Backlog, nodelay=NoDelay}) ->
-    process_flag(trap_exit, true),
-    BaseOpts = [binary,
-                {reuseaddr, true},
-                {packet, 0},
-                {backlog, Backlog},
-                {recbuf, ?RECBUF_SIZE},
-                {active, false},
-                {nodelay, NoDelay}],
-    Opts = case Ip of
-        any ->
-            case ipv6_supported() of % IPv4, and IPv6 if supported
-                true -> [inet, inet6 | BaseOpts];
-                _ -> BaseOpts
-            end;
-        {_, _, _, _} -> % IPv4
-            [inet, {ip, Ip} | BaseOpts];
-        {_, _, _, _, _, _, _, _} -> % IPv6
-            [inet6, {ip, Ip} | BaseOpts]
-    end,
-    case listen(Port, Opts, State) of
-        {stop, eacces} ->
-            case Port < 1024 of
-                true ->
-                    case catch fdsrv:start() of
-                        {ok, _} ->
-                            case fdsrv:bind_socket(tcp, Port) of
-                                {ok, Fd} ->
-                                    listen(Port, [{fd, Fd} | Opts], State);
-                                _ ->
-                                    {stop, fdsrv_bind_failed}
-                            end;
-                        _ ->
-                            {stop, fdsrv_start_failed}
-                    end;
-                false ->
-                    {stop, eacces}
-            end;
-        Other ->
-            Other
-    end.
-
-new_acceptor_pool(Listen,
-                  State=#mochiweb_socket_server{acceptor_pool=Pool,
-                                                acceptor_pool_size=Size,
-                                                loop=Loop}) ->
-    F = fun (_, S) ->
-                Pid = mochiweb_acceptor:start_link(self(), Listen, Loop),
-                sets:add_element(Pid, S)
-        end,
-    Pool1 = lists:foldl(F, Pool, lists:seq(1, Size)),
-    State#mochiweb_socket_server{acceptor_pool=Pool1}.
-
-listen(Port, Opts, State=#mochiweb_socket_server{ssl=Ssl, ssl_opts=SslOpts}) ->
-    case mochiweb_socket:listen(Ssl, Port, Opts, SslOpts) of
-        {ok, Listen} ->
-            {ok, ListenPort} = mochiweb_socket:port(Listen),
-            {ok, new_acceptor_pool(
-                   Listen,
-                   State#mochiweb_socket_server{listen=Listen,
-                                                port=ListenPort})};
-        {error, Reason} ->
-            {stop, Reason}
-    end.
-
-do_get(port, #mochiweb_socket_server{port=Port}) ->
-    Port;
-do_get(active_sockets, #mochiweb_socket_server{active_sockets=ActiveSockets}) ->
-    ActiveSockets.
-
-
-state_to_proplist(#mochiweb_socket_server{name=Name,
-                                          port=Port,
-                                          active_sockets=ActiveSockets}) ->
-    [{name, Name}, {port, Port}, {active_sockets, ActiveSockets}].
-
-upgrade_state(State = #mochiweb_socket_server{}) ->
-    State;
-upgrade_state({mochiweb_socket_server, Port, Loop, Name,
-             Max, IP, Listen, NoDelay, Backlog, ActiveSockets,
-             AcceptorPoolSize, SSL, SSL_opts,
-             AcceptorPool}) ->
-    #mochiweb_socket_server{port=Port, loop=Loop, name=Name, max=Max, ip=IP,
-                            listen=Listen, nodelay=NoDelay, backlog=Backlog,
-                            active_sockets=ActiveSockets,
-                            acceptor_pool_size=AcceptorPoolSize,
-                            ssl=SSL,
-                            ssl_opts=SSL_opts,
-                            acceptor_pool=AcceptorPool}.
-
-handle_call(Req, From, State) when ?is_old_state(State) ->
-    handle_call(Req, From, upgrade_state(State));
-handle_call({get, Property}, _From, State) ->
-    Res = do_get(Property, State),
-    {reply, Res, State};
-handle_call(_Message, _From, State) ->
-    Res = error,
-    {reply, Res, State}.
-
-
-handle_cast(Req, State) when ?is_old_state(State) ->
-    handle_cast(Req, upgrade_state(State));
-handle_cast({accepted, Pid, Timing},
-            State=#mochiweb_socket_server{active_sockets=ActiveSockets}) ->
-    State1 = State#mochiweb_socket_server{active_sockets=1 + ActiveSockets},
-    case State#mochiweb_socket_server.profile_fun of
-        undefined ->
-            undefined;
-        F when is_function(F) ->
-            catch F([{timing, Timing} | state_to_proplist(State1)])
-    end,
-    {noreply, recycle_acceptor(Pid, State1)};
-handle_cast({set, profile_fun, ProfileFun}, State) ->
-    State1 = case ProfileFun of
-                 ProfileFun when is_function(ProfileFun); ProfileFun =:= undefined ->
-                     State#mochiweb_socket_server{profile_fun=ProfileFun};
-                 _ ->
-                     State
-             end,
-    {noreply, State1};
-handle_cast(stop, State) ->
-    {stop, normal, State}.
-
-
-terminate(Reason, State) when ?is_old_state(State) ->
-    terminate(Reason, upgrade_state(State));
-terminate(_Reason, #mochiweb_socket_server{listen=Listen, port=Port}) ->
-    mochiweb_socket:close(Listen),
-    case Port < 1024 of
-        true ->
-            catch fdsrv:stop(),
-            ok;
-        false ->
-            ok
-    end.
-
-code_change(_OldVsn, State, _Extra) ->
-    State.
-
-recycle_acceptor(Pid, State=#mochiweb_socket_server{
-                        acceptor_pool=Pool,
-                        listen=Listen,
-                        loop=Loop,
-                        active_sockets=ActiveSockets}) ->
-    case sets:is_element(Pid, Pool) of
-        true ->
-            Acceptor = mochiweb_acceptor:start_link(self(), Listen, Loop),
-            Pool1 = sets:add_element(Acceptor, sets:del_element(Pid, Pool)),
-            State#mochiweb_socket_server{acceptor_pool=Pool1};
-        false ->
-            State#mochiweb_socket_server{active_sockets=ActiveSockets - 1}
-    end.
-
-handle_info(Msg, State) when ?is_old_state(State) ->
-    handle_info(Msg, upgrade_state(State));
-handle_info({'EXIT', Pid, normal}, State) ->
-    {noreply, recycle_acceptor(Pid, State)};
-handle_info({'EXIT', Pid, Reason},
-            State=#mochiweb_socket_server{acceptor_pool=Pool}) ->
-    case sets:is_element(Pid, Pool) of
-        true ->
-            %% If there was an unexpected error accepting, log and sleep.
-            error_logger:error_report({?MODULE, ?LINE,
-                                       {acceptor_error, Reason}}),
-            timer:sleep(100);
-        false ->
-            ok
-    end,
-    {noreply, recycle_acceptor(Pid, State)};
-
-% this is what release_handler needs to get a list of modules,
-% since our supervisor modules list is set to 'dynamic'
-% see sasl-2.1.9.2/src/release_handler_1.erl get_dynamic_mods
-handle_info({From, Tag, get_modules}, State = #mochiweb_socket_server{name={local,Mod}}) ->
-    From ! {element(2,Tag), [Mod]},
-    {noreply, State};
-
-% If for some reason we can't get the module name, send empty list to avoid release_handler timeout:
-handle_info({From, Tag, get_modules}, State) ->
-    error_logger:info_msg("mochiweb_socket_server replying to dynamic modules request as '[]'~n",[]),
-    From ! {element(2,Tag), []},
-    {noreply, State};
-
-handle_info(Info, State) ->
-    error_logger:info_report([{'INFO', Info}, {'State', State}]),
-    {noreply, State}.
-
-
-
-%%
-%% Tests
-%%
--include_lib("eunit/include/eunit.hrl").
--ifdef(TEST).
-
-upgrade_state_test() ->
-    OldState = {mochiweb_socket_server,
-                port, loop, name,
-                max, ip, listen,
-                nodelay, backlog,
-                active_sockets,
-                acceptor_pool_size,
-                ssl, ssl_opts, acceptor_pool},
-    State = upgrade_state(OldState),
-    CmpState = #mochiweb_socket_server{port=port, loop=loop,
-                                       name=name, max=max, ip=ip,
-                                       listen=listen, nodelay=nodelay,
-                                       backlog=backlog,
-                                       active_sockets=active_sockets,
-                                       acceptor_pool_size=acceptor_pool_size,
-                                       ssl=ssl, ssl_opts=ssl_opts,
-                                       acceptor_pool=acceptor_pool,
-                                       profile_fun=undefined},
-    ?assertEqual(CmpState, State).
-
--endif.
-

http://git-wip-us.apache.org/repos/asf/couchdb/blob/acf8eaff/src/mochiweb/src/mochiweb_sup.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb/src/mochiweb_sup.erl b/src/mochiweb/src/mochiweb_sup.erl
deleted file mode 100644
index af7df9b..0000000
--- a/src/mochiweb/src/mochiweb_sup.erl
+++ /dev/null
@@ -1,41 +0,0 @@
-%% @author Bob Ippolito <bo...@mochimedia.com>
-%% @copyright 2007 Mochi Media, Inc.
-
-%% @doc Supervisor for the mochiweb application.
-
--module(mochiweb_sup).
--author('bob@mochimedia.com').
-
--behaviour(supervisor).
-
-%% External exports
--export([start_link/0, upgrade/0]).
-
-%% supervisor callbacks
--export([init/1]).
-
-%% @spec start_link() -> ServerRet
-%% @doc API for starting the supervisor.
-start_link() ->
-    supervisor:start_link({local, ?MODULE}, ?MODULE, []).
-
-%% @spec upgrade() -> ok
-%% @doc Add processes if necessary.
-upgrade() ->
-    {ok, {_, Specs}} = init([]),
-    [supervisor:start_child(?MODULE, Spec) || Spec <- Specs],
-    ok.
-
-%% @spec init([]) -> SupervisorTree
-%% @doc supervisor callback, ensures yaws is in embedded mode and then
-%%      returns the supervisor tree.
-init([]) ->
-    Processes = [],
-    {ok, {{one_for_one, 10, 10}, Processes}}.
-
-%%
-%% Tests
-%%
--include_lib("eunit/include/eunit.hrl").
--ifdef(TEST).
--endif.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/acf8eaff/src/mochiweb/src/mochiweb_util.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb/src/mochiweb_util.erl b/src/mochiweb/src/mochiweb_util.erl
deleted file mode 100644
index 6b88818..0000000
--- a/src/mochiweb/src/mochiweb_util.erl
+++ /dev/null
@@ -1,980 +0,0 @@
-%% @author Bob Ippolito <bo...@mochimedia.com>
-%% @copyright 2007 Mochi Media, Inc.
-
-%% @doc Utilities for parsing and quoting.
-
--module(mochiweb_util).
--author('bob@mochimedia.com').
--export([join/2, quote_plus/1, urlencode/1, parse_qs/1, unquote/1]).
--export([path_split/1]).
--export([urlsplit/1, urlsplit_path/1, urlunsplit/1, urlunsplit_path/1]).
--export([guess_mime/1, parse_header/1]).
--export([shell_quote/1, cmd/1, cmd_string/1, cmd_port/2, cmd_status/1]).
--export([record_to_proplist/2, record_to_proplist/3]).
--export([safe_relative_path/1, partition/2]).
--export([parse_qvalues/1, pick_accepted_encodings/3]).
--export([make_io/1]).
-
--define(PERCENT, 37).  % $\%
--define(FULLSTOP, 46). % $\.
--define(IS_HEX(C), ((C >= $0 andalso C =< $9) orelse
-                    (C >= $a andalso C =< $f) orelse
-                    (C >= $A andalso C =< $F))).
--define(QS_SAFE(C), ((C >= $a andalso C =< $z) orelse
-                     (C >= $A andalso C =< $Z) orelse
-                     (C >= $0 andalso C =< $9) orelse
-                     (C =:= ?FULLSTOP orelse C =:= $- orelse C =:= $~ orelse
-                      C =:= $_))).
-
-hexdigit(C) when C < 10 -> $0 + C;
-hexdigit(C) when C < 16 -> $A + (C - 10).
-
-unhexdigit(C) when C >= $0, C =< $9 -> C - $0;
-unhexdigit(C) when C >= $a, C =< $f -> C - $a + 10;
-unhexdigit(C) when C >= $A, C =< $F -> C - $A + 10.
-
-%% @spec partition(String, Sep) -> {String, [], []} | {Prefix, Sep, Postfix}
-%% @doc Inspired by Python 2.5's str.partition:
-%%      partition("foo/bar", "/") = {"foo", "/", "bar"},
-%%      partition("foo", "/") = {"foo", "", ""}.
-partition(String, Sep) ->
-    case partition(String, Sep, []) of
-        undefined ->
-            {String, "", ""};
-        Result ->
-            Result
-    end.
-
-partition("", _Sep, _Acc) ->
-    undefined;
-partition(S, Sep, Acc) ->
-    case partition2(S, Sep) of
-        undefined ->
-            [C | Rest] = S,
-            partition(Rest, Sep, [C | Acc]);
-        Rest ->
-            {lists:reverse(Acc), Sep, Rest}
-    end.
-
-partition2(Rest, "") ->
-    Rest;
-partition2([C | R1], [C | R2]) ->
-    partition2(R1, R2);
-partition2(_S, _Sep) ->
-    undefined.
-
-
-
-%% @spec safe_relative_path(string()) -> string() | undefined
-%% @doc Return the reduced version of a relative path or undefined if it
-%%      is not safe. safe relative paths can be joined with an absolute path
-%%      and will result in a subdirectory of the absolute path. Safe paths
-%%      never contain a backslash character.
-safe_relative_path("/" ++ _) ->
-    undefined;
-safe_relative_path(P) ->
-    case string:chr(P, $\\) of
-        0 ->
-           safe_relative_path(P, []);
-        _ ->
-           undefined
-    end.
-
-safe_relative_path("", Acc) ->
-    case Acc of
-        [] ->
-            "";
-        _ ->
-            string:join(lists:reverse(Acc), "/")
-    end;
-safe_relative_path(P, Acc) ->
-    case partition(P, "/") of
-        {"", "/", _} ->
-            %% /foo or foo//bar
-            undefined;
-        {"..", _, _} when Acc =:= [] ->
-            undefined;
-        {"..", _, Rest} ->
-            safe_relative_path(Rest, tl(Acc));
-        {Part, "/", ""} ->
-            safe_relative_path("", ["", Part | Acc]);
-        {Part, _, Rest} ->
-            safe_relative_path(Rest, [Part | Acc])
-    end.
-
-%% @spec shell_quote(string()) -> string()
-%% @doc Quote a string according to UNIX shell quoting rules, returns a string
-%%      surrounded by double quotes.
-shell_quote(L) ->
-    shell_quote(L, [$\"]).
-
-%% @spec cmd_port([string()], Options) -> port()
-%% @doc open_port({spawn, mochiweb_util:cmd_string(Argv)}, Options).
-cmd_port(Argv, Options) ->
-    open_port({spawn, cmd_string(Argv)}, Options).
-
-%% @spec cmd([string()]) -> string()
-%% @doc os:cmd(cmd_string(Argv)).
-cmd(Argv) ->
-    os:cmd(cmd_string(Argv)).
-
-%% @spec cmd_string([string()]) -> string()
-%% @doc Create a shell quoted command string from a list of arguments.
-cmd_string(Argv) ->
-    string:join([shell_quote(X) || X <- Argv], " ").
-
-%% @spec cmd_status([string()]) -> {ExitStatus::integer(), Stdout::binary()}
-%% @doc Accumulate the output and exit status from the given application, will be
-%%      spawned with cmd_port/2.
-cmd_status(Argv) ->
-    Port = cmd_port(Argv, [exit_status, stderr_to_stdout,
-                           use_stdio, binary]),
-    try cmd_loop(Port, [])
-    after catch port_close(Port)
-    end.
-
-%% @spec cmd_loop(port(), list()) -> {ExitStatus::integer(), Stdout::binary()}
-%% @doc Accumulate the output and exit status from a port.
-cmd_loop(Port, Acc) ->
-    receive
-        {Port, {exit_status, Status}} ->
-            {Status, iolist_to_binary(lists:reverse(Acc))};
-        {Port, {data, Data}} ->
-            cmd_loop(Port, [Data | Acc])
-    end.
-
-%% @spec join([iolist()], iolist()) -> iolist()
-%% @doc Join a list of strings or binaries together with the given separator
-%%      string or char or binary. The output is flattened, but may be an
-%%      iolist() instead of a string() if any of the inputs are binary().
-join([], _Separator) ->
-    [];
-join([S], _Separator) ->
-    lists:flatten(S);
-join(Strings, Separator) ->
-    lists:flatten(revjoin(lists:reverse(Strings), Separator, [])).
-
-revjoin([], _Separator, Acc) ->
-    Acc;
-revjoin([S | Rest], Separator, []) ->
-    revjoin(Rest, Separator, [S]);
-revjoin([S | Rest], Separator, Acc) ->
-    revjoin(Rest, Separator, [S, Separator | Acc]).
-
-%% @spec quote_plus(atom() | integer() | float() | string() | binary()) -> string()
-%% @doc URL safe encoding of the given term.
-quote_plus(Atom) when is_atom(Atom) ->
-    quote_plus(atom_to_list(Atom));
-quote_plus(Int) when is_integer(Int) ->
-    quote_plus(integer_to_list(Int));
-quote_plus(Binary) when is_binary(Binary) ->
-    quote_plus(binary_to_list(Binary));
-quote_plus(Float) when is_float(Float) ->
-    quote_plus(mochinum:digits(Float));
-quote_plus(String) ->
-    quote_plus(String, []).
-
-quote_plus([], Acc) ->
-    lists:reverse(Acc);
-quote_plus([C | Rest], Acc) when ?QS_SAFE(C) ->
-    quote_plus(Rest, [C | Acc]);
-quote_plus([$\s | Rest], Acc) ->
-    quote_plus(Rest, [$+ | Acc]);
-quote_plus([C | Rest], Acc) ->
-    <<Hi:4, Lo:4>> = <<C>>,
-    quote_plus(Rest, [hexdigit(Lo), hexdigit(Hi), ?PERCENT | Acc]).
-
-%% @spec urlencode([{Key, Value}]) -> string()
-%% @doc URL encode the property list.
-urlencode(Props) ->
-    Pairs = lists:foldr(
-              fun ({K, V}, Acc) ->
-                      [quote_plus(K) ++ "=" ++ quote_plus(V) | Acc]
-              end, [], Props),
-    string:join(Pairs, "&").
-
-%% @spec parse_qs(string() | binary()) -> [{Key, Value}]
-%% @doc Parse a query string or application/x-www-form-urlencoded.
-parse_qs(Binary) when is_binary(Binary) ->
-    parse_qs(binary_to_list(Binary));
-parse_qs(String) ->
-    parse_qs(String, []).
-
-parse_qs([], Acc) ->
-    lists:reverse(Acc);
-parse_qs(String, Acc) ->
-    {Key, Rest} = parse_qs_key(String),
-    {Value, Rest1} = parse_qs_value(Rest),
-    parse_qs(Rest1, [{Key, Value} | Acc]).
-
-parse_qs_key(String) ->
-    parse_qs_key(String, []).
-
-parse_qs_key([], Acc) ->
-    {qs_revdecode(Acc), ""};
-parse_qs_key([$= | Rest], Acc) ->
-    {qs_revdecode(Acc), Rest};
-parse_qs_key(Rest=[$; | _], Acc) ->
-    {qs_revdecode(Acc), Rest};
-parse_qs_key(Rest=[$& | _], Acc) ->
-    {qs_revdecode(Acc), Rest};
-parse_qs_key([C | Rest], Acc) ->
-    parse_qs_key(Rest, [C | Acc]).
-
-parse_qs_value(String) ->
-    parse_qs_value(String, []).
-
-parse_qs_value([], Acc) ->
-    {qs_revdecode(Acc), ""};
-parse_qs_value([$; | Rest], Acc) ->
-    {qs_revdecode(Acc), Rest};
-parse_qs_value([$& | Rest], Acc) ->
-    {qs_revdecode(Acc), Rest};
-parse_qs_value([C | Rest], Acc) ->
-    parse_qs_value(Rest, [C | Acc]).
-
-%% @spec unquote(string() | binary()) -> string()
-%% @doc Unquote a URL encoded string.
-unquote(Binary) when is_binary(Binary) ->
-    unquote(binary_to_list(Binary));
-unquote(String) ->
-    qs_revdecode(lists:reverse(String)).
-
-qs_revdecode(S) ->
-    qs_revdecode(S, []).
-
-qs_revdecode([], Acc) ->
-    Acc;
-qs_revdecode([$+ | Rest], Acc) ->
-    qs_revdecode(Rest, [$\s | Acc]);
-qs_revdecode([Lo, Hi, ?PERCENT | Rest], Acc) when ?IS_HEX(Lo), ?IS_HEX(Hi) ->
-    qs_revdecode(Rest, [(unhexdigit(Lo) bor (unhexdigit(Hi) bsl 4)) | Acc]);
-qs_revdecode([C | Rest], Acc) ->
-    qs_revdecode(Rest, [C | Acc]).
-
-%% @spec urlsplit(Url) -> {Scheme, Netloc, Path, Query, Fragment}
-%% @doc Return a 5-tuple, does not expand % escapes. Only supports HTTP style
-%%      URLs.
-urlsplit(Url) ->
-    {Scheme, Url1} = urlsplit_scheme(Url),
-    {Netloc, Url2} = urlsplit_netloc(Url1),
-    {Path, Query, Fragment} = urlsplit_path(Url2),
-    {Scheme, Netloc, Path, Query, Fragment}.
-
-urlsplit_scheme(Url) ->
-    case urlsplit_scheme(Url, []) of
-        no_scheme ->
-            {"", Url};
-        Res ->
-            Res
-    end.
-
-urlsplit_scheme([C | Rest], Acc) when ((C >= $a andalso C =< $z) orelse
-                                       (C >= $A andalso C =< $Z) orelse
-                                       (C >= $0 andalso C =< $9) orelse
-                                       C =:= $+ orelse C =:= $- orelse
-                                       C =:= $.) ->
-    urlsplit_scheme(Rest, [C | Acc]);
-urlsplit_scheme([$: | Rest], Acc=[_ | _]) ->
-    {string:to_lower(lists:reverse(Acc)), Rest};
-urlsplit_scheme(_Rest, _Acc) ->
-    no_scheme.
-
-urlsplit_netloc("//" ++ Rest) ->
-    urlsplit_netloc(Rest, []);
-urlsplit_netloc(Path) ->
-    {"", Path}.
-
-urlsplit_netloc("", Acc) ->
-    {lists:reverse(Acc), ""};
-urlsplit_netloc(Rest=[C | _], Acc) when C =:= $/; C =:= $?; C =:= $# ->
-    {lists:reverse(Acc), Rest};
-urlsplit_netloc([C | Rest], Acc) ->
-    urlsplit_netloc(Rest, [C | Acc]).
-
-
-%% @spec path_split(string()) -> {Part, Rest}
-%% @doc Split a path starting from the left, as in URL traversal.
-%%      path_split("foo/bar") = {"foo", "bar"},
-%%      path_split("/foo/bar") = {"", "foo/bar"}.
-path_split(S) ->
-    path_split(S, []).
-
-path_split("", Acc) ->
-    {lists:reverse(Acc), ""};
-path_split("/" ++ Rest, Acc) ->
-    {lists:reverse(Acc), Rest};
-path_split([C | Rest], Acc) ->
-    path_split(Rest, [C | Acc]).
-
-
-%% @spec urlunsplit({Scheme, Netloc, Path, Query, Fragment}) -> string()
-%% @doc Assemble a URL from the 5-tuple. Path must be absolute.
-urlunsplit({Scheme, Netloc, Path, Query, Fragment}) ->
-    lists:flatten([case Scheme of "" -> "";  _ -> [Scheme, "://"] end,
-                   Netloc,
-                   urlunsplit_path({Path, Query, Fragment})]).
-
-%% @spec urlunsplit_path({Path, Query, Fragment}) -> string()
-%% @doc Assemble a URL path from the 3-tuple.
-urlunsplit_path({Path, Query, Fragment}) ->
-    lists:flatten([Path,
-                   case Query of "" -> ""; _ -> [$? | Query] end,
-                   case Fragment of "" -> ""; _ -> [$# | Fragment] end]).
-
-%% @spec urlsplit_path(Url) -> {Path, Query, Fragment}
-%% @doc Return a 3-tuple, does not expand % escapes. Only supports HTTP style
-%%      paths.
-urlsplit_path(Path) ->
-    urlsplit_path(Path, []).
-
-urlsplit_path("", Acc) ->
-    {lists:reverse(Acc), "", ""};
-urlsplit_path("?" ++ Rest, Acc) ->
-    {Query, Fragment} = urlsplit_query(Rest),
-    {lists:reverse(Acc), Query, Fragment};
-urlsplit_path("#" ++ Rest, Acc) ->
-    {lists:reverse(Acc), "", Rest};
-urlsplit_path([C | Rest], Acc) ->
-    urlsplit_path(Rest, [C | Acc]).
-
-urlsplit_query(Query) ->
-    urlsplit_query(Query, []).
-
-urlsplit_query("", Acc) ->
-    {lists:reverse(Acc), ""};
-urlsplit_query("#" ++ Rest, Acc) ->
-    {lists:reverse(Acc), Rest};
-urlsplit_query([C | Rest], Acc) ->
-    urlsplit_query(Rest, [C | Acc]).
-
-%% @spec guess_mime(string()) -> string()
-%% @doc  Guess the mime type of a file by the extension of its filename.
-guess_mime(File) ->
-    case mochiweb_mime:from_extension(filename:extension(File)) of
-        undefined ->
-            "text/plain";
-        Mime ->
-            Mime
-    end.
-
-%% @spec parse_header(string()) -> {Type, [{K, V}]}
-%% @doc  Parse a Content-Type like header, return the main Content-Type
-%%       and a property list of options.
-parse_header(String) ->
-    %% TODO: This is exactly as broken as Python's cgi module.
-    %%       Should parse properly like mochiweb_cookies.
-    [Type | Parts] = [string:strip(S) || S <- string:tokens(String, ";")],
-    F = fun (S, Acc) ->
-                case lists:splitwith(fun (C) -> C =/= $= end, S) of
-                    {"", _} ->
-                        %% Skip anything with no name
-                        Acc;
-                    {_, ""} ->
-                        %% Skip anything with no value
-                        Acc;
-                    {Name, [$\= | Value]} ->
-                        [{string:to_lower(string:strip(Name)),
-                          unquote_header(string:strip(Value))} | Acc]
-                end
-        end,
-    {string:to_lower(Type),
-     lists:foldr(F, [], Parts)}.
-
-unquote_header("\"" ++ Rest) ->
-    unquote_header(Rest, []);
-unquote_header(S) ->
-    S.
-
-unquote_header("", Acc) ->
-    lists:reverse(Acc);
-unquote_header("\"", Acc) ->
-    lists:reverse(Acc);
-unquote_header([$\\, C | Rest], Acc) ->
-    unquote_header(Rest, [C | Acc]);
-unquote_header([C | Rest], Acc) ->
-    unquote_header(Rest, [C | Acc]).
-
-%% @spec record_to_proplist(Record, Fields) -> proplist()
-%% @doc calls record_to_proplist/3 with a default TypeKey of '__record'
-record_to_proplist(Record, Fields) ->
-    record_to_proplist(Record, Fields, '__record').
-
-%% @spec record_to_proplist(Record, Fields, TypeKey) -> proplist()
-%% @doc Return a proplist of the given Record with each field in the
-%%      Fields list set as a key with the corresponding value in the Record.
-%%      TypeKey is the key that is used to store the record type
-%%      Fields should be obtained by calling record_info(fields, record_type)
-%%      where record_type is the record type of Record
-record_to_proplist(Record, Fields, TypeKey)
-  when tuple_size(Record) - 1 =:= length(Fields) ->
-    lists:zip([TypeKey | Fields], tuple_to_list(Record)).
-
-
-shell_quote([], Acc) ->
-    lists:reverse([$\" | Acc]);
-shell_quote([C | Rest], Acc) when C =:= $\" orelse C =:= $\` orelse
-                                  C =:= $\\ orelse C =:= $\$ ->
-    shell_quote(Rest, [C, $\\ | Acc]);
-shell_quote([C | Rest], Acc) ->
-    shell_quote(Rest, [C | Acc]).
-
-%% @spec parse_qvalues(string()) -> [qvalue()] | invalid_qvalue_string
-%% @type qvalue() = {media_type() | encoding() , float()}.
-%% @type media_type() = string().
-%% @type encoding() = string().
-%%
-%% @doc Parses a list (given as a string) of elements with Q values associated
-%%      to them. Elements are separated by commas and each element is separated
-%%      from its Q value by a semicolon. Q values are optional but when missing
-%%      the value of an element is considered as 1.0. A Q value is always in the
-%%      range [0.0, 1.0]. A Q value list is used for example as the value of the
-%%      HTTP "Accept" and "Accept-Encoding" headers.
-%%
-%%      Q values are described in section 2.9 of the RFC 2616 (HTTP 1.1).
-%%
-%%      Example:
-%%
-%%      parse_qvalues("gzip; q=0.5, deflate, identity;q=0.0") ->
-%%          [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 0.0}]
-%%
-parse_qvalues(QValuesStr) ->
-    try
-        lists:map(
-            fun(Pair) ->
-                [Type | Params] = string:tokens(Pair, ";"),
-                NormParams = normalize_media_params(Params),
-                {Q, NonQParams} = extract_q(NormParams),
-                {string:join([string:strip(Type) | NonQParams], ";"), Q}
-            end,
-            string:tokens(string:to_lower(QValuesStr), ",")
-        )
-    catch
-        _Type:_Error ->
-            invalid_qvalue_string
-    end.
-
-normalize_media_params(Params) ->
-    {ok, Re} = re:compile("\\s"),
-    normalize_media_params(Re, Params, []).
-
-normalize_media_params(_Re, [], Acc) ->
-    lists:reverse(Acc);
-normalize_media_params(Re, [Param | Rest], Acc) ->
-    NormParam = re:replace(Param, Re, "", [global, {return, list}]),
-    normalize_media_params(Re, Rest, [NormParam | Acc]).
-
-extract_q(NormParams) ->
-    {ok, KVRe} = re:compile("^([^=]+)=([^=]+)$"),
-    {ok, QRe} = re:compile("^((?:0|1)(?:\\.\\d{1,3})?)$"),
-    extract_q(KVRe, QRe, NormParams, []).
-
-extract_q(_KVRe, _QRe, [], Acc) ->
-    {1.0, lists:reverse(Acc)};
-extract_q(KVRe, QRe, [Param | Rest], Acc) ->
-    case re:run(Param, KVRe, [{capture, [1, 2], list}]) of
-        {match, [Name, Value]} ->
-            case Name of
-            "q" ->
-                {match, [Q]} = re:run(Value, QRe, [{capture, [1], list}]),
-                QVal = case Q of
-                    "0" ->
-                        0.0;
-                    "1" ->
-                        1.0;
-                    Else ->
-                        list_to_float(Else)
-                end,
-                case QVal < 0.0 orelse QVal > 1.0 of
-                false ->
-                    {QVal, lists:reverse(Acc) ++ Rest}
-                end;
-            _ ->
-                extract_q(KVRe, QRe, Rest, [Param | Acc])
-            end
-    end.
-
-%% @spec pick_accepted_encodings([qvalue()], [encoding()], encoding()) ->
-%%    [encoding()]
-%%
-%% @doc Determines which encodings specified in the given Q values list are
-%%      valid according to a list of supported encodings and a default encoding.
-%%
-%%      The returned list of encodings is sorted, descendingly, according to the
-%%      Q values of the given list. The last element of this list is the given
-%%      default encoding unless this encoding is explicitily or implicitily
-%%      marked with a Q value of 0.0 in the given Q values list.
-%%      Note: encodings with the same Q value are kept in the same order as
-%%            found in the input Q values list.
-%%
-%%      This encoding picking process is described in section 14.3 of the
-%%      RFC 2616 (HTTP 1.1).
-%%
-%%      Example:
-%%
-%%      pick_accepted_encodings(
-%%          [{"gzip", 0.5}, {"deflate", 1.0}],
-%%          ["gzip", "identity"],
-%%          "identity"
-%%      ) ->
-%%          ["gzip", "identity"]
-%%
-pick_accepted_encodings(AcceptedEncs, SupportedEncs, DefaultEnc) ->
-    SortedQList = lists:reverse(
-        lists:sort(fun({_, Q1}, {_, Q2}) -> Q1 < Q2 end, AcceptedEncs)
-    ),
-    {Accepted, Refused} = lists:foldr(
-        fun({E, Q}, {A, R}) ->
-            case Q > 0.0 of
-                true ->
-                    {[E | A], R};
-                false ->
-                    {A, [E | R]}
-            end
-        end,
-        {[], []},
-        SortedQList
-    ),
-    Refused1 = lists:foldr(
-        fun(Enc, Acc) ->
-            case Enc of
-                "*" ->
-                    lists:subtract(SupportedEncs, Accepted) ++ Acc;
-                _ ->
-                    [Enc | Acc]
-            end
-        end,
-        [],
-        Refused
-    ),
-    Accepted1 = lists:foldr(
-        fun(Enc, Acc) ->
-            case Enc of
-                "*" ->
-                    lists:subtract(SupportedEncs, Accepted ++ Refused1) ++ Acc;
-                _ ->
-                    [Enc | Acc]
-            end
-        end,
-        [],
-        Accepted
-    ),
-    Accepted2 = case lists:member(DefaultEnc, Accepted1) of
-        true ->
-            Accepted1;
-        false ->
-            Accepted1 ++ [DefaultEnc]
-    end,
-    [E || E <- Accepted2, lists:member(E, SupportedEncs),
-        not lists:member(E, Refused1)].
-
-make_io(Atom) when is_atom(Atom) ->
-    atom_to_list(Atom);
-make_io(Integer) when is_integer(Integer) ->
-    integer_to_list(Integer);
-make_io(Io) when is_list(Io); is_binary(Io) ->
-    Io.
-
-%%
-%% Tests
-%%
--include_lib("eunit/include/eunit.hrl").
--ifdef(TEST).
-
-make_io_test() ->
-    ?assertEqual(
-       <<"atom">>,
-       iolist_to_binary(make_io(atom))),
-    ?assertEqual(
-       <<"20">>,
-       iolist_to_binary(make_io(20))),
-    ?assertEqual(
-       <<"list">>,
-       iolist_to_binary(make_io("list"))),
-    ?assertEqual(
-       <<"binary">>,
-       iolist_to_binary(make_io(<<"binary">>))),
-    ok.
-
--record(test_record, {field1=f1, field2=f2}).
-record_to_proplist_test() ->
-    ?assertEqual(
-       [{'__record', test_record},
-        {field1, f1},
-        {field2, f2}],
-       record_to_proplist(#test_record{}, record_info(fields, test_record))),
-    ?assertEqual(
-       [{'typekey', test_record},
-        {field1, f1},
-        {field2, f2}],
-       record_to_proplist(#test_record{},
-                          record_info(fields, test_record),
-                          typekey)),
-    ok.
-
-shell_quote_test() ->
-    ?assertEqual(
-       "\"foo \\$bar\\\"\\`' baz\"",
-       shell_quote("foo $bar\"`' baz")),
-    ok.
-
-cmd_port_test_spool(Port, Acc) ->
-    receive
-        {Port, eof} ->
-            Acc;
-        {Port, {data, {eol, Data}}} ->
-            cmd_port_test_spool(Port, ["\n", Data | Acc]);
-        {Port, Unknown} ->
-            throw({unknown, Unknown})
-    after 1000 ->
-            throw(timeout)
-    end.
-
-cmd_port_test() ->
-    Port = cmd_port(["echo", "$bling$ `word`!"],
-                    [eof, stream, {line, 4096}]),
-    Res = try lists:append(lists:reverse(cmd_port_test_spool(Port, [])))
-          after catch port_close(Port)
-          end,
-    self() ! {Port, wtf},
-    try cmd_port_test_spool(Port, [])
-    catch throw:{unknown, wtf} -> ok
-    end,
-    try cmd_port_test_spool(Port, [])
-    catch throw:timeout -> ok
-    end,
-    ?assertEqual(
-       "$bling$ `word`!\n",
-       Res).
-
-cmd_test() ->
-    ?assertEqual(
-       "$bling$ `word`!\n",
-       cmd(["echo", "$bling$ `word`!"])),
-    ok.
-
-cmd_string_test() ->
-    ?assertEqual(
-       "\"echo\" \"\\$bling\\$ \\`word\\`!\"",
-       cmd_string(["echo", "$bling$ `word`!"])),
-    ok.
-
-cmd_status_test() ->
-    ?assertEqual(
-       {0, <<"$bling$ `word`!\n">>},
-       cmd_status(["echo", "$bling$ `word`!"])),
-    ok.
-
-
-parse_header_test() ->
-    ?assertEqual(
-       {"multipart/form-data", [{"boundary", "AaB03x"}]},
-       parse_header("multipart/form-data; boundary=AaB03x")),
-    %% This tests (currently) intentionally broken behavior
-    ?assertEqual(
-       {"multipart/form-data",
-        [{"b", ""},
-         {"cgi", "is"},
-         {"broken", "true\"e"}]},
-       parse_header("multipart/form-data;b=;cgi=\"i\\s;broken=true\"e;=z;z")),
-    ok.
-
-guess_mime_test() ->
-    "text/plain" = guess_mime(""),
-    "text/plain" = guess_mime(".text"),
-    "application/zip" = guess_mime(".zip"),
-    "application/zip" = guess_mime("x.zip"),
-    "text/html" = guess_mime("x.html"),
-    "application/xhtml+xml" = guess_mime("x.xhtml"),
-    ok.
-
-path_split_test() ->
-    {"", "foo/bar"} = path_split("/foo/bar"),
-    {"foo", "bar"} = path_split("foo/bar"),
-    {"bar", ""} = path_split("bar"),
-    ok.
-
-urlsplit_test() ->
-    {"", "", "/foo", "", "bar?baz"} = urlsplit("/foo#bar?baz"),
-    {"http", "host:port", "/foo", "", "bar?baz"} =
-        urlsplit("http://host:port/foo#bar?baz"),
-    {"http", "host", "", "", ""} = urlsplit("http://host"),
-    {"", "", "/wiki/Category:Fruit", "", ""} =
-        urlsplit("/wiki/Category:Fruit"),
-    ok.
-
-urlsplit_path_test() ->
-    {"/foo/bar", "", ""} = urlsplit_path("/foo/bar"),
-    {"/foo", "baz", ""} = urlsplit_path("/foo?baz"),
-    {"/foo", "", "bar?baz"} = urlsplit_path("/foo#bar?baz"),
-    {"/foo", "", "bar?baz#wibble"} = urlsplit_path("/foo#bar?baz#wibble"),
-    {"/foo", "bar", "baz"} = urlsplit_path("/foo?bar#baz"),
-    {"/foo", "bar?baz", "baz"} = urlsplit_path("/foo?bar?baz#baz"),
-    ok.
-
-urlunsplit_test() ->
-    "/foo#bar?baz" = urlunsplit({"", "", "/foo", "", "bar?baz"}),
-    "http://host:port/foo#bar?baz" =
-        urlunsplit({"http", "host:port", "/foo", "", "bar?baz"}),
-    ok.
-
-urlunsplit_path_test() ->
-    "/foo/bar" = urlunsplit_path({"/foo/bar", "", ""}),
-    "/foo?baz" = urlunsplit_path({"/foo", "baz", ""}),
-    "/foo#bar?baz" = urlunsplit_path({"/foo", "", "bar?baz"}),
-    "/foo#bar?baz#wibble" = urlunsplit_path({"/foo", "", "bar?baz#wibble"}),
-    "/foo?bar#baz" = urlunsplit_path({"/foo", "bar", "baz"}),
-    "/foo?bar?baz#baz" = urlunsplit_path({"/foo", "bar?baz", "baz"}),
-    ok.
-
-join_test() ->
-    ?assertEqual("foo,bar,baz",
-                  join(["foo", "bar", "baz"], $,)),
-    ?assertEqual("foo,bar,baz",
-                  join(["foo", "bar", "baz"], ",")),
-    ?assertEqual("foo bar",
-                  join([["foo", " bar"]], ",")),
-    ?assertEqual("foo bar,baz",
-                  join([["foo", " bar"], "baz"], ",")),
-    ?assertEqual("foo",
-                  join(["foo"], ",")),
-    ?assertEqual("foobarbaz",
-                  join(["foo", "bar", "baz"], "")),
-    ?assertEqual("foo" ++ [<<>>] ++ "bar" ++ [<<>>] ++ "baz",
-                 join(["foo", "bar", "baz"], <<>>)),
-    ?assertEqual("foobar" ++ [<<"baz">>],
-                 join(["foo", "bar", <<"baz">>], "")),
-    ?assertEqual("",
-                 join([], "any")),
-    ok.
-
-quote_plus_test() ->
-    "foo" = quote_plus(foo),
-    "1" = quote_plus(1),
-    "1.1" = quote_plus(1.1),
-    "foo" = quote_plus("foo"),
-    "foo+bar" = quote_plus("foo bar"),
-    "foo%0A" = quote_plus("foo\n"),
-    "foo%0A" = quote_plus("foo\n"),
-    "foo%3B%26%3D" = quote_plus("foo;&="),
-    "foo%3B%26%3D" = quote_plus(<<"foo;&=">>),
-    ok.
-
-unquote_test() ->
-    ?assertEqual("foo bar",
-                 unquote("foo+bar")),
-    ?assertEqual("foo bar",
-                 unquote("foo%20bar")),
-    ?assertEqual("foo\r\n",
-                 unquote("foo%0D%0A")),
-    ?assertEqual("foo\r\n",
-                 unquote(<<"foo%0D%0A">>)),
-    ok.
-
-urlencode_test() ->
-    "foo=bar&baz=wibble+%0D%0A&z=1" = urlencode([{foo, "bar"},
-                                                 {"baz", "wibble \r\n"},
-                                                 {z, 1}]),
-    ok.
-
-parse_qs_test() ->
-    ?assertEqual(
-       [{"foo", "bar"}, {"baz", "wibble \r\n"}, {"z", "1"}],
-       parse_qs("foo=bar&baz=wibble+%0D%0a&z=1")),
-    ?assertEqual(
-       [{"", "bar"}, {"baz", "wibble \r\n"}, {"z", ""}],
-       parse_qs("=bar&baz=wibble+%0D%0a&z=")),
-    ?assertEqual(
-       [{"foo", "bar"}, {"baz", "wibble \r\n"}, {"z", "1"}],
-       parse_qs(<<"foo=bar&baz=wibble+%0D%0a&z=1">>)),
-    ?assertEqual(
-       [],
-       parse_qs("")),
-    ?assertEqual(
-       [{"foo", ""}, {"bar", ""}, {"baz", ""}],
-       parse_qs("foo;bar&baz")),
-    ok.
-
-partition_test() ->
-    {"foo", "", ""} = partition("foo", "/"),
-    {"foo", "/", "bar"} = partition("foo/bar", "/"),
-    {"foo", "/", ""} = partition("foo/", "/"),
-    {"", "/", "bar"} = partition("/bar", "/"),
-    {"f", "oo/ba", "r"} = partition("foo/bar", "oo/ba"),
-    ok.
-
-safe_relative_path_test() ->
-    "foo" = safe_relative_path("foo"),
-    "foo/" = safe_relative_path("foo/"),
-    "foo" = safe_relative_path("foo/bar/.."),
-    "bar" = safe_relative_path("foo/../bar"),
-    "bar/" = safe_relative_path("foo/../bar/"),
-    "" = safe_relative_path("foo/.."),
-    "" = safe_relative_path("foo/../"),
-    undefined = safe_relative_path("/foo"),
-    undefined = safe_relative_path("../foo"),
-    undefined = safe_relative_path("foo/../.."),
-    undefined = safe_relative_path("foo//"),
-    undefined = safe_relative_path("foo\\bar"),
-    ok.
-
-parse_qvalues_test() ->
-    [] = parse_qvalues(""),
-    [{"identity", 0.0}] = parse_qvalues("identity;q=0"),
-    [{"identity", 0.0}] = parse_qvalues("identity ;q=0"),
-    [{"identity", 0.0}] = parse_qvalues(" identity; q =0 "),
-    [{"identity", 0.0}] = parse_qvalues("identity ; q = 0"),
-    [{"identity", 0.0}] = parse_qvalues("identity ; q= 0.0"),
-    [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
-        "gzip,deflate,identity;q=0.0"
-    ),
-    [{"deflate", 1.0}, {"gzip", 1.0}, {"identity", 0.0}] = parse_qvalues(
-        "deflate,gzip,identity;q=0.0"
-    ),
-    [{"gzip", 1.0}, {"deflate", 1.0}, {"gzip", 1.0}, {"identity", 0.0}] =
-        parse_qvalues("gzip,deflate,gzip,identity;q=0"),
-    [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
-        "gzip, deflate , identity; q=0.0"
-    ),
-    [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
-        "gzip; q=1, deflate;q=1.0, identity;q=0.0"
-    ),
-    [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
-        "gzip; q=0.5, deflate;q=1.0, identity;q=0"
-    ),
-    [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 0.0}] = parse_qvalues(
-        "gzip; q=0.5, deflate , identity;q=0.0"
-    ),
-    [{"gzip", 0.5}, {"deflate", 0.8}, {"identity", 0.0}] = parse_qvalues(
-        "gzip; q=0.5, deflate;q=0.8, identity;q=0.0"
-    ),
-    [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 1.0}] = parse_qvalues(
-        "gzip; q=0.5,deflate,identity"
-    ),
-    [{"gzip", 0.5}, {"deflate", 1.0}, {"identity", 1.0}, {"identity", 1.0}] =
-        parse_qvalues("gzip; q=0.5,deflate,identity, identity "),
-    [{"text/html;level=1", 1.0}, {"text/plain", 0.5}] =
-        parse_qvalues("text/html;level=1, text/plain;q=0.5"),
-    [{"text/html;level=1", 0.3}, {"text/plain", 1.0}] =
-        parse_qvalues("text/html;level=1;q=0.3, text/plain"),
-    [{"text/html;level=1", 0.3}, {"text/plain", 1.0}] =
-        parse_qvalues("text/html; level = 1; q = 0.3, text/plain"),
-    [{"text/html;level=1", 0.3}, {"text/plain", 1.0}] =
-        parse_qvalues("text/html;q=0.3;level=1, text/plain"),
-    invalid_qvalue_string = parse_qvalues("gzip; q=1.1, deflate"),
-    invalid_qvalue_string = parse_qvalues("gzip; q=0.5, deflate;q=2"),
-    invalid_qvalue_string = parse_qvalues("gzip, deflate;q=AB"),
-    invalid_qvalue_string = parse_qvalues("gzip; q=2.1, deflate"),
-    invalid_qvalue_string = parse_qvalues("gzip; q=0.1234, deflate"),
-    invalid_qvalue_string = parse_qvalues("text/html;level=1;q=0.3, text/html;level"),
-    ok.
-
-pick_accepted_encodings_test() ->
-    ["identity"] = pick_accepted_encodings(
-        [],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 1.0}],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["identity"] = pick_accepted_encodings(
-        [{"gzip", 0.0}],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 1.0}, {"deflate", 1.0}],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 0.5}, {"deflate", 1.0}],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["identity"] = pick_accepted_encodings(
-        [{"gzip", 0.0}, {"deflate", 0.0}],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["gzip"] = pick_accepted_encodings(
-        [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}],
-        ["gzip", "identity"],
-        "identity"
-    ),
-    ["gzip", "deflate", "identity"] = pick_accepted_encodings(
-        [{"gzip", 1.0}, {"deflate", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "deflate"] = pick_accepted_encodings(
-        [{"gzip", 1.0}, {"deflate", 1.0}, {"identity", 0.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["deflate", "gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 0.2}, {"deflate", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["deflate", "deflate", "gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 0.2}, {"deflate", 1.0}, {"deflate", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["deflate", "gzip", "gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 0.2}, {"deflate", 1.0}, {"gzip", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "deflate", "gzip", "identity"] = pick_accepted_encodings(
-        [{"gzip", 0.2}, {"deflate", 0.9}, {"gzip", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    [] = pick_accepted_encodings(
-        [{"*", 0.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "deflate", "identity"] = pick_accepted_encodings(
-        [{"*", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "deflate", "identity"] = pick_accepted_encodings(
-        [{"*", 0.6}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip"] = pick_accepted_encodings(
-        [{"gzip", 1.0}, {"*", 0.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "deflate"] = pick_accepted_encodings(
-        [{"gzip", 1.0}, {"deflate", 0.6}, {"*", 0.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["deflate", "gzip"] = pick_accepted_encodings(
-        [{"gzip", 0.5}, {"deflate", 1.0}, {"*", 0.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "identity"] = pick_accepted_encodings(
-        [{"deflate", 0.0}, {"*", 1.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ["gzip", "identity"] = pick_accepted_encodings(
-        [{"*", 1.0}, {"deflate", 0.0}],
-        ["gzip", "deflate", "identity"],
-        "identity"
-    ),
-    ok.
-
--endif.

http://git-wip-us.apache.org/repos/asf/couchdb/blob/acf8eaff/src/mochiweb/src/reloader.erl
----------------------------------------------------------------------
diff --git a/src/mochiweb/src/reloader.erl b/src/mochiweb/src/reloader.erl
deleted file mode 100644
index c0f5de8..0000000
--- a/src/mochiweb/src/reloader.erl
+++ /dev/null
@@ -1,161 +0,0 @@
-%% @copyright 2007 Mochi Media, Inc.
-%% @author Matthew Dempsky <ma...@mochimedia.com>
-%%
-%% @doc Erlang module for automatically reloading modified modules
-%% during development.
-
--module(reloader).
--author("Matthew Dempsky <ma...@mochimedia.com>").
-
--include_lib("kernel/include/file.hrl").
-
--behaviour(gen_server).
--export([start/0, start_link/0]).
--export([stop/0]).
--export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
--export([all_changed/0]).
--export([is_changed/1]).
--export([reload_modules/1]).
--record(state, {last, tref}).
-
-%% External API
-
-%% @spec start() -> ServerRet
-%% @doc Start the reloader.
-start() ->
-    gen_server:start({local, ?MODULE}, ?MODULE, [], []).
-
-%% @spec start_link() -> ServerRet
-%% @doc Start the reloader.
-start_link() ->
-    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
-
-%% @spec stop() -> ok
-%% @doc Stop the reloader.
-stop() ->
-    gen_server:call(?MODULE, stop).
-
-%% gen_server callbacks
-
-%% @spec init([]) -> {ok, State}
-%% @doc gen_server init, opens the server in an initial state.
-init([]) ->
-    {ok, TRef} = timer:send_interval(timer:seconds(1), doit),
-    {ok, #state{last = stamp(), tref = TRef}}.
-
-%% @spec handle_call(Args, From, State) -> tuple()
-%% @doc gen_server callback.
-handle_call(stop, _From, State) ->
-    {stop, shutdown, stopped, State};
-handle_call(_Req, _From, State) ->
-    {reply, {error, badrequest}, State}.
-
-%% @spec handle_cast(Cast, State) -> tuple()
-%% @doc gen_server callback.
-handle_cast(_Req, State) ->
-    {noreply, State}.
-
-%% @spec handle_info(Info, State) -> tuple()
-%% @doc gen_server callback.
-handle_info(doit, State) ->
-    Now = stamp(),
-    doit(State#state.last, Now),
-    {noreply, State#state{last = Now}};
-handle_info(_Info, State) ->
-    {noreply, State}.
-
-%% @spec terminate(Reason, State) -> ok
-%% @doc gen_server termination callback.
-terminate(_Reason, State) ->
-    {ok, cancel} = timer:cancel(State#state.tref),
-    ok.
-
-
-%% @spec code_change(_OldVsn, State, _Extra) -> State
-%% @doc gen_server code_change callback (trivial).
-code_change(_Vsn, State, _Extra) ->
-    {ok, State}.
-
-%% @spec reload_modules([atom()]) -> [{module, atom()} | {error, term()}]
-%% @doc code:purge/1 and code:load_file/1 the given list of modules in order,
-%%      return the results of code:load_file/1.
-reload_modules(Modules) ->
-    [begin code:purge(M), code:load_file(M) end || M <- Modules].
-
-%% @spec all_changed() -> [atom()]
-%% @doc Return a list of beam modules that have changed.
-all_changed() ->
-    [M || {M, Fn} <- code:all_loaded(), is_list(Fn), is_changed(M)].
-
-%% @spec is_changed(atom()) -> boolean()
-%% @doc true if the loaded module is a beam with a vsn attribute
-%%      and does not match the on-disk beam file, returns false otherwise.
-is_changed(M) ->
-    try
-        module_vsn(M:module_info()) =/= module_vsn(code:get_object_code(M))
-    catch _:_ ->
-            false
-    end.
-
-%% Internal API
-
-module_vsn({M, Beam, _Fn}) ->
-    {ok, {M, Vsn}} = beam_lib:version(Beam),
-    Vsn;
-module_vsn(L) when is_list(L) ->
-    {_, Attrs} = lists:keyfind(attributes, 1, L),
-    {_, Vsn} = lists:keyfind(vsn, 1, Attrs),
-    Vsn.
-
-doit(From, To) ->
-    [case file:read_file_info(Filename) of
-         {ok, #file_info{mtime = Mtime}} when Mtime >= From, Mtime < To ->
-             reload(Module);
-         {ok, _} ->
-             unmodified;
-         {error, enoent} ->
-             %% The Erlang compiler deletes existing .beam files if
-             %% recompiling fails.  Maybe it's worth spitting out a
-             %% warning here, but I'd want to limit it to just once.
-             gone;
-         {error, Reason} ->
-             io:format("Error reading ~s's file info: ~p~n",
-                       [Filename, Reason]),
-             error
-     end || {Module, Filename} <- code:all_loaded(), is_list(Filename)].
-
-reload(Module) ->
-    io:format("Reloading ~p ...", [Module]),
-    code:purge(Module),
-    case code:load_file(Module) of
-        {module, Module} ->
-            io:format(" ok.~n"),
-            case erlang:function_exported(Module, test, 0) of
-                true ->
-                    io:format(" - Calling ~p:test() ...", [Module]),
-                    case catch Module:test() of
-                        ok ->
-                            io:format(" ok.~n"),
-                            reload;
-                        Reason ->
-                            io:format(" fail: ~p.~n", [Reason]),
-                            reload_but_test_failed
-                    end;
-                false ->
-                    reload
-            end;
-        {error, Reason} ->
-            io:format(" fail: ~p.~n", [Reason]),
-            error
-    end.
-
-
-stamp() ->
-    erlang:localtime().
-
-%%
-%% Tests
-%%
--include_lib("eunit/include/eunit.hrl").
--ifdef(TEST).
--endif.