PDA

View Full Version : QNetworkAccessManager and redirections



alexandernst
17th September 2010, 17:46
I have problems handling redirects using QNetworkAccessManager. Could I get some help? Example code here: http://pastebin.com/bu7rWx2X

I can't get the file that I want (hosted on sourceforge) using the first link in the code, but if I use the second link (commented), I get the file without problems.

I know that this is almost only-c++-code forum, but the code is ~50 lines and I haven't used python-specific things. Only Qt calls.

Thanks

alexandernst
18th September 2010, 20:37
Not a single reply? Nobody knows something about QNAM and redirections?

Talei
18th September 2010, 23:30
I looked briefly on Your code, so maybe I'm wrong on this - also tired from all day work ;/, but why do You use https for sourceforge?, try http.
Also try to use WireShark and capture Your request and browser request and compare both. That's probably fastest way to figure out why this don't work.

alexandernst
19th September 2010, 05:32
I use https because that's the link. Qt should be able to manage that link. Also, going the Wireshark way is way too wrong for that problem. That is clearly a Qt bug.
Both wget and curl are perfectly able to handle that link, so Qt should be able to handle it too. Could somebody try to run the code or maybe even better, point me to the right direction.

wysota
19th September 2010, 08:14
Maybe you need to handle the redirection yourself. I'm not sure QNetworkAccessManager does that on its own. There are situations when you'd like to know a redirection is in place and not actually follow it blindly so I guess it could be that QNetworkAccessManager will not make the second request automatically.

alexandernst
19th September 2010, 15:37
wysota, I already handle the redirections. I'm here because I'm doing something wrong and I need and example/advice.

wysota
19th September 2010, 20:47
So what happens exactly if you use the first link? Did you connect appropriate signals and slots regarding handling ssl errors as it says in the docs?

alexandernst
20th September 2010, 14:21
Yes, I connected the appropriate signals. I also manage sslErrors signal, but no ssl errors happen at all.
In my app I get a 302 with the same URL but http instead of https. Then I get a 200 with exactly the same URL as from the 302 redirection. And it stops there.

Using wget I get 302, 302, 302 and then 200. I also saw a cookie, but I don't know how to implement/use them with my code. I haven't found any example about doing that.

wysota
20th September 2010, 14:24
Then I get a 200 with exactly the same URL as from the 302 redirection. And it stops there.
And what would you expect? 200 is the last status code in chain, there are no more requests after that. Did you look at the headers you get with the response?

alexandernst
20th September 2010, 14:37
I'm not sure if I'm looking them the right way. I use this:

for item in reply.rawHeaderList():
print "HEADER: " + reply.rawHeader(str(item))

wysota
20th September 2010, 14:55
And what do you get?

alexandernst
20th September 2010, 22:01
This is what I get using my app:



UPDATE: 163 of 163
ERROR CODE: (302, True)
HEADER: nginx/0.7.63
HEADER: Mon, 20 Sep 2010 20:00:07 GMT
HEADER: text/html; charset=UTF-8
HEADER: close
HEADER: sf.consume=fc962df5a9f7681b705057aa739f02d9b40bdab 2gAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUDX2lkcQVVIGViNjkxNjc2YTN hZGNjYjhkNWE3ZGYyODQwM2EwZjQwcQZVDl9hY2Nlc3NlZF90a W1lcQdHQdMl71HYCOFVDl9jcmVhdGlvbl90aW1lcQhHQdMl71H YCN11Lg==; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
HEADER: http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download
HEADER: 163
REDIRECT: PyQt4.QtCore.QUrl(u'http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download')
UPDATE: 697 of 17593
UPDATE: 2145 of 17593
UPDATE: 3593 of 17593
UPDATE: 5041 of 17593
UPDATE: 6489 of 17593
UPDATE: 7937 of 17593
UPDATE: 9385 of 17593
UPDATE: 10833 of 17593
UPDATE: 12281 of 17593
UPDATE: 13729 of 17593
UPDATE: 15177 of 17593
UPDATE: 16625 of 17593
UPDATE: 17593 of 17593
ERROR CODE: (200, True)
HEADER: nginx/0.7.63
HEADER: Mon, 20 Sep 2010 20:00:08 GMT
HEADER: text/html; charset=utf-8
HEADER: close
HEADER: no-cache
HEADER: no-cache
HEADER: VISITOR=4c97bd47d3179d696c000c1b; expires="Thu, 17-Sep-2020 20:00:08 GMT"; httponly; Max-Age=315360000; Path=/
sf.consume=18a7bbdc908cf4ebec1332d6b6582817c21d481 7gAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUFcHJlZnNxBX1xBlUOdXNlc19 yZWxhdGlvbnNxB4lVB3ZlcnNpb25xCFUBMlUDa2V5cQlVGDRjO TdiZDQ3ZDMxNzlkNjk2YzAwMGMxYnEKVQNfaWRxC1UgYjhjNzI wZTg0YTIwMTEyYTllMWNlODE0NjIxNjU0NTVxDFUOX2FjY2Vzc 2VkX3RpbWVxDUdB0yXvUiUFHVUOX2NyZWF0aW9uX3RpbWVxDkd B0yXvUiUD/3Uu; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
HEADER: 17593


and it hangs there.

And this is what I get with wget:



--2010-09-20 22:11:01-- https://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download
Resolviendo sourceforge.net... 216.34.181.60
Connecting to sourceforge.net|216.34.181.60|:443... conectado.
Petición HTTP enviada, esperando respuesta... 302 Found
Localización: http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download [siguiendo]
--2010-09-20 22:11:02-- http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download
Connecting to sourceforge.net|216.34.181.60|:80... conectado.
Petición HTTP enviada, esperando respuesta... 302 Found
Localización: http://downloads.sourceforge.net/project/python-jake/betas/Jake-PyQT4-0.1.zip?r=&ts=1285012816&use_mirror=garr [siguiendo]
--2010-09-20 22:11:02-- http://downloads.sourceforge.net/project/python-jake/betas/Jake-PyQT4-0.1.zip?r=&ts=1285012816&use_mirror=garr
Resolviendo downloads.sourceforge.net... 216.34.181.59
Connecting to downloads.sourceforge.net|216.34.181.59|:80... conectado.
Petición HTTP enviada, esperando respuesta... 302 Found
Localización: http://garr.dl.sourceforge.net/project/python-jake/betas/Jake-PyQT4-0.1.zip [siguiendo]
--2010-09-20 22:11:03-- http://garr.dl.sourceforge.net/project/python-jake/betas/Jake-PyQT4-0.1.zip
Resolviendo garr.dl.sourceforge.net... 193.206.140.34, 2001:760:ffff:b0::34
Connecting to garr.dl.sourceforge.net|193.206.140.34|:80... conectado.
Petición HTTP enviada, esperando respuesta... 200 OK
Longitud: 1218027 (1,2M) [application/zip]
Saving to: `Jake-PyQT4-0.1.zip'

100%[================================================== ================================================== ================================================== =============================================>] 1.218.027 547K/s in 2,2s

2010-09-20 22:11:05 (547 KB/s) - `Jake-PyQT4-0.1.zip' saved [1218027/1218027]

wysota
20th September 2010, 22:05
You are only showing header values and not keys (I think I can guess them correctly though). One thing I would surely do is to return the cookie set by the first request with the second request.

alexandernst
20th September 2010, 22:19
Yup, exactly! That's the thing that I don't know how to do. How do I return the cookie?
Also, how do I show to header values + keys?

wysota
20th September 2010, 22:32
Yup, exactly! That's the thing that I don't know how to do. How do I return the cookie?
Setting a cookie jar for your QNAM should be enough. If not then you'll have to set the "Cookie" header in the second request.


Also, how do I show to header values + keys?
QNetworkReply::rawHeaderList() probably returns a list of header names (or "key: value" pairs).

alexandernst
21st September 2010, 08:16
Ok, now I'm setting a cookieJar this way:



self.manager = QNetworkAccessManager()
self.jar = QNetworkCookieJar()
self.manager.setCookieJar(self.jar)


but I keep getting the same output.
I also managed to show the keys&values if you wish to see the output:



