Trolltech Home | Qt-interest Home | Recent Threads | All Threads | Author | Date
All threads index page 3

Qt-interest Archive, September 2007
QHttp::setSocket() not setting the socket


Message 1 in thread

Hi,

Below is a small code snippet that should connect to the localhost with
a QSslSocket, then pass that socket to QHttp and QHttp should use that
socket to issue the request. At least that's how it makes sense to me,
as I never used QHttp::setSocket before.

Now, if I try this connection with just QHttp (SSL) without using
setSocket, it works.

If I add the setHost (commented below), then QHttp will attempt to
connect with its internal socket, instead of the one that was passed.

How can I make QHttp use the socket I provide to pass/receive HTTP
traffic without trying to connect again?

Tried this with 4.3.1, 4.3.0 and latest 4.3.2 snapshot.

Thanks,
Adam


PS. The SSL socket connects and is just sitting there waiting to be used.

============

#include <QHttp>
#include <QSslSocket>
#include <QCoreApplication>

const QString test_server = "localhost";
const int test_port = 8888;


class HttpsTest : public QObject
{
    Q_OBJECT

private:
    QHttp http;
    QSslSocket sock;

public slots:
    void reqFini( int id, bool err ){
       qDebug( "id: %d, ok?: %d", id, (int)!err );
       QByteArray ba = http.readAll().constData();
       qDebug( "size: %d", ba.size());
       qDebug( "txt: %s", ba.constData());
    }

    void done( bool err ){
       qDebug( "all done: %d", (int)!err );
       QCoreApplication::exit(0);
    }

public:
    HttpsTest():sock(this),http(this){
       // connect to test server, post a GET request
       sock.connectToHostEncrypted( test_server, test_port );
       sock.waitForEncrypted();

       connect( &http, SIGNAL(requestFinished(int,bool)), this,
SLOT(reqFini(int,bool)));
       // http.setHost(test_server,test_port);
       http.setSocket( &sock );
       int id = http.get( "/upload/test" );
       qDebug( "id: %d", id );
    }
};

#include "test_moc.h"

int main( int argc, char*argv[]){
    QCoreApplication app( argc, argv );
    HttpsTest test;
    return app.exec();
}


--
 [ signature omitted ] 

Message 2 in thread

On Friday 14 September 2007 21:21:49 Adam M wrote:
> Below is a small code snippet that should connect to the localhost with
> a QSslSocket, then pass that socket to QHttp and QHttp should use that
> socket to issue the request. At least that's how it makes sense to me,
> as I never used QHttp::setSocket before.
>
> Now, if I try this connection with just QHttp (SSL) without using
> setSocket, it works.
>
> If I add the setHost (commented below), then QHttp will attempt to
> connect with its internal socket, instead of the one that was passed.
>
> How can I make QHttp use the socket I provide to pass/receive HTTP
> traffic without trying to connect again?
>
> Tried this with 4.3.1, 4.3.0 and latest 4.3.2 snapshot.
>
> Thanks,
> Adam

Please update to the latest snapshots and try again.

I have been working with QHttp trying to fix bugs. One I have recently fixed 
dealt with setSocket and a QSslSocket.

So maybe your problem is gone.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 3 in thread

Thiago Macieira wrote:
> On Friday 14 September 2007 21:21:49 Adam M wrote:
>> Below is a small code snippet that should connect to the localhost with
>> a QSslSocket, then pass that socket to QHttp and QHttp should use that
>> socket to issue the request. At least that's how it makes sense to me,
>> as I never used QHttp::setSocket before.
>>
>> Now, if I try this connection with just QHttp (SSL) without using
>> setSocket, it works.
>>
>> If I add the setHost (commented below), then QHttp will attempt to
>> connect with its internal socket, instead of the one that was passed.
>>
>> How can I make QHttp use the socket I provide to pass/receive HTTP
>> traffic without trying to connect again?
>>
>> Tried this with 4.3.1, 4.3.0 and latest 4.3.2 snapshot.
>>
>> Thanks,
>> Adam
> 
> Please update to the latest snapshots and try again.
> 
> I have been working with QHttp trying to fix bugs. One I have recently fixed 
> dealt with setSocket and a QSslSocket.

Checked with the latest snapshot (Sept. 14). The problem remains. It is 
like the encrypted socket is never used. The server never received a 
request.

Or maybe my test app is messed up (in original post) or I don't 
understand the way setSocket is suppose to work.

- Adam

--
 [ signature omitted ] 

Message 4 in thread

Problem solved. QHttp works since the Sept 14th snapshot, although there 
are some issues with the documentation for setSocket. If the socket set 
with setSocket is connected, QHttp will only use that connection if,

  * hostname/port for socket matches that of QHttp request
  * socket isEnrypted() is compatible with encryption setting for QHttp
  * QHttp has a destination host/port set

On my wishlist would be,
  * socket set with setSocket should only be checked if connected and 
used irrespective of encryption of hostname/port settings.
  * Host: header does not need to be set (my reading of RFC for HTTP 
1.1). If unset, it must be transmitted as an empty header.

Furthermore, snapshots prior to Sept 14th, did not work correctly with 
setSocket.

Cheers,
Adam

--
 [ signature omitted ] 

Message 5 in thread

Adam M wrote:
>  * Host: header does not need to be set (my reading of RFC for HTTP
>1.1). If unset, it must be transmitted as an empty header.

The Host: header has to be set for a meaningful page to be retrieved. 

Compare the difference in the three requests below. Notice that only the 
third one would return any meaningful information.

$ telnet www.trolltech.com 80
Trying 62.70.27.147...
Connected to www.trolltech.com (62.70.27.147).
Escape character is '^]'.
GET / HTTP/1.1
Connection: close

HTTP/1.1 200 OK
Content-Type: text/html
ETag: "1158161509220634264"
Last-Modified: Wed, 11 Apr 2007 10:24:35 GMT
Date: Mon, 17 Sep 2007 19:52:20 GMT
Server: lighttpd/1.4.11
Content-Length: 14
X-Varnish: 1873178347 1873161654
Age: 2296
Via: 1.1 varnish
Connection: close

<html></html>
Connection closed by foreign host

$ telnet www.trolltech.com 80
Trying 62.70.27.147...
Connected to www.trolltech.com (62.70.27.147).
Escape character is '^]'.
GET / HTTP/1.1
Host:

HTTP/1.1 200 OK
Content-Type: text/html
ETag: "1158161509220634264"
Last-Modified: Wed, 11 Apr 2007 10:24:35 GMT
Date: Mon, 17 Sep 2007 19:52:20 GMT
Server: lighttpd/1.4.11
Content-Length: 14
X-Varnish: 1873178537 1873161654
Age: 2314
Via: 1.1 varnish

<html></html>

$ telnet www.trolltech.com 80
Trying 62.70.27.147...
Connected to www.trolltech.com (62.70.27.147).
Escape character is '^]'.
GET / HTTP/1.1
Host: www.trolltech.com

HTTP/1.1 301 Moved Permanently
Location: http://trolltech.com/
Date: Mon, 17 Sep 2007 20:19:18 GMT
Server: lighttpd/1.4.11
Content-Length: 0
X-Varnish: 1873178737 1873173418
Age: 711
Via: 1.1 varnish

Connection closed by foreign host.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 6 in thread

Thiago Macieira wrote:
> Adam M wrote:
>>   * Host: header does not need to be set (my reading of RFC for HTTP
>> 1.1). If unset, it must be transmitted as an empty header.
> 
> The Host: header has to be set for a meaningful page to be retrieved. 
> 

http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23

HTTP protocol does not require this.

"A client MUST include a Host header field in all HTTP/1.1 request 
messages . If the requested URI does not include an Internet host name 
for the service being requested, then the Host header field MUST be 
given with an empty value. An HTTP/1.1 proxy MUST ensure that any 
request message it forwards does contain an appropriate Host header 
field that identifies the service being requested by the proxy. All 
Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request) 
status code to any HTTP/1.1 request message which lacks a Host header 
field."

