Why is my program reading extra bytes in HTTP/1.1 - c++

I'm experimenting with sockets and trying to build a very simple webbot.
This is my code:
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <errno.h>
#include <cstring>
#include <iostream>
#include <string>
#define HTTP_PORT "80"
#define HOST "www.taringa.net"
#define PORT HTTP_PORT
#define IN_BUFFSIZE 1024
#define OUT_BUFFSIZE 1024
#define REQUEST "GET /Taringa/posts HTTP/1.0\r\nHost: www.taringa.net\r\nUser-Agent: foo\r\n\r\n"
using namespace std;
int main(int argc, char **argv) {
struct addrinfo hints, *res;
struct sockaddr_in servAddress;
int sockfd;
char addrstr[100];
char buff_msg_out[OUT_BUFFSIZE], buff_msg_in[IN_BUFFSIZE];
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
if ( getaddrinfo(HOST, HTTP_PORT, &hints, &res) != 0) {
cerr << "Error en getaddrinfo" << endl;
return -1;
}
// Crear socket
if ( ( sockfd = socket(res->ai_family, res->ai_socktype, res->ai_protocol) ) < 0 )
{
cerr << "Error en socket()" << endl;
return -1;
}
// Iniciar conexion
if ( connect(sockfd, res->ai_addr, res->ai_addrlen) == -1 )
{
cerr << "Error en connect()" << endl;
cerr << "Error: " << strerror(errno) << endl;
return -1;
}
cout << "Conectado con éxito" << endl;
// Enviar datos
strncpy(buff_msg_out, REQUEST, strlen(REQUEST));
if ( send(sockfd, buff_msg_out, strlen(buff_msg_out), 0) <= 0 )
{
cerr << "Error en write()" << endl;
return -1;
}
cout << "Mensaje enviado:" << endl << buff_msg_out << endl << endl;
int bytes_recv = 0;
while ( ( bytes_recv = recv(sockfd, buff_msg_in, IN_BUFFSIZE-1, 0)) > 0 )
{
buff_msg_in[bytes_recv] = '\0';
cout << buff_msg_in << endl;
}
freeaddrinfo(res);
close(sockfd);
return 0;
}
This is the output when the request has HTTP/1.0
HTTP/1.1 200 OK
Server: n0
Date: Fri, 01 Feb 2013 19:57:26 GMT
Content-Type: text/html; charset=utf8
Connection: close
Set-Cookie: trngssn=06359673; path=/
Set-Cookie: trngssn=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: taringa_user_id=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: lastNick=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: fbs=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: tws=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: iB-friendfind=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es" >
<head profile="http://purl.org/NET/erdf/profile" prefix="og: http://ogp.me/ns
# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv=”X-Frame-Options” content=”Deny” />
<link rel="alternate" type="application/atom+xml" title="Últimos Posts de Taringa" href="/rss/Taringa/posts/" />
<link rel="alternate" type="application/atom+xml" title="Últimos Temas de Taringa" href="/rss/Taringa/tem
as/" />
<title>Posts de Taringa! - Taringa!</title>
...
</body>
</html>
But when I specify HTTP/1.1, the reply is
HTTP/1.1 200 OK
Server: n0
Date: Fri, 01 Feb 2013 20:03:54 GMT
Content-Type: text/html; charset=utf8
Transfer-Encoding: chunked
Connection: keep-alive
Set-Cookie: trngssn=81047255; path=/
Set-Cookie: trngssn=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: taringa_user_id=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: lastNick=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: fbs=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: tws=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
Set-Cookie: iB-friendfind=deleted; expires=Thu, 01-Jan-1970 00:00:01 GMT; path=/; domain=.taringa.net
d0f
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="es" xml:lang="es" >
<head profile="http://purl.org/NET/erdf
/profile" prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv=”X-Frame-Options” content=”Deny” />
<link rel="alternate" type="application/atom+xml" title="Últimos Posts de Taringa" href="/rss/Taringa/posts/" />
<link rel="alternate" type="application/atom+xml" title="Últimos Te
mas de Taringa" href="/rss/Taringa/temas/" />
<title>Posts de Taringa! - Taringa!</title>
...
and here is the problem
</body>
</html>
0
and it waits a few seconds before closing the communication.
I just tried with stackoverflow.com/about and it works fine. Except for the following text that the server sends me after the webpage
</html>HTTP/1.0 400 Bad request
Cache-Control: no-cache
Connection: close
Content-Type: text/html
<html><body><h1>400 Bad request</h1>
Your browser sent an invalid request.
</body></html>
Am I missing something?

