mirror of https://github.com/aria2/aria2
Added JSONP support. Callback query parameter is "jsoncallback".
parent
feb4e2e53a
commit
bf01bb84b6
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 {
|
||||
json = json::decode(httpServer_->getBody());
|
||||
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",
|
||||
|
|
49
src/json.cc
49
src/json.cc
|
@ -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
|
||||
|
|
62
src/json.h
62
src/json.h
|
@ -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_ << ",";
|
||||
(*i)->accept(*this);
|
||||
}
|
||||
}
|
||||
++i;
|
||||
for(List::ValueType::const_iterator eoi = list.end(); i != eoi; ++i){
|
||||
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_ << ",";
|
||||
std::string key = jsonEscape((*i).first);
|
||||
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_ << ',';
|
||||
std::string key = jsonEscape((*i).first);
|
||||
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¶ms=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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue