PDA

View Full Version : HTTP GET authentication does not proceed



SailingDreams
27th May 2009, 23:03
I am trying to authenticate but get the QT "Authentication required" from the QT requestFinished handler. My code outputs the qDebug below. The "Authenication req'd ..." statement gets printed when the QT signal authenticationRequired is fired. So since the authentication signal fired, and can't figure out why I get teh "Authentication required" error.

When I look at the wireShark trace, I can see the HTTP 401 unauthorized response from the server and then I see the TCP connection close (as it should). But what does not happen is QT creating a new TCP session followed by the second GET - this one having the authentication info (password and username).

I stepped into the QAuthenticator::setpassword and setuser and I can see the passworkd and user being set.

The error output is kinda useless.

I have compared my code to the QT examples and I don't think I am missing anything that would prevent the second TCP session from starting.

I also have my code below the qDebug output. Any ideas what I am missing?


HTTP requestStarted slot handler for request type setHost (id = 1)
HTTP requestFinished handler: error for request setHost, error = No error
HTTP done signal slot handler. No Error.
HTTP requestStarted slot handler for request type GET (id = 2)
HTTP State for request type GET changed to Connecting
HTTP State for request type GET changed to Sending
HTTP State for request type GET changed to Reading
Authentication req'd for host 169.xxx.xxx.xxx, User Name = root, Password = smokey
HTTP requestFinished handler: error for request GET, error = Authentication required
HTTP done signal slot handler. Error: Authentication required
HTTP State for request type changed to Closing
HTTP State for request type changed to Unconnected



My cpp file. The run() is at the bottom.


#include <QtCore/QCoreApplication>
#include <QThread>
#include <QHttp>
#include <QTimer>
#include <QUrl>
#include <QHash>
#include "MyThread.h"
#include "Windows.h"

//----------------------------------------------------------------------------------
MyThread::MyThread()
{
}
//----------------------------------------------------------------------------------
void MyThread::done( bool error ) // true if error occurs
{
if(error)
{
QHttp::Error err = m_pHttp->error();
QString err_Str = m_pHttp->errorString();
qDebug("HTTP done signal slot handler. Error: %s", err_Str.toAscii().data());
}
else
qDebug("HTTP done signal slot handler. No Error.");
}

//-------------------------------------------------------------------------------------------
void MyThread::init(void)
{
m_Host = "169.254.177.84";
m_UserName = "root";
m_Password = "smokey";
m_HttpPort = 80;
m_SerialPort = 1;

m_HttpStateTable[QHttp::Unconnected] = "Unconnected";
m_HttpStateTable[QHttp::HostLookup] = "HostLookup";
m_HttpStateTable[QHttp::Connecting] = "Connecting";
m_HttpStateTable[QHttp::Sending] = "Sending";
m_HttpStateTable[QHttp::Reading] = "Reading";
m_HttpStateTable[QHttp::Connected] = "Connected";
m_HttpStateTable[QHttp::Closing] = "Closing";

}
// -----------------------------------------------------------------------------
void MyThread::initSignalsAndSlots(void)
{
connect(m_pHttp, SIGNAL(authenticationRequired(const QString &, quint16, QAuthenticator *)),
this, SLOT(slotAuthenticationRequired(const QString &, quint16, QAuthenticator *)));
connect( m_pHttp, SIGNAL( requestStarted ( int ) ), this, SLOT( requestStarted( int ) ) );
connect( m_pHttp, SIGNAL( requestFinished ( int , bool ) ), this, SLOT( requestFinished ( int , bool ) ) );
connect( m_pHttp, SIGNAL( stateChanged ( int ) ), this, SLOT( stateChanged ( int ) ) );
connect( m_pHttp, SIGNAL(responseHeaderReceived(const QHttpResponseHeader &)),
this, SLOT(readResponseHeader(const QHttpResponseHeader &)));
connect( m_pHttp, SIGNAL( done ( bool ) ), this, SLOT( done (bool ) ) );
}

// -----------------------------------------------------------------------------
void MyThread::requestStarted( int id )
{
qDebug( "HTTP requestStarted slot handler for request type %s (id = %d)",
m_httpRequestIdHashTable[id].toAscii().data(),id);
int nothing = 0;
nothing++;
}

// -----------------------------------------------------------------------------