The server is using chunked encoding. The d0f is the length of the "chunk" in octets expressed as hex. The 0 is the length of the next chunk (i.e. there is none).

Server: n0
Date: Fri, 01 Feb 2013 20:03:54 GMT
Content-Type: text/html; charset=utf8
Transfer-Encoding: chunked
Connection: keep-alive
Don't say you support HTTP 1.1 if you don't.
All HTTP/1.1 applications MUST be able to receive and decode the "chunked" transfer-coding, and MUST ignore chunk-extension extensions they do not understand. -- HTTP 1.1

Related

Discord Webhooks With C++

So I've taken up the challenge of doing webhooks in c++ and I wanted to just get some help with the post requests. Here is the code I have at the moment, I wanted to send embeds through post requests in C++.
Here is my code along with errors and all, the webhook is still active if you want to test yourself. Am trying to keep it all using windows librarys on purpose.
#include <winsock2.h>
#include <ws2tcpip.h>
#include <string>
#pragma warning(disable:4996)
#pragma comment(lib, "ws2_32.lib")
using namespace std;
int Plug(string address, string port, SOCKET* csock) {
WSADATA WSAData;
WSAStartup(MAKEWORD(2, 0), &WSAData);
PADDRINFOA result;
ADDRINFOA hints;
ZeroMemory(&hints, sizeof(ADDRINFO));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
int res = getaddrinfo(address.c_str(), port.c_str(), &hints, &result);
*csock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
if (SOCKET_ERROR == connect(*csock, (SOCKADDR*)result->ai_addr, sizeof(SOCKADDR))) return WSAGetLastError();
return 0;
}
void Unplug(SOCKET* csock) {
closesocket(*csock);
WSACleanup();
}
string PostRequest(string host, string query, string data) {
string req = "POST " + query + " HTTP/1.1" + "\r\n";
req += "Host: " + host + "\r\n";
req += "Content-Type: application/x-www-form-urlencoded\r\n";
req += "Content-Length: " + to_string(data.length()) + "\r\n";
req += "Connection: Close";
req += "\r\n\r\n" + data + "\r\n\r\n";
SOCKET s;;
Plug(host, "80", &s);
Send(&s, req);
while (GetAvailable(&s) == 0) Sleep(10);
string result = Receive(&s);
//if (result.find("\r\n\r\n") == string::npos && DEBUG) return result;
//if (result.find("\r\n\r\n") == string::npos) return "PR_INVALID_RESPONSE";
//result = result.substr(result.find("\r\n\r\n") + 4, string::npos);
Unplug(&s);
return result;
}
int main() {
//https://discordapp.com/api/webhooks/705211476553629747/zwzqZMnTTgLtHBm3kc_DvvD71IW9FfE4ur-PQlkgeZhd56cT7UjSJCWI-V8wPiEUWV2w
std::cout<<PostRequest("162.159.129.233","/api/webhooks/705249405141516360/s8ioXr6IZEeuPnMi1O37CmY3o5pUZcu6ho7aIJdieSAqgGyTXOZjkOZdMNe1uJre6dto","{'embeds': [{'description': '**ERROR**: `TESTSTRING`\n', 'color': 4508791}]}");
}
However when I make the post requests it is unable to send my content and instead returns 400. I've tried a few more things but Im wondering if its my query?
HTTP/1.1 301 Moved Permanently
Cache-Control: max-age=3600
Cf-Ray: 58bd304dec1ff2c0-WAW
Cf-Request-Id: 026a1c84ad0000f2c054113200000001
Date: Thu, 30 Apr 2020 00:36:28 GMT
Expires: Thu, 30 Apr 2020 01:36:28 GMT
Location: MYWEBHOOKURL
Server: cloudflare
Set-Cookie: __cfruid=5adc23f36cce3f0a398b8f9e91429b4349ef9314-1588206988; path=/; domain=.discordapp.com; HttpOnly
Vary: Accept-Encoding
Content-Length: 0
Connection: close
And lets say I use discords actual ip instead of resolving it I end up getting
this instead
HTTP/1.1 403 Forbidden
Cache-Control: max-age=15
Cf-Ray: 58bd37782e6dffbc-WAW
Cf-Request-Id: 026a20ff1a0000ffbcc89df200000001
Content-Type: text/plain; charset=UTF-8
Date: Thu, 30 Apr 2020 00:41:21 GMT
Expires: Thu, 30 Apr 2020 00:41:36 GMT
Server: cloudflare
Set-Cookie: __cfduid=d4cb17401215362929759e2da8110f0e31588207281; expires=Sat, 30-May-20 00:41:21 GMT; path=/; domain=.162.159.129.233; HttpOnly; SameSite=Lax
Vary: Accept-Encoding
Content-Length: 16
Connection: close
error code: 1003
If you have any ideas dont hesitate to put them down below, ive been lost on this for a long time.
You could just use D++ to post to webhooks:
https://dpp.dev/classdpp_1_1webhook.html
In fact you could do everything with this lib instead of rolling your own solution.

