Cookies handling and Base64 content
Added by David Hubbard over 14 years ago
Hi
Now I don't know if this is expected behaviour or not but I wanted to report something I found.
I am using cookies to pass data across sessions. I'm encrypting the content (using another library) before storing in cookie and the output is Base64 encoded. I was expecting to be able to store this in cookie via Wt::WApplication::setCookie and retrieve in other session by Wt::WEnvironment::getCookie.
However, I had a problem with embedded carriage returns. The other library embeds these as standard C-style CRLF or "\n\r". However when I look at the cookie content they appear as "%d%a".
Of course when I retrieve the data from the cookie again and decrypt I get decryption exception (other library). Now, I'm inclined to think that there is a problem with the other library - after all the spec [[[http://www.ietf.org/rfc/rfc1521.txt?number=1521]]] states that it should be using "=OD=OA". But, just wondering what Wt is doing here.
I've got round the problem by applying an extra layer of URI encoding/decoding (again with the other library) - which forces these to "%OD%OA" and back to "\n\r" equivalent. But I wondered, as Wt appears to be doing something on the setCookie side whether it should be applying the reverse on the getCookie side or performing explicit URI encoding, decoding within, possibly as an option.
Regards
Replies (6)
RE: Cookies handling and Base64 content - Added by Wim Dumon over 14 years ago
Hello David,
I remember upgrading the cookie code a (long) while back to be able to support a wider range of characters to store on the client. The intention was that a random cookie string would be stored in a format that is generally supported by the browser, and when you retrieve the cookie, the data should be identical to what you have stored - no matter what characters were stored. No surprise that URL encoding is used for this purpose.
Maybe I have ignored some characters that should be encoded. Can you test with a small test case and confirm that \r and/or \n (or others?) are stored/retrieved correctly? If not, Wt should be patched. The code that encodes the cookie headers is in WebRenderer::setHeaders (file src/web/WebRenderer.C).
Thank you,
Wim.
RE: Cookies handling and Base64 content - Added by David Hubbard over 14 years ago
Wim
Hi
I've run this with a list test program, which basically does writes a cookie on first page
sInput_ = new WText("abcdABCD 01234567890\r\n!\"£$%^&*()\t-+{}[]:;<>,./?~#", root());
...
wApp->setCookie("cookie_test", sInput_->text().toUTF8(), 365, "127.0.0.1", "/");
and (following a button push) gets the cookie back and displays it
std::string cookie = wApp->environment().getCookie("cookie_test");
i.e. the intial string includes the \r\n and a \t - for which I get
[input=]abcdABCD 01234567890
!"£$%^&*() -+{}[]:;<>,./?~#
[output=]abcdABCD 01234567890%d%a!"£$%^&*()-+{}[]:;<>,./?~#
Note: the tab (\t) also disappears
The cookie has %d%a and %9 for these.
So I think what is happening is that characters less than 16, which in escape notation you'd expect would have a preceding '0', are coming out as only one character after the % escaping.
In Wt::WDomElement::urlEncodeS() has (on the assumption that #define WT_CNOR is true)
result << '%';
result << (int)c;
Whereas Utils::unescapeHexTokens has
if (v[i] == '%') {
std::string h = v.substr(i + 1, 2);
...
}
i.e. an assumed 2 char length following the %
As I never like to receive just a problem, I can offer two possible fixes (I'll leave you to decide on solution)
#include <iomanip>
...
std::string DomElement::urlEncodeS(const std::string& url,
const std::string &allowed)
{
std::stringstream result;
#ifndef WT_CNOR
result << std::setw(2) << std::setfill('0') << std::hex;
...
some info here [[[http://faq.cprogramming.com/cgi-bin/smartfaq.cgi?answer=1048380213&id=1043284385]]]
or (slightly more direct)
if ((int)c < 16)
result << '0';
result << (int)c;
Regards
Dave
RE: Cookies handling and Base64 content - Added by David Hubbard over 14 years ago
Wim
I managed to patch my copy of Wt with my second fix (the extra "if" test), which now works for me. I confess I couldn't get the stream format technique to work in situ - this did work in a simple single character test, but I may be missing something with a multi-character stream (e.g. it may only apply the padding when you extract the data, which is then rather more than the 2 character width).
I did also in passing look at boost::format since std::string doesn't have the old-style printf formatting functionality built-in
boost::format("%02.2d") % (int)c;
I notice that there is also an issue with the "$" which comes out as an "Â" (%C2). This doesn't affect my use case as my data is Base64 where the \n and \r are the only non-standard characters.
All the best
Dave
RE: Cookies handling and Base64 content - Added by David Hubbard over 14 years ago
Sorry that boost::format should probably specify hex format(x):
result << boost::format("%02.2x") % (int)c;
RE: Cookies handling and Base64 content - Added by Wim Dumon over 14 years ago
David,
Well spot. Fix will be in git soon.
I've taken the if c < 16 method because this bug report also applies to JWt and with that method, both are fixed in one go.
Wim.
RE: Cookies handling and Base64 content - Added by David Hubbard over 14 years ago
Wim
No worries, thanks.
Please ignore the comment about "$" above
1) it was actually around the double-quote (\") rather than the dollar
and
2) it was me being a bit slap-dash. I wasn't actually passing the std::string, that I'd set with my test string, into setCookie. I was pulling it back out of the WText field via toUTF8() instead. This was inserting extra %C2 character, which appeared as an extra character in my output
My mistake - it all works fine with std::string.
Cheers
Dave