when I refresh chrome ripple for the first page, I get these error messages in the console log :
1. "Uncaught SyntaxError: Unexpected token u"
2. GET http://local.drupalgap5.fr/cordova.js 404 (Not Found)
3. "extension.onRequest: Cannot send a response more than once per chrome.extension.onRequest listener per document (message was sent by extensionhlngmmdolgbdnnimbmblfhhndibdipaf for URL undefined). "

For the login page after trying to connect, I get this alert message :
"parsererror (SyntaxError: Unexpected token <) [OK][undefined]"

Do you have any ideas ?

I installed phonegap2.9 and the last version of drupalgap mobile application development kit, enabled module services 3.5 (the last spync.php). I don't see why it doesn't work. Have you any ideas ?

Thanks for your help,
Regards,
Yoann

Comments

tyler.frankenstein’s picture

Title: Chrome Ripple - Unexpected token - Login » Chrome Ripple - Login Problems
Status: Active » Needs review

I've seen the 'unexpected token u' warning multiple times, it is un related to DrupalGap (I think). I'm fairly certain it is jQuery, jQueryMobile, or the cordova javascript provided by Ripple that throws that error/warning.

Regarding the missing cordova.js file, make sure you are using the ripple.index.html contents for your index.html file. You may have to clear Chrome's cache to get this one to go away. It sounds like your browser is still trying to refer to a file that it doesn't need (since Ripple automatically loads the cordova files into the environment).

The "parsererror (SyntaxError: Unexpected token <) [OK][undefined]" is almost certainly a syntax error somewhere in your custom code (settings.js, custom module, or theme).

There are other known issues with user authentication (login) with Chrome:

It most likely is due to some cross browser scripting restrictions in place in Chrome for security, but I haven't quite figured it out yet. Refer to @cschaub for better help on this, he's been able to successfully get user authentication working in Chrome. More info available in the links above.

yoannl’s picture

I got the origin of my problem :
"parsererror (SyntaxError: Unexpected token <) [OK][undefined]"

It comes from the authcache module which adds footer messages to some AJAX requests. So some ajax jquery don't succeed to parse the answer and we get a parserror message.

The code which adds this footer is located in the authcache.helpers.inc file from authcache module beginning at the line 288 :
// JSON to send via Ajax
// The "q" key is need during Ajax phase
$authcache_ajax = array(
'q' => $_GET['q'],
);

// Invoke hook_authcache_info() operation to allow modules to modify info array
_authcache_invoke_hook('authcache_info', $_authcache_info);

// Invoke hook_authcache() operation to allow modules to modify ajax array
_authcache_invoke_hook('authcache_ajax', $authcache_ajax);

// Get buffered HTML
$buffer = ob_get_contents();

if (substr($buffer, 0, 5) == '<?xml') {
$is_cached_nonhtml = TRUE; // don't append JS to XML pages
}