socket, request http webpage

I am fetching some websites with sockets by making a http request and reading the response header like this:
char buffer[1000];
while ((bytesReceived = tcpSocket.Receive(buffer, 1000-1)) > 0)
{
buffer[bytesReceived] = '\0';
myFile << buffer;
memset(buffer, 0, 1000);
}
This is the receive function:
int fsx::TcpSocket::Receive(char* _buffer, size_t _length)
{
int iResult = recv(this->socketHandler, _buffer, _length, 0);
if (iResult >= 0)
{
return iResult;
}
else
{
return SOCKET_ERROR;
}
}
And this part of the response im getting:
HTTP/1.1 200 OK
Date: Tue, 22 Sep 2015 10:46:10 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: close
Set-Cookie: __cfduid=d01e9db42c5332c444d5105c2cd9fd9e01442918769; expires=Wed, 21-Sep-16 10:46:09 GMT; path=/; domain=.stackoverflow.com; HttpOnly
Cache-Control: public, no-cache="Set-Cookie", max-age=60
Cf-Railgun: 2b57bd3274 5.38 0.314316 0030 3350
Expires: Tue, 22 Sep 2015 10:47:09 GMT
Last-Modified: Tue, 22 Sep 2015 10:46:09 GMT
Vary: *
X-Frame-Options: SAMEORIGIN
X-Request-Guid: 9921fd42-6fd5-4a34-a839-c87d26b2f39a
Set-Cookie: prov=e6796729-38a7-4754-af17-96349ae78010; domain=.stackoverflow.com; expires=Fri, 01-Jan-2055 00:00:00 GMT; path=/; HttpOnly
Server: cloudflare-nginx
CF-RAY: 229d6ca79fef05b5-ARN
3b19 //<------------- WHAT THE HECK IS THIS?
<!DOCTYPE html>
<html itemscope itemtype="http://schema.org/QAPage">
<head>
As you can see, im getting this characters '3b19' at the end of the response header, what is that? Its a different set of characters every single time and I can't seem to find them at: http://www.stackoverflow.com/questions/12691882/how-to-send-and-receive-data-socket-tcp-c-c which is the page that im fetching.
It is a length of the content send used in "chunked encoding".
RFC2616 3.6.1 Chunked Transfer Coding is describing about "chunked encoding".

retrieve multiple cookies from winhttp header

I want to retrieve the cookies from winhttpheader.The problem is that header is in this form:
Header-Contents
Transfer-Encoding: chunked
Server: nginx
Set-Cookie: name=xyz; Path=/
; secure; httponly
Set-Cookie: token=45e8e18440859e769a56b0e1191bea8f1cc049d1; Path=/
; secure; httponly
Now using winhttp_query_set_cookie , I am only getting name field,not token.
do
{
bQuerySizeResult=WinHttpQueryHeaders(hRequest,WINHTTP_QUERY_SET_COOKIE,WINHTTP_HEADER_NAME_BY_INDEX,NULL,&nCookie,WINHTTP_NO_HEADER_INDEX);
WCHAR *strCookie=new WCHAR[nCookie];
LPCTSTR ws1;
bQuerySizeResult=WinHttpQueryHeaders(hRequest,WINHTTP_QUERY_SET_COOKIE,WINHTTP_HEADER_NAME_BY_INDEX,strCookie,&nCookie,WINHTTP_NO_HEADER_INDEX);
std::wcout<<"\n" <<strCookie[0]<<" "<<strCookie[1];
ws1=strCookie;
std::wstring ws(ws1);
std::string str(ws.begin(), ws.end());
LPSTR mystring ;
mystring= const_cast<LPSTR>(str.c_str());
std::cout<<"\nthe str is "<<mystring<<"\n";
}while(bQuerySizeResult);*/

Stay Logged In Cookies with Qt Webview

