[CONTROLLER-559] RPC with malformed JSON data picks ad-hoc interpretation instead of error code 400. Created: 18/Jun/14  Updated: 14/Nov/17  Resolved: 09/Jul/14

Status: Verified
Project: controller
Component/s: restconf
Affects Version/s: Helium
Fix Version/s: None

Type: Bug
Reporter: Vratko Polak Assignee: Jozef Gloncak
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified
Environment:

Operating System: Linux
Platform: PC


External issue ID: 1204
Priority: Low

 Description   

This bug uses data from CONTROLLER-333 now with knowledge it is malformed. Original comment:

Hi.
I have tried creating curl command using JSON data
that would create tunnel with explicit path.
This is XML data version which works ok:
curl -X POST -H "Content-Type:application/yang.data+xml" -d '<input><node>pcc://39.39.39.39</node><name>odveci</name><network-topology-ref xmlns:topo="urn:TBD:params:xml:ns:yang:network-topology">/topo:network-topology/topo:topology[topo:topology-id="pcep-topology"]</network-topology-ref><arguments><endpoints-obj><ipv4><source-ipv4-address>39.39.39.39</source-ipv4-address><destination-ipv4-address>43.43.43.43</destination-ipv4-address></ipv4></endpoints-obj><ero><subobject><loose>false</loose><ip-prefix><ip-prefix>195.20.160.40/32</ip-prefix></ip-prefix></subobject><subobject><loose>false</loose><ip-prefix><ip-prefix>201.20.160.43/32</ip-prefix></ip-prefix></subobject><subobject><loose>false</loose><ip-prefix><ip-prefix>43.43.43.43/32</ip-prefix></ip-prefix></subobject></ero></arguments></input>' 127.0.0.1:8080/restconf/operations/network-topology-pcep:add-lsp
and this is JSON version which almost works:
curl -X POST -H "Content-Type:application/yang.data+json" -d '{"input":{"node":"pcc://39.39.39.39","name":"odveci","network-topology-ref":"/network-topology:network-topology/network-topology:topology[network-topology:topology-id=\"pcep-topology\"]","arguments":{"endpoints-obj":{"ipv4":{"source-ipv4-address":"39.39.39.39","destination-ipv4-address":"43.43.43.43"}},"ero":[{"subobject":{"loose":false,"ip-prefix":

{"ip-prefix":"195.20.160.40/32"}

}},{"subobject":{"loose":false,"ip-prefix":

{"ip-prefix":"201.20.160.43/32"}

}},{"subobject":{"loose":false,"ip-prefix":

{"ip-prefix":"43.43.43.43/32"}

}}]}}}' 127.0.0.1:8080/restconf/operations/network-topology-pcep:add-lsp
but in this case created tunnel only has
one of 3 hops, the first one to 195.20.160.40.
Is this a known issue?

What is malformed:
grouping explicit-route-object contains
container ero {
...omitted....
list subobject

{ ...omitted... }

...omitted...
}
So conclusion is that YANG element has to be mapped to JSON:

  • container -> "container_name":{}
  • list -> "list_name":[{},{},...{}]

I would expect to get error code 400 when submitting "container_name":[...] or "list_name":

{<fields>}

as silent reinterpretation leads to confusing behavior (only first hop present in resulting path).



 Comments   
Comment by Jozef Gloncak [ 24/Jun/14 ]

https://git.opendaylight.org/gerrit/#/c/8280/

1. case
container schema node + multiple data nodes for container -> RestconfDocumentedException with error tag bad-element which is mapped to return code 400

2. case
list schema node + single data node -> valid case regardles if it is specified in json:
-> incorrectly as container
"list-name":

{...}

-> correctly as list
"list-name": [{},{}...,{}]

Comment by Jozef Gloncak [ 25/Jun/14 ]

3 Remarks from Tom Pantelis. 2 of them were incorporated. 1 requires more clarification.

Comment by Jozef Gloncak [ 25/Jun/14 ]

Patch set 3 was comitted
https://git.opendaylight.org/gerrit/#/c/8280

Comment by Tom Pantelis [ 26/Jun/14 ]

I noted https://git.opendaylight.org/gerrit/#/c/8280 with my test findings.

I reproduced the issue by adding the following to the toaster's make-toast input:

container ero {
list sub {
leaf lf

{ type string; }

}
}

then sending payload:

{
"input" :
{
"toaster:toasterDoneness" : "3",
"toaster:toasterToastType":"wheat-bread",

"ero":
[
{
"sub" :

{ "lf" : "1" }

,
"sub" :

{ "lf" : "2" }

}
]
}
}

The RPC will succeed but in the output from the toaster you will only see 1 of the "sub" elements.

I also tested make-toast passing in 2 "ero" elements:

{
"input" :
{
"toaster:toasterDoneness" : "3",
"toaster:toasterToastType":"wheat-bread",

"ero": {
"sub" :
[

{ "lf" : "1" }

]
},

"ero": {
"sub" :
[

{ "lf" : "2" }

]
}
}
}

and it succeeded but only the last "ero" element was taken.

In fact this seems to be a general problem with any type of json element, even leafs. This also succeeds:

{
"input" :

{ "toaster:toasterDoneness" : "3", "toaster:toasterToastType":"wheat-bread", "toaster:toasterToastType" : "frozen-waffle" }

}

