Thread: [Cppcms-users] JSON-RPC dispatching together with Normal Web Page
Brought to you by:
artyom-beilis
|
From: Varstray Pl <var...@gm...> - 2020-11-05 14:00:49
|
I am setting up a basic webcomic site which uses a class:
class webcomic : cppcms::application { /*...*/ };
for delivering the webcomic functionality, and a class:
class json_service : public cppcms::rpc::json_rpc_server { /*...*/ };
to deliver additional widget based content in a widgets panel. But now I
can't figure out how to properly dispatch the '/rpc' call that is supposed
to be sent to the rpc server in my overloaded webcomic::main function.
The source code for the implementing chat using json-rpc was... somewhat
helpful, but also confusing, as I couldn't see any other class in there
that inherited from cppcms::application. I'm kind of at a loss for how to
do this.
Please help me. And thank you for your time.
|
|
From: Jon F. <jon...@jf...> - 2020-11-08 22:11:53
|
I feel like I'm missing a piece of the picture but I'll give it a go:
Typically to mount an application in the URL space you do something like
this in the program's main():
cppcms::service srv(argc,argv);
srv.applications_pool().mount(
cppcms::create_pool<rpc_app_class>(),
cppcms::mount_point("/rpc")
);
Or you can mount it in another applications URL space with attach() like
this inside a cppcms::application constructor:
attach( new rpc_app_class(s),
"rpc",
"/rpc{1}",
"/rpc((/.*)?)",1);
And technically you can use dispatcher() and mapper() directly to dispatch
from one app class to another. Just create the additional app object in the
constructor of a parent app object. Then map/dispatch in the traditional
way, but supply the child object to dispatcher. Something like this in the
parent's (app1) constructor:
mapper().assign("rpc", "/rpc");
dispatcher().assign("/rpc", &app2_child::handler, app2);
Obviously the app2 object has to be constructed as a member of app1 in the
usual manner. And don't forget to make sure the object gets destroyed too.
Lastly you can call one app from another through the top most
application::main(). You would need to construct the child app yourself, as
above. But since main() gets the URL you can customize the URL handling to
dispatch the call however you see fit.
I'm sure this is "clear as mud". So ask questions and provide more detail
and I'll see if I can't lend a hand.
- Jon
On 11/05/2020 06:00 AM, Varstray Pl wrote:
> I am setting up a basic webcomic site which uses a class:
>
> class webcomic : cppcms::application { /*...*/ };
>
> for delivering the webcomic functionality, and a class:
>
> class json_service : public cppcms::rpc::json_rpc_server { /*...*/ };
>
> to deliver additional widget based content in a widgets panel. But now I
> can't figure out how to properly dispatch the '/rpc' call that is
> supposed to be sent to the rpc server in my overloaded webcomic::main
> function.
>
> The source code for the implementing chat using json-rpc was... somewhat
> helpful, but also confusing, as I couldn't see any other class in there
> that inherited from cppcms::application. I'm kind of at a loss for how to
> do this.
>
> Please help me. And thank you for your time.
>
>
>
>
> _______________________________________________
> Cppcms-users mailing list
> Cpp...@li...
> https://lists.sourceforge.net/lists/listinfo/cppcms-users
--
Sent from my Devuan Linux workstation -- https://devuan.org/
"Init Freedom", Yeah!
Jon Foster
JF Possibilities, Inc.
jo...@jf...
|
|
From: Varstray Pl <var...@gm...> - 2020-11-09 17:29:43
|
Ah! Ok. So this is actually very helpful!
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:
* * *
webcomic::webcomic(cppcms::service &srv) : cppcms::application(srv){
attach(new json_service(srv), "rpc", "/rpc{1}", "/rpc(/(.*))?", 1);
//.. various dispatcher and mapper calls.
};
***
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". 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?
First, the basic class definition:
* * *
class json_service: public cppcms::rpc::json_rpc_server{
public:
json_service(cppcms::service &srv);
// Ajax Methods
void widgets();
};
* * *
And then the implementation of the server constructor and the widgets
method:
* * *
json_service::json_service(cppcms::service &srv) :
cppcms::rpc::json_rpc_server(srv)
{
bind("widgets", cppcms::rpc::json_method(&json_service::widgets,
this),method_role);
}
void json_service::widgets()
{
return_result("widgets via AJAX-RPC!!! Cool!");
}
* * *
Finally, this is how the request is set up on the client side via
javascript:
* * *
function getWidgets() {
var xhr = new XMLHttpRequest();
xhr.open("post", '/rpc');
// Required by JSON-RPC over HTTP
xhr.setRequestHeader("Content-Type","application/json");
// Configure JSON-RPC request.
var request = '{"method":"widgets"}';
// Define our callback function.
xhr.onreadystatechange = function(){
if (xhr.readyState === 4){
var response;
if (xhr.status === 200){
response = xhr.responseText;
} else {
response = 'Invalid Status: ' + xhr.status;
}
document.getElementById('widgets').innerHTML = response;
}
}
xhr.send(request);
return false;
}
* * *
The javascript method is pretty much taken from the json-rpc tutorial on
the cppcms.com 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.
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.
* * *
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. ^^;
|
|
From: Jon F. <jon...@jf...> - 2020-11-09 19:51:40
|
<html>
<head>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
</head>
<body bgcolor="#FFFFFF" text="#000000">
<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 class="moz-txt-link-freetext" href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">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 class="moz-cite-prefix">On 11/09/2020 09:29 AM, Varstray Pl
wrote:<br>
</div>
<blockquote
cite="mid:CAN...@ma..."
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">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 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>
|
|
From: Varstray Pl <var...@gm...> - 2020-11-10 22:32:41
|
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 "http:localhost:8080/webcomic/rpc"
.
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
"http:localhost:8080/webcomic/http:localhost:8080/webcomic/rpc". 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.
A quick bash command:
for fd in `ls $SRCDIR`; do echo "In file: $fd" ; cat ./$fd | grep -e
"JSON-RPC" ; done
Revealed:
In file: rpc_json.cpp
throw call_error("Invalid JSON-RPC");
BOOSTER_DEBUG("cppcms") << "JSON-RPC Method call:" << method();
throw cppcms_error("JSON-RPC Request is not assigned to class");
Which led me to this snippet of code in rpc_json.cpp:
if( request.type("method")!=json::is_string
|| request.type("params")!=json::is_array
|| request.type("id")==json::is_undefined)
{
throw call_error("Invalid JSON-RPC");
}
Boom. That was the issue. My JSON request was originally
{"method":"widgets"}, but it needed to be
{"method":"widgets","params":[],"id":1}.
Making the appropriate change and also updating the XMLHttpRequest url to
"/webcomic/rpc" solved the issue 100%!
Whew! Thank you very much for your help on this, Jon! I am DEEPLY grateful
for all of this!
Sincerely,
VarstrayPl.
On Mon, Nov 9, 2020 at 1:52 PM Jon Foster <jon...@jf...>
wrote:
> 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.
>
> "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.
>
> 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.
>
> I don't know your experience level so this page from MDN might be useful
> in understanding CORS:
> https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
>
> 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.
>
> I'll try to help out as I can.
>
> - Jon
>
> On 11/09/2020 09:29 AM, Varstray Pl wrote:
>
> Ah! Ok. So this is actually very helpful!
>
> 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:
> * * *
> webcomic::webcomic(cppcms::service &srv) : cppcms::application(srv){
> attach(new json_service(srv), "rpc", "/rpc{1}", "/rpc(/(.*))?", 1);
> //.. various dispatcher and mapper calls.
> };
> ***
> 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". 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?
>
> First, the basic class definition:
> * * *
> class json_service: public cppcms::rpc::json_rpc_server{
> public:
> json_service(cppcms::service &srv);
>
> // Ajax Methods
> void widgets();
> };
> * * *
>
> And then the implementation of the server constructor and the widgets
> method:
> * * *
> json_service::json_service(cppcms::service &srv) :
> cppcms::rpc::json_rpc_server(srv)
> {
> bind("widgets", cppcms::rpc::json_method(&json_service::widgets,
> this),method_role);
> }
>
> void json_service::widgets()
> {
> return_result("widgets via AJAX-RPC!!! Cool!");
> }
> * * *
>
> Finally, this is how the request is set up on the client side via
> javascript:
> * * *
> function getWidgets() {
> var xhr = new XMLHttpRequest();
> xhr.open("post", '/rpc');
>
> // Required by JSON-RPC over HTTP
> xhr.setRequestHeader("Content-Type","application/json");
>
> // Configure JSON-RPC request.
> var request = '{"method":"widgets"}';
>
> // Define our callback function.
> xhr.onreadystatechange = function(){
> if (xhr.readyState === 4){
> var response;
>
> if (xhr.status === 200){
> response = xhr.responseText;
> } else {
> response = 'Invalid Status: ' + xhr.status;
> }
>
> document.getElementById('widgets').innerHTML = response;
> }
> }
>
> xhr.send(request);
> return false;
> }
> * * *
> The javascript method is pretty much taken from the json-rpc tutorial on
> the cppcms.com 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.
>
> 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.
> * * *
>
> 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. ^^;
>
>
>
>
>
>
> _______________________________________________
> Cppcms-users mailing lis...@li...://lists.sourceforge.net/lists/listinfo/cppcms-users
>
>
> --
> Sent from my Devuan Linux workstation -- https://devuan.org/
> "Init Freedom", Yeah!
>
> Jon Foster
> JF Possibilities, In...@jf...
>
> _______________________________________________
> Cppcms-users mailing list
> Cpp...@li...
> https://lists.sourceforge.net/lists/listinfo/cppcms-users
>
|
|
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>
|