Background on the program (in case that helps):
I'm trying to make a simple wrapper to go around "web applications" to give them some of the look/feel + isolation that a traditional application brings. I understand that using web technologies makes it way easier to develop for cross platform (especially when it comes to the UI) but I don't like how it has become a sort of catch all solution for lots of dev teams. I don't want to run software inside my web browser.
Browsers are heavy and support a wide range of functions that aren't relevant to what the application does and having a program function entirely in a browser tab can lead to a clunky user experience (I'm looking at you Bittorrent Sync for linux). Instead I would rather use a stripped down browser that is much lighter and runs in its own isolated space rather than in the browser ecosystem.
Additional functionally can be easily tacked on to provide a more fluid user experience (for example if the user doesn't start the program and tries to connect to it through a browser they are going to get HTTP error codes. In this separate wrapper the program could read the error code itself and show some preloaded html to give a more useful error specific to the program).
To accomplish this I am trying to use Qt to create a browser that is simply a web render-er, http communicator, cookie support, and some basic management features (shortcuts for running the program instead of relying on the command line)
PROBLEM:
Checking the "Stay Signed In" box does nothing. I'm pretty sure the way stay signed in works is the server generates an authentication for the browser to store as a cookie.
When I sign into my google account I can see several cookies that are created after logging in that appear to do just that. I can have access to my gmail, calendar, etc. and when I exit the non session cookies are stored to the disk.
When I start the program back up they are loaded from the disk and appear in each request, but I am not signed into an account and the sign in link is visible. If I don't log in again, the old cookies aren't stored to disk again when the program exists.
Here is some debug output of the cookies when I close the program when logged in (cookies saved to disk) then restart the program (loaded from disk) and close it without logging in again (cookies saved):
SAVING COOKIES
GAPS=1:8-XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=accounts.google.com; path=/
NID=XXXXX; HttpOnly; expires=Fri, 01-Jan-2016 17:34:10 GMT; domain=.google.com; path=/
SID=XXXXX; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
LSID=XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=accounts.google.com; path=/
HSID=XXXXX; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
SSID=XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
APISID=XXXXX; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
SAPISID=XXXXX; secure; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
ACCOUNT_CHOOSER=XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=accounts.google.com; path=/
PREF=ID=1111111111111111:FF=0:LD=en:TM=XXXXX:LM=XXXXX:V=1:S=XXXXX_rr5; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
OGPC=5-2:; expires=Sat, 01-Aug-2015 17:34:10 GMT; domain=.google.com; path=/
OTZ=XXXXX; secure; expires=Sat, 01-Aug-2015 17:34:15 GMT; domain=plus.google.com; path=/
build-WebView-Desktop-Debug/WebView exited with code 0
LOADING COOKIES
GAPS=1:8-XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=accounts.google.com; path=/
NID=XXXXX; HttpOnly; expires=Fri, 01-Jan-2016 17:34:10 GMT; domain=.google.com; path=/
SID=XXXXX; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
LSID=XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=accounts.google.com; path=/
HSID=XXXXX; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
SSID=XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
APISID=XXXXX; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
SAPISID=XXXXX; secure; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
ACCOUNT_CHOOSER=XXXXX; secure; HttpOnly; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=accounts.google.com; path=/
PREF=ID=1111111111111111:FF=0:LD=en:TM=XXXXX:LM=XXXXX:V=1:S=XXXXX_rr5; expires=Sat, 01-Jul-2017 17:34:10 GMT; domain=.google.com; path=/
OGPC=5-2:; expires=Sat, 01-Aug-2015 17:34:10 GMT; domain=.google.com; path=/
OTZ=XXXXX; secure; expires=Sat, 01-Aug-2015 17:34:15 GMT; domain=plus.google.com; path=/
SAVING COOKIES
PREF=ID=1111111111111111:FF=0:TM=XXXXX:LM=XXXXX:V=1:S=XXXXX; expires=Sat, 01-Jul-2017 17:34:51 GMT; domain=.google.com; path=/
NID=XXXXX; HttpOnly; expires=Fri, 01-Jan-2016 17:34:51 GMT; domain=.google.com; path=/
OGPC=5-2:; expires=Sat, 01-Aug-2015 17:35:03 GMT; domain=.google.com; path=/
I replaced some keys and numbers with XXXXX to avoid posting anything important online.
Here's the source code producing this output:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
//Manager to allow use of cookiejar
QNetworkAccessManager* nam = new QNetworkAccessManager;
//Used for debug, prints out all cookies after each request is finished
connect(nam, SIGNAL(finished(QNetworkReply*)), this, SLOT(echo(QNetworkReply*)));
//create and assign cookiejar to nam
jar = new CookieJar();
nam->setCookieJar(jar);
//create webview and assign nam to it
webview = new QWebView();
webview->page()->setNetworkAccessManager(nam);
//Display cookies loaded from disk
const QList<QNetworkCookie> cookies = jar->getCookies();
std::cout << std::endl << "Cookies From Disk:" << std::endl << std::endl;
for(QNetworkCookie cookie: cookies)
std::cout << cookie.toRawForm().data() << std::endl;
//Load the test url
QUrl url("http://www.google.com");
webview->load(url);
//place webview on screen
ui->setupUi(this);
setCentralWidget(webview);
}
//Used for debug, prints out all cookies after each request is finished
void MainWindow::echo(QNetworkReply *reply){
const QList<QNetworkCookie> cookies2 = jar->getCookies();
std::cout << std::endl << "Cookies After HTTP:" << std::endl << std::endl;
for(QNetworkCookie cookie: cookies2)
std::cout << cookie.toRawForm().data() << std::endl;
}
Relevant parts of my cookiejar implementation:
bool CookieJar::saveCookiesToDisk(){
std::ofstream output("cookies.dat");
this->purgeOldCookies();
if(output){
QList<QNetworkCookie> cookies = this->allCookies();
std::cout << "\nSAVING COOKIES" << std::endl << std::endl;
for(QNetworkCookie cookie: cookies)
if(!cookie.isSessionCookie()){
std::cout << cookie.toRawForm().data() << std::endl;
output << cookie.toRawForm().data() << this->COOKIE_DELIMITER;
}
output.close();
return true;
}
else{
return false;
}
}
bool CookieJar::loadCookiesFromDisk(){
std::ifstream input("cookies.dat");
if(input){
QList<QNetworkCookie> cookies;
std::string cookieData;
std::cout << "\nLOADING COOKIES" << std::endl << std::endl;
while(getline(input, cookieData, this->COOKIE_DELIMITER)){
std::cout << cookieData << std::endl;
cookies.append(QNetworkCookie(QByteArray(cookieData.c_str(), cookieData.length())));
}
this->setAllCookies(cookies);
return true;
}
else{
return false;
}
}
/**
* This function comes from the official qt demo at
* http://doc.qt.io/qt-5/qtwebkitexamples-webkitwidgets-browser-cookiejar-cpp.html
*/
void CookieJar::purgeOldCookies(){
QList<QNetworkCookie> cookies = allCookies();
if (cookies.isEmpty())
return;
int oldCount = cookies.count();
QDateTime now = QDateTime::currentDateTime();
for (int i = cookies.count() - 1; i >= 0; --i) {
if (!cookies.at(i).isSessionCookie() && cookies.at(i).expirationDate() < now)
cookies.removeAt(i);
}
if (oldCount == cookies.count())
return;
setAllCookies(cookies);
//This last line from the example was omitted as it is not relevant to the function of this project?
//emit cookiesChanged();
}
Any help figuring out why my stored cookies seem to be ignored by the server would be greatly appreciated. As far as I can tell I am properly storing and sending all cookies so I wouldn't be surprised if I've oversimplified how these authentication cookies work.
Thank you to anyone taking time out of their day to help me out here.
I have an working example of a 'stay logged' application, here are the load&save functions:
bool loadLoginCookie()
{
QDir cookiesDir("dir where cookie is stored");
if(! cookiesDir.exists())
{
return false;
}
QFile cookieFile(cookiesDir.path() + "/cookie.dat");
if(! cookieFile.exists())
{
return false;
}
if(! cookieFile.open(QIODevice::ReadOnly))
{
qDebug() << "Error reading the cookie file:" << cookieFile.fileName();
}
QByteArray cookieRaw = cookieFile.readAll();
cookieFile.close();
QList<QNetworkCookie> newCookies = QNetworkCookie::parseCookies(cookieRaw);
if (newCookies.count() == 0 && cookieRaw.length() != 0)
{
qDebug() << "CookieJar: Unable to parse saved cookie:" << cookieRaw;
}
QNetworkManager& myAppNetworkManager =Application::getInstance().getNetworkManager();
myAppNetworkManager.fillCookiesJar(newCookies, QUrl("theurl:443"));
foreach (QNetworkCookie cookie, newCookies)
{
if(cookie.name() == "connect.sid") //loging cookie
{
Application::getInstance().setLoginCookie(cookie); //here i save the login cookie in a class QNetworkCookie*
qDebug() << "cookie loaded";
}
else
{
qDebug() << "Error loading the login cookie.";
}
}
return true;
}
bool Application::saveLoginCookie(const QNetworkCookie &cookie)
{
QDir cookiesDir("dir where cookie must be stored");
if(! cookiesDir.exists())
{
if(! cookiesDir.mkpath("."))
{
qDebug() << "Error creating the cookies directory";
return false;
}
}
QFile cookieFile(cookiesDir.path() + "/cookie.dat");
if(! cookieFile.open(QIODevice::WriteOnly))
{
qDebug() << "Error saving the cookie file:" << cookieFile.fileName();
return false;
}
cookieFile.write(cookie.toRawForm());
cookieFile.close();
qDebug() << "Login cookie created successfully.";
return true;
});
This save function is called after the login operation:
QVariant cookieVar = reply.header(QNetworkRequest::SetCookieHeader);//reply is the QNetworkReply returned by the login operation
if(cookieVar.isValid())
{
QList<QNetworkCookie> cookies = cookieVar.value<QList<QNetworkCookie> >();
foreach (QNetworkCookie cookie, cookies)
{
if(cookie.name() == "connect.sid") //loging cookie
{
if(! saveLoginCookie(cookie))
{
qDebug() << "Error saving login cookie";
}
}
}
}
else
{
qDebug() << "Login cookie not valid";
}
}
I know that its not a reimplementation of the cookieJar but it maybe gives you inspiration. We can discuss it further if you can't make it work.

