PDA

View Full Version : QHttp.get() is failing to download the entire file



WinchellChung
19th February 2010, 20:58
I'm back with yet another stupid newbie question.

I wrote a file downloader module (cleverly hidden in a QProgressDialog) that downloads files from the internet. While it works fine on small files, I have discovered that on huge files (e.g., 900 MB) it will often fail to download the entire file. The last 1000 bytes or so will be missing. If I repeat the download four or five times it will eventually get the file, but obviously I am doing something wrong. Perhaps somebody here can spot my error.
The downloader is:



#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PyQt4.QtNetwork import *
from PyQt4.QtCore import *
from PyQt4.QtGui import *


#==========
class UpdateDownloader(QProgressDialog):
#==========
def __init__(self, theUpdateNode, updateServer, downloadPath, parent=None):
QProgressDialog.__init__(self, parent)

self.urlString = "%s/%s" % (updateServer, theUpdateNode.URL)
self.fileName = QString(downloadPath)
self.title = theUpdateNode.title
self.outFile = None
self.httpGetId = 0
self.httpRequestAborted = False
self.http = QHttp(self)
self.successfulDownload = True
self.contentLength = 0

self.setCancelButton(None)
self.http.requestFinished.connect(self.httpRequest Finished)
self.http.dataReadProgress.connect(self.updateData ReadProgress)
self.http.responseHeaderReceived.connect(self.read ResponseHeader)

#==========
def httpRequestFinished(self, requestId, error):
if requestId != self.httpGetId:
return

filesize = self.outFile.size()
self.outFile.close()

if error:
self.outFile.remove()
# QMessageBox.information(self, self.tr("Download"),
# self.tr("Download failed: %1.").arg(self.http.errorString()))
self.successfulDownload = False
else:
if filesize != self.contentLength:
# QMessageBox.information(self, "Download",
# "Download failed: filesize is ", filesize, " should be ", self.contentLength))
self.successfulDownload = False
else:
self.successfulDownload = True

self.outFile = None
self.done(0)

#==========
def updateDataReadProgress(self, bytesRead, totalBytes):
self.setMaximum(totalBytes)
self.setValue(bytesRead)

#==========
def readResponseHeader(self, responseHeader):
self.contentLength = responseHeader.contentLength()
# Check for genuine error conditions.
if responseHeader.statusCode() not in (200, 300, 301, 302, 303, 307):
# QMessageBox.information(self, self.tr("Download"),
# self.tr("Download failed: %1.")
# .arg(responseHeader.reasonPhrase()))
self.http.abort()
if self.outFile is not None:
self.outFile.close()
self.outFile.remove()
self.outFile = None
self.successfulDownload = False
self.done(0)

#==========
def downloadFile(self):
url = QUrl(self.urlString)
if QFile.exists(self.fileName):
QFile.remove(self.fileName)

self.outFile = QFile(self.fileName)
if not self.outFile.open(QIODevice.WriteOnly):
# QMessageBox.information(self, self.tr("Updates"),
# self.tr("Unable to save the file %1: %2.").arg(self.fileName).arg(self.outFile.errorString( )))
self.outFile = None
self.successfulDownload = False
self.done(0)
return

if url.scheme().toLower() == 'https':
mode = QHttp.ConnectionModeHttps
else:
mode = QHttp.ConnectionModeHttp

port = url.port()

if port == -1:
port = 0

self.http.setHost(url.host(), mode, port)

if not url.userName().isEmpty():
self.http.setUser(url.userName(), url.password())

path = QUrl.toPercentEncoding(url.path(), "!$&'()*+,;=:@/")
if path.isEmpty():
path = "/"
path = QString(path)
self.httpGetId = self.http.get(path, self.outFile)

self.setWindowTitle(self.tr("Download"))
self.setLabelText(self.tr("Downloading %1.").arg(self.title))
self.show()

#==========
def doDownload(self):
self.downloadFile()
self.exec_()
self.hide()
return self.successfulDownload

it is called thusly:


from UpdateDownloader import UpdateDownloader

updateNode.URL = "archive1.zip"
updateNode.title = "The initial archive file"
downloadPath = "%s/%s" % (self.host.DOWNLOAD_DIR, updateNode.URL)
downloadSuccessful = UpdateDownloader(updateNode, UPDATE_COM, downloadPath).doDownload()