Search code examples
pysideqwebviewqnetworkaccessmanager

Pyside qwebview custom protocol


I'd like to support custom protocol inside my pyside app but without success. So far I tried:

class MainWindow(QWebView):
    def __init__(self, parent=None):
        oldManager = self.page().networkAccessManager()
        self.page().setNetworkAccessManager(NetworkAccessManager(self, oldManager))

#in another file
class NetworkAccessManager(QNetworkAccessManager):
    def __init__(self, parent, oldManager):
        QNetworkAccessManager.__init__(self)
        self.oldManager = oldManager
        self.setCache(oldManager.cache())
        self.setCookieJar(oldManager.cookieJar())
        self.setProxy(oldManager.proxy())
        self.setProxyFactory(oldManager.proxyFactory())
        print('There')

    def createRequest(self, operation, request, data):
        print('And there')

This results in a segmentation faultunder windows. I saw this :

It is currently not supported to change the network access manager after the PySide.QtWebKit.QWebPage has used it.

But I don't see where it would be used in this case. I tried to set a web page object after setting the network manager and the segmentation fault disappeared.

PS: none of the print statement is displayed inside the console.


Solution

  • If createRequest doesn't return a reply it crahes. So the complete solution is:

    class MainWindow(QWebView):
        def __init__(self, parent=None):
            oldManager = self.page().networkAccessManager()
            self.setPage(DebugWebPage()) #if you want to set a custom page
            self.page().setNetworkAccessManager(NetworkAccessManager(self))
    
    class NetworkAccessManager(QNetworkAccessManager):
        def __init__(self, parent):
            QNetworkAccessManager.__init__(self)
    
        def createRequest(self, operation, request, data):
            if request.url().scheme() != 'page':
                return QNetworkAccessManager.createRequest(self, operation, request, data)
    
            if operation == self.GetOperation:
                # Handle page:// URLs separately by creating custom
                # QNetworkReply objects.
                reply = PageReply(self, request.url(), self.GetOperation)
                print('here')
                return reply
            else:
                return QNetworkAccessManager.createRequest(self, operation, request, data)
    
    class PageReply(QNetworkReply):
        def __init__(self, parent, url, operation):
            QNetworkReply.__init__(self, parent)
            self.content = '<html><head><title>Test</title></head><body>This is a test.</body></html>'
            self.offset = 0
    
            self.setHeader(QNetworkRequest.ContentTypeHeader, 'text/html; charset=utf-8')
            self.setHeader(QNetworkRequest.ContentLengthHeader, len(self.content))
            QTimer.singleShot(0, self, SIGNAL('readyRead()'))
            QTimer.singleShot(0, self, SIGNAL('finished()'))
            self.open(self.ReadOnly | self.Unbuffered)
            self.setUrl(url)
    
        def abort(self):
            pass
    
        def bytesAvailable(self):
            return len(self.content) - self.offset + QNetworkReply.bytesAvailable(self)
    
        def isSequential(self):
            return True
    
        def readData(self, maxSize):
            if self.offset < len(self.content):
                end = min(self.offset + maxSize, len(self.content))
                data = self.content[self.offset:end]
                self.offset = end
                return data
    

    Note: I don't really know why but any error while the script is in the network manager or the reply results in a segmentation fault.

    Based on this with some correction.