This also means your proxy is buggy? Or troll's server is buggy?

Furthermore, not specifying the host does NOT work with transparent 
proxies, but that is not the issue here.

> Compare the difference in the three requests below. Notice that only the 
> third one would return any meaningful information.

That is the problem of having named virtual hosts. Or transparent 
proxies. But this is not a problem for HTTPS.

The bottom line is I do not think Qt should be really babying us too 
much by trying to do too much and only allowing the expected states. 
After all, we are developers not little kids. And QHttp should issue the 
request without setting the host. :) If we do not set the host, it 
should be up to us to know better.

Another peeve I have is that QHttp expects the Host: and socket hostname 
and encryption to be the same. Why does QHttp deal at all with the 
transport layer? It is supposedly transparent. Trolls, stop babying us! :)

- Adam

--
 [ signature omitted ] 

Message 7 in thread

Adam M wrote:
>Thiago Macieira wrote:
>> Adam M wrote:
>>>   * Host: header does not need to be set (my reading of RFC for HTTP
>>> 1.1). If unset, it must be transmitted as an empty header.
>>
>> The Host: header has to be set for a meaningful page to be retrieved.
>
>http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23
>
>HTTP protocol does not require this.
>
>"A client MUST include a Host header field in all HTTP/1.1 request
>messages . If the requested URI does not include an Internet host name
>for the service being requested, then the Host header field MUST be
>given with an empty value. An HTTP/1.1 proxy MUST ensure that any
>request message it forwards does contain an appropriate Host header
>field that identifies the service being requested by the proxy. All
>Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
>status code to any HTTP/1.1 request message which lacks a Host header
>field."

The first sentence of the excerpt you quoted contradicts your assertion. 
The Host: header is mandatory in HTTP/1.1.

See also §19.6.1.1:
"      - Both clients and servers MUST support the Host request-header.

      - A client that sends an HTTP/1.1 request MUST send a Host header.

      - Servers MUST report a 400 (Bad Request) error if an HTTP/1.1
        request does not include a Host request-header."

>This also means your proxy is buggy? Or troll's server is buggy?

Neither. The Trolltech webserver is operating just fine, as is Apache on 
my laptop.

For verification:
$ (echo GET / HTTP/1.1; echo) | nc localhost 80
HTTP/1.1 400 Bad Request
Date: Thu, 20 Sep 2007 20:04:01 GMT
Server: Apache/2.2.4 (Mandriva Linux/PREFORK-6mdv2007.1)
Content-Length: 335
Connection: close
Content-Type: text/html; charset=iso-8859-1
[....]

>Furthermore, not specifying the host does NOT work with transparent
>proxies, but that is not the issue here.

It's the other way around. If you don't specify a Host, transparent 
proxies can't work. They only work *because* there is a Host: field.

>> Compare the difference in the three requests below. Notice that only
>> the third one would return any meaningful information.
>
>That is the problem of having named virtual hosts. Or transparent
>proxies. But this is not a problem for HTTPS.

There's an extension to the SSL protocol that allows for requesting 
a "virtual host" in the SSL negotiation. QHttp does not implement this, 
but the possibility is there. (As far as I know, no browser implements 
it; Apache-httpd doesn't have it because no browser has it either)

Not to mention that the reply can be different according to the Host: 
field, even on SSL. There is such a thing as wildcard certificates.

>The bottom line is I do not think Qt should be really babying us too
>much by trying to do too much and only allowing the expected states.
>After all, we are developers not little kids. And QHttp should issue the
>request without setting the host. :) If we do not set the host, it
>should be up to us to know better.

I don't agree. QHttp will always set the host. Read 19.6.1.1 above.

This means you must somehow inform QHttp what the hostname is. I can agree 
that it should let you do that without calling connectToHost. Please file 
a suggestion with qt-bugs@xxxxxxxxxxxxx (or support@xxxxxxxxxxxxx if you 
have a support contract). I will take that into consideration for future 
improvements.

