Ajax/jQuery-like page loading from C++

453 views
Skip to first unread message

Aleksandar Stančić

unread,
Nov 13, 2014, 3:58:58 AM11/13/14
to emscripte...@googlegroups.com
Hi! I'm writing a game in C++/OGL (to be published on the web through Emscripten) that needs some interaction with a server, written in PHP/MySQL. I already prepared the database and PHP code, and now, the surprisingly difficult part is connecting the two. Is there a simple way of loading a web page with a few POST strings in C++/Emscripten? Two-to-three strings go in (POST) and I need to read one string or integer on the output (HTTP response). emscripten_wget just hangs on me, and mixing JS + C++ seems to be able to transfer only numbers (ASM). Can someone point me in the right direction? I feel like I'm missing something obvious, and I wouldn't really know, since I'm not much of a web developer. Thanks.

Just to clarify, I have a PHP page like this:

$a = $_POST['a']  // a and b need to come from C++
$b
= $_POST['b']



// do stuff with $a & $b


echo
($c)  // a string, under 100 regular ASCII chars, nothing special

So, I need to do a HTTP POST request (I can switch to GET if that'll make things easier), and read a single line of text back into C++.  What would be a good way of doing that? I hate to be that guy, but it is kind urgent (I really wrote myself into a corner with this one, I expected this to be easy), so any tips are greatly appreciated.

Sergey Kurdakov

unread,
Nov 13, 2014, 5:24:15 AM11/13/14
to emscripte...@googlegroups.com
Hi Alexandar.

won't emscripten_async_wget serve your needs? it sends requests to server and params can adjast which type of request is sent.

Regards
Sergey

--
You received this message because you are subscribed to the Google Groups "emscripten-discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sergey Kurdakov

unread,
Nov 13, 2014, 5:36:36 AM11/13/14
to emscripte...@googlegroups.com
Hi Alexandar,


>won't emscripten_async_wget serve your needs?

I mean set of functions

emscripten_async_wget
emscripten_async_wget2
emscripten_async_wget_data
emscripten_async_wget2_data

Regards
Sergey

Aleksandar Stančić

unread,
Nov 13, 2014, 6:12:47 AM11/13/14
to emscripte...@googlegroups.com
Ok, I tried the "sync" version before, and even when it didn't hang, I didn't know where to find the data. I don't really need the virtual file system, so the "data" versions seem like the thing for me. I'll wrap it a bit to make it synchronous. Some examples in the API documentation would go a long way towards understanding it, imho. I'll be sure to report back mine, if it works out.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Aleksandar Stančić

unread,
Nov 14, 2014, 1:59:55 PM11/14/14
to emscripte...@googlegroups.com
I tried this now, but it's alway giving me an error, no matter what I try to download:

char _lastResponse[1024] = { '\0' };
int _wgetLock = 0;
bool _success = false;

void _net_ems_onload(void * arg, void * data, int size)
{
if(size > 1023) size = 1023;

RLog("EMS in onload callback, got response, size = %d", size);

memcpy(_lastResponse, data, size);
_lastResponse[size] = '\0';
_success = true;
_wgetLock = 0;
}

void _net_ems_onerror(void * arg)
{
RLog("EMS onerror callback :(");
_success = false;
_wgetLock = 0;
}

bool net_httpGet(const char * page,
const char * key1, const char * val1,
const char * key2, const char * val2,
const char * key3, const char * val3,
char * response)
{
if(page == NULL) return false;

RLog("EMS httpGet entry, target = \"%s\"", page);

//while(_wgetLock) { cu_sleep(100); }

RLog("EMS Lock passed, pausing main loop");

_wgetLock = 1;
emscripten_pause_main_loop();

char request[1024] = { 0 };
memset(_lastResponse, 0, 1024);

strcpy(request, page);

RLog("EMS Preparing request");

if(key1 != NULL && key2 != NULL)
{
strcat(request, "?");
strcat(request, key1);
strcat(request, "=");
strcat(request, val1);

if(key2 != NULL && val2 != NULL)
{
strcat(request, "&");
strcat(request, key2);
strcat(request, "=");
strcat(request, val2);

if(key3 != NULL && val3 != NULL)
{
strcat(request, "&");
strcat(request, key3);
strcat(request, "=");
strcat(request, val3);
}
}
}

//strcpy(request, "http://www.google.com");

_success = false;

RLog("EMS Full request = \"%s\"", request);
RLog("EMS Starting async wget...");

emscripten_async_wget_data(request, NULL, _net_ems_onload, _net_ems_onerror);

RLog("EMS Waiting for async wget to complete...");

while(_wgetLock) { cu_sleep(100); }

RLog("EMS Async complete! Resuming main loop");

emscripten_resume_main_loop();

if(_success)
{
RLog("EMS Success! Response : \"%s\"", _lastResponse);
strcpy(response, _lastResponse);
return true;
}
else
{
RLog("EMS Fail :(");
return false;
}
}

Pardon the not-so-elegant construction of GET request, but that at least isn't the problem, I checked generated requests manually and they work in a browser or in terminal using the real wget. Am I doing something wrong here? And btw, cu_sleep is just my multi-platform wrap of sleep functions, it resolves to nanosleep(). Is there a better way of waiting for async request to complete? I need this net_httpGet function to effectively be blocking, to wait and return when the request is complete. I tried no waiting, this function returns false immediately, but still, only error callback gets called afterwards, always, and I don't see any way of finding out exactly what kind of error occured. Also, RLog is just my logging system, same signature as printf.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Aleksandar Stančić

unread,
Nov 14, 2014, 2:43:14 PM11/14/14
to emscripte...@googlegroups.com
I tried wget2_data now and it still doesn't work. It seems it isn't even trying to download the file, it's not HTTP related, as with v2 I immediately get onerror callback and error code is 0, and my error message is NULL, so I still have no clue what is going on. I am relatively new to Emscripten, so I might be missing something. Do I need some special settings for compiler and/or linker to make this work? Anything browser-related? I tested on latest Firefox and Chrome on Linux, same thing every time.
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsub...@googlegroups.com.

Sergey Kurdakov

unread,
Nov 14, 2014, 3:08:30 PM11/14/14
to emscripte...@googlegroups.com
Hi Alexandar,

as it was me, who advised - emscripent_wget - if you try to search code is done around async xmlhttprequest , it works just fine if it is used in async way.

if you want how to make things, there is an engine https://github.com/floooh/oryol which implements IQ queues such that after you got response it is stored and on next tick you can get if from IO queue 

it is possible to make things sync, but that requires deeper knowledge of internals so most probably you will fail with that.

thus my suggestion - to keep things async as if you used pure
xmlhttprequest

Regards
Sergey



To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

Aleksandar Stančić

unread,
Nov 14, 2014, 4:03:31 PM11/14/14
to emscripte...@googlegroups.com
The thing is, even when I comment out my "sync" code that makes the game wait, it still doesn't work. Without pausing the main loop and without sleep calls, my net_httpGet function returns false immediately, but the game still runs, and callback happens a bit later, but it's always status 0 and message is NULL, so I don't know what's wrong. Under what conditions does this happen? 

Ok, I searched through Emscripten source, and by modifying it a bit, I located where the call happens:
emscripten_async_wget2_data: function(url, request, param, arg, free, onload, onerror, onprogress) {
  var _url = Pointer_stringify(url);
  var _request = Pointer_stringify(request);
  var _param = Pointer_stringify(param);

  var http = new XMLHttpRequest();
  http.open(_request, _url, true);
  http.responseType = 'arraybuffer';

  var handle = Browser.getNextWgetRequestHandle();

  // LOAD
  http.onload = function http_onload(e) {
    if (http.status == 200 || _url.substr(0,4).toLowerCase() != "http") {
      var byteArray = new Uint8Array(http.response);
      var buffer = _malloc(byteArray.length);
      HEAPU8.set(byteArray, buffer);
      if (onload) Runtime.dynCall('viiii', onload, [handle, arg, buffer, byteArray.length]);
      if (free) _free(buffer);
    } else {
      if (onerror) Runtime.dynCall('viiii', onerror, [handle, arg, http.status, http.statusText]);
    }
    delete Browser.wgetRequests[handle];
  };

  // ERROR
  http.onerror = function http_onerror(e) {
    if (onerror) {
      Runtime.dynCall('viiii', onerror, [handle, arg, http.status, http.statusText]);  <--- HERE!
    }
    delete Browser.wgetRequests[handle];
  };

  // PROGRESS
  http.onprogress = function http_onprogress(e) {
    if (onprogress) Runtime.dynCall('viiii', onprogress, [handle, arg, e.loaded, e.lengthComputable || e.lengthComputable === undefined ? e.total : 0]);
  };

  // ABORT
  http.onabort = function http_onabort(e) {
    delete Browser.wgetRequests[handle];
  };

  // Useful because the browser can limit the number of redirection
  try {
    if (http.channel instanceof Ci.nsIHttpChannel)
    http.channel.redirectionLimit = 0;
  } catch (ex) { /* whatever */ }

  if (_request == "POST") {
    //Send the proper header information along with the request
    http.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
    http.setRequestHeader("Content-length", _param.length);
    http.setRequestHeader("Connection", "close");
    http.send(_param);
  } else {
    http.send(null);
  }

  Browser.wgetRequests[handle] = http;

  return handle;
},

So, it's being called as XMLHttpRequest onerror handler, but it gives me zero as status and no message. At least I know now that it isn't in the onload() call if HTTP status is different than 200 or the URL doesn't start with http. But still - why? What makes this XMLHttp request fail in such a way?
To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-discuss+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Sergey Kurdakov

unread,
Nov 14, 2014, 4:53:02 PM11/14/14
to emscripte...@googlegroups.com
Hi Alexandar,

I'm sorry, I hardly see reasons, so would like others to help here.

but as you might see - it is already not an emscripten problem, but a problem between  XMLHttpRequest

request from client and your server part. So you might write a simple test case in javascript to make things work with your php part ( I never returned anything xml from server though, except for files, so again -I'm sorry - let anyone else shed some light here, maybe a problem is in misconfiguration between what you send and what you receive ).

Regards
Sergey

To unsubscribe from this group and stop receiving emails from it, send an email to emscripten-disc...@googlegroups.com.

asnapper

unread,
Jan 14, 2015, 9:37:40 AM1/14/15
to emscripte...@googlegroups.com
Just a wild guess, but did you consider CORS restrictions?

Aleksandar Stančić

unread,
Jan 14, 2015, 9:45:25 PM1/14/15
to emscripte...@googlegroups.com
Your guess would be right :) I was meaning to report back, just in case someone else stumbles upon this. It was indeed the problem with such restrictions. The thing is, I was aware of those restrictions and I did some "testing", somehow figured out that wasn't the problem, and proceeded to look for bugs in all the wrong places. I moved to async methods anyways and when I finally came back around to this and figured out it was probably domain and access control issue all along, I slapped myself on the forehead really hard. It all works as advertised now, it was just me completely missing the obvious.

--
You received this message because you are subscribed to a topic in the Google Groups "emscripten-discuss" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/emscripten-discuss/x1k3yNOBjco/unsubscribe.
To unsubscribe from this group and all its topics, send an email to emscripten-disc...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages