Re: [Cppcms-users] JSON-RPC dispatching together with Normal Web Page
Brought to you by:
artyom-beilis
|
From: Jon F. <jon...@jf...> - 2020-11-10 23:39:41
|
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<p>Splendid! Good job! It seems everyone implements their JSON based
APIs/RPCs differently. Looks like Artyom implements the
JSON-RPC-1.0 spec pretty strictly, which is probably a good thing.
Get to know those in-browser debugging tools. They can save a ton
of time!<br>
</p>
<p>@Artyom, if you read this I wanted to let you know: the link to
the spec is broken. Probably should go here:
<a class="moz-txt-link-freetext" href="https://www.jsonrpc.org/specification_v1">https://www.jsonrpc.org/specification_v1</a>. Also RPC is transposed
at least once on your tutorial page.</p>
<p>Congratulations,<br>
Jon<br>
</p>
<br>
<div class="moz-cite-prefix">On 11/10/2020 02:32 PM, Varstray Pl
wrote:<br>
</div>
<blockquote
cite="mid:CAN...@ma..."
type="cite">
<div dir="ltr">Wow! Ok, so I took your information and ran with
it, Jon. The information on CORS was definitely useful.
Originally I thought I was going to have to set the necessary
cors-compliant response headers in my webcomic.cpp code itself,
but something was bugging me about it. My test environment is
essentially from localhost:8080/webcomic, whereas the url given
in the widgets.js getWidgets() method was just simply '/rpc'.
So, to make absolutely sure that I wasn't engaging in any cross
site scripting, I set the xmlhttprequest url to
<a class="moz-txt-link-rfc2396E" href="http:localhost:8080/webcomic/rpc">"http:localhost:8080/webcomic/rpc"</a><br>
<div>.</div>
<div>The response was actually a 404 status code, lol. Verifying
the actual url that the browser tried to contact shed some
light on the issue: It was
<a class="moz-txt-link-rfc2396E" href="http:localhost:8080/webcomic/http:localhost:8080/webcomic/rpc">"http:localhost:8080/webcomic/http:localhost:8080/webcomic/rpc"</a>.
Aha! So the xml request was reaching the json_server backend
after all! I didn't actually have much experience with the
firefox developer console, but your information regarding how
to manually trigger the getWidgets() method and view the
response set me on the right track quickly. I was able to
verify that the "Invalid JSON-RPC" string was actually coming
from the response payload, indicating an issue in the CppCMS
codebase itself.</div>
<div><br>
</div>
<div>A quick bash command:</div>
<div><span style="font-family:monospace">for fd in `ls $SRCDIR`;
do echo "In file: $fd" ; cat ./$fd | grep -e "JSON-RPC" ;
done</span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif"><br>
</font></span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">Revealed:</font></span></div>
<div><span style="font-family:monospace">In file: rpc_json.cpp<br>
throw call_error("Invalid JSON-RPC");<br>
BOOSTER_DEBUG("cppcms") << "JSON-RPC Method call:"
<< method();<br>
throw cppcms_error("JSON-RPC Request is not assigned to
class");<br>
</span></div>
<div><span style="font-family:monospace"><br>
</span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">Which led me to this snippet of
code in rpc_json.cpp:</font></span></div>
<div><span style="font-family:monospace"> if(
request.type("method")!=json::is_string <br>
|| request.type("params")!=json::is_array<br>
|| request.type("id")==json::is_undefined)<br>
{<br>
throw call_error("Invalid JSON-RPC");<br>
}</span></div>
<div><span style="font-family:monospace"><br>
</span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">Boom. That was the issue. My JSON
request was originally <span
style="font-family:monospace">{"method":"widgets"}</span>,
but it needed to be <span style="font-family:monospace">{"method":"widgets","params":[],"id":1}</span></font>.</span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">Making the appropriate change and
also updating the XMLHttpRequest url to "/webcomic/rpc"
solved the issue 100%!</font></span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif"><br>
</font></span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">Whew! Thank you very much for your
help on this, Jon! I am DEEPLY grateful for all of this!</font></span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif"><br>
</font></span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">Sincerely,</font></span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">VarstrayPl.<br>
</font></span></div>
</div>
<br>
<div class="gmail_quote">
<div dir="ltr" class="gmail_attr">On Mon, Nov 9, 2020 at 1:52 PM
Jon Foster <<a moz-do-not-send="true"
href="mailto:jon...@jf...">jon...@jf...</a>>
wrote:<br>
</div>
<blockquote class="gmail_quote" style="margin:0px 0px 0px
0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
<div bgcolor="#FFFFFF">
<p>Glad to hear it. I've never actually used the C++CMS JSON
RPC server class because the docs leave too much unsaid,
making it far simpler to write my own handler. I think you
might have to dig through the source to see what its
actually doing. I put together a test environment made
from the "clippings" you sent along and I'm not sure I
made it as far as you did. :-) What I'm seeing is the call
dying in the CORS authentication phase (OPTIONS req) my
C++CMS app failing to respond with the appropriate
"allowed" response, in fact it says nothing and FF just
drops the request.</p>
<p>"CORS" is fairly recent pseudo-security feature. Its
possible that C++CMS is not prepared for it and a simple
extension to the JSON RPC server class may be needed. But
I could be getting ahead of myself.</p>
<p>The primary thing you need to do is fire up your
browser's "dev tools". The "console" section will allow
you to call your javascript function, to manually trigger
requests to the server side. It should also log the
requests and responses made to your server. All XHR
requests should come in two phases the "OPTIONS" request
to ask the server for permission, followed by the actual
JSON request you made, which would be a "POST"
transaction. Check the request and response to make sure
your getting what you expect. Often times what you see
there will reveal the issue.</p>
<p>I don't know your experience level so this page from MDN
might be useful in understanding CORS: <a
moz-do-not-send="true"
href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS"
target="_blank">https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS</a></p>
<p>Anyhow I have client needs to attend to or I'd drill the
rest of the way down. Use your browser's debugger and
sprinkle "std::cerr << ..." stuff liberally in your
server side code to get a picture of what its doing. On my
setup I can call the RPC url with a generic client
(browser, wget, curl, ...) and get "invalid content type"
so I know the request is getting dispatched to the RPC
handler. Yet an override of main() fails to show an URL
hit the application so the call must be getting blocked
further up in the class. maybe init()? Or I fat-fingered
something? Like I said I'd have to drill down on the
source to figure out what its up to.</p>
<p>I'll try to help out as I can.</p>
<p>- Jon<br>
</p>
<br>
<div>On 11/09/2020 09:29 AM, Varstray Pl wrote:<br>
</div>
<blockquote type="cite">
<div dir="ltr">
<div>Ah! Ok. So this is actually very helpful!</div>
<div><br>
</div>
<div>I've decided to go with mounting the rpc server in
the webcomic's url space using the attach method you
described above. The code for my webcomic page
constructor is as follows:</div>
<div>* * *<br>
</div>
<div><span style="font-family:monospace">webcomic::webcomic(cppcms::service
&srv) : cppcms::application(srv){<br>
attach(new json_service(srv), "rpc", "/rpc{1}",
"/rpc(/(.*))?", 1);</span></div>
<div><span style="font-family:monospace"> //.. various
dispatcher and mapper calls.<br>
</span></div>
<div><span style="font-family:monospace">};</span></div>
<div><span style="font-family:monospace">***<br>
</span></div>
<div><span style="font-family:monospace"><font
face="arial,sans-serif">The browser now appears to
be successfully calling the rpc server! Yay!
Unfortunately (there's always an unfortunately,
isn't there? xD), I think I haven't set up the
handling of the rpc request properly within the
server, because instead of a proper response, the
widgets panel is simply filled with the text
"Invalid JSON-RPC"</font>. <span
style="font-family:arial,sans-serif">I'm not sure
where in the pipeline things are going wrong, but
here is how I've set up the rpc server. Maybe you
can see what I'm doing wrong?</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">First, the
basic class definition:</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *</span></span></div>
<div><span style="font-family:monospace">class
json_service: public cppcms::rpc::json_rpc_server{<br>
public:<br>
json_service(cppcms::service &srv);<br>
<br>
// Ajax Methods<br>
void widgets();<br>
};</span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">And then the
implementation of the server constructor and the
widgets method:</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *</span></span></div>
<div><span style="font-family:monospace">json_service::json_service(cppcms::service
&srv) : cppcms::rpc::json_rpc_server(srv)<br>
{<br>
bind("widgets",
cppcms::rpc::json_method(&json_service::widgets,
this),method_role);<br>
}<br>
<br>
void json_service::widgets()<br>
{<br>
return_result("widgets via AJAX-RPC!!! Cool!");<br>
}</span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">Finally, this
is how the request is set up on the client side
via javascript:</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><span
style="font-family:monospace">function
getWidgets() { <br>
var xhr = new XMLHttpRequest(); <br>
xhr.open("post", '/rpc');<br>
<br>
// Required by JSON-RPC over HTTP <br>
xhr.setRequestHeader("Content-Type","application/json");<br>
<br>
// Configure JSON-RPC request.<br>
var request = '{"method":"widgets"}';<br>
<br>
// Define our callback function.<br>
xhr.onreadystatechange = function(){<br>
if (xhr.readyState === 4){<br>
var response;<br>
<br>
if (xhr.status === 200){<br>
response = xhr.responseText;<br>
} else {<br>
response = 'Invalid Status: ' + xhr.status;<br>
}<br>
<br>
document.getElementById('widgets').innerHTML =
response;<br>
}<br>
}<br>
<br>
xhr.send(request);<br>
return false;<br>
} </span><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *<br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">The
javascript method is pretty much taken from the
json-rpc tutorial on the <a
moz-do-not-send="true" href="http://cppcms.com"
target="_blank">cppcms.com</a> website. Although
because this method doesn't take any
parameters(yet), I *think* perhaps the issue lies
somewhere in the modifications I made for sending
a request for a non-parameter method, whereas the
tutorial method does take parameters. Also, up
till this point, diagnostic information on stderr
and stdout has been very helpful, but now there
doesn't appear to be any stderr output at all,
lol.</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">I *can*
verify that on the browser end the rpc call is
actually being sent to the rpc server, and because
'Invalid RPC-JSON' is different from 'Invalid
Status: bla bla', I think that the getWidgets()
method is actually getting a proper response from
the rpc server. It's just clearly there's
something else going wrong somewhere.</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">* * *</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif">Thank you for
your help, Jon, and sorry for any additional
trouble. I'll also keep searching on my end for an
answer as well. ^^;<br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"><br>
</span></span></div>
<div><span style="font-family:monospace"><span
style="font-family:arial,sans-serif"></span><br>
</span></div>
</div>
<br>
<fieldset></fieldset>
<br>
<br>
<fieldset></fieldset>
<br>
<pre>_______________________________________________
Cppcms-users mailing list
<a moz-do-not-send="true" href="mailto:Cpp...@li..." target="_blank">Cpp...@li...</a>
<a moz-do-not-send="true" href="https://lists.sourceforge.net/lists/listinfo/cppcms-users" target="_blank">https://lists.sourceforge.net/lists/listinfo/cppcms-users</a>
</pre>
</blockquote>
<br>
<pre cols="75">--
Sent from my Devuan Linux workstation -- <a moz-do-not-send="true" href="https://devuan.org/" target="_blank">https://devuan.org/</a>
"Init Freedom", Yeah!
Jon Foster
JF Possibilities, Inc.
<a moz-do-not-send="true" href="mailto:jo...@jf..." target="_blank">jo...@jf...</a>
</pre>
</div>
_______________________________________________<br>
Cppcms-users mailing list<br>
<a moz-do-not-send="true"
href="mailto:Cpp...@li..."
target="_blank">Cpp...@li...</a><br>
<a moz-do-not-send="true"
href="https://lists.sourceforge.net/lists/listinfo/cppcms-users"
rel="noreferrer" target="_blank">https://lists.sourceforge.net/lists/listinfo/cppcms-users</a><br>
</blockquote>
</div>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<br>
<fieldset class="mimeAttachmentHeader"></fieldset>
<br>
<pre wrap="">_______________________________________________
Cppcms-users mailing list
<a class="moz-txt-link-abbreviated" href="mailto:Cpp...@li...">Cpp...@li...</a>
<a class="moz-txt-link-freetext" href="https://lists.sourceforge.net/lists/listinfo/cppcms-users">https://lists.sourceforge.net/lists/listinfo/cppcms-users</a>
</pre>
</blockquote>
<br>
<pre class="moz-signature" cols="75">--
Sent from my Devuan Linux workstation -- <a class="moz-txt-link-freetext" href="https://devuan.org/">https://devuan.org/</a>
"Init Freedom", Yeah!
Jon Foster
JF Possibilities, Inc.
<a class="moz-txt-link-abbreviated" href="mailto:jo...@jf...">jo...@jf...</a>
</pre>
</body>
</html>
|