Extract cookies from an http header

I'm writing a C++ function that's going to extract cookies from an http header. The header is inside a string and it looks like this:
HTTP/1.1 200 OK
cache-control: no-cache, no-store, max-age=0, must-revalidate
content-language: en
content-length: 3202
content-type: text/html; charset=utf-8
date: Fri, 25 Apr 2014 13:31:44 GMT
etag: "46ec0cd3920851f7b63dbaa70280cd32"
expires: Mon, 01 Jan 1990 00:00:00 GMT
pragma: no-cache
server: tfe
set-cookie: d=32; path=/; expires=Sat, 25-Apr-2015 13:31:44 GMT
set-cookie: req_country=United+Kingdom; path=/; expires=Sun, 25-May-2014 13:31:44 GMT
I need this function to find the cookies:
set-cookie: d=32; path=/; expires=Sat, 25-Apr-2015 13:31:44 GMT
set-cookie: req_country=United+Kingdom; path=/; expires=Sun, 25-May-2014 13:31:44 GMT
and put them in to another string that's going to look lie this:
d=32; req_country=United+Kingdom;
There can also be more than 2 cookies in each header.
I've tried:
size_t p1 = header_data.find("set-cookie:");
size_t p2 = header_data.find(";");
std::string head = header_data.substr(p1,p2-p1);
and after execution it gave me the following error:
terminate called after throwing an instance of 'std::out_of_range'
what(): basic_string::substr
Aborted (core dumped)
Try this code. Not optimized, but i guess it works in way you want:
#include <iostream>
#include <vector>
#include <sstream>
using namespace std;
std::vector<std::string> &split(const std::string &s, char delim, std::vector<std::string> &elems) {
std::stringstream ss(s);
std::string item;
while (std::getline(ss, item, delim)) {
elems.push_back(item);
}
return elems;
}
std::vector<std::string> split(const std::string &s, char delim) {
std::vector<std::string> elems;
split(s, delim, elems);
return elems;
}
int main() {
std::string header =
"HTTP/1.1 200 OK\n"
"cache-control: no-cache, no-store, max-age=0, must-revalidate\n"
"content-language: en\n"
"content-length: 3202\n"
"content-type: text/html; charset=utf-8\n"
"date: Fri, 25 Apr 2014 13:31:44 GMT\n"
"etag: \"46ec0cd3920851f7b63dbaa70280cd32\"\n"
"expires: Mon, 01 Jan 1990 00:00:00 GMT\n"
"pragma: no-cache\n"
"server: tfe\n"
"set-cookie: d=32; path=/; expires=Sat, 25-Apr-2015 13:31:44 GMT\n"
"set-cookie: req_country=United+Kingdom; path=/; expires=Sun, 25-May-2014 13:31:44 GMT\";\n";
vector<string> headerLines = split(header, '\n');
for (int i(0); i != headerLines.size(); ++i) {
if (headerLines[i].find("set-cookie:") != std::string::npos) {
std::string variablesPart = split(split(headerLines[i], ';')[0], ':')[1];
std::cout << "\nExtracted: {" << variablesPart << "}";
}
}
}