Skip to content

Commit

Permalink
Merge pull request appium#3829 from sebv/doccookies
Browse files Browse the repository at this point in the history
ios cookie rewrite
  • Loading branch information
sebv committed Oct 16, 2014
2 parents 68ed31b + 3a73699 commit 23d1a76
Show file tree
Hide file tree
Showing 4 changed files with 144 additions and 42 deletions.
97 changes: 97 additions & 0 deletions lib/cookies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"use strict";

var _ = require('underscore');

/*
* derived from jQuery Cookie Plugin v1.4.1
* https://github.com/carhartl/jquery-cookie
*/

module.exports = function (cookieString) {

var pluses = /\+/g;

function encode(s) {
return encodeURIComponent(s);
}

function decode(s) {
return decodeURIComponent(s);
}

function stringifyCookieValue(value) {
return encode(String(value));
}

function parseCookieValue(s) {
if (s.indexOf('"') === 0) {
// This is a quoted cookie as according to RFC2068, unescape...
s = s.slice(1, -1).replace(/\\"/g, '"').replace(/\\\\/g, '\\');
}

try {
// Replace server-side written pluses with spaces.
// If we can't decode the cookie, ignore it, it's unusable.
// If we can't parse the cookie, ignore it, it's unusable.
return decodeURIComponent(s.replace(pluses, ' '));
} catch (e) {}
}

function read(s, converter) {
var value = parseCookieValue(s);
return _.isFunction(converter) ? converter(value) : value;
}

this.cookie = this.cookies = function (key, value, options) {

// Write

if (arguments.length > 1 && !_.isFunction(value)) {
options = _.extend({}, options);

var ret = [
encode(key), '=', stringifyCookieValue(value),
options.expires ? '; expires=' + options.expires : '', // use expires attribute, max-age is not supported by IE
options.path ? '; path=' + options.path : '',
options.domain ? '; domain=' + options.domain : '',
options.secure ? '; secure' : ''
].join('');
return ret;
}

// Read

var result = key ? undefined : {};

// To prevent the for loop in the first place assign an empty array
// in case there are no cookies at all. Also prevents odd result when
// calling this.cookie().
var cookies = cookieString ? cookieString.split('; ') : [];

for (var i = 0, l = cookies.length; i < l; i++) {
var parts = cookies[i].split('=');
var name = decode(parts.shift());
var cookie = parts.join('=');

if (key && key === name) {
// If second argument (value) is a function it's a converter...
result = read(cookie, value);
break;
}

// Prevent storing a cookie that we couldn't decode.
if (!key && (cookie = read(cookie)) !== undefined) {
result[name] = cookie;
}
}

return result;
};

this.removeCookie = function (key, options) {
// Must not alter options, thus extending a fresh object...
return this.cookie(key, '', _.extend({}, options, {
expires: "Thu, 01 Jan 1970 00:00:00 GMT" }));
};

};
65 changes: 41 additions & 24 deletions lib/devices/ios/ios-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var uuid = require('uuid-js')
, logger = require('../../server/logger.js').get('appium')
, helpers = require('../../helpers.js')
, escapeSpecialChars = helpers.escapeSpecialChars
, parseWebCookies = helpers.parseWebCookies
, CookieMan = require('../../cookies')
, rotateImage = helpers.rotateImage
, request = require('request')
, mkdirp = require('mkdirp')
Expand Down Expand Up @@ -1892,9 +1892,12 @@ iOSController.getCookies = function (cb) {
var script = "return document.cookie";
this.executeAtom('execute_script', [script, []], function (err, res) {
if (this.checkSuccess(err, res, cb)) {
var cookies;
var cookieMan = new CookieMan(res.value);
var cookies = [];
try {
cookies = parseWebCookies(res.value);
cookies = _(cookieMan.cookies()).map(function (v,k) {
return {name: k, value: v};
});
} catch (e) {
return cb(null, {
status: status.codes.UnknownError.code
Expand All @@ -1907,36 +1910,35 @@ iOSController.getCookies = function (cb) {
});
}
}.bind(this), true);

};

iOSController.setCookie = function (cookie, cb) {
if (!this.isWebContext()) {
return cb(new NotImplementedError(), null);
}

var webCookie = encodeURIComponent(cookie.name) + "=" +
encodeURIComponent(cookie.value);

var expiry = cookie.expiry || null;

if (!expiry && cookie.value === "") {
expiry = (new Date(0)).toUTCString();
} else if (expiry && typeof expiry === "number") {
expiry = (new Date(expiry * 1000)).toUTCString();
}

if (expiry) {
webCookie += "; expires=" + expiry;
}

cookie = _.clone(cookie);
// if 'Path' field is not specified, Safari will not update cookies as expected; eg issue #1708
if (!cookie.path) {
cookie.path = "/";
}
var webCookie = (new CookieMan()).cookie(cookie.name, cookie.value, {
expires: _.isNumber(cookie.expiry) ? (new Date(cookie.expiry * 1000)).toUTCString() :
cookie.expiry, path: cookie.path, domain: cookie.domain,
httpOnly: cookie.httpOnly, secure: cookie.secure});
var script = "document.cookie = " + JSON.stringify(webCookie);
this.executeAtom('execute_script', [script, []], function (err, res) {
if (this.checkSuccess(err, res, cb)) {
cb(null, {
status: status.codes.Success.code
, value: true
});
}
}.bind(this), true);
};

webCookie += ";path=" + cookie.path;

iOSController._deleteCookie = function (cookieName, cb) {
var webCookie = (new CookieMan()).removeCookie(cookieName , {path: "/"});
var script = "document.cookie = " + JSON.stringify(webCookie);
this.executeAtom('execute_script', [script, []], function (err, res) {
if (this.checkSuccess(err, res, cb)) {
Expand All @@ -1948,12 +1950,27 @@ iOSController.setCookie = function (cookie, cb) {
}.bind(this), true);
};


iOSController.deleteCookie = function (cookieName, cb) {
if (!this.isWebContext()) {
return cb(new NotImplementedError(), null);
}
var cookie = {name: cookieName, value: ""};
this.setCookie(cookie, cb);
// check cookie existence
var script = "return document.cookie";
this.executeAtom('execute_script', [script, []], function (err, res) {
if (this.checkSuccess(err, res, cb)) {
var cookieMan = new CookieMan(res.value);
if (_.isUndefined(cookieMan.cookie(cookieName))) {
// nothing to delete
return cb(null, {
status: status.codes.Success.code
, value: true
});
}
// delete cookie
this._deleteCookie(cookieName, cb);
}
}.bind(this), true);
};

iOSController.deleteCookies = function (cb) {
Expand All @@ -1969,7 +1986,7 @@ iOSController.deleteCookies = function (cb) {
var deleteNextCookie = function (cookieIndex) {
if (!returned) {
var cookie = cookies[cookieIndex];
this.deleteCookie(cookie.name, function (err, res) {
this._deleteCookie(cookie.name, function (err, res) {
if (err || res.status !== status.codes.Success.code) {
returned = true;
cb(err, res);
Expand Down
16 changes: 0 additions & 16 deletions lib/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -198,22 +198,6 @@ exports.escapeSpecialChars = function (str, quoteEscape) {
return str;
};

exports.parseWebCookies = function (cookieStr) {
var cookies = [];
var splits = cookieStr.trim().split(";");
_.each(splits, function (split) {
split = split.trim();
if (split !== "") {
split = split.split("=");
cookies.push({
name: decodeURIComponent(split[0])
, value: decodeURIComponent(split[1])
});
}
});
return cookies;
};

var warningsEmitted = {};
var deprecationWarnings = [];

Expand Down
8 changes: 6 additions & 2 deletions test/functional/common/webview/cookies-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ module.exports = function (desired) {
it('should be able to get cookies for a page with none', function (done) {
loadWebView(desired, driver, testEndpoint(desired) + 'iframes.html',
"Iframe guinea pig").then(function () {
return driver.allCookies().should.eventually.have.length(0);
return driver
.deleteAllCookies()
.get(testEndpoint(desired))
.allCookies().should.eventually.have.length(0);
}).nodeify(done);
});
});
Expand Down Expand Up @@ -87,7 +90,8 @@ module.exports = function (desired) {
// should not clobber old cookies
_.pluck(cookies, 'name').should.include("guineacookie1");
_.pluck(cookies, 'value').should.include(_ignoreEncodingBug("i am a cookie value"));
}).nodeify(done);
})
.nodeify(done);
});
it('should be able to delete one cookie', function (done) {
var newCookie = {name: "newcookie", value: "i'm new here"};
Expand Down

0 comments on commit 23d1a76

Please sign in to comment.