void MyThread::requestFinished( int id, bool error )
{
//qDebug( "HTTP requestFinished slot handler for request type %s (id = %d), error = %d",
// m_httpRequestIdHashTable[id].toAscii().data(), id, error);

int nothing = 0;
nothing++;
QString err_Str = "No error";
if( error )
{
QHttp::Error err = m_pHttp->error();
err_Str = m_pHttp->errorString();
nothing--;
}
qDebug( "HTTP requestFinished handler: error for request %s, error = %s",
m_httpRequestIdHashTable[id].toAscii().data(), err_Str.toAscii().data());
}
// -----------------------------------------------------------------------------
void MyThread::readResponseHeader(const QHttpResponseHeader &responseHeader)
{
# if 1
switch (responseHeader.statusCode()) {
case 200: // Ok
//case 301: // Moved Permanently
//case 302: // Found
//case 303: // See Other
//case 307: // Temporary Redirect
{
qDebug("HTTP Header status 200 (OK) found");

// See if there are pending requests
if(m_pHttp->hasPendingRequests())
qDebug("There are pending requests.");
else
qDebug("There are NO pending requests.");

// Get info on current ID
int id = m_pHttp->currentId();
qDebug( "Closing connection for request type %s",
m_httpRequestIdHashTable[id].toAscii().data());
//emit( abortHttpConnection() ); //??ejp This kills the TCP link and stops the video stream.
m_pHttp->clearPendingRequests(); // clear pending request and start close request.
id = m_pHttp->close(); // Tried close() but nothing happened.
m_httpRequestIdHashTable.insert(id,"close");
break;
}
default:
//QMessageBox::information(this, tr("HTTP"),
// tr("Download failed: %1.")
// .arg(responseHeader.reasonPhrase()));
break;
}
#endif
}
//----------------------------------------------------------------------------------
void MyThread::slotAuthenticationRequired(const QString & hostname,
quint16 port, QAuthenticator * authenticator)
{
qDebug( "Authentication req'd for host %s, User Name = %s, Password = %s",
hostname.toAscii().data(), m_UserName.toAscii().data(), m_Password.toAscii().data() ); //??ejp debug
authenticator->setUser( m_UserName );
authenticator->setPassword( m_Password );

}
//----------------------------------------------------------------------------------
void MyThread::stateChanged( int state)
{
Q_ASSERT(state < 7); // There are only 7 states for QHTTP
QString request = m_httpRequestIdHashTable[m_pHttp->currentId()];
qDebug( "HTTP State for request type %s changed to %s",
request.toAscii().data(), m_HttpStateTable[state].toAscii().data());
}

//----------------------------------------------------------------------------------
void MyThread::callbackFunc(void)
{
int id = m_pHttp->setHost( m_Host, QHttp::ConnectionModeHttp, m_HttpPort );
m_httpRequestIdHashTable.insert(id,"setHost");

Sleep( 100); // wait for setHost to finish.

QString port_str = QString::number( m_SerialPort+1 );
#if 0
QString url_for_cmds = QString("/axis-cgi/com/serial.cgi?port=" + port_str );
#else
QString url_for_cmds = QString("/axis-cgi/mjpg/video.cgi");
#endif
id = m_pHttp->get(QUrl::toPercentEncoding(url_for_cmds) );
m_httpRequestIdHashTable.insert(id,"GET");

id = m_pHttp->get(url_for_cmds );
m_httpRequestIdHashTable.insert(id,"GET");

//while(1)
// Sleep( 10);

//m_pHttp->get();
};

//----------------------------------------------------------------------------------
void MyThread::run(void)
{
init();
m_pHttp = new QHttp();
initSignalsAndSlots(); // Need m_pHttp initialized first!

QTimer::singleShot(1000, this, SLOT(callbackFunc())); // milli second timeout.

//m_pTimer = new QTimer(callback ;

QThread::exec ();
//int res = QCoreApplication::exec();

};

wysota
28th May 2009, 01:36
QHttp won't "rerequest" a failed request. It's a low-level mechanism, not a full blown solution. If you get an authentication error, it is your responsibility to set the user and password and send another request.

SailingDreams
1st June 2009, 02:27
:confused:I'm confused then by the QT exaple in

http://doc.trolltech.com/4.4/network-http.html

I followed the QT example where they set the password in the slot connected to the QHttp signal authenticationRequired(). I copied the QT example slot function below.


void HttpWindow::slotAuthenticationRequired(const QString &hostName, quint16, QAuthenticator *authenticator)
{
QDialog dlg;
Ui::Dialog ui;
ui.setupUi(&dlg);
dlg.adjustSize();
ui.siteDescription->setText(tr("%1 at %2").arg(authenticator->realm()).arg(hostName));

if (dlg.exec() == QDialog::Accepted) {
authenticator->setUser(ui.userEdit->text());
authenticator->setPassword(ui.passwordEdit->text());
}
}

When I looked at the example's header response handler below, it does not have any case for authentication required. So perhaps the example is incorrect? Should it have a case 401 Unauthorized? I understand what you are saying about handling the error manually, but I'd sure like to know how QT's example is supposed to work.


void HttpWindow::readResponseHeader(const QHttpResponseHeader &responseHeader)
{
switch (responseHeader.statusCode()) {
case 200: // Ok
case 301: // Moved Permanently
case 302: // Found
case 303: // See Other
case 307: // Temporary Redirect
// these are not error conditions
break;

default:
QMessageBox::information(this, tr("HTTP"),
tr("Download failed: %1.")
.arg(responseHeader.reasonPhrase()));
httpRequestAborted = true;
progressDialog->hide();
http->abort();
}
}:o