UPDATE: 163 of 163
ERROR CODE: (302, True)
HEADER: Server === nginx/0.7.63
HEADER: Date === Tue, 21 Sep 2010 06:11:40 GMT
HEADER: Content-Type === text/html; charset=UTF-8
HEADER: Connection === close
HEADER: Set-cookie === sf.consume=dbbb479a1e149425adaf118787d664ea2a761e9 dgAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUDX2lkcQVVIDk1YWNiNmQxYzQ zNjBkNjk0NjRmNzVkNThmM2Y5NzNmcQZVDl9hY2Nlc3NlZF90a W1lcQdHQdMmEycBVPhVDl9jcmVhdGlvbl90aW1lcQhHQdMmEyc BVPN1Lg==; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
HEADER: Location === http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download
HEADER: Content-Length === 163
REDIRECT: PyQt4.QtCore.QUrl(u'http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download')
UPDATE: 697 of 17537
UPDATE: 2145 of 17537
UPDATE: 3593 of 17537
UPDATE: 5041 of 17537
UPDATE: 6489 of 17537
UPDATE: 7937 of 17537
UPDATE: 9385 of 17537
UPDATE: 10833 of 17537
UPDATE: 12281 of 17537
UPDATE: 13729 of 17537
UPDATE: 15177 of 17537
UPDATE: 17537 of 17537
ERROR CODE: (200, True)
HEADER: Server === nginx/0.7.63
HEADER: Date === Tue, 21 Sep 2010 06:11:40 GMT
HEADER: Content-Type === text/html; charset=utf-8
HEADER: Connection === close
HEADER: Pragma === no-cache
HEADER: Cache-Control === no-cache
HEADER: Set-cookie === VISITOR=4c984c9c91aa911ff50011b7; expires="Fri, 18-Sep-2020 06:11:40 GMT"; httponly; Max-Age=315360000; Path=/
sf.consume=74bd0beb5266058fee435c8078db828cf65ffca agAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUFcHJlZnNxBX1xBlUOdXNlc19 yZWxhdGlvbnNxB4lVB3ZlcnNpb25xCFUBMlUDa2V5cQlVGDRjO Tg0YzljOTFhYTkxMWZmNTAwMTFiN3EKVQNfaWRxC1UgZWRmNmM 5MzZmMjczZjFlNmI1ZTdkZjE1ZDk4ZTIyZjlxDFUOX2FjY2Vzc 2VkX3RpbWVxDUdB0yYTJxjnklUOX2NyZWF0aW9uX3RpbWVxDkd B0yYTJxjmuHUu; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
HEADER: Content-Length === 17537


What am I doing wrong?

wysota
21st September 2010, 08:25
Check if the cookie is sent back with the second request. Also, what is the content of the second reply?

alexandernst
21st September 2010, 09:21
How can I check if the cookie was sent back?

I think you can see the content of the second reply in my last post. Or you mean another thing? :confused:

wysota
21st September 2010, 09:31
How can I check if the cookie was sent back?
Either dump headers of the second request or run some network sniffer to check what goes through the network. You may use this one: NetworqDebugger (http://www.qtcentre.org/threads/34082-NetworqDebugger).


I think you can see the content of the second reply in my last post. Or you mean another thing? :confused:
The content of the second reply is 17537 bytes long and you did not show it to us.

alexandernst
21st September 2010, 10:05
That's because the app dies there. It just gets to the redirect and waits for something...
I'll try wireshark when I'm at home.

wysota
21st September 2010, 14:11
That's because the app dies there.
The content gets downloaded, it's even in the log you posted. Just check what's inside.

alexandernst
21st September 2010, 15:02
You're right. after the last "HEADER: xxxxxxxx", I get a file to the path that I specified in my code, but the content of the file is a HTML page. What does that mean?

wysota
21st September 2010, 15:10
It means you should show us the contents of the page.

alexandernst
21st September 2010, 15:13
Here you go: http://pastebin.com/qhh6sfvt

wysota
21st September 2010, 15:19
What about the cookies? Did you return them with the request properly?

alexandernst
21st September 2010, 18:24
I had a look at wireshark but I can't see the second GET :confused:
Can you see something wrong? http://pastebin.com/8VzT0JLc

wysota
21st September 2010, 18:31
Please don't use pastebin. Attach files to your post instead.

Please, do me a favour - dump headers of your second request to the console and show them to me.

alexandernst
21st September 2010, 20:17
Please don't use pastebin. Attach files to your post instead.
Ok, I'll do that from now on ;)


Please, do me a favour - dump headers of your second request to the console and show them to me.

The log that I posted from my app in one of my posts is the entire output, and the entire output that QNetworkReply/QNAM can get me. Look at the part of my code where I output information.



def downloadFinished(self, reply):
redirect = reply.attribute(QNetworkRequest.RedirectionTargetA ttribute).toUrl()
print "ERROR CODE: " + str(reply.attribute(QNetworkRequest.HttpStatusCode Attribute).toInt())
for item in reply.rawHeaderList():
print "HEADER: " + str(item) + " === " + reply.rawHeader(str(item))
if not redirect.isEmpty():
print "REDIRECT: " + str(redirect)
self.reply = self.manager.get(QNetworkRequest(redirect))
self.reply.downloadProgress.connect(self.updateDat aReadProgress)
else:
self.updateFile = QFile(self.downloadPath)
self.updateFile.open(QIODevice.WriteOnly)
self.updateFile.write(self.reply.readAll())
self.updateFile.close()
self.reply.deleteLater()
self.manager.deleteLater()
reply.deleteLater()


As you can see, the second redirect's header list is printed item by item, and it gets only 1 item (the Content-Lenght one). Then evaluates the redirect.isEmpty(), and goes to the "else". And then saves the reply.readAll() to the file that I posted in #24.

wysota
21st September 2010, 22:11
The log that I posted from my app in one of my posts is the entire output, and the entire output that QNetworkReply/QNAM can get me.
I'm asking for the request, not for the reply.

alexandernst
22nd September 2010, 14:07
I'm trying to get the request header but I'm not able to get it. I don't get anything with request.rawHeaderList().
My actual code looks like this:



def downloadFinished(self, reply):
redirect = reply.attribute(QNetworkRequest.RedirectionTargetA ttribute).toUrl()
print "ERROR CODE: " + str(reply.attribute(QNetworkRequest.HttpStatusCode Attribute).toInt())
for item in reply.rawHeaderList():
print "REPLY HEADER: " + str(item) + " === " + reply.rawHeader(str(item))
request = QNetworkRequest(redirect)
for item in request.rawHeaderList():
print "REQUEST HEADER: " + str(item) + " === " + request.rawHeader(str(item))
if not redirect.isEmpty():
print "REDIRECT: " + str(redirect)
self.reply = self.manager.get(request)
self.reply.downloadProgress.connect(self.updateDat aReadProgress)
else:
self.updateFile = QFile(self.downloadPath)
self.updateFile.open(QIODevice.WriteOnly)
self.updateFile.write(self.reply.readAll())
self.updateFile.close()
self.reply.deleteLater()
self.manager.deleteLater()
reply.deleteLater()


PS: Is it really that hard to make Qt act like urllib in python or wget/curl? Isn't really there something in Qt that will just work?

wysota
22nd September 2010, 14:29
PS: Is it really that hard to make Qt act like urllib in python or wget/curl?
It is as hard as making wget/curl/urllib act like Qt.


Isn't really there something in Qt that will just work?
It does work.

Edit: Try 'reply.request()' instead of 'request' (whatever that is).

Don't blame Qt for your own mistakes.

alexandernst
22nd September 2010, 14:46
Yep, that worked. Now I get the request header.

Output:



UPDATE: 163 of 163
ERROR CODE: (302, True)
REPLY HEADER: Server === nginx/0.7.63
REPLY HEADER: Date === Wed, 22 Sep 2010 12:44:44 GMT
REPLY HEADER: Content-Type === text/html; charset=UTF-8
REPLY HEADER: Connection === close
REPLY HEADER: Set-cookie === sf.consume=0fc84a4cf5c340bc4b568a7694abce97a8a762e dgAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUDX2lkcQVVIGMwNzM1ZWU5YzV lZjFlYjk4OTU5MWI0ZTg3YjZlZDRhcQZVDl9hY2Nlc3NlZF90a W1lcQdHQdMmfo8Q+CtVDl9jcmVhdGlvbl90aW1lcQhHQdMmfo8 Q+Cd1Lg==; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
REPLY HEADER: Location === http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download
REPLY HEADER: Content-Length === 163
REDIRECT: PyQt4.QtCore.QUrl(u'http://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download')
UPDATE: 697 of 17529
UPDATE: 2145 of 17529
UPDATE: 3593 of 17529
UPDATE: 6489 of 17529
UPDATE: 7937 of 17529
UPDATE: 9385 of 17529
UPDATE: 10833 of 17529
UPDATE: 12281 of 17529
UPDATE: 13729 of 17529
UPDATE: 15177 of 17529
UPDATE: 16625 of 17529
UPDATE: 17529 of 17529
ERROR CODE: (200, True)
REPLY HEADER: Server === nginx/0.7.63
REPLY HEADER: Date === Wed, 22 Sep 2010 12:44:47 GMT
REPLY HEADER: Content-Type === text/html; charset=utf-8
REPLY HEADER: Connection === close
REPLY HEADER: Pragma === no-cache
REPLY HEADER: Cache-Control === no-cache
REPLY HEADER: Set-cookie === VISITOR=4c99fa3c86502b0357001464; expires="Sat, 19-Sep-2020 12:44:47 GMT"; httponly; Max-Age=315360000; Path=/
sf.consume=be407794209dedb983a3e46c45e09112972ef41 5gAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUFcHJlZnNxBX1xBlUOdXNlc19 yZWxhdGlvbnNxB4lVB3ZlcnNpb25xCFUBMlUDa2V5cQlVGDRjO TlmYTNjODY1MDJiMDM1NzAwMTQ2NHEKVQNfaWRxC1UgZmRmOGI xMWEyZDQ2ZDkzMjljMTU1NjY5MTc0ZTJiMDdxDFUOX2FjY2Vzc 2VkX3RpbWVxDUdB0yZ+j9wyalUOX2NyZWF0aW9uX3RpbWVxDkd B0yZ+j9wxanUu; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
REPLY HEADER: Content-Length === 17529
REQUEST HEADER: Cookie === sf.consume=0fc84a4cf5c340bc4b568a7694abce97a8a762e dgAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUDX2lkcQVVIGMwNzM1ZWU5YzV lZjFlYjk4OTU5MWI0ZTg3YjZlZDRhcQZVDl9hY2Nlc3NlZF90a W1lcQdHQdMmfo8Q+CtVDl9jcmVhdGlvbl90aW1lcQhHQdMmfo8 Q+Cd1Lg==
ERROR CODE: (200, True)
REPLY HEADER: Server === nginx/0.7.63
REPLY HEADER: Date === Wed, 22 Sep 2010 12:44:47 GMT
REPLY HEADER: Content-Type === text/html; charset=utf-8
REPLY HEADER: Connection === close
REPLY HEADER: Pragma === no-cache
REPLY HEADER: Cache-Control === no-cache
REPLY HEADER: Set-cookie === VISITOR=4c99fa3c86502b0357001464; expires="Sat, 19-Sep-2020 12:44:47 GMT"; httponly; Max-Age=315360000; Path=/
sf.consume=be407794209dedb983a3e46c45e09112972ef41 5gAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUFcHJlZnNxBX1xBlUOdXNlc19 yZWxhdGlvbnNxB4lVB3ZlcnNpb25xCFUBMlUDa2V5cQlVGDRjO TlmYTNjODY1MDJiMDM1NzAwMTQ2NHEKVQNfaWRxC1UgZmRmOGI xMWEyZDQ2ZDkzMjljMTU1NjY5MTc0ZTJiMDdxDFUOX2FjY2Vzc 2VkX3RpbWVxDUdB0yZ+j9wyalUOX2NyZWF0aW9uX3RpbWVxDkd B0yZ+j9wxanUu; expires=Tue, 19-Jan-2038 03:14:07 GMT; Path=/
REPLY HEADER: Content-Length === 17529
REQUEST HEADER: Cookie === sf.consume=0fc84a4cf5c340bc4b568a7694abce97a8a762e dgAJ9cQEoVQhfZXhwaXJlc3ECY2RhdGV0aW1lCmRhdGV0aW1lC nEDVQoH9gETAw4HAAAAhVJxBFUDX2lkcQVVIGMwNzM1ZWU5YzV lZjFlYjk4OTU5MWI0ZTg3YjZlZDRhcQZVDl9hY2Nlc3NlZF90a W1lcQdHQdMmfo8Q+CtVDl9jcmVhdGlvbl90aW1lcQhHQdMmfo8 Q+Cd1Lg==



Code:



def downloadFinished(self, reply):
redirect = reply.attribute(QNetworkRequest.RedirectionTargetA ttribute).toUrl()
print "ERROR CODE: " + str(reply.attribute(QNetworkRequest.HttpStatusCode Attribute).toInt())
for item in reply.rawHeaderList():
print "REPLY HEADER: " + str(item) + " === " + reply.rawHeader(str(item))
for item in reply.request().rawHeaderList():
print "REQUEST HEADER: " + str(item) + " === " + reply.request().rawHeader(str(item))
if not redirect.isEmpty():
print "REDIRECT: " + str(redirect)
request = QNetworkRequest(redirect)
self.reply = self.manager.get(request)
self.reply.downloadProgress.connect(self.updateDat aReadProgress)
else:
self.updateFile = QFile(self.downloadPath)
self.updateFile.open(QIODevice.WriteOnly)
self.updateFile.write(self.reply.readAll())
self.updateFile.close()
self.reply.deleteLater()
self.manager.deleteLater()
reply.deleteLater()


So, I do send the cookie, but the app just stays there. No progress, no further replies, no nothing.

wysota
22nd September 2010, 15:02
Ok but what further reply would you expect? The webpage you are getting is setup in a way that after a couple of seconds a (probably javascript based) event kicks in and redirects you elsewhere.

You are probably not sending some header sf.net requires to redirect you automatically without the waiting period. It could be a user-agent, for instance. Compare the traffic between wget and sf.net with that between your application and sf.net. Try sending the same headers and see what reply you get.

alexandernst
22nd September 2010, 20:05
Finally!!! :D:D:D
It's working!!!!!!
I set (as you suggested) the user-agent to wget's user-agent and now it's working just fine :)