>Another peeve I have is that QHttp expects the Host: and socket hostname
>and encryption to be the same. Why does QHttp deal at all with the
>transport layer? It is supposedly transparent. Trolls, stop babying us!
> :)

Again, no. The SSL verification on the certificate forces the hostname on 
the certificate to match the hostname we tried to connect to. This is the 
most basic security possible. Just try going to any HTTPS website whose 
certificate doesn't match the address you typed. Your browser is going to 
tell you that there's a problem.

You can call ignoreSslErrors() on your socket if you want. That way, the 
hostname will not be verified to match the certificate. Only do that if 
you're absolutely sure of what you're doing. It could be a security 
breach in your application.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 8 in thread

On 9/20/07, Thiago Macieira <thiago.macieira@xxxxxxxxxxxxx> wrote:
> There's an extension to the SSL protocol that allows for requesting
> a "virtual host" in the SSL negotiation. QHttp does not implement this,
> but the possibility is there. (As far as I know, no browser implements
> it; Apache-httpd doesn't have it because no browser has it either)

There is a patch set for apache that adds support for this, I suspect
it will make it into the release before too long. I also vaguely
remember reading that it is supported by IE 7 but I've no idea if
that's true.

Rich.

--
 [ signature omitted ] 

Message 9 in thread

On 9/20/07, Richard Moore <richmoore44@xxxxxxxxx> wrote:
> On 9/20/07, Thiago Macieira <thiago.macieira@xxxxxxxxxxxxx> wrote:
> > There's an extension to the SSL protocol that allows for requesting
> > a "virtual host" in the SSL negotiation. QHttp does not implement this,
> > but the possibility is there. (As far as I know, no browser implements
> > it; Apache-httpd doesn't have it because no browser has it either)
>
> There is a patch set for apache that adds support for this, I suspect
> it will make it into the release before too long. I also vaguely
> remember reading that it is supported by IE 7 but I've no idea if
> that's true.

Here's the reference for IE support, search for Server Name Indication:

http://blogs.msdn.com/ie/archive/2005/10/22/483795.aspx

Rich.

--
 [ signature omitted ] 

Message 10 in thread

Richard Moore wrote:
> On 9/20/07, Thiago Macieira <thiago.macieira@xxxxxxxxxxxxx> wrote:
>> There's an extension to the SSL protocol that allows for requesting
>> a "virtual host" in the SSL negotiation. QHttp does not implement this,
>> but the possibility is there. (As far as I know, no browser implements
>> it; Apache-httpd doesn't have it because no browser has it either)
> 
> There is a patch set for apache that adds support for this, I suspect
> it will make it into the release before too long. I also vaguely
> remember reading that it is supported by IE 7 but I've no idea if
> that's true.

This is nice and dandy, but also quite irrelevant.

Host:

is just as valid as,

Host: my.host.name

That's what I'm trying to get across here.

- Adam

--
 [ signature omitted ] 

Message 11 in thread

Adam M wrote:
>Richard Moore wrote:
>> On 9/20/07, Thiago Macieira <thiago.macieira@xxxxxxxxxxxxx> wrote:
>>> There's an extension to the SSL protocol that allows for requesting
>>> a "virtual host" in the SSL negotiation. QHttp does not implement
>>> this, but the possibility is there. (As far as I know, no browser
>>> implements it; Apache-httpd doesn't have it because no browser has it
>>> either)
>>
>> There is a patch set for apache that adds support for this, I suspect
>> it will make it into the release before too long. I also vaguely
>> remember reading that it is supported by IE 7 but I've no idea if
>> that's true.
>
>This is nice and dandy, but also quite irrelevant.
>
>Host:
>
>is just as valid as,
>
>Host: my.host.name
>
>That's what I'm trying to get across here.

Indeed. But QHttp has no support for that, since the only way of 
specifying a hostname is via connectToHost().

Like I said, please file an improvement request to set the hostname 
without causing a socket connection. I'll consider that for future 
improvements for QHttp.

-- 
 [ signature omitted ] 

Attachment: signature.asc
Description: This is a digitally signed message part.


Message 12 in thread

Replying to newsgroup... Trolltech email gateway is not co-ordinated 
with the news authenticator. Sorry in advance for the bad formatting....

Same content, maybe slightly different formatting, Thiago..

Thiago Macieira wrote:
> Adam M wrote:
>> Thiago Macieira wrote:
>>> Adam M wrote:
>>>>   * Host: header does not need to be set (my reading of RFC for HTTP
>>>> 1.1). If unset, it must be transmitted as an empty header.
>>> The Host: header has to be set for a meaningful page to be retrieved.
>> http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.23
>>
>> HTTP protocol does not require this.
>>
>> "A client MUST include a Host header field in all HTTP/1.1 request


>> messages . If the requested URI does not include an Internet host name
>> for the service being requested, then the Host header field MUST be
>> given with an empty value. An HTTP/1.1 proxy MUST ensure that any

========================================================================
=== Above 3 lines are the key here.

>> request message it forwards does contain an appropriate Host header
>> field that identifies the service being requested by the proxy. All
>> Internet-based HTTP/1.1 servers MUST respond with a 400 (Bad Request)
>> status code to any HTTP/1.1 request message which lacks a Host header
>> field."
> 
> The first sentence of the excerpt you quoted contradicts your assertion. 
> The Host: header is mandatory in HTTP/1.1.
> 
> See also §19.6.1.1:
> "      - Both clients and servers MUST support the Host request-header.
> 
>       - A client that sends an HTTP/1.1 request MUST send a Host header.
> 
>       - Servers MUST report a 400 (Bad Request) error if an HTTP/1.1
>         request does not include a Host request-header."
> 

Sometimes I keep writing one thing and mean another. I did not mean that 
you have Host that is absent. I meant that you have a NULL Host.

When QHttp hostname/port is NOT set, QHost should export Host header as 
an empty header. That is what is required. It is NOT required that Host: 
header be non-empty.


>> This also means your proxy is buggy? Or troll's server is buggy?
> 
> Neither. The Trolltech webserver is operating just fine, as is Apache on 
> my laptop.
> 
> For verification:
> $ (echo GET / HTTP/1.1; echo) | nc localhost 80
> HTTP/1.1 400 Bad Request
> Date: Thu, 20 Sep 2007 20:04:01 GMT
> Server: Apache/2.2.4 (Mandriva Linux/PREFORK-6mdv2007.1)
> Content-Length: 335
> Connection: close
> Content-Type: text/html; charset=iso-8859-1
> [....]
> 

Add en empty Host:
It will work

See this,

adamm@mira:~$ (echo GET / HTTP/1.1; echo Host: ;echo) | nc localhost 80
HTTP/1.1 302 Found
Date: Thu, 20 Sep 2007 20:33:03 GMT
Server: Apache/2.2.4 (Debian)
Location: http:///apache2-default/
Content-Length: 273
Content-Type: text/html; charset=iso-8859-1


Furthermore, trolltech webserver IS broken (you should have noriced it 
if you tried your command on www.trolltech.com -- it replied with 200!),

proxy:~# (echo GET / HTTP/1.1; echo Host:;echo) | nc www.trolltech.com 
80 | head -20
HTTP/1.1 400 Bad Request
Content-Type: text/html
Date: Thu, 20 Sep 2007 20:44:57 GMT

proxy:~# (echo GET / HTTP/1.1; echo) | nc www.trolltech.com 80 | head
HTTP/1.1 200 OK
Content-Type: text/html
ETag: "1158161509220634264"

The first one should WORK, and second one should FAIL. It does it 
backwards. Apache does it correctly.


>> Furthermore, not specifying the host does NOT work with transparent
>> proxies, but that is not the issue here.
> 
> It's the other way around. If you don't specify a Host, transparent 
> proxies can't work. They only work *because* there is a Host: field.
> 
>>> Compare the difference in the three requests below. Notice that only
>>> the third one would return any meaningful information.
>> That is the problem of having named virtual hosts. Or transparent
>> proxies. But this is not a problem for HTTPS.
> 
> There's an extension to the SSL protocol that allows for requesting 
> a "virtual host" in the SSL negotiation. QHttp does not implement this, 
> but the possibility is there. (As far as I know, no browser implements 
> it; Apache-httpd doesn't have it because no browser has it either)
> 
> Not to mention that the reply can be different according to the Host: 
> field, even on SSL. There is such a thing as wildcard certificates.
> 

Yes, but that is not the issue here. The issue is that,

Host:

is just as valid as,

Host: hostname.is.here

Having NO Host header in HTTP 1.1 request is WRONG but that is not my 
argument.


>> The bottom line is I do not think Qt should be really babying us too
>> much by trying to do too much and only allowing the expected states.
>> After all, we are developers not little kids. And QHttp should issue the
>> request without setting the host. :) If we do not set the host, it
>> should be up to us to know better.
> 
> I don't agree. QHttp will always set the host. Read 19.6.1.1 above.

Which is wrong. See my explanation above. Read the 3 lines above too  :)

> This means you must somehow inform QHttp what the hostname is. I can agree 
> that it should let you do that without calling connectToHost. Please file 
> a suggestion with qt-bugs@xxxxxxxxxxxxx (or support@xxxxxxxxxxxxx if you 
> have a support contract). I will take that into consideration for future 
> improvements.

It already does that  :)  setSocket with connected socket does that, but 
QHttp is anal about checking conditions for the connection instead of 
just checking that the state is Connected.

I can send you a patch that fixes the problem. It is literally a handful 
of lines long.

>> Another peeve I have is that QHttp expects the Host: and socket hostname
>> and encryption to be the same. Why does QHttp deal at all with the
>> transport layer? It is supposedly transparent. Trolls, stop babying us!
>> :)
> 
> Again, no. The SSL verification on the certificate forces the hostname on 
> the certificate to match the hostname we tried to connect to. This is the 
> most basic security possible. Just try going to any HTTPS website whose 
> certificate doesn't match the address you typed. Your browser is going to 
> tell you that there's a problem.
> 

