freeconf / restconf

Implementation of RESTCONF Management protocol - IETF RFC8040
Apache License 2.0
27 stars 9 forks source link

Question: how to post binary data with JSON #59

Open b-kamphorst opened 3 months ago

b-kamphorst commented 3 months ago

Hey!

I've been playing around with FreeCONF for some days. In general I like it, and it really helps me to get a better understanding of YANG and RESTCONF. Today I tried to patch/put/post data to a binary leaf, without success. Perhaps you could point me to a solution?

Approach: I follow the "Getting started" tutorial and change the type of message into type binary;. If I start the server, I get the following error:

Starting server...
Traceback (most recent call last):
  File ".../freeconf/server.py", line 62, in <module>
    browser = main()
  File ".../freeconf/server.py", line 55, in main
    dev.apply_startup_config_file("./startup.json")
  File ".../freeconf/.venv/lib/python3.10/site-packages/freeconf/device.py", line 26, in apply_startup_config_file
    self.__apply_startup_config_stream(self.driver.fs.new_rdr_file(configFile))
  File ".../freeconf/.venv/lib/python3.10/site-packages/freeconf/device.py", line 36, in __apply_startup_config_stream
    self.driver.g_device.ApplyStartupConfig(req)
  File ".../freeconf/.venv/lib/python3.10/site-packages/grpc/_channel.py", line 1176, in __call__
    return _end_unary_response_blocking(state, call, False, None)
  File ".../freeconf/.venv/lib/python3.10/site-packages/grpc/_channel.py", line 1005, in _end_unary_response_blocking
    raise _InactiveRpcError(state)  # pytype: disable=not-instantiable
grpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with:
        status = StatusCode.UNKNOWN
        details = "cannot coerse 'string' to binary value"
        debug_error_string = "UNKNOWN:Error received from peer  {created_time:"2024-04-09T14:41:51.964747905+02:00", grpc_status:2, grpc_message:"cannot coerse \'string\' to binary value"}"
>

So that didn't go very well. For now, I can remove the "message" key from ./startup.json (so "hello: {}") and start the server again without issues. Then, I try to POST a base64-encoded string as described in RFC7950 as follows:

# base64 encoding of "Hello, world!"
curl -X POST -d '{"message": "SGVsbG8sIHdvcmxkIQ=="}' http://localhost:8080/restconf/data/hello

which returns

cannot coerse 'string' to binary value

Is base64 decoding of JSON strings for binary types not implemented? If it is, what am I doing wrong?

Looking forward to your help.

dhubler commented 3 months ago

1.) I think you want either PATCH or PUT because you are not creating a new data structure

2.) I also think you need the ":" and the end

curl -X PATCH -d '{"message": "normal text"}' http://localhost:8080/restconf/data/hello:

On Tue, Apr 9, 2024 at 8:47 AM bart @.***> wrote:

Hey!

I've been playing around with FreeCONF for some days. In general I like it, and it really helps me to get a better understanding of YANG and RESTCONF. Today I tried to patch/put/post data to a binary leaf, without success. Perhaps you could point me to a solution?

Approach: I follow the "Getting started" https://freeconf.org/docs/gettingstarted/ tutorial and change the type of message into type binary;. If I start the server, I get the following error:

Starting server...Traceback (most recent call last): File ".../freeconf/server.py", line 62, in browser = main() File ".../freeconf/server.py", line 55, in main dev.apply_startup_config_file("./startup.json") File ".../freeconf/.venv/lib/python3.10/site-packages/freeconf/device.py", line 26, in apply_startup_config_file self.apply_startup_config_stream(self.driver.fs.new_rdr_file(configFile)) File ".../freeconf/.venv/lib/python3.10/site-packages/freeconf/device.py", line 36, in __apply_startup_config_stream self.driver.g_device.ApplyStartupConfig(req) File ".../freeconf/.venv/lib/python3.10/site-packages/grpc/_channel.py", line 1176, in call__ return _end_unary_response_blocking(state, call, False, None) File ".../freeconf/.venv/lib/python3.10/site-packages/grpc/_channel.py", line 1005, in _end_unary_response_blocking raise _InactiveRpcError(state) # pytype: disable=not-instantiablegrpc._channel._InactiveRpcError: <_InactiveRpcError of RPC that terminated with: status = StatusCode.UNKNOWN details = "cannot coerse 'string' to binary value" debug_error_string = "UNKNOWN:Error received from peer {created_time:"2024-04-09T14:41:51.964747905+02:00", grpc_status:2, grpc_message:"cannot coerse \'string\' to binary value"}"

So that didn't go very well. For now, I can remove the "message" key from ./startup.json (so "hello: {}") and start the server again without issues. Then, I try to POST a base64-encoded string as described in RFC7950 https://www.rfc-editor.org/rfc/rfc7950#section-9.8 as follows:

base64 encoding of "Hello, world!"curl -X POST -d '{"message": "SGVsbG8sIHdvcmxkIQ=="}' http://localhost:8080/restconf/data/hello

which returns

cannot coerse 'string' to binary value

Is base64 decoding of JSON strings for binary types not implemented? If it is, what am I doing wrong?

Looking forward to your help.

— Reply to this email directly, view it on GitHub https://github.com/freeconf/restconf/issues/59, or unsubscribe https://github.com/notifications/unsubscribe-auth/AAACA7SWR7WM6G2B5XLIQOTY4PPNVAVCNFSM6AAAAABF6QJ36CVHI2DSMVQWIX3LMV43ASLTON2WKOZSGIZTGMZWGQYTQMQ . You are receiving this because you are subscribed to this thread.Message ID: @.***>

b-kamphorst commented 3 months ago

Thank you for your quick response! Your suggestions do cause me to get another error.

If I do NOT define "message" in the startup file, I get the following for a PUT request:

client

$ curl -X PUT -d '{"hello:message": "R29vZGJ5ZSwgd29ybGQh"}' http://localhost:8080/restconf/data/hello:
curl: (52) Empty reply from server

server

Starting server...
Serving. Press Ctrl+C to exit.
2024/04/11 15:46:06 http: panic serving 127.0.0.1:46410: runtime error: invalid memory address or nil pointer dereference
goroutine 28 [running]:
net/http.(*conn).serve.func1()
        /opt/hostedtoolcache/go/1.20.10/x64/src/net/http/server.go:1854 +0xbf
panic({0xa213a0, 0xff7530})
        /opt/hostedtoolcache/go/1.20.10/x64/src/runtime/panic.go:890 +0x263
github.com/freeconf/yang/node.(*Selection).Delete(0xc0005773b0)
        /home/runner/go/pkg/mod/github.com/freeconf/yang@v0.0.0-20231107135057-5f971eab6dd7/node/selection.go:400 +0x20d
github.com/freeconf/yang/node.(*Selection).ReplaceFrom(0xc000366700?, {0xbe7038, 0xc0001523f0})
        /home/runner/go/pkg/mod/github.com/freeconf/yang@v0.0.0-20231107135057-5f971eab6dd7/node/selection.go:469 +0x2c
github.com/freeconf/restconf.(*browserHandler).ServeHTTP(0xc0000141f0, {0x1, 0x1, 0x1, 0x1, 0x1}, {0xbe2c80?, 0xc00056ee70?}, {0xbe1ee0, 0xc0003541c0}, ...)
        /home/runner/go/pkg/mod/github.com/freeconf/restconf@v0.0.0-20231107135249-d6c6b5b9348d/browser_handler.go:175 +0xcd8
github.com/freeconf/restconf.(*Server).serve(0xc00003a725?, {0x1, 0x1, 0x1, 0x1, 0x1}, {0xbe2c80, 0xc00056ee70}, {0xbe3770, 0xc0002ba8d0}, ...)
        /home/runner/go/pkg/mod/github.com/freeconf/restconf@v0.0.0-20231107135249-d6c6b5b9348d/server.go:243 +0x125
github.com/freeconf/restconf.(*Server).ServeHTTP(0xc0002b4500, {0xbe1ee0, 0xc0003541c0}, 0xc000366700)
        /home/runner/go/pkg/mod/github.com/freeconf/restconf@v0.0.0-20231107135249-d6c6b5b9348d/server.go:185 +0xb6c
net/http.serverHandler.ServeHTTP({0xbe08b0?}, {0xbe1ee0, 0xc0003541c0}, 0xc000366700)
        /opt/hostedtoolcache/go/1.20.10/x64/src/net/http/server.go:2936 +0x316
net/http.(*conn).serve(0xc0001c8fc0, {0xbe2c80, 0xc000584060})
        /opt/hostedtoolcache/go/1.20.10/x64/src/net/http/server.go:1995 +0x612
created by net/http.(*Server).Serve
        /opt/hostedtoolcache/go/1.20.10/x64/src/net/http/server.go:3089 +0x5ed

A PATCH request works much better:

client

curl -X PATCH -d '{"hello:message": "R29vZGJ5ZSwgd29ybGQh"}' http://localhost:8080/restconf/data/hello:
cannot coerse 'string' to binary value

No terminal output on server side. So this seems to be the correct request, apart from the fact that the string is not decoded with base64.

On the other hand, if I define "message": "SGVsbG8sIHdvcmxkIQ==" in the startup file then I get the same "cannot coerse 'string' to binary value" as before on server side.

To me it looks like an issue in the base64 JSON string to binary parsing (invocation / logic / ...)? The inputs should be valid base64.

b-kamphorst commented 3 months ago

Note: I just tried the Go implementation, and everything seems to work fine there.