diff --git a/src/GZipEncoder.cc b/src/GZipEncoder.cc index def1c281..c272ce97 100644 --- a/src/GZipEncoder.cc +++ b/src/GZipEncoder.cc @@ -143,4 +143,10 @@ GZipEncoder& GZipEncoder::operator<<(int64_t i) return *this; } +GZipEncoder& GZipEncoder::write(const char* s, size_t length) +{ + internalBuf_ += encode(reinterpret_cast(s), length); + return *this; +} + } // namespace aria2 diff --git a/src/GZipEncoder.h b/src/GZipEncoder.h index b5cf66de..4ba83ac2 100644 --- a/src/GZipEncoder.h +++ b/src/GZipEncoder.h @@ -68,6 +68,10 @@ public: // in this class. GZipEncoder& operator<<(const std::string& s); + // Feeds binary data in s with size length to deflater. The + // deflated result is kept in this class. + GZipEncoder& write(const char* s, size_t length); + // Feeds integer to deflator. Before passed to deflator, i is // converted to std::string using util::itos(). The deflated result // is kept in this class. diff --git a/src/HttpServerBodyCommand.cc b/src/HttpServerBodyCommand.cc index e49c253c..3d39e111 100644 --- a/src/HttpServerBodyCommand.cc +++ b/src/HttpServerBodyCommand.cc @@ -54,6 +54,8 @@ #include "util.h" #include "fmt.h" #include "SocketRecvBuffer.h" +#include "json.h" +#include "DlAbortEx.h" namespace aria2 { @@ -92,8 +94,16 @@ bool HttpServerBodyCommand::execute() timeoutTimer_ = global::wallclock; if(httpServer_->receiveBody()) { + A2_LOG_DEBUG(fmt("%s", httpServer_->getBody().c_str())); + + std::string reqPath = httpServer_->getRequestPath(); + reqPath.erase(std::find(reqPath.begin(), reqPath.end(), '#'), + reqPath.end()); + std::string query(std::find(reqPath.begin(), reqPath.end(), '?'), + reqPath.end()); + reqPath.erase(reqPath.size()-query.size(), query.size()); // Do something for requestpath and body - if(httpServer_->getRequestPath() == "/rpc") { + if(reqPath == "/rpc") { xmlrpc::XmlRpcRequest req = xmlrpc::XmlRpcRequestProcessor().parseMemory(httpServer_->getBody()); @@ -108,6 +118,50 @@ bool HttpServerBodyCommand::execute() e_->addCommand(command); e_->setNoWait(true); return true; + } else if(reqPath == "/jsonrpc") { + // TODO handle query parameter + std::string callback;// = "callback"; + + SharedHandle json = json::decode(httpServer_->getBody()); + const Dict* jsondict = asDict(json); + if(!jsondict) { + // TODO code: -32600, Invalid Request + throw DL_ABORT_EX("JSON-RPC Invalid Request"); + } + const String* methodName = asString(jsondict->get("method")); + if(!methodName) { + // TODO Batch request does not have method + throw DL_ABORT_EX("JSON-RPC No Method Found"); + } + SharedHandle params; + const SharedHandle& tempParams = jsondict->get("params"); + if(asList(tempParams)) { + params = static_pointer_cast(tempParams); + } else if(!tempParams) { + params = List::g(); + } else { + // TODO No support for Named params + throw DL_ABORT_EX("JSON-RPC Named params are not supported"); + } + SharedHandle id = jsondict->get("id"); + if(!id) { + // TODO Batch request does not have id + throw DL_ABORT_EX("JSON-RPC NO id found"); + } + xmlrpc::XmlRpcRequest req(methodName->s(), params, id); + + SharedHandle method = + xmlrpc::XmlRpcMethodFactory::create(req.methodName); + method->setJsonRpc(true); + xmlrpc::XmlRpcResponse res = method->execute(req, e_); + bool gzip = httpServer_->supportsGZip(); + std::string responseData = res.toJson(callback, gzip); + httpServer_->feedResponse(responseData, "application/json-rpc"); + Command* command = + new HttpServerResponseCommand(getCuid(), httpServer_, e_, socket_); + e_->addCommand(command); + e_->setNoWait(true); + return true; } else { return true; } diff --git a/src/Makefile.am b/src/Makefile.am index 05cb27c4..8a3b3d79 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -210,7 +210,8 @@ SRCS = Socket.h\ NullSinkStreamFilter.cc NullSinkStreamFilter.h\ uri.cc uri.h\ Triplet.h\ - cookie_helper.cc cookie_helper.h + cookie_helper.cc cookie_helper.h\ + json.cc json.h if ENABLE_XML_RPC SRCS += XmlRpcRequestParserController.cc XmlRpcRequestParserController.h\ diff --git a/src/ValueBase.cc b/src/ValueBase.cc index 5048970d..ab388c36 100644 --- a/src/ValueBase.cc +++ b/src/ValueBase.cc @@ -97,6 +97,45 @@ void Integer::accept(ValueBaseVisitor& v) const v.visit(*this); } +const SharedHandle Bool::trueValue_(new Bool(true)); +const SharedHandle Bool::falseValue_(new Bool(false)); + +SharedHandle Bool::gTrue() +{ + return trueValue_; +} + +SharedHandle Bool::gFalse() +{ + return falseValue_; +} + +bool Bool::val() const +{ + return val_; +} + +void Bool::accept(ValueBaseVisitor& v) const +{ + v.visit(*this); +} + +Bool::Bool(bool val):val_(val) {} + +const SharedHandle Null::nullValue_(new Null()); + +SharedHandle Null::g() +{ + return nullValue_; +} + +void Null::accept(ValueBaseVisitor& v) const +{ + v.visit(*this); +} + +Null::Null() {} + List::List() {} List::~List() {} @@ -262,7 +301,7 @@ void Dict::accept(ValueBaseVisitor& v) const const String* asString(const ValueBase* v) { if(v) { - return downcast(v); + return downcast(v); } else { return 0; } @@ -271,7 +310,7 @@ const String* asString(const ValueBase* v) String* asString(ValueBase* v) { if(v) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } @@ -280,7 +319,7 @@ String* asString(ValueBase* v) String* asString(const SharedHandle& v) { if(v.get()) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } @@ -289,7 +328,7 @@ String* asString(const SharedHandle& v) const Integer* asInteger(const ValueBase* v) { if(v) { - return downcast(v); + return downcast(v); } else { return 0; } @@ -298,7 +337,7 @@ const Integer* asInteger(const ValueBase* v) Integer* asInteger(ValueBase* v) { if(v) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } @@ -307,7 +346,43 @@ Integer* asInteger(ValueBase* v) Integer* asInteger(const SharedHandle& v) { if(v.get()) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); + } else { + return 0; + } +} + +const Bool* asBool(const ValueBase* v) +{ + if(v) { + return downcast(v); + } else { + return 0; + } +} + +Bool* asBool(const SharedHandle& v) +{ + if(v.get()) { + return const_cast(downcast(v)); + } else { + return 0; + } +} + +const Null* asNull(const ValueBase* v) +{ + if(v) { + return downcast(v); + } else { + return 0; + } +} + +Null* asNull(const SharedHandle& v) +{ + if(v) { + return const_cast(downcast(v)); } else { return 0; } @@ -316,7 +391,7 @@ Integer* asInteger(const SharedHandle& v) const List* asList(const ValueBase* v) { if(v) { - return downcast(v); + return downcast(v); } else { return 0; } @@ -325,7 +400,7 @@ const List* asList(const ValueBase* v) List* asList(ValueBase* v) { if(v) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } @@ -334,7 +409,7 @@ List* asList(ValueBase* v) List* asList(const SharedHandle& v) { if(v.get()) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } @@ -343,7 +418,7 @@ List* asList(const SharedHandle& v) const Dict* asDict(const ValueBase* v) { if(v) { - return downcast(v); + return downcast(v); } else { return 0; } @@ -352,7 +427,7 @@ const Dict* asDict(const ValueBase* v) Dict* asDict(ValueBase* v) { if(v) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } @@ -361,7 +436,7 @@ Dict* asDict(ValueBase* v) Dict* asDict(const SharedHandle& v) { if(v.get()) { - return const_cast(downcast(v)); + return const_cast(downcast(v)); } else { return 0; } diff --git a/src/ValueBase.h b/src/ValueBase.h index a262b853..e13d12d2 100644 --- a/src/ValueBase.h +++ b/src/ValueBase.h @@ -58,19 +58,19 @@ public: class String; class Integer; +class Bool; +class Null; class List; class Dict; class ValueBaseVisitor { public: virtual ~ValueBaseVisitor() {} - virtual void visit(const String& string) = 0; - virtual void visit(const Integer& integer) = 0; - + virtual void visit(const Bool& boolValue) = 0; + virtual void visit(const Null& nullValue) = 0; virtual void visit(const List& list) = 0; - virtual void visit(const Dict& dict) = 0; }; @@ -133,6 +133,34 @@ private: ValueType integer_; }; +class Bool:public ValueBase { +public: + static SharedHandle gTrue(); + static SharedHandle gFalse(); + bool val() const; + virtual void accept(ValueBaseVisitor& visitor) const; +private: + Bool(bool val); + // Don't allow copying + Bool(const Bool&); + Bool& operator=(const Bool&); + bool val_; + static const SharedHandle trueValue_; + static const SharedHandle falseValue_; +}; + +class Null:public ValueBase { +public: + static SharedHandle g(); + virtual void accept(ValueBaseVisitor& visitor) const; +private: + Null(); + // Don't allow copying + Null(const Null&); + Null& operator=(const Null&); + static const SharedHandle nullValue_; +}; + class List:public ValueBase { public: typedef std::vector > ValueType; @@ -256,10 +284,19 @@ private: ValueType dict_; }; -template -class DowncastValueBaseVisitor:public ValueBaseVisitor { -private: - const T* result_; +class EmptyDowncastValueBaseVisitor:public ValueBaseVisitor { +public: + EmptyDowncastValueBaseVisitor() {} + virtual void visit(const String& v) {} + virtual void visit(const Integer& v) {} + virtual void visit(const Bool& v) {} + virtual void visit(const Null& v) {} + virtual void visit(const List& v) {} + virtual void visit(const Dict& v) {} +}; + +template +class DowncastValueBaseVisitor:public EmptyDowncastValueBaseVisitor { public: DowncastValueBaseVisitor():result_(0) {} @@ -268,10 +305,6 @@ public: result_ = &t; } - virtual void visit(const T1& t1) {} - virtual void visit(const T2& t2) {} - virtual void visit(const T3& t3) {} - const T* getResult() const { return result_; @@ -281,12 +314,14 @@ public: { result_ = r; } +private: + const T* result_; }; -template +template const T* downcast(const VPtr& v) { - DowncastValueBaseVisitor visitor; + DowncastValueBaseVisitor visitor; v->accept(visitor); return visitor.getResult(); } @@ -303,6 +338,14 @@ Integer* asInteger(ValueBase* v); Integer* asInteger(const SharedHandle& v); +const Bool* asBool(const ValueBase* v); + +Bool* asBool(const SharedHandle& v); + +const Null* asNull(const ValueBase* v); + +Null* asNull(const SharedHandle& v); + const List* asList(const ValueBase* v); List* asList(ValueBase* v); diff --git a/src/XmlRpcMethod.cc b/src/XmlRpcMethod.cc index 75b7ebca..7621b0f2 100644 --- a/src/XmlRpcMethod.cc +++ b/src/XmlRpcMethod.cc @@ -53,7 +53,8 @@ namespace aria2 { namespace xmlrpc { XmlRpcMethod::XmlRpcMethod() - : optionParser_(OptionParser::getInstance()) + : optionParser_(OptionParser::getInstance()), + jsonRpc_(false) {} XmlRpcMethod::~XmlRpcMethod() {} @@ -62,8 +63,8 @@ SharedHandle XmlRpcMethod::createErrorResponse (const Exception& e) { SharedHandle params = Dict::g(); - params->put("faultCode", Integer::g(1)); - params->put("faultString", std::string(e.what())); + params->put((jsonRpc_ ? "code" : "faultCode"), Integer::g(1)); + params->put((jsonRpc_ ? "message" : "faultString"), std::string(e.what())); return params; } @@ -71,10 +72,10 @@ XmlRpcResponse XmlRpcMethod::execute (const XmlRpcRequest& req, DownloadEngine* e) { try { - return XmlRpcResponse(0, process(req, e)); + return XmlRpcResponse(0, process(req, e), req.id); } catch(RecoverableException& e) { A2_LOG_DEBUG_EX(EX_EXCEPTION_CAUGHT, e); - return XmlRpcResponse(1, createErrorResponse(e)); + return XmlRpcResponse(1, createErrorResponse(e), req.id); } } diff --git a/src/XmlRpcMethod.h b/src/XmlRpcMethod.h index cbdf65c1..80a49fe5 100644 --- a/src/XmlRpcMethod.h +++ b/src/XmlRpcMethod.h @@ -64,6 +64,7 @@ struct XmlRpcResponse; class XmlRpcMethod { private: SharedHandle optionParser_; + bool jsonRpc_; protected: // Subclass must implement this function to fulfil XmlRpcRequest // req. The return value of this method is used as a return value @@ -102,6 +103,15 @@ public: // Do work to fulfill XmlRpcRequest req and returns its result as // XmlRpcResponse. This method delegates to process() method. XmlRpcResponse execute(const XmlRpcRequest& req, DownloadEngine* e); + // Set whether JSON-RPC style parameter handling. + void setJsonRpc(bool f) + { + jsonRpc_ = f; + } + bool getJsonRpc() const + { + return jsonRpc_; + } }; } // namespace xmlrpc diff --git a/src/XmlRpcMethodImpl.cc b/src/XmlRpcMethodImpl.cc index 4e2a9007..1b9edb74 100644 --- a/src/XmlRpcMethodImpl.cc +++ b/src/XmlRpcMethodImpl.cc @@ -63,6 +63,7 @@ #include "SegmentMan.h" #include "TimedHaltCommand.h" #include "PeerStat.h" +#include "Base64.h" #ifdef ENABLE_BITTORRENT # include "bittorrent_helper.h" # include "BtRegistry.h" @@ -266,7 +267,11 @@ SharedHandle AddTorrentXmlRpcMethod::process if(!torrentParam) { throw DL_ABORT_EX("Torrent data is not provided."); } - + SharedHandle tempTorrentParam; + if(getJsonRpc()) { + tempTorrentParam = String::g(Base64::decode(torrentParam->s())); + torrentParam = tempTorrentParam.get(); + } std::vector uris; extractUris(std::back_inserter(uris), req.getListParam(1)); @@ -309,7 +314,11 @@ SharedHandle AddMetalinkXmlRpcMethod::process if(!metalinkParam) { throw DL_ABORT_EX("Metalink data is not provided."); } - + SharedHandle tempMetalinkParam; + if(getJsonRpc()) { + tempMetalinkParam = String::g(Base64::decode(metalinkParam->s())); + metalinkParam = tempMetalinkParam.get(); + } SharedHandle