I can export my cookies using "EditThisCookie" for Google Chrome.
The export looks like this:
"domain": ".stackoverflow.com",
"expirationDate": 1698322697,
"hostOnly": false,
"httpOnly": false,
"name": "_ga",
"path": "/",
"sameSite": "unspecified",
"secure": false,
"session": false,
"storeId": "0",
"value": "some",
"id": 1
Now, I wish to store/parse this string to an existing TIdHTTP
Cookie Manager.
How can I add these values to the Cookie Manager using TIdCookie
?
This is what I tried, with no luck:
procedure ImportCookies (JSONCookies: string; CookieManager: TIdCookieManager);
var
StringList: TStringList;
I : Integer;
InCookie : Boolean;
MyCookie: TidCookie;
function BoolStrToBool(s: string): Boolean;
begin
if Copy(UpperCase(Trim(s)), 1, 4) = 'TRUE' then Exit(True) else Exit(False);
end;
begin
InCookie := False;
StringList := TStringList.Create;
try
StringList.Text:= JSONCookies;
for I := 0 to StringList.Count - 1 do
begin
if Trim(StringList.Strings[i]) = '{' then
begin
InCookie := True;
MyCookie := CookieManager.CookieCollection.Add;
Continue;
end;
if (Trim(StringList.Strings[i]) = '}') or (Trim(StringList.Strings[i]) = '},') then
begin
InCookie := False;
Continue;
end;
if InCookie then
begin
if Copy(StringList.Strings[i], 1, 9) = '"domain":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 10, MaxInt);
MyCookie.Domain := GetBetween(StringList.Strings[i], '"', '"');
Continue;
end;
if Copy(StringList.Strings[i], 1, 11) = '"hostOnly":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 12, MaxInt);
MyCookie.HostOnly := BoolStrToBool(StringList.Strings[i]);
Continue;
end;
if Copy(StringList.Strings[i], 1, 11) = '"httpOnly":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 12, MaxInt);
MyCookie.HttpOnly := BoolStrToBool(StringList.Strings[i]);
Continue;
end;
if Copy (StringList.Strings[i], 1, 7) = '"name":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 8, MaxInt);
MyCookie.CookieName := GetBetween(StringList.Strings[i], '"', '"');
Continue;
end;
if Copy(StringList.Strings[i], 1, 7) = '"path":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 8, MaxInt);
MyCookie.Path := GetBetween(StringList.Strings[i], '"', '"');
Continue;
end;
if Copy(StringList.Strings[i], 1, 9) = '"secure":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 10, MaxInt);
MyCookie.Secure := BoolStrToBool(StringList.Strings[i]);
Continue;
end;
if Copy(StringList.Strings[i], 1, 8) = '"value":' then
begin
StringList.Strings[i] := Copy(StringList.Strings[i], 9, MaxInt);
MyCookie.Path := GetBetween(StringList.Strings[i], '"', '"');
Continue;
end;
end;
end;
finally
StringList.Free;
end;
end;
I don't see why I'd need a TIdURI
instance - the origin shouldn't matter, since there's a destination domain already?!
FYI, your code can be greatly simplified if you use an actual JSON parser, as well as existing RTL/library functions, such as:
StrUtils.StartsText()
or IdGlobal.TextStartsWith()
SysUtils.StrToBool()
SysUtils.AnsiExtractQuotedStr()
or IdGlobalProtocols.UnquotedStr()
IdGlobal.PosInStrAray()
Or, you could simply reformat the exported cookie data into a standard HTTP cookie format and then let TIdCookieManager.AddServerCookie()
do all of the parsing for you (but then you would need a TIdURI
).
In any case, TIdURI
is used by TIdCookieManager
's parser, as certain aspects of a cookie need to be validated against the origin it came from. For instance, when determining the cookie's Path, or matching it against a domain/host, or even just knowing what the origin host is for a HostOnly
cookie, or whether an HttpOnly
cookie was received over HTTP, etc. There are rules to cookie processing, when receiving cookies, and when sending cookies to servers, that are tied to the cookie's origin URL.
In your case, since you are skipping TIdCookieManager.AddServerCookie()
, you don't really need a TIdURI
since Chrome has already done the heavy processing for you.
However, one thing that AddServerCookie()
does do, which you are not doing, is it adds the TIdCookie
to an internal TIdCookies
list that is later used when deciding which cookies get sent back to which servers in TIdHTTP
requests (see TIdCookieManager.GenerateClientCookies()
).
So, it is not enough to just call TIdCookieManager.CookieCollection.Add()
, which merely creates the TIdCookie
object. You would also need to call TIdCookieManager.CookieCollection.AddCookie()
- which also takes a TIdURI
, though this one is optional, whereas the one in AddServerCookie()
is required.
So, try something more like this:
procedure ImportCookies(JSONCookies: string; CookieManager: TIdCookieManager);
var
StringList: TStringList;
I : Integer;
MyCookie: TidCookie;
S, FieldName, FieldValue: string;
procedure AddMyCookieIfReady;
begin
if MyCookie <> nil then
begin
if not CookieManager.CookieCollection.AddCookie(MyCookie, nil) then
begin
MyCookie.Collection := nil;
MyCookie.Free;
end;
MyCookie = nil;
end;
end;
begin
StringList := TStringList.Create;
try
StringList.Text := JSONCookies;
MyCookie := nil;
for I := 0 to StringList.Count - 1 do
begin
s := Trim(StringList.Strings[I]);
if s = '{' then
begin
AddMyCookieIfReady;
MyCookie := CookieManager.CookieCollection.Add;
Continue;
end;
if TextStartsWith(s, '}') then
begin
AddMyCookieIfReady;
Continue;
end;
if (MyCookie = nil) or (not TextStartsWith(s, '"')) then
Continue;
Delete(s, 1, 1);
FieldName := Fetch(s, '"');
Fetch(s, ':');
FieldValue := UnquotedStr(TrimLeft(s));
case PosInStrArray(FieldName, ['domain', 'hostOnly', 'httpOnly', 'name', 'path', 'secure', 'value'], False) of
0: begin
if TextStartsWith(FieldValue, '.') then Delete(FieldValue, 1, 1);
MyCookie.Domain := FieldValue;
end;
1: MyCookie.HostOnly := StrToBool(FieldValue);
2: MyCookie.HttpOnly := StrToBool(FieldValue);
3: MyCookie.CookieName := FieldValue;
4: MyCookie.Path := FieldValue;
5: MyCookie.Secure := StrToBool(FieldValue);
6: MyCookie.Value := FieldValue;
end;
end;
AddMyCookieIfReady;
finally
StringList.Free;
end;
end;