You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by fd...@apache.org on 2011/07/10 14:22:05 UTC
svn commit: r1144848 - /couchdb/trunk/src/couchdb/couch_httpd.erl
Author: fdmanana
Date: Sun Jul 10 12:22:04 2011
New Revision: 1144848
URL: http://svn.apache.org/viewvc?rev=1144848&view=rev
Log:
Cheaper request authentication
Parsing the auth handlers on every request is more expensive then
it needs to be. Just the regexp split operation by itself is rather
expensive:
2> Conf = couch_config:get("httpd", "authentication_handlers").
"{couch_httpd_oauth, oauth_authentication_handler}, {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, default_authentication_handler}"
3>
3> timer:tc(re, split, [Conf, "(?<=})\\s*,\\s*(?={)", [{return, list}]]).
{289,
["{couch_httpd_oauth, oauth_authentication_handler}",
"{couch_httpd_auth, cookie_authentication_handler}",
"{couch_httpd_auth, default_authentication_handler}"]}
4> timer:tc(re, split, [Conf, "(?<=})\\s*,\\s*(?={)", [{return, list}]]).
{292,
["{couch_httpd_oauth, oauth_authentication_handler}",
"{couch_httpd_auth, cookie_authentication_handler}",
"{couch_httpd_auth, default_authentication_handler}"]}
5> timer:tc(re, split, [Conf, "(?<=})\\s*,\\s*(?={)", [{return, list}]]).
{297,
["{couch_httpd_oauth, oauth_authentication_handler}",
"{couch_httpd_auth, cookie_authentication_handler}",
"{couch_httpd_auth, default_authentication_handler}"]}
6> timer:tc(re, split, [Conf, "(?<=})\\s*,\\s*(?={)", [{return, list}]]).
And so is the parsing of each auth handler function:
1> timer:tc(couch_httpd, make_arity_1_fun, ["{couch_httpd_auth, default_authentication_handler}"]).
{63,#Fun<couch_httpd.6.41794127>}
2> timer:tc(couch_httpd, make_arity_1_fun, ["{couch_httpd_auth, default_authentication_handler}"]).
{58,#Fun<couch_httpd.6.41794127>}
3> timer:tc(couch_httpd, make_arity_1_fun, ["{couch_httpd_auth, default_authentication_handler}"]).
{56,#Fun<couch_httpd.6.41794127>}
4> timer:tc(couch_httpd, make_arity_1_fun, ["{couch_httpd_auth, default_authentication_handler}"]).
{58,#Fun<couch_httpd.6.41794127>}
5> timer:tc(couch_httpd, make_arity_1_fun, ["{couch_httpd_auth, default_authentication_handler}"]).
{59,#Fun<couch_httpd.6.41794127>}
Getting the preprocessed auth handler functions from the application
environment is however much cheaper:
6> timer:tc(application, get_env, [couch, auth_handlers]).
{13,
{ok,[{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_oauth, oauth_authentication_handler}">>},
{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_auth, cookie_authentication_handler}">>},
{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_auth, default_authentication_handler}">>}]}}
7> timer:tc(application, get_env, [couch, auth_handlers]).
{14,
{ok,[{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_oauth, oauth_authentication_handler}">>},
{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_auth, cookie_authentication_handler}">>},
{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_auth, default_authentication_handler}">>}]}}
8> timer:tc(application, get_env, [couch, auth_handlers]).
{13,
{ok,[{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_oauth, oauth_authentication_handler}">>},
{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_auth, cookie_authentication_handler}">>},
{#Fun<couch_httpd.6.41794127>,
<<"{couch_httpd_auth, default_authentication_handler}">>}]}}
The application environment is backed by an ets and created when
the couch OTP application is started.
Modified:
couchdb/trunk/src/couchdb/couch_httpd.erl
Modified: couchdb/trunk/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd.erl?rev=1144848&r1=1144847&r2=1144848&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd.erl Sun Jul 10 12:22:04 2011
@@ -124,6 +124,8 @@ start_link(Name, Options) ->
{ok, SocketOptions} = couch_util:parse_term(
couch_config:get("httpd", "socket_options", "[]")),
+ set_auth_handlers(),
+
Loop = fun(Req)->
case SocketOptions of
[] ->
@@ -168,6 +170,8 @@ config_change("httpd", "server_options")
?MODULE:stop();
config_change("httpd", "socket_options") ->
?MODULE:stop();
+config_change("httpd", "authentication_handlers") ->
+ set_auth_handlers();
config_change("httpd_global_handlers", _) ->
?MODULE:stop();
config_change("httpd_db_handlers", _) ->
@@ -175,6 +179,13 @@ config_change("httpd_db_handlers", _) ->
config_change("ssl", _) ->
?MODULE:stop().
+set_auth_handlers() ->
+ AuthenticationSrcs = make_fun_spec_strs(
+ couch_config:get("httpd", "authentication_handlers", "")),
+ AuthHandlers = lists:map(
+ fun(A) -> {make_arity_1_fun(A), ?l2b(A)} end, AuthenticationSrcs),
+ ok = application:set_env(couch, auth_handlers, AuthHandlers).
+
% SpecStr is a string like "{my_module, my_fun}"
% or "{my_module, my_fun, <<"my_arg">>}"
make_arity_1_fun(SpecStr) ->
@@ -216,8 +227,6 @@ handle_request(MochiReq, DefaultFun, Url
handle_request_int(MochiReq, DefaultFun,
UrlHandlers, DbUrlHandlers, DesignUrlHandlers) ->
Begin = now(),
- AuthenticationSrcs = make_fun_spec_strs(
- couch_config:get("httpd", "authentication_handlers")),
% for the path, use the raw path with the query string and fragment
% removed, but URL quoting left intact
RawUri = MochiReq:get(raw_path),
@@ -293,10 +302,11 @@ handle_request_int(MochiReq, DefaultFun,
},
HandlerFun = couch_util:dict_find(HandlerKey, UrlHandlers, DefaultFun),
+ {ok, AuthHandlers} = application:get_env(couch, auth_handlers),
{ok, Resp} =
try
- case authenticate_request(HttpReq, AuthenticationSrcs) of
+ case authenticate_request(HttpReq, AuthHandlers) of
#httpd{} = Req ->
HandlerFun(Req);
Response ->
@@ -347,7 +357,7 @@ handle_request_int(MochiReq, DefaultFun,
% Try authentication handlers in order until one sets a user_ctx
% the auth funs also have the option of returning a response
% move this to couch_httpd_auth?
-authenticate_request(#httpd{user_ctx=#user_ctx{}} = Req, _AuthSrcs) ->
+authenticate_request(#httpd{user_ctx=#user_ctx{}} = Req, _AuthHandlers) ->
Req;
authenticate_request(#httpd{} = Req, []) ->
case couch_config:get("couch_httpd_auth", "require_valid_user", "false") of
@@ -356,14 +366,13 @@ authenticate_request(#httpd{} = Req, [])
"false" ->
Req#httpd{user_ctx=#user_ctx{}}
end;
-authenticate_request(#httpd{} = Req, [AuthSrc|Rest]) ->
- AuthFun = make_arity_1_fun(AuthSrc),
+authenticate_request(#httpd{} = Req, [{AuthFun, AuthSrc} | RestAuthHandlers]) ->
R = case AuthFun(Req) of
#httpd{user_ctx=#user_ctx{}=UserCtx}=Req2 ->
- Req2#httpd{user_ctx=UserCtx#user_ctx{handler=?l2b(AuthSrc)}};
+ Req2#httpd{user_ctx=UserCtx#user_ctx{handler=AuthSrc}};
Else -> Else
end,
- authenticate_request(R, Rest);
+ authenticate_request(R, RestAuthHandlers);
authenticate_request(Response, _AuthSrcs) ->
Response.