But that is NOT the issue with HTTP! It belongs to the TCP layer of the 
connection. It belongs to the QSslSocket.

QSslSocket checks the peerCertificate (at least it *should* - it DOES 
NOT at the moment). This has nothing to do with HTTP or QHttp. It is 
another transport layer.

> You can call ignoreSslErrors() on your socket if you want. That way, the 
> hostname will not be verified to match the certificate. Only do that if 
> you're absolutely sure of what you're doing. It could be a security 
> breach in your application.
> 

I know, but as you said it, it is bad. I know. That is why I do not use 
that function.  :)

The summary is,

   QHttp should WORK without setting the hostname or port. It should 
just put in an empty Host: header as per RFCs if these are not specified.

   QHttp should not check the hostname/port/enryption state of connected 
sockets. These sockets are set with setSocket and thus it should assume 
that the application developer knows what they are doing. As you stated 
above, most of these checks are also redundant with SSL anyway.

Ideally, QHttp should be completely independent of any specific socket 
stuff. It should be able to live with just an QAbstractSocket interface 
and let others from outside that class connect their sockets. Much 
cleaner I think, though this will not be done -- not backwards 
compatible with current implementation. *sigh*

- Adam

PS. I do have a support contract but these simple changes seem to be 
sitting these longer and longer these days. I know that Trolltech 
support used to be a lot snappier back in the Qt 3.1 days. Now bugs and 
suggestions seem get rejected and it can take weeks trying to explain 
(with examples) what is wrong... BTW, nothing personal (it does not 
apply to you). This is just my overall impression. Sometimes it is much 
faster to fix something yourself and custom apply a few line patch than 
wait a few releases for Trolltech to fix it.

--
 [ signature omitted ]