Handling cookies in Plone
Cookies in Plone are read from the request and set on the response. There are methods on request and response for cookie handling. Reading the raw cookie direct from the request header is still possible, but not needed. Same is valid for setting or expiring cookies on the response.
Incoming cookies are sent by the browser in the request header.
The incoming request was already parsed by the publisher.
Cookies are available as
cookies mapping variable on the request.
Setting cookies is done on the response.
Each cookie name there can be a new or an existing one.
When sending the response, the information is turned into a properly formatted
A cookie may have cookie-attributes set.
Those are passed as keyword arguments to
Turning a cookie into a non-session cookie requires an
expires='date' keyword and value.
Limiting the cookie to a path requires a
path='/somepath' keyword and value for the
The usual browser cookie rules apply here.
self.request.response.setCookie( "cookie_name", "cookie_value", quoted=False, # default is True attribute_on_cookie="attribute value", another_attribute="another attribute value", )
If a cookie needs to be removed, the browser has to be told to expire it.
expireCookie method does this.
It always sets
0 and the
expires date to the past.
Additionally the cookie value will be set to
expireCookie allows additional attributes to be passed as keyword arguments, similar to
The aforementioned keywords
value are reserved and are not allowed.
A common keyword used here is
Default Plone cookies¶
Typical Plone cookies:
# Logged in cookie __ac="NjE2NDZkNjk2ZTMyOjcyNzQ3NjQxNjQ2ZDY5NmUzNjM2MzczNw%253D%253D"; # Language chooser I18N_LANGUAGE="fi"; # Status message statusmessages="BURUZXJ2ZXR1bG9hISBPbGV0IG55dCBraXJqYXV0dW51dCBzaXPDpMOkbi5pbmZv" # Google Analytics tracking __utma=39444192.1440286234.1270737994.1321356818.1321432528.21; __utmz=39444192.1306272121.6.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); __utmb=39444126.96.36.1991432528; __utmc=39444192; # Plone copy-paste clipboard __cp="x%25DA%2515%258AA%250A%25800%250C%2504%25A3%25A0%25E0E%257CF%25FF%25E4%2529%2587%25801%25D5B%25B3-%25F8%257B%25D3%25C3%250E%25CC%25B0i%2526%2522%258D%25D19%2505%25D2%2512%25C0P%25DF%2502%259D%25AB%253E%250C%2514_%25C3%25CAu%258B%25C0%258Fq%2511s%25E8k%25EC%250AH%25FE%257C%258Fh%25AD%25B3qm.9%252B%257E%25FD%25D1%2516%25B3"; Path=/
__ac cookie is set by the PluggableAuthentication service after login.
For better and more secure control over the cookie and its lifetime plone.session can be used.
Zope session cookie¶
This cookie looks like:
It is set first time when session data is written.
I18N_LANGUAGE is set by Plone
The cookie can be disabled. Be aware, after disabling the cookie, language switching using the language selector viewlet is no longer functional. To disable the cookie, untick the checkbox Use cookie for manual override in Plone controlpanel Language under Negotiation Scheme.
Also, language cookie has a special lifecycle when plone.app.multilingual is installed. This may affect your front-end web server caching. If configured improperly, the language cookie gets set on images and static assets like CSS HTTP responses.
Sanitizing cookies for the cache¶
You do not want to store HTTP responses with cookies in a front end cache server, because this would be a leak of other users’ information.
Do not cache pages with cookies set. Also with multilingual sites it makes sense to have unique URLs for different translations as this greatly simplifies caching (you can ignore language cookie).
Note that cookies can be set:
by the server (Plone itself)
… so you might need to clean cookies for both incoming HTTP requests and HTTP responses.
More info in Varnish section of this manual.
Late cleanup of HTTP response cookies¶
You can do this after all processing is done and before the transaction is committed by subscribing to the
Put the code below in a file
"""Clean I18N cookies from non-HTML responses. E.g. Image content, which has language set, and is cross-linked across page, do not inadvertently change the language. """ from zope.interface import Interface from zope.component import adapter from ZPublisher.interfaces import IPubBeforeCommit @adapter(Interface, IAfterPublicationEvent) def clean_language(object, event): """ Clean up cookies after HTTPResponse object has been constructed completely. Post-publication handler. """ request = event.request # All non-HTML payloads if ( not event.request.response.headers["content-type"].startswith("text/html"): and "I18N_LANGUAGE" in request.response.cookies ): del request.response.cookies["I18N_LANGUAGE"]
Register the clean_language function as a subscriber in ZCML:
<subscriber handler=".cleancookies.clean_language" />
Kind of… crude example