123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663 |
- /* <!-- copyright */
- /*
- * aria2 - The high speed download utility
- *
- * Copyright (C) 2011 Tatsuhiro Tsujikawa
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * In addition, as a special exception, the copyright holders give
- * permission to link the code of portions of this program with the
- * OpenSSL library under certain conditions as described in each
- * individual source file, and distribute linked combinations
- * including the two.
- * You must obey the GNU General Public License in all respects
- * for all of the code used other than OpenSSL. If you modify
- * file(s) with this exception, you may extend this exception to your
- * version of the file(s), but you are not obligated to do so. If you
- * do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source
- * files in the program, then also delete it here.
- */
- /* copyright --> */
- #include "json.h"
- #include <sstream>
- #include "array_fun.h"
- #include "DlAbortEx.h"
- #include "error_code.h"
- #include "a2functional.h"
- #include "util.h"
- #include "fmt.h"
- #include "Base64.h"
- namespace aria2 {
- namespace json {
- // Function prototype declaration
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decode
- (std::string::const_iterator first,
- std::string::const_iterator last,
- size_t depth);
- } // namespace
- namespace {
- const char WS[] = { 0x20, 0x09, 0x0a, 0x0d };
- const char ESCAPE_CHARS[] = { '"', '\\', '/', '\b', '\f', '\n', '\r', '\t' };
- const size_t MAX_STRUCTURE_DEPTH = 100;
- } // namespace
- namespace {
- std::string::const_iterator skipWs
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- while(first != last && std::find(vbegin(WS), vend(WS), *first) != vend(WS)) {
- ++first;
- }
- return first;
- }
- } // namespace
- namespace {
- void checkEof
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- if(first == last) {
- throw DL_ABORT_EX2("JSON decoding failed: unexpected EOF",
- error_code::JSON_PARSE_ERROR);
- }
- }
- } // namespace
- namespace {
- std::string::const_iterator
- decodeKeyword
- (std::string::const_iterator first,
- std::string::const_iterator last,
- const std::string& keyword)
- {
- size_t len = keyword.size();
- for(size_t i = 0; i < len; ++i) {
- checkEof(first, last);
- if(*first != keyword[i]) {
- throw DL_ABORT_EX2(fmt("JSON decoding failed: %s not found.",
- keyword.c_str()),
- error_code::JSON_PARSE_ERROR);
- }
- ++first;
- }
- return first;
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeTrue
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- first = decodeKeyword(first, last, "true");
- return std::make_pair(Bool::gTrue(), first);
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeFalse
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- first = decodeKeyword(first, last, "false");
- return std::make_pair(Bool::gFalse(), first);
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeNull
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- first = decodeKeyword(first, last, "null");
- return std::make_pair(Null::g(), first);
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeString
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- // Consume first char, assuming it is '"'.
- ++first;
- std::string s;
- std::string::const_iterator offset = first;
- while(first != last) {
- if(*first == '"') {
- break;
- }
- if(*first == '\\') {
- s += std::string(offset, first);
- ++first;
- checkEof(first, last);
- if(*first == 'u') {
- ++first;
- std::string uchars;
- for(int i = 0; i < 4; ++i, ++first) {
- checkEof(first, last);
- uchars += *first;
- }
- checkEof(first, last);
- uint16_t codepoint = util::parseUInt(uchars, 16);
- if(codepoint <= 0x007fu) {
- s += static_cast<char>(codepoint);
- } else if(codepoint <= 0x07ffu) {
- unsigned char c2 = 0x80u | (codepoint & 0x003fu);
- unsigned char c1 = 0xC0u | (codepoint >> 6);
- s += c1;
- s += c2;
- } else if(in(codepoint, 0xD800u, 0xDBFFu)) {
- // surrogate pair
- if(*first != '\\' || first+1 == last ||
- *(first+1) != 'u') {
- throw DL_ABORT_EX2("JSON decoding failed: bad UTF-8 sequence.",
- error_code::JSON_PARSE_ERROR);
- }
- first += 2;
- std::string uchars;
- for(int i = 0; i < 4; ++i, ++first) {
- checkEof(first, last);
- uchars += *first;
- }
- checkEof(first, last);
- uint16_t codepoint2 = util::parseUInt(uchars, 16);
- if(!in(codepoint2, 0xDC00u, 0xDFFFu)) {
- throw DL_ABORT_EX2("JSON decoding failed: bad UTF-8 sequence.",
- error_code::JSON_PARSE_ERROR);
- }
- uint32_t fullcodepoint = 0x010000u;
- fullcodepoint += (codepoint & 0x03FFu) << 10;
- fullcodepoint += (codepoint2 & 0x03FFu);
- unsigned char c4 = 0x80u | (fullcodepoint & 0x003Fu);
- unsigned char c3 = 0x80u | ((fullcodepoint >> 6) & 0x003Fu);
- unsigned char c2 = 0x80u | ((fullcodepoint >> 12) & 0x003Fu);
- unsigned char c1 = 0xf0u | (fullcodepoint >> 18);
- s += c1;
- s += c2;
- s += c3;
- s += c4;
- } else if(codepoint <= 0xffffu) {
- unsigned char c3 = 0x80u | (codepoint & 0x003Fu);
- unsigned char c2 = 0x80u | ((codepoint >> 6) & 0x003Fu);
- unsigned char c1 = 0xE0u | (codepoint >> 12);
- s += c1;
- s += c2;
- s += c3;
- }
- offset = first;
- } else {
- if(*first == 'b') {
- s += '\b';
- } else if(*first == 'f') {
- s += '\f';
- } else if(*first == 'n') {
- s += '\n';
- } else if(*first == 'r') {
- s += '\r';
- } else if(*first == 't') {
- s += '\t';
- } else {
- s += *first;
- }
- ++first;
- offset = first;
- }
- } else {
- ++first;
- }
- }
- checkEof(first, last);
- if(std::distance(offset, first) > 0) {
- s += std::string(offset, first);
- }
- if(!util::isUtf8(s)) {
- throw DL_ABORT_EX2("JSON decoding failed: Non UTF-8 string.",
- error_code::JSON_PARSE_ERROR);
- }
- ++first;
- return std::make_pair(String::g(s), first);
- }
- } // namespace
- namespace {
- void checkEmptyDigit
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- if(std::distance(first, last) == 0) {
- throw DL_ABORT_EX2("JSON decoding failed: zero DIGIT.",
- error_code::JSON_PARSE_ERROR);
- }
- }
- } // namespace
- namespace {
- void checkLeadingZero
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- if(std::distance(first, last) > 2 && *first == '0') {
- throw DL_ABORT_EX2("JSON decoding failed: leading zero.",
- error_code::JSON_PARSE_ERROR);
- }
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeNumber
- (std::string::const_iterator first,
- std::string::const_iterator last)
- {
- std::string s;
- if(*first == '-') {
- s += *first;
- ++first;
- }
- std::string::const_iterator offset = first;
- while(first != last && in(*first, '0', '9')) {
- ++first;
- }
- checkEof(first, last);
- checkEmptyDigit(offset, first);
- checkLeadingZero(offset, first);
- s += std::string(offset, first);
- bool fp = false;
- if(*first == '.') {
- fp = true;
- s += *first;
- ++first;
- offset = first;
- while(first != last && in(*first, '0', '9')) {
- ++first;
- }
- checkEof(first, last);
- checkEmptyDigit(offset, first);
- s += std::string(offset, first);
- }
- if(*first == 'e') {
- fp = true;
- s += *first;
- ++first;
- checkEof(first, last);
- if(*first == '+' || *first == '-') {
- s += *first;
- ++first;
- }
- offset = first;
- while(first != last && in(*first, '0', '9')) {
- ++first;
- }
- checkEof(first, last);
- checkEmptyDigit(offset, first);
- s += std::string(offset, first);
- }
- if(fp) {
- // Since we don't have floating point coutner part in ValueBase,
- // we just treat it as string.
- return std::make_pair(String::g(s), first);
- } else {
- Integer::ValueType val = util::parseLLInt(s);
- return std::make_pair(Integer::g(val), first);
- }
- }
- } // namespace
- namespace {
- void checkDepth(size_t depth)
- {
- if(depth >= MAX_STRUCTURE_DEPTH) {
- throw DL_ABORT_EX2("JSON decoding failed: Structure is too deep.",
- error_code::JSON_PARSE_ERROR);
- }
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeArray
- (std::string::const_iterator first,
- std::string::const_iterator last,
- size_t depth)
- {
- checkDepth(depth);
- SharedHandle<List> list = List::g();
- // Consume first char, assuming it is '['.
- ++first;
- first = skipWs(first, last);
- checkEof(first, last);
- if(*first != ']') {
- while(1) {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- r = decode(first, last, depth);
- list->append(r.first);
- first = r.second;
- first = skipWs(first, last);
- if(first == last || (*first != ',' && *first != ']')) {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " value-separator ',' or ']' is not found.",
- error_code::JSON_PARSE_ERROR);
- }
- if(*first == ']') {
- break;
- }
- ++first;
- }
- }
- ++first;
- return std::make_pair(list, first);
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decodeObject
- (std::string::const_iterator first,
- std::string::const_iterator last,
- size_t depth)
- {
- checkDepth(depth);
- SharedHandle<Dict> dict = Dict::g();
- // Consume first char, assuming it is '{'
- ++first;
- first = skipWs(first, last);
- checkEof(first, last);
- if(*first != '}') {
- while(1) {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- keyRet = decodeString(first, last);
- first = keyRet.second;
- first = skipWs(first, last);
- if(first == last || *first != ':') {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " name-separator ':' is not found.",
- error_code::JSON_PARSE_ERROR);
- }
- ++first;
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- valueRet = decode(first, last, depth);
- dict->put(asString(keyRet.first)->s(), valueRet.first);
- first = valueRet.second;
- first = skipWs(first, last);
- if(first == last || (*first != ',' && *first != '}')) {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " value-separator ',' or '}' is not found.",
- error_code::JSON_PARSE_ERROR);
- }
- if(*first == '}') {
- break;
- }
- ++first;
- first = skipWs(first, last);
- checkEof(first, last);
- }
- }
- ++first;
- return std::make_pair(dict, first);
- }
- } // namespace
- namespace {
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator>
- decode
- (std::string::const_iterator first,
- std::string::const_iterator last,
- size_t depth)
- {
- first = skipWs(first, last);
- if(first == last) {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " Unexpected EOF in term context.",
- error_code::JSON_PARSE_ERROR);
- }
- if(*first == '[') {
- return decodeArray(first, last, depth+1);
- } else if(*first == '{') {
- return decodeObject(first, last, depth+1);
- } else if(*first == '"') {
- return decodeString(first, last);
- } else if(*first == '-' || in(*first, '0', '9')) {
- return decodeNumber(first, last);
- } else if(*first == 't') {
- return decodeTrue(first, last);
- } else if(*first == 'f') {
- return decodeFalse(first, last);
- } else if(*first == 'n') {
- return decodeNull(first, last);
- } else {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " Unexpected character in term context.",
- error_code::JSON_PARSE_ERROR);
- }
- }
- } // namespace
- SharedHandle<ValueBase> decode(const std::string& json)
- {
- std::string::const_iterator first = json.begin();
- std::string::const_iterator last = json.end();
- first = skipWs(first, last);
- if(first == last) {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " Unexpected EOF in term context.",
- error_code::JSON_PARSE_ERROR);
- }
- std::pair<SharedHandle<ValueBase>, std::string::const_iterator> r;
- if(*first == '[') {
- r = decodeArray(first, last, 1);
- } else if(*first == '{') {
- r = decodeObject(first, last, 1);
- } else {
- throw DL_ABORT_EX2("JSON decoding failed:"
- " Unexpected EOF in term context.",
- error_code::JSON_PARSE_ERROR);
- }
- return r.first;
- }
- std::string jsonEscape(const std::string& s)
- {
- std::string t;
- for(std::string::const_iterator i = s.begin(), eoi = s.end(); i != eoi;
- ++i) {
- if(*i == '"' || *i == '\\' || *i == '/') {
- t += '\\';
- t += *i;
- } else if(*i == '\b') {
- t += "\\b";
- } else if(*i == '\f') {
- t += "\\f";
- } else if(*i == '\n') {
- t += "\\n";
- } else if(*i == '\r') {
- t += "\\r";
- } else if(*i == '\t') {
- t += "\\t";
- } else if(in(static_cast<unsigned char>(*i), 0x00u, 0x1Fu)) {
- t += "\\u00";
- char temp[3];
- temp[2] = '\0';
- temp[0] = (*i >> 4);
- temp[1] = (*i)&0x0Fu;
- for(int j = 0; j < 2; ++j) {
- if(temp[j] < 10) {
- temp[j] += '0';
- } else {
- temp[j] += 'A'-10;
- }
- }
- t += temp;
- } else {
- t += *i;
- }
- }
- return t;
- }
- std::string encode(const ValueBase* vlb)
- {
- class JsonValueBaseVisitor:public ValueBaseVisitor {
- private:
- std::ostringstream out_;
- public:
- virtual void visit(const String& string)
- {
- const std::string& s = string.s();
- std::string t = jsonEscape(s);
- out_ << '"';
- out_.write(t.data(), t.size());
- out_ << '"';
- }
- virtual void visit(const Integer& integer)
- {
- out_ << integer.i();
- }
- virtual void visit(const Bool& boolValue)
- {
- out_ << (boolValue.val() ? "true" : "false");
- }
- virtual void visit(const Null& nullValue)
- {
- out_ << "null";
- }
- virtual void visit(const List& list)
- {
- 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);
- }
- out_ << ']';
- }
- virtual void visit(const Dict& dict)
- {
- 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_.write(key.data(), key.size());
- out_ << "\":";
- (*i).second->accept(*this);
- }
- out_ << '}';
- }
- std::string getResult() const
- {
- return out_.str();
- }
- };
- JsonValueBaseVisitor visitor;
- vlb->accept(visitor);
- return visitor.getResult();
- }
- // Serializes JSON object or array.
- std::string encode(const SharedHandle<ValueBase>& json)
- {
- std::ostringstream out;
- 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, "\"");
- }
- if(!params.empty()) {
- strappend(jsonRequest, ",\"params\":", jsonParam);
- }
- jsonRequest += '}';
- }
- }
- return JsonGetParam(jsonRequest, callback);
- }
- } // namespace json
- } // namespace aria2
|