Added JSONP support. Callback query parameter is "jsoncallback".

pull/1/head
Tatsuhiro Tsujikawa 2011-03-14 00:57:05 +09:00
parent feb4e2e53a
commit bf01bb84b6
6 changed files with 135 additions and 24 deletions

View File

@ -137,6 +137,11 @@ std::string HttpServer::getBody() const
return lastBody_.str();
}
const std::string& HttpServer::getMethod() const
{
return lastRequestHeader_->getMethod();
}
const std::string& HttpServer::getRequestPath() const
{
return lastRequestHeader_->getRequestPath();

View File

@ -79,6 +79,8 @@ public:
std::string getBody() const;
const std::string& getMethod() const;
const std::string& getRequestPath() const;
void feedResponse(const std::string& text, const std::string& contentType);

View File

@ -213,12 +213,16 @@ bool HttpServerBodyCommand::execute()
addHttpServerResponseCommand();
return true;
} else if(reqPath == "/jsonrpc") {
// TODO handle query parameter
std::string callback;
SharedHandle<ValueBase> json;
try {
if(httpServer_->getMethod() == "GET") {
json::JsonGetParam param = json::decodeGetParams(query);
callback = param.callback;
json = json::decode(param.request);
} else {
json = json::decode(httpServer_->getBody());
}
} catch(RecoverableException& e) {
A2_LOG_INFO_EX
(fmt("CUID#%lld - Failed to parse JSON-RPC request",

View File

@ -42,6 +42,7 @@
#include "a2functional.h"
#include "util.h"
#include "fmt.h"
#include "Base64.h"
namespace aria2 {
@ -607,6 +608,54 @@ std::string encode(const SharedHandle<ValueBase>& json)
return encode(out, json.get()).str();
}
JsonGetParam::JsonGetParam
(const std::string& request, const std::string& callback)
: request(request), callback(callback)
{}
JsonGetParam
decodeGetParams(const std::string& query)
{
std::string jsonRequest;
std::string callback;
if(!query.empty() && query[0] == '?') {
std::string method;
std::string id;
std::string params;
std::vector<std::string> getParams;
util::split(query.substr(1), std::back_inserter(getParams), "&");
for(std::vector<std::string>::const_iterator i =
getParams.begin(), eoi = getParams.end(); i != eoi; ++i) {
if(util::startsWith(*i, "method=")) {
method = (*i).substr(7);
} else if(util::startsWith(*i, "id=")) {
id = (*i).substr(3);
} else if(util::startsWith(*i, "params=")) {
params = (*i).substr(7);
} else if(util::startsWith(*i, "jsoncallback=")) {
callback = (*i).substr(13);
}
}
std::string jsonParam =
Base64::decode(util::percentDecode(params));
if(method.empty() && id.empty()) {
// Assume batch call.
jsonRequest = jsonParam;
} else {
jsonRequest = '{';
if(!method.empty()) {
strappend(jsonRequest, "\"method\":\"", method, "\",");
}
if(!id.empty()) {
strappend(jsonRequest, "\"id\":\"", id, "\",");
}
strappend(jsonRequest, "\"params\":", jsonParam);
jsonRequest += '}';
}
}
return JsonGetParam(jsonRequest, callback);
}
} // namespace json
} // namespace aria2

View File

@ -58,9 +58,9 @@ OutputStream& encode(OutputStream& out, const ValueBase* vlb)
{
const std::string& s = string.s();
std::string t = jsonEscape(s);
out_ << '"';
out_ << "\"";
out_.write(t.data(), t.size());
out_ << '"';
out_ << "\"";
}
virtual void visit(const Integer& integer)
@ -80,40 +80,40 @@ OutputStream& encode(OutputStream& out, const ValueBase* vlb)
virtual void visit(const List& list)
{
out_ << '[';
out_ << "[";
List::ValueType::const_iterator i = list.begin();
if(!list.empty()) {
(*i)->accept(*this);
}
++i;
for(List::ValueType::const_iterator eoi = list.end(); i != eoi; ++i){
out_ << ',';
out_ << ",";
(*i)->accept(*this);
}
out_ << ']';
}
out_ << "]";
}
virtual void visit(const Dict& dict)
{
out_ << '{';
out_ << "{";
Dict::ValueType::const_iterator i = dict.begin();
if(!dict.empty()) {
std::string key = jsonEscape((*i).first);
out_ << '"';
out_ << "\"";
out_.write(key.data(), key.size());
out_ << "\":";
(*i).second->accept(*this);
}
++i;
for(Dict::ValueType::const_iterator eoi = dict.end(); i != eoi; ++i){
out_ << ',';
out_ << ",";
std::string key = jsonEscape((*i).first);
out_ << '"';
out_ << "\"";
out_.write(key.data(), key.size());
out_ << "\":";
(*i).second->accept(*this);
}
out_ << '}';
}
out_ << "}";
}
private:
OutputStream& out_;
@ -133,6 +133,26 @@ OutputStream& encode(OutputStream& out, const SharedHandle<ValueBase>& vlb)
std::string encode(const ValueBase* json);
std::string encode(const SharedHandle<ValueBase>& json);
struct JsonGetParam {
std::string request;
std::string callback;
JsonGetParam(const std::string& request, const std::string& callback);
};
// Decodes JSON-RPC request from GET query parameter query. query must
// starts with "?". This function identifies method name, id,
// parameters and jsonp callback. For method name, it searches
// "method" query parameter. For id, it searches "id" query
// parameter. The id is always treated as string. For parameters, it
// searches "params" query parameter. The params is Base64 encoded
// JSON string normally associated "params" key in POST request. For
// jsonp callback, it searches "jsoncallback". For example, calling
// remote method, sum([1,2,3]) with id=300 looks like this:
// ?method=sum&id=300&params=WzEsMiwzXQ%3D%3D
//
// If both method and id are missing, params is treated as batch call.
JsonGetParam decodeGetParams(const std::string& query);
} // namespace json
} // namespace aria2

