From db55453ae3ea2c1952ee6c114c733dc934e25682 Mon Sep 17 00:00:00 2001 From: Paul Joseph Davis Date: Wed, 13 May 2009 03:33:31 +0000 Subject: Closes COUCHDB-334 - Add JSONP support to CouchDB Use JSONP by providing a ?callback=function_name URL paramter for any URL returning JSON data. git-svn-id: https://svn.apache.org/repos/asf/couchdb/trunk@774180 13f79535-47bb-0310-9956-ffa450edef68 --- src/couchdb/couch_db.hrl | 3 +- src/couchdb/couch_httpd.erl | 64 +++++++++++++++++++++++++++++++++++++--- src/couchdb/couch_httpd_view.erl | 2 ++ 3 files changed, 64 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/couchdb/couch_db.hrl b/src/couchdb/couch_db.hrl index c00792a8..0f7e344e 100644 --- a/src/couchdb/couch_db.hrl +++ b/src/couchdb/couch_db.hrl @@ -167,7 +167,8 @@ include_docs = false, stale = false, multi_get = false, - ignore = false + ignore = false, + callback = nil }). -record(view_fold_helper_funs, { diff --git a/src/couchdb/couch_httpd.erl b/src/couchdb/couch_httpd.erl index 7a803c85..0f29bae7 100644 --- a/src/couchdb/couch_httpd.erl +++ b/src/couchdb/couch_httpd.erl @@ -386,8 +386,10 @@ send_json(Req, Code, Headers, Value) -> {"Content-Type", negotiate_content_type(Req)}, {"Cache-Control", "must-revalidate"} ], - send_response(Req, Code, DefaultHeaders ++ Headers, - list_to_binary([?JSON_ENCODE(Value), $\n])). + Body = list_to_binary( + [start_jsonp(Req), ?JSON_ENCODE(Value), end_jsonp(), $\n] + ), + send_response(Req, Code, DefaultHeaders ++ Headers, Body). start_json_response(Req, Code) -> start_json_response(Req, Code, []). @@ -397,12 +399,66 @@ start_json_response(Req, Code, Headers) -> {"Content-Type", negotiate_content_type(Req)}, {"Cache-Control", "must-revalidate"} ], - start_chunked_response(Req, Code, DefaultHeaders ++ Headers). + start_jsonp(Req), % Validate before starting chunked. + %start_chunked_response(Req, Code, DefaultHeaders ++ Headers). + {ok, Resp} = start_chunked_response(Req, Code, DefaultHeaders ++ Headers), + case start_jsonp(Req) of + [] -> ok; + Start -> send_chunk(Resp, Start) + end, + {ok, Resp}. end_json_response(Resp) -> - send_chunk(Resp, [$\n]), + send_chunk(Resp, end_jsonp() ++ [$\n]), + %send_chunk(Resp, [$\n]), send_chunk(Resp, []). +start_jsonp(Req) -> + case get(jsonp) of + undefined -> put(jsonp, qs_value(Req, "callback", no_jsonp)); + _ -> ok + end, + case get(jsonp) of + no_jsonp -> []; + [] -> []; + CallBack -> + try + validate_callback(CallBack), + CallBack ++ "(" + catch + Error -> + put(jsonp, no_jsonp), + throw(Error) + end + end. + +end_jsonp() -> + Resp = case get(jsonp) of + no_jsonp -> []; + [] -> []; + _ -> ");" + end, + put(jsonp, undefined), + Resp. + +validate_callback(CallBack) when is_binary(CallBack) -> + validate_callback(binary_to_list(CallBack)); +validate_callback([]) -> + ok; +validate_callback([Char | Rest]) -> + case Char of + _ when Char >= $a andalso Char =< $z -> ok; + _ when Char >= $A andalso Char =< $Z -> ok; + _ when Char >= $0 andalso Char =< $9 -> ok; + _ when Char == $. -> ok; + _ when Char == $_ -> ok; + _ when Char == $[ -> ok; + _ when Char == $] -> ok; + _ -> + throw({bad_request, invalid_callback}) + end, + validate_callback(Rest). + error_info({Error, Reason}) when is_list(Reason) -> error_info({Error, ?l2b(Reason)}); diff --git a/src/couchdb/couch_httpd_view.erl b/src/couchdb/couch_httpd_view.erl index 016a391a..8db561ac 100644 --- a/src/couchdb/couch_httpd_view.erl +++ b/src/couchdb/couch_httpd_view.erl @@ -270,6 +270,8 @@ parse_view_param("reduce", Value) -> [{reduce, parse_bool_param(Value)}]; parse_view_param("include_docs", Value) -> [{include_docs, parse_bool_param(Value)}]; +parse_view_param("callback", _) -> + []; % Verified in the JSON response functions parse_view_param(Key, Value) -> [{extra, {Key, Value}}]. -- cgit v1.2.3