Man kann Cookies auch aus den Response Headern auslesen, was ich auch eher empfehlen würde, weil man die Cookies dann auch bearbeiten und speichern kann.
Die folgende Funktion kannst du als CURLOPT_WRITEFUNCTION benutzen um den Response Body in eine std::string Variable zu speichern oder eben als CURLOPT_HEADERFUNCTION um den Response Header in eine std::string Variable zu speichern.
Code:
std::size_t writeToString(char* data, std::size_t size, std::size_t nmemb, std::string* string)
{
if (!string)
{
return 0;
}
string->append(data, size * nmemb);
return size * nmemb;
}
Wie macht man das?
Code:
CURL* handle = curl_easy_init();
std::string body;
std::string header;
// ...
// other settings like url
// ...
// save body
curl_easy_setopt(handle, CURLOPT_WRITEDATA, &body);
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, writeToString);
// save header
curl_easy_setopt(handle, CURLOPT_HEADERDATA, &header);
curl_easy_setopt(handle, CURLOPT_HEADERFUNCTION, writeToString);
CURLcode result = curl_easy_perform(handle);
if (result != CURLE_OK)
{
// do error handling
}
Nun hast du den Response Body in der Variable body und den Response Header in der Variable header gespeichert. Wie ist ein Header aufgebaut?
So könnte ein Header, den du als Antwort auf dein Post Request kriegst, aussehen.
Code:
HTTP/1.0 200 OK
Date: Fri, 31 Dec 1999 23:59:59 GMT
Set-Cookie: sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT
Content-Type: text/html
Content-Length: 1354
Was wäre für uns interessant? Die Set-Cookie Direktive natürlich. Wie filtern wir diese bloß? Dafür gibt es reguläre Ausdrücke, in C++ auch unter std::regex zu finden.
Code:
std::regex regex("Set-Cookie: ([^=]+?)=([^;]+?);");
std::string cookies;
// get cookies
for (std::sregex_iterator it(header.cbegin(), header.cend(), regex), end_it; it != end_it; ++it)
{
cookies += it->str(1) + "=" + it->str(2) + ";";
}
W-was!?!? Es sieht komplizierter aus, als es tatsächlich ist.
In der ersten Zeile initialisieren wir einen regulären Ausdruck, der eben dazu da ist, um die Set-Cookie Direktiven herauszufiltern. Direktive
n? Ja, es bleibt nämlich nur selten bei einem Cookie. Meistens findet man im Response Header mehr als nur eine Set-Cookie Direktive. Den regulären Ausdruck ansich werde ich nicht erklären, dafür gibt es Google.
In der darauffolgenden Zeile wird die Variable cookies definiert, in die wir die gefilterten Cookies speichern. Wir speichern sie auch direkt in einem Format, mit dem libcurl problemlos umgehen kann.
Für die for-Schleife sollten dir Iteratoren nicht ganz fremd sein: Hier wird durch den header String iteriert anhand des oben initialisierten regulären Ausdruckes, für jeden "Fund" wird der "Body" der for-Schleife ausgeführt. it->str(n) gibt immer die n-te "Capture Group" des regulären Ausdrückes zurück, in unserem Fall also it->str(1) für den Namen und it->str(2) für den Wert des Cookies.
Nun haben wir in unserem Fall einen String mit dem Inhalt
sessionToken=abc123;. Wie benutzen wir ihn nun beim nächsten Request?
Code:
CURL* handle2 = curl_easy_init();
// ...
// other options like url
// ...
curl_easy_setopt(handle2, CURLOPT_COOKIE, cookies.c_str());
Wieso std::string::c_str()? Weil libcurl eine C Bibliothek ist und somit kein std::string erkennt. Sollte irgendwann mal deine Applikation abstürzen, kann es sehr gut daran liegen, dass du irgendwo einen Datentyp übergeben hast, mit dem libcurl nicht klarkommt. Pointer stellen da eine Ausnahme dar, weshalb das Beispiel von oben auch problemlos funktioniert.
Voila.