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 2009/05/13 05:33:35 UTC
svn commit: r774180 - in /couchdb/trunk: share/Makefile.am
share/www/script/couch_tests.js share/www/script/test/jsonp.js
src/couchdb/couch_db.hrl src/couchdb/couch_httpd.erl
src/couchdb/couch_httpd_view.erl
Author: davisp
Date: Wed May 13 03:33:31 2009
New Revision: 774180
URL: http://svn.apache.org/viewvc?rev=774180&view=rev
Log:
Closes COUCHDB-334 - Add JSONP support to CouchDB
Use JSONP by providing a ?callback=function_name URL paramter for any URL
returning JSON data.
Added:
couchdb/trunk/share/www/script/test/jsonp.js
Modified:
couchdb/trunk/share/Makefile.am
couchdb/trunk/share/www/script/couch_tests.js
couchdb/trunk/src/couchdb/couch_db.hrl
couchdb/trunk/src/couchdb/couch_httpd.erl
couchdb/trunk/src/couchdb/couch_httpd_view.erl
Modified: couchdb/trunk/share/Makefile.am
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/Makefile.am?rev=774180&r1=774179&r2=774180&view=diff
==============================================================================
--- couchdb/trunk/share/Makefile.am (original)
+++ couchdb/trunk/share/Makefile.am Wed May 13 03:33:31 2009
@@ -107,6 +107,7 @@
www/script/test/multiple_rows.js \
www/script/test/large_docs.js \
www/script/test/utf8.js \
+ www/script/test/jsonp.js \
www/script/test/attachments.js \
www/script/test/attachment_paths.js \
www/script/test/attachment_views.js \
Modified: couchdb/trunk/share/www/script/couch_tests.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/couch_tests.js?rev=774180&r1=774179&r2=774180&view=diff
==============================================================================
--- couchdb/trunk/share/www/script/couch_tests.js [utf-8] (original)
+++ couchdb/trunk/share/www/script/couch_tests.js [utf-8] Wed May 13 03:33:31 2009
@@ -42,6 +42,7 @@
loadTest("multiple_rows.js");
loadTest("large_docs.js");
loadTest("utf8.js");
+loadTest("jsonp.js");
loadTest("attachments.js");
loadTest("attachment_names.js");
loadTest("attachment_paths.js");
Added: couchdb/trunk/share/www/script/test/jsonp.js
URL: http://svn.apache.org/viewvc/couchdb/trunk/share/www/script/test/jsonp.js?rev=774180&view=auto
==============================================================================
--- couchdb/trunk/share/www/script/test/jsonp.js (added)
+++ couchdb/trunk/share/www/script/test/jsonp.js Wed May 13 03:33:31 2009
@@ -0,0 +1,69 @@
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// Verify callbacks ran
+var jsonp_flag = 0;
+
+// Callbacks
+function jsonp_no_chunk(doc) {
+ T(jsonp_flag == 0);
+ T(doc._id == "0");
+ jsonp_flag = 1;
+}
+
+function jsonp_chunk(doc) {
+ T(jsonp_flag == 0);
+ T(doc.total_rows == 1);
+ jsonp_flag = 1;
+}
+
+// Do some jsonp tests.
+couchTests.jsonp = function(debug) {
+ var db = new CouchDB("test_suite_db");
+ db.deleteDb();
+ db.createDb();
+ if (debug) debugger;
+
+ var doc = {_id:"0",a:0,b:0};
+ T(db.save(doc).ok);
+
+ // Test unchunked callbacks.
+ var xhr = CouchDB.request("GET", "/test_suite_db/0?callback=jsonp_no_chunk");
+ T(xhr.status == 200);
+ jsonp_flag = 0;
+ eval(xhr.responseText);
+ T(jsonp_flag == 1);
+ xhr = CouchDB.request("GET", "/test_suite_db/0?callback=foo\"");
+ T(xhr.status == 400);
+
+ // Test chunked responses
+ var doc = {_id:"1",a:1,b:1};
+ T(db.save(doc).ok);
+
+ var designDoc = {
+ _id:"_design/test",
+ language: "javascript",
+ views: {
+ all_docs: {map: "function(doc) {if(doc.a) emit(null, doc.a);}"}
+ }
+ }
+ T(db.save(designDoc).ok);
+
+ var url = "/test_suite_db/_design/test/_view/all_docs?callback=jsonp_chunk";
+ xhr = CouchDB.request("GET", url);
+ T(xhr.status == 200);
+ jsonp_flag = 0;
+ eval(xhr.responseText);
+ T(jsonp_flag == 1);
+ xhr = CouchDB.request("GET", url + "\'");
+ T(xhr.status == 400);
+};
Modified: couchdb/trunk/src/couchdb/couch_db.hrl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_db.hrl?rev=774180&r1=774179&r2=774180&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_db.hrl (original)
+++ couchdb/trunk/src/couchdb/couch_db.hrl Wed May 13 03:33:31 2009
@@ -167,7 +167,8 @@
include_docs = false,
stale = false,
multi_get = false,
- ignore = false
+ ignore = false,
+ callback = nil
}).
-record(view_fold_helper_funs, {
Modified: couchdb/trunk/src/couchdb/couch_httpd.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd.erl?rev=774180&r1=774179&r2=774180&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd.erl Wed May 13 03:33:31 2009
@@ -386,8 +386,10 @@
{"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 @@
{"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)});
Modified: couchdb/trunk/src/couchdb/couch_httpd_view.erl
URL: http://svn.apache.org/viewvc/couchdb/trunk/src/couchdb/couch_httpd_view.erl?rev=774180&r1=774179&r2=774180&view=diff
==============================================================================
--- couchdb/trunk/src/couchdb/couch_httpd_view.erl (original)
+++ couchdb/trunk/src/couchdb/couch_httpd_view.erl Wed May 13 03:33:31 2009
@@ -270,6 +270,8 @@
[{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}}].