summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2011-03-14 00:57:05 +0900
committerTatsuhiro Tsujikawa <tatsuhiro.t@gmail.com>2011-03-14 00:57:05 +0900
commitbf01bb84b6b96fe2cba529f588e29a9038c0daf6 (patch)
tree929c8ad8e4ec3eebdae8ffd046f7990b9f6dccae /src
parentfeb4e2e53a368baa64dffd5e2182204548fe86d5 (diff)
Added JSONP support. Callback query parameter is "jsoncallback".
Diffstat (limited to 'src')
-rw-r--r--src/HttpServer.cc5
-rw-r--r--src/HttpServer.h2
-rw-r--r--src/HttpServerBodyCommand.cc10
-rw-r--r--src/json.cc49
-rw-r--r--src/json.h62
5 files changed, 104 insertions, 24 deletions
diff --git a/src/HttpServer.cc b/src/HttpServer.cc
index 15016501..31893c95 100644
--- a/src/HttpServer.cc
+++ b/src/HttpServer.cc
@@ -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();
diff --git a/src/HttpServer.h b/src/HttpServer.h
index cdd1e40e..2f8d6329 100644
--- a/src/HttpServer.h
+++ b/src/HttpServer.h
@@ -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);
diff --git a/src/HttpServerBodyCommand.cc b/src/HttpServerBodyCommand.cc
index c60502b1..7577d3eb 100644
--- a/src/HttpServerBodyCommand.cc
+++ b/src/HttpServerBodyCommand.cc
@@ -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",
diff --git a/src/json.cc b/src/json.cc
index 05d4e618..f1b84d40 100644
--- a/src/json.cc
+++ b/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
diff --git a/src/json.h b/src/json.h
index 186f3a4c..97d00e94 100644
--- a/src/json.h
+++ b/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_.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_ << "\"";
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&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