Store's putCookie never called from setCookie?
MauriceArikoglu opened this issue · comments
I am having issues with a custom Store's methods not being called. I looked through the code in this repo and it seems CookieJar never calls store.putCookie from within setCookie (or any other method)?
Hello @MauriceArikoglu,
What do you mean by using a "custom Store's method"? Can you post some of the code you are trying to use so I can replicate the issue?
Thanks,
Mike
@medelibero-sfdc hey, thanks for looking into this.
You can setup a spike project and setup a plain object conforming to the Store interface. You will notice its setCookie / putCookie method is never called on CookieJar.setCookie.
Have a look at the implementation for CookieJar.setCookie here:
Line 1094 in 1b25269
setCookie(cookie, url, options, cb) { |
If you follow the method implementation you will notice there is no path where putCookie will be called...
The full method in question, as its quite big and not so straightforward:
Lines 1094 to 1277 in 1b25269
setCookie(cookie, url, options, cb) { | |
validators.validate(validators.isNonEmptyString(url), cb, options); | |
let err; | |
if (validators.isFunction(url)) { | |
cb = url; | |
return cb(new Error("No URL was specified")); | |
} | |
const context = getCookieContext(url); | |
if (validators.isFunction(options)) { | |
cb = options; | |
options = {}; | |
} | |
validators.validate(validators.isFunction(cb), cb); | |
if(!validators.isNonEmptyString(cookie) && !validators.isObject(cookie) && ( cookie instanceof String && cookie.length == 0)) { | |
return cb(null); | |
} | |
const host = canonicalDomain(context.hostname); | |
const loose = options.loose || this.enableLooseMode; | |
let sameSiteContext = null; | |
if (options.sameSiteContext) { | |
sameSiteContext = checkSameSiteContext(options.sameSiteContext); | |
if (!sameSiteContext) { | |
return cb(new Error(SAME_SITE_CONTEXT_VAL_ERR)); | |
} | |
} | |
// S5.3 step 1 | |
if (typeof cookie === "string" || cookie instanceof String) { | |
cookie = Cookie.parse(cookie, { loose: loose }); | |
if (!cookie) { | |
err = new Error("Cookie failed to parse"); | |
return cb(options.ignoreError ? null : err); | |
} | |
} else if (!(cookie instanceof Cookie)) { | |
// If you're seeing this error, and are passing in a Cookie object, | |
// it *might* be a Cookie object from another loaded version of tough-cookie. | |
err = new Error( | |
"First argument to setCookie must be a Cookie object or string" | |
); | |
return cb(options.ignoreError ? null : err); | |
} | |
// S5.3 step 2 | |
const now = options.now || new Date(); // will assign later to save effort in the face of errors | |
// S5.3 step 3: NOOP; persistent-flag and expiry-time is handled by getCookie() | |
// S5.3 step 4: NOOP; domain is null by default | |
// S5.3 step 5: public suffixes | |
if (this.rejectPublicSuffixes && cookie.domain) { | |
const suffix = pubsuffix.getPublicSuffix(cookie.cdomain()); | |
if (suffix == null) { | |
// e.g. "com" | |
err = new Error("Cookie has domain set to a public suffix"); | |
return cb(options.ignoreError ? null : err); | |
} | |
} | |
// S5.3 step 6: | |
if (cookie.domain) { | |
if (!domainMatch(host, cookie.cdomain(), false)) { | |
err = new Error( | |
`Cookie not in this host's domain. Cookie:${cookie.cdomain()} Request:${host}` | |
); | |
return cb(options.ignoreError ? null : err); | |
} | |
if (cookie.hostOnly == null) { | |
// don't reset if already set | |
cookie.hostOnly = false; | |
} | |
} else { | |
cookie.hostOnly = true; | |
cookie.domain = host; | |
} | |
//S5.2.4 If the attribute-value is empty or if the first character of the | |
//attribute-value is not %x2F ("/"): | |
//Let cookie-path be the default-path. | |
if (!cookie.path || cookie.path[0] !== "/") { | |
cookie.path = defaultPath(context.pathname); | |
cookie.pathIsDefault = true; | |
} | |
// S5.3 step 8: NOOP; secure attribute | |
// S5.3 step 9: NOOP; httpOnly attribute | |
// S5.3 step 10 | |
if (options.http === false && cookie.httpOnly) { | |
err = new Error("Cookie is HttpOnly and this isn't an HTTP API"); | |
return cb(options.ignoreError ? null : err); | |
} | |
// 6252bis-02 S5.4 Step 13 & 14: | |
if (cookie.sameSite !== "none" && sameSiteContext) { | |
// "If the cookie's "same-site-flag" is not "None", and the cookie | |
// is being set from a context whose "site for cookies" is not an | |
// exact match for request-uri's host's registered domain, then | |
// abort these steps and ignore the newly created cookie entirely." | |
if (sameSiteContext === "none") { | |
err = new Error( | |
"Cookie is SameSite but this is a cross-origin request" | |
); | |
return cb(options.ignoreError ? null : err); | |
} | |
} | |
/* 6265bis-02 S5.4 Steps 15 & 16 */ | |
const ignoreErrorForPrefixSecurity = | |
this.prefixSecurity === PrefixSecurityEnum.SILENT; | |
const prefixSecurityDisabled = | |
this.prefixSecurity === PrefixSecurityEnum.DISABLED; | |
/* If prefix checking is not disabled ...*/ | |
if (!prefixSecurityDisabled) { | |
let errorFound = false; | |
let errorMsg; | |
/* Check secure prefix condition */ | |
if (!isSecurePrefixConditionMet(cookie)) { | |
errorFound = true; | |
errorMsg = "Cookie has __Secure prefix but Secure attribute is not set"; | |
} else if (!isHostPrefixConditionMet(cookie)) { | |
/* Check host prefix condition */ | |
errorFound = true; | |
errorMsg = | |
"Cookie has __Host prefix but either Secure or HostOnly attribute is not set or Path is not '/'"; | |
} | |
if (errorFound) { | |
return cb( | |
options.ignoreError || ignoreErrorForPrefixSecurity | |
? null | |
: new Error(errorMsg) | |
); | |
} | |
} | |
const store = this.store; | |
if (!store.updateCookie) { | |
store.updateCookie = function(oldCookie, newCookie, cb) { | |
this.putCookie(newCookie, cb); | |
}; | |
} | |
function withCookie(err, oldCookie) { | |
if (err) { | |
return cb(err); | |
} | |
const next = function(err) { | |
if (err) { | |
return cb(err); | |
} else { | |
cb(null, cookie); | |
} | |
}; | |
if (oldCookie) { | |
// S5.3 step 11 - "If the cookie store contains a cookie with the same name, | |
// domain, and path as the newly created cookie:" | |
if (options.http === false && oldCookie.httpOnly) { | |
// step 11.2 | |
err = new Error("old Cookie is HttpOnly and this isn't an HTTP API"); | |
return cb(options.ignoreError ? null : err); | |
} | |
cookie.creation = oldCookie.creation; // step 11.3 | |
cookie.creationIndex = oldCookie.creationIndex; // preserve tie-breaker | |
cookie.lastAccessed = now; | |
// Step 11.4 (delete cookie) is implied by just setting the new one: | |
store.updateCookie(oldCookie, cookie, next); // step 12 | |
} else { | |
cookie.creation = cookie.lastAccessed = now; | |
store.putCookie(cookie, next); // step 12 | |
} | |
} | |
store.findCookie(cookie.domain, cookie.path, cookie.key, withCookie); | |
} |
Yes, and putCookie is called on lines 1240 and 1272.
@medelibero-sfdc
You are right. It seems I lost my ability to read. My bad.
Still, I observed putCookie not being called on my custom Store...
Hi @MauriceArikoglu,
What do you mean by your custom store? Can you show me the code that is not working?
-Mike
Is this still an issue we should look at @MauriceArikoglu?
@awaterma I think it isn't. I am not a part of the project anymore. IIRC I used a workaround, but it also might've been a mistake on my end. Can be closed I guess :)
Thank you!