View File

@ -5,6 +5,7 @@
#include "RecoverableException.h"
#include "util.h"
#include "array_fun.h"
#include "Base64.h"
namespace aria2 {
@ -14,6 +15,7 @@ class JsonTest:public CppUnit::TestFixture {
CPPUNIT_TEST(testDecode);
CPPUNIT_TEST(testDecode_error);
CPPUNIT_TEST(testEncode);
CPPUNIT_TEST(testDecodeGetParams);
CPPUNIT_TEST_SUITE_END();
private:
@ -21,6 +23,7 @@ public:
void testDecode();
void testDecode_error();
void testEncode();
void testDecodeGetParams();
};
CPPUNIT_TEST_SUITE_REGISTRATION( JsonTest );
@ -443,4 +446,32 @@ void JsonTest::testEncode()
}
}
void JsonTest::testDecodeGetParams()
{
{
std::string param = util::percentEncode(Base64::encode("[1,2,3]"));
std::string query = "?params=";
query += param;
query += '&';
query += "method=sum&";
query += "id=300&";
query += "jsoncallback=cb";
json::JsonGetParam gparam = json::decodeGetParams(query);
CPPUNIT_ASSERT_EQUAL(std::string("{\"method\":\"sum\","
"\"id\":\"300\","
"\"params\":[1,2,3]}"),
gparam.request);
CPPUNIT_ASSERT_EQUAL(std::string("cb"), gparam.callback);
}
{
std::string query = "?params=";
query += util::percentEncode(Base64::encode("[{}]"));
query += '&';
query += "jsoncallback=cb";
json::JsonGetParam gparam = json::decodeGetParams(query);
CPPUNIT_ASSERT_EQUAL(std::string("[{}]"), gparam.request);
CPPUNIT_ASSERT_EQUAL(std::string("cb"), gparam.callback);
}
}
} // namespace aria2