Here is the complete code:



# -*- coding: utf-8 -*-
import sys, os
from PyQt4 import QtCore, QtGui
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtNetwork import *
class QDownloader(QProgressDialog):
def __init__(self, parent=None):
QProgressDialog.__init__(self, parent)
self.parent = parent
self.url = "https://sourceforge.net/projects/python-jake/files/betas/Jake-PyQT4-0.1.zip/download"
self.downloadPath = "/tmp/tmpreadfile"
self.manager = QNetworkAccessManager()
self.jar = QNetworkCookieJar()
self.manager.setCookieJar(self.jar)
self.resize(self.size().width()*2, self.size().height())
self.manager.finished.connect(self.downloadFinishe d)
self.canceled.connect(self.cancelDownload)
self.show()
self.download()

def download(self):
self.url = QUrl(self.url)
self.request = QNetworkRequest(self.url)
self.request.setRawHeader("User-Agent", "Wget/1.12 (linux-gnu)")
self.reply = self.manager.get(self.request)
self.reply.downloadProgress.connect(self.updateDat aReadProgress)

def updateDataReadProgress(self, done, total):
self.setMaximum(total)
self.setValue(done)

def downloadFinished(self, reply):
self.redirect = reply.attribute(QNetworkRequest.RedirectionTargetA ttribute).toUrl()
if not self.redirect.isEmpty():
self.request = QNetworkRequest(self.redirect)
self.request.setRawHeader("User-Agent", "Wget/1.12 (linux-gnu)")
self.reply = self.manager.get(self.request)
self.reply.downloadProgress.connect(self.updateDat aReadProgress)
else:
self.updateFile = QFile(self.downloadPath)
self.updateFile.open(QIODevice.WriteOnly)
self.updateFile.write(self.reply.readAll())
self.updateFile.close()
self.reply.deleteLater()
self.manager.deleteLater()
self.close()
reply.deleteLater()

def cancelDownload(self):
self.reply.abort()

app = QtGui.QApplication(sys.argv)
window = QDownloader()
sys.exit(app.exec_())