diff --git a/src/UKHASExtractor.cxx b/src/UKHASExtractor.cxx index e5da8e5..a7bcd93 100644 --- a/src/UKHASExtractor.cxx +++ b/src/UKHASExtractor.cxx @@ -285,6 +285,9 @@ static void extract_fields(Json::Value &data, const Json::Value &fields, while (field != fields.end() && part != parts.end()) { + if (!(*field).isObject()) + throw runtime_error("Invalid configuration (field not an object)"); + const string key = (*field)["name"].asString(); const string value = (*part); @@ -317,6 +320,9 @@ static void attempt_settings(Json::Value &data, const Json::Value &sentence, const string &checksum_name, const vector &parts) { + if (!sentence.isObject()) + throw runtime_error("Invalid configuration (sentence not an object)"); + const Json::Value &fields = sentence["fields"]; const string callsign = sentence["payload"].asString(); @@ -343,6 +349,11 @@ Json::Value UKHASExtractor::crude_parse() const Json::Value &settings = *settings_ptr; + if (!settings.isObject()) + /* note: Json::Value::null.isObject() == true */ + throw runtime_error("Invalid configuration: " + "settings is not an object"); + string data, checksum; split_string(buffer, &data, &checksum); @@ -355,17 +366,19 @@ Json::Value UKHASExtractor::crude_parse() Json::Value basic(Json::objectValue); cook_basic(basic, buffer, parts[0]); - const Json::Value &sentence = settings["sentence"]; + const Json::Value &sentences = settings["sentences"]; - /* If array: multiple sentence settings to try with. - * No settings? No problem; we can still test the checksum */ - if (!sentence.isNull() && sentence.isArray()) + if (!sentences.isNull()) { + if (!sentences.isArray()) + throw runtime_error("Invalid configuration: " + "sentences is not an array"); + /* Silence errors, and only log them if all attempts fail */ vector errors; - for (Json::Value::iterator it = sentence.begin(); - it != sentence.end(); it++) + for (Json::Value::iterator it = sentences.begin(); + it != sentences.end(); it++) { try { @@ -387,20 +400,6 @@ Json::Value UKHASExtractor::crude_parse() mgr->status("UKHAS Extractor: " + (*it)); } } - else if (!sentence.isNull() && sentence.isObject()) - { - try - { - Json::Value data(basic); - attempt_settings(data, sentence, checksum_name, parts); - return data; - } - catch (runtime_error e) - { - mgr->status("UKHAS Extractor: full parse failed: " + - string(e.what())); - } - } basic["_basic"] = true; return basic; diff --git a/src/Uploader.cxx b/src/Uploader.cxx index aade647..78b3568 100644 --- a/src/Uploader.cxx +++ b/src/Uploader.cxx @@ -113,14 +113,15 @@ static void payload_telemetry_merge(Json::Value &doc, const string &callsign, Json::Value &receiver_info) { + if (!doc.isObject() || !doc["data"].isObject() || + !doc["receivers"].isObject()) + throw runtime_error("Server gave us an invalid payload telemetry doc"); + string other_b64 = doc["data"]["_raw"].asString(); if (!other_b64.length() || other_b64 != data_b64) throw CollisionError(); - if (!doc["receivers"].isObject()) - throw runtime_error("Server gave us an invalid payload telemetry doc"); - doc["receivers"][callsign] = receiver_info; } @@ -260,17 +261,31 @@ vector *Uploader::flights() vector *result = new vector; auto_ptr< vector > result_destroyer(result); + if (!response->isObject()) + throw runtime_error("Invalid response: was not an object"); + const Json::Value &rows = (*response)["rows"]; Json::Value::const_iterator it; + if (!rows.isArray()) + throw runtime_error("Invalid response: rows was not an array"); + result->reserve(rows.size()); Json::Value *current_pcfg_list = NULL; for (it = rows.begin(); it != rows.end(); it++) { const Json::Value &row = *it; + if (!row.isObject()) + throw runtime_error("Invalid response: row was not an object"); + const Json::Value &key = row["key"], &doc = row["doc"]; - bool is_pcfg = (key[2u].asInt() == 1); + + if (!doc.isObject() || !key.isArray() || key.size() != 3 || + !key[2u].isIntegral()) + throw runtime_error("Invalid response: bad key or doc in row"); + + bool is_pcfg = key[2u].asBool(); if (!is_pcfg) { @@ -304,13 +319,21 @@ vector *Uploader::payloads() vector *result = new vector; auto_ptr< vector > result_destroyer(result); + if (!response->isObject()) + throw runtime_error("Invalid response: was not an object"); + const Json::Value &rows = (*response)["rows"]; Json::Value::const_iterator it; + if (!rows.isArray()) + throw runtime_error("Invalid response: rows was not an array"); + result->reserve(rows.size()); for (it = rows.begin(); it != rows.end(); it++) { + if (!(*it).isObject()) + throw runtime_error("Invalid response: doc was not an object"); result->push_back((*it)["doc"]); } diff --git a/tests/test_extractor.py b/tests/test_extractor.py index 531f0ad..59c19cb 100644 --- a/tests/test_extractor.py +++ b/tests/test_extractor.py @@ -232,7 +232,7 @@ class TestUKHASExtractor: "mypayload") crude_parse_flight_doc = { - "sentence": { + "sentences": [ { "payload": "TESTING", "checksum": "crc16-ccitt", "fields": [ @@ -240,7 +240,7 @@ class TestUKHASExtractor: {"name": "field_b"}, {"name": "field_c"} ], - } + } ] } def test_crude_parse_config(self): @@ -257,26 +257,30 @@ class TestUKHASExtractor: def test_crude_checks(self): checks = [ - ("$$TESTING,a,b,c*asdfg\n", "invalid checksum len"), - ("$$TESTING,a,b,c*45\n", "invalid checksum: expected 1A"), - ("$$TESTING,a,b,c*AAAA\n", "invalid checksum: expected BEBC"), - ("$$TESTING,val_a,val_b*4EB7\n", "incorrect number of fields"), - ("$$TESTING,a,b,c*1A\n", "wrong checksum type"), - ("$$ANOTHER,a,b,c*2355\n", "incorrect callsign"), + ("$$TESTING,a,b,c*asdfg\n", "invalid checksum len", False), + ("$$TESTING,a,b,c*45\n", "invalid checksum: expected 1A", False), + ("$$TESTING,a,b,c*AAAA\n", "invalid checksum: expected BEBC", + False), + ("$$TESTING,val_a,val_b*4EB7\n", "incorrect number of fields", + True), + ("$$TESTING,a,b,c*1A\n", "wrong checksum type", True), + ("$$ANOTHER,a,b,c*2355\n", "incorrect callsign", True), ] self.extr.set_current_payload(self.crude_parse_flight_doc) - for (string, error) in checks: + for (string, error, full_parse_line) in checks: self.extr.push(string) self.extr.check_status("start delim") self.extr.check_upload(string) self.extr.check_status("extracted") + if full_parse_line: + self.extr.check_status("full parse failed:") self.extr.check_status(error) self.extr.check_data() multi_config_flight_doc = { - "sentence": [ + "sentences": [ { "payload": "AWKWARD", "checksum": "crc16-ccitt", "fields": [ {"name": "fa"}, {"name": "fo"}, {"name": "fc"} ] }, @@ -307,7 +311,7 @@ class TestUKHASExtractor: "fa": "extended", "fo": "other", "fc": "data"}) ddmmmmmm_flight_doc = { - "sentence": { + "sentences": [ { "payload": "TESTING", "checksum": "crc16-ccitt", "fields": [ @@ -317,7 +321,7 @@ class TestUKHASExtractor: "format":"ddmm.mm"}, {"name": "field_b"} ], - } + } ] } def test_ddmmmmmm(self):