The toaster got called with "frozen-waffle".

The google JsonParser is lenient with allowing duplicate elements with the same name. It internally stores the elements in a map by name so it weeds out duplicates (last one in wins).

I tried the input above with a few on-line validators. 2 of them said it was valid (JSONLint and http://jsonformatter.curiousconcept.com/). But the one at http://www.freeformatter.com/json-validator.html said the

"input is NOT valid according to RFC 4627 (JSON specification). Unexpected duplicate key:toaster:toasterToastType".

But it also said it was valid in JavaScript.

So it seems it's up to the json parser whether or not it is strictly compliant with the JSON spec with respect to duplicate elements.

I didn't see any setting in the JsonParser to configure it to be strict. Maybe there's a way to hook into it to enforce key uniqueness. Other than that, if we want to address this issue, we may have to explore other parsers that are more strict.

Comment by Tony Tkacik [ 26/Jun/14 ]

Good analysis Tom,
yes your input

{
"input" :

{ "toaster:toasterDoneness" : "3", "toaster:toasterToastType":"wheat-bread", "toaster:toasterToastType" : "frozen-waffle" }

}

is valid Javascript, but "maybe-invalid" JSON, RPC for JSON states:

2.2. Objects

...
The names within an object SHOULD be unique.
...

That's why also existing external tooling is confused about whether this is valid JSON or not and probably most implementations opted for Javascript semantics - latest value wins.

I would go with behaviour that duplicate is error, because default behaviour of GSon hides potential bug in user input.

Comment by Vratko Polak [ 26/Jun/14 ]

> So it seems it's up to the json parser whether or not it is strictly compliant with the JSON spec with respect to duplicate elements.

True. There are even more obvious semantic questions. For example, is order of elements in JSON array important, or could elements be re-ordered arbitrarily? Answer: It depends on the Yang model definition, specifically whether "order-by user;" is present. (This affects testing, in analyzing response.)

What we are dealing with is not just JSON syntax, but also "Content-Type:application/yang.data+json" semantics, which is just being defined as we run into corner cases. Ideally, we should have a wiki page tracking details like "list schema node + single data node -> valid case regardles if it is specified in json".

I mean, it is probably not worth to spend developer time to make JSON handling as close to RFC intentions as possible; user frienliness is more important. In this case, friendliness is a balance between strict error checking and sane error correction.

Comment by Tom Pantelis [ 26/Jun/14 ]

(In reply to Vratko Polák from comment #6)
> I mean, it is probably not worth to spend developer time to make JSON
> handling as close to RFC intentions as possible; user frienliness is more
> important. In this case, friendliness is a balance between strict error
> checking and sane error correction.

The problem is that the silent error correction wrt duplicates is ambiguous. In the make-toast input, did I really mean "wheat-toast" or "frozen-waffle"? In this case I don't mind either for breakfast but in real, critical situations, we shouldn't have ODL potentially guessing what the user really intends semantically. So I agree with Tony that we should be strict wrt to duplicates.

Syntactically I think we can be more user-friendly and not be strictly compliant. Eg, in the JSON spec, each element name has to be in double-quotes but most parsers are probably lenient about this (gson is, except if the name contains a yang prefix with ':').

Comment by Jozef Gloncak [ 26/Jun/14 ]

@Tom
can you advise some JSON parser which checks uniqueness of names in JSON object?
Thanks

Comment by Tom Pantelis [ 26/Jun/14 ]

(In reply to Jozef Gloncak from comment #8)
> @Tom
> can you advise some JSON parser which checks uniqueness of names in JSON
> object?
> Thanks

I haven't investigated other parsers. Try googling - there's probably other free/open-source parsers out there.

Another option is to change the gson parser to add a flag to disallow duplicates, either by filing a request with Google or contributing a change ourselves if it's open-source.

Comment by Jozef Gloncak [ 30/Jun/14 ]

Currently the case when not unique key name in JSON object occurs is caught. In such a case RestconfDocumentatedException is raised.
https://git.opendaylight.org/gerrit/#/c/8280/

Comment by Jozef Gloncak [ 02/Jul/14 ]

draft
https://git.opendaylight.org/gerrit/#/c/8557/

gson code was changed and added to opendaylight
JSON file is now parsed only once.

Comment by Jozef Gloncak [ 03/Jul/14 ]

gson framework - https://git.opendaylight.org/gerrit/#/c/8559
CONTROLLER-559 - exception if multiple container node occures - https://git.opendaylight.org/gerrit/#/c/8561/

gson code was changed and added to opendaylight
JSON file is now parsed only once.

Comment by Jozef Gloncak [ 07/Jul/14 ]

JsonParser was implemented as was advised by Tom Pantelis.
Current patch set 7
https://git.opendaylight.org/gerrit/#/c/8280/

Comment by Jozef Gloncak [ 08/Jul/14 ]

patch set 8 uploaded
https://git.opendaylight.org/gerrit/#/c/8280/

Comment by Vratko Polak [ 09/Jul/14 ]

> I would expect to get error code 400

I have verified that my expectation is met now.

Generated at Wed Feb 07 19:53:19 UTC 2024 using Jira 8.20.10#820010-sha1:ace47f9899e9ee25d7157d59aa17ab06aee30d3d.