// Add JS for debug mode?
if ((variable_get('authcache_debug_all', FALSE)
|| ($user->uid && ($debug_users = variable_get('authcache_debug_users', array()))))
&& !$is_cached_nonhtml
) {
$js = '

if (!Authcache) Authcache = {}; Authcache.info = ' . drupal_json_encode($_authcache_info) .'

';

// Insert JSON before , otherwise just append
if (strripos($buffer, '') !== FALSE) {
$buffer = str_replace('', $js . '', $buffer);
}
else {
$buffer .= $js;
}

$js = $_GET;
print $js; //since by this point the drupal page has already been sent to the browser
// Also see authcache_authcache_info() for user debug settings
drupal_add_js($js, array('type' => 'inline', 'scope' => 'header'));

I don't have yet the good correction but the origin fo my problem.

tyler.frankenstein’s picture

Status: Needs review » Closed (works as designed)

I'm glad you found the problem. You are correct, some modules may interfere with JSON output, which in turns will cause syntax errors in DrupalGap. I'd now recommend taking this issue up with the authcache module.

yoannl’s picture

Status: Closed (works as designed) » Needs review

I just added this code

if (strpos($_GET['q'], 'drupalgap') !== false) {
$is_cached_nonhtml = TRUE; // don't append JS to drupalgap ajax requests
}

after

if (substr($buffer, 0, 5) == '<?xml') {
$is_cached_nonhtml = TRUE; // don't append JS to XML pages
}

and my problem is removed to login via drupalgap

I check now the other requests ...

Regards,
Yoann

jentle07’s picture

I just found this with the very first titled problem. and saw #4 solution and tried it with successful login on "mobile.Mysite.com//index.html?enableripple=cordova-2.9.0"

But when I tried to logout, I cannot get out with the following message;

error (Not Acceptable) [User is not logged in.][undefined] drupalgap

and upon clicking home link on upperleft directs me to the home page with MY Account and Logout link on top under Dashboard.

Wondering what to do...???!!! as I am newbie with absoultely no knowledge with code or anything except copying and pasting from discussion boards like this.

tyler.frankenstein’s picture

Status: Needs review » Postponed

This is a known problem with DrupalGap running in Ripple. After logging in, the user doesn't stay logged in. Refer to these issues on GitHub for more information:

https://github.com/signalpoint/DrupalGap/issues/12
https://github.com/signalpoint/DrupalGap/issues/51

Once the above issues are resolved on GitHub, this issue should be closed.

yoannl’s picture

I continue to look for a solution to avoid the message [User is not logged in] when we log out with Ripple.
After reading the issues on Github and information from others sites, I understand the problem come from the fact no cookies are sent via Ripple to our drupal website. Even if a session has been created during the login process, drupal needs to receive the token CRSF and {session_name : sessid } in a cookie to allow us to logout because it will identify correctly.

On solution could be to add xhr.setRequestHeader("Cookie", cookie) in our ajax command :
$.ajax({
url:url_logout,
type:"post",
dataType:"json",
beforeSend: function (xhr){
xhr.setRequestHeader("X-CSRF-Token", token);
xhr.setRequestHeader("Cookie", cookie);
},
...

but all browser forbids that as explained here :
http://stackoverflow.com/questions/15198231/why-cookies-and-set-cookie-h...

Developpers from node.js use a library which allow them to emulate the browser and disable the header check :
https://github.com/LearnBoost/socket.io-client/pull/512
https://github.com/driverdan/node-XMLHttpRequest

I am not an expert in node.js so ... if you know an other solution...

Regards,
Yoann

tyler.frankenstein’s picture

Status: Postponed » Needs work

Thank you for this additional information, this is very helpful.

If I understand your research correctly, then it sounds like we need to adjust the DrupalGap Ajax API caller function to set the cookie in the request header (if the client is using ripple). The DG API function is located here: https://github.com/signalpoint/DrupalGap/blob/7.x-1.x-alpha/modules/api/...

There is more information about the cookie here: https://drupal.org/node/2013781

Then after that, maybe if we use the --disable-web-security option when launching Chrome the user authentication will work.

(On a side note, remember to never be logged into the Drupal site in Chrome when using Ripple. Also, I haven't used node.js yet.)

yoannl’s picture

Yes if we succeed to send a cookie from the client using ripple to the drupal site server, then the opened session during the login request will become available to the client. I tried again to send cookies without success at the moment.

Maybe an other solution could be enough for tests with ripple :

In the drupalgap.resource.inc, I created 2 functions :
function check_ripple_login() {

if ((isset($_POST['ripple']))||(isset($_GET['ripple']))) {
//new login because logins don't work ! Thinks to remove sessions added each time
module_load_include('inc', 'services', 'resources/user_resource');
$username = $_POST['username'];
$password = $_POST['password'];
$results['_user_resource_login'] = _user_resource_login($username, $password);

// If the user login was successful, make a call to the drupalgap system
// connect resource.
if ($results['_user_resource_login']) {
$results['drupalgap_system_connect'] = _drupalgap_resource_system_connect();
}
}
}

function check_ripple_logout() {

if ((isset($_POST['ripple']))||(isset($_GET['ripple']))) {
//Make a call to the user login resource.
module_load_include('inc', 'services', 'resources/user_resource');
$results['_user_resource_logout'] = _user_resource_logout();

// If the user logout was successful, make a call to the drupalgap system
// connect resource.
if ($results['_user_resource_logout']) {
$results['drupalgap_system_connect'] = _drupalgap_resource_system_connect();
}
}
}

Before making a call to the user login resource in the _drupalgap_resource_user_logout, I added check_ripple_login() :
function _drupalgap_resource_user_logout() {
$results = array();

global $user;

check_ripple_login();

//Make a call to the user login resource.
module_load_include('inc', 'services', 'resources/user_resource');
$results['_user_resource_logout'] = _user_resource_logout();

// If the user logout was successful, make a call to the drupalgap system
// connect resource.
if ($results['_user_resource_logout']) {
$results['drupalgap_system_connect'] = _drupalgap_resource_system_connect();
}

// $env['results'] = $results;
return $results;
}

In the js file on the client, I modified the logout process like this :
// Global Variables at the beginning of the file
var ripple = 'true'
...
// In the logout function :
...
var settings = {
url:url_logout,
type:"post",
dataType:"json",
beforeSend: function (xhr){
xhr.setRequestHeader("X-CSRF-Token", token);
},
error:function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
},
success: function (result) {
my stuff to do ...
}
};

if (ripple == 'true') {
settings.data = {
ripple: 'true',
username: ...yours,
password: ...yours
};
}

$.ajax(settings);

It allows me to test properly all drupalgap functions without altering the futur mobile application.
I can use check_ripple_login and check_ripple_logout in the other drupalgap ajax functions to emulate the current session without using cookies process. But Is means that I have a session on my drupal site server which is still available the can be killed on our test environment. You can kill it manually via interfaces ou directly database. Not to forget ...

It's not the best solution but let us test properly without altering the final mobile application, for which the session process (login, logout, token, ...) works.

Regards,
Yoann

yoannl’s picture

I get it ! It works now after some hours working around ...

Here is my configuration with Ripple or just chrome :

My local drupal server site : http://mysite.com
My local application mobile site : http://app.mysite.com

They are configured in the hosts file :
127.0.0.1 mysite.com
127.0.0.1 app.mysite.com

They are configured in the httpd-vhosts.txt on windows :

DocumentRoot "c:/wamp/www/drupal-7.22/"
ServerName mysite.com


DocumentRoot "c:/wamp/www/phonegap/appmysite/www/"
ServerName app.mysite.com

I added the following lines at the end of httpd.conf from apache server :
Header set Access-Control-Allow-Origin "http://app.cocourse.fr"
Header set Access-Control-Allow-Credentials "true"
Header set Access-Control-Allow-Headers 'X-CSRF-Token'
Think to restart your apache server after that.

At the end of the drupal file: sites.php add :
$sites['mysite.com'] = 'mysite.com';

For drupalgap at admin/structure/services/list/drupalgap/, be sure to have selected the
"Session authentication" & REST server & all useful resourses

If you use the authcache module, add in the autchcache.helpers.inc file _authcache_shutdown_save_page function these lines :
if (strpos($_GET['q'], 'drupalgap') !== false) {
$is_cached_nonhtml = TRUE; // don't append JS to drupalgap ajax requests
}

if (strpos($_GET['q'], 'any other endpoints services') !== false) {
$is_cached_nonhtml = TRUE; // don't append JS to drupalgap ajax requests
}

after these lines :
// Invoke hook_authcache_info() operation to allow modules to modify info array
_authcache_invoke_hook('authcache_info', $_authcache_info);

// Invoke hook_authcache() operation to allow modules to modify ajax array
_authcache_invoke_hook('authcache_ajax', $authcache_ajax);

// Get buffered HTML
$buffer = ob_get_contents();

if (substr($buffer, 0, 5) == '<?xml') {
$is_cached_nonhtml = TRUE; // don't append JS to XML pages
}

Think to clean the cache

On the client side, first the login process :
$.ajax({
url:http://mysite.com?q=drupalgap/user/login.json,
type:"post",
data: 'username=' + login + '&password=' + password,
dataType:"json",
xhrFields: {withCredentials: true},
error:function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
},
success: function (result) {
window.localStorage.setItem("sessid", result.sessid);
window.localStorage.setItem("session_name", result.session_name);
window.localStorage.setItem("cookie", result.session_name + "=" + result.sessid);
window.localStorage.setItem("uid", result.user.uid);
window.localStorage.setItem("name", result.user.name);
your stuff ...
$.ajax({
url:http://mysite.com/services/session/token,
type:"get",
dataType:"text",
xhrFields: {withCredentials: true},
error:function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
},
success: function (token) {
window.localStorage.setItem("token", token);
your stuff ...
}
});

On the client side, second the logout process :
var settings = {
url:http://mysite.com?q=drupalgap/drupalgap_user/logout,
type:"post",
dataType:"json",
xhrFields: {withCredentials: true},
beforeSend: function (xhr){
xhr.setRequestHeader("X-CSRF-Token", token);
},
crossDomain: true,
error:function (jqXHR, textStatus, errorThrown) {
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
},
success: function (result) {
window.localStorage.removeItem("token");
window.localStorage.removeItem("sessid");
window.localStorage.removeItem("session_name");
window.localStorage.removeItem("cookie");
window.localStorage.removeItem("uid");
window.localStorage.removeItem("name");
}
};

$.ajax(settings);

You can now connect to http://app.mysite.com with and try a login and logout on chrome and ripple chrome. It doesn't work on Firefox. Avoid to be connected in chrome on your website http://mysite.com in the same time you connect on http://app.mysite.com

Regards,
Yoann

yoannl’s picture

a last thing : you need to disable the cross domain proxy on ripple in settings before trying to login or logout

tyler.frankenstein’s picture

Status: Needs work » Closed (fixed)

Closing this issue. The work around to be able to develop in Chrome with Ripple is to install DrupalGap within the same domain as your Drupal site. For example, if your Drupal site is available at example.com, then install DrupalGap at example.com/mobile-application as the place to run the app. No need to disable web securtiy. For more information, see the Ripple guide: http://drupalgap.org/node/103