예제 #1
0
    def request(self,
                url,
                method="GET",
                body=None,
                headers=None,
                redirections=DEFAULT_MAX_REDIRECTS,
                connection_type=None,
                blocking=True):
        """
        Make a network request by calling QgsNetworkAccessManager.
        redirections argument is ignored and is here only for httplib2 compatibility.
        """
        self.http_call_result.url = url
        self.msg_log(u'http_call request: {0}'.format(url))

        self.blocking_mode = blocking
        req = QNetworkRequest()
        # Avoid double quoting form QUrl
        url = urllib.parse.unquote(url)
        req.setUrl(QUrl(url))
        if headers is not None:
            # This fixes a weird error with compressed content not being correctly
            # inflated.
            # If you set the header on the QNetworkRequest you are basically telling
            # QNetworkAccessManager "I know what I'm doing, please don't do any content
            # encoding processing".
            # See: https://bugs.webkit.org/show_bug.cgi?id=63696#c1
            try:
                del headers['Accept-Encoding']
            except KeyError:
                pass
            for k, v in list(headers.items()):
                self.msg_log("Setting header %s to %s" % (k, v))
                req.setRawHeader(k, v)
        if self.authid:
            self.msg_log("Update request w/ authid: {0}".format(self.authid))
            QgsAuthManager.instance().updateNetworkRequest(req, self.authid)
        if self.reply is not None and self.reply.isRunning():
            self.reply.close()
        if method.lower() == 'delete':
            func = getattr(QgsNetworkAccessManager.instance(),
                           'deleteResource')
        else:
            func = getattr(QgsNetworkAccessManager.instance(), method.lower())
        # Calling the server ...
        # Let's log the whole call for debugging purposes:
        self.msg_log("Sending %s request to %s" %
                     (method.upper(), req.url().toString()))
        self.on_abort = False
        headers = {str(h): str(req.rawHeader(h)) for h in req.rawHeaderList()}
        for k, v in list(headers.items()):
            self.msg_log("%s: %s" % (k, v))
        if method.lower() in ['post', 'put']:
            if isinstance(body, file):
                body = body.read()
            self.reply = func(req, body)
        else:
            self.reply = func(req)
        if self.authid:
            self.msg_log("Update reply w/ authid: {0}".format(self.authid))
            QgsAuthManager.instance().updateNetworkReply(
                self.reply, self.authid)

        # necessary to trap local timeout manage by QgsNetworkAccessManager
        # calling QgsNetworkAccessManager::abortRequest
        QgsNetworkAccessManager.instance().requestTimedOut.connect(
            self.requestTimedOut)

        self.reply.sslErrors.connect(self.sslErrors)
        self.reply.finished.connect(self.replyFinished)
        self.reply.downloadProgress.connect(self.downloadProgress)

        # block if blocking mode otherwise return immediately
        # it's up to the caller to manage listeners in case of no blocking mode
        if not self.blocking_mode:
            return None, None

        # Call and block
        self.el = QEventLoop()
        self.reply.finished.connect(self.el.quit)

        # Catch all exceptions (and clean up requests)
        try:
            self.el.exec_(QEventLoop.ExcludeUserInputEvents)
        except Exception as e:
            raise e

        if self.reply:
            self.reply.finished.disconnect(self.el.quit)

        # emit exception in case of error
        if not self.http_call_result.ok:
            if self.http_call_result.exception and not self.exception_class:
                raise self.http_call_result.exception
            elif self.exception_class:
                raise self.exception_class(self.http_call_result.reason)
            else:
                raise RequestsException('Unknown reason')

        return self.http_call_result, self.http_call_result.content
예제 #2
0
    def execute_request(self, url, **kwargs):
        """
        Uses QgsNetworkAccessManager and QgsAuthManager.
        """
        method = kwargs.get('http_method', 'get')

        headers = kwargs.get('headers', {})
        # This fixes a weird error with compressed content not being correctly
        # inflated.
        # If you set the header on the QNetworkRequest you are basically telling
        # QNetworkAccessManager "I know what I'm doing, please don't do any content
        # encoding processing".
        # See: https://bugs.webkit.org/show_bug.cgi?id=63696#c1
        try:
            del headers[b'Accept-Encoding']
        except KeyError as ke:
            # only debugging here as after 1st remove it isn't there anymore
            self.util.msg_log_debug(
                u'unexpected error deleting request header: {}'.format(ke))
            pass

        # Avoid double quoting form QUrl
        url = unquote(url)

        self.util.msg_log_debug(u'http_call request: {} {}'.format(
            method, url))

        class Response:
            status_code = 200
            status_message = 'OK'
            text = ''
            ok = True
            headers = {}
            reason = ''
            exception = None

            def iter_content(self, _):
                return [self.text]

        self.http_call_result = Response()
        url = self.util.remove_newline(url)

        req = QNetworkRequest()
        req.setUrl(QUrl(url))
        req.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)

        for k, v in headers.items():
            self.util.msg_log_debug("%s: %s" % (k, v))
            try:
                req.setRawHeader(k, v)
            except:
                self.util.msg_log_error(
                    u'FAILED to set header: {} => {}'.format(k, v))
                self.util.msg_log_last_exception()
        if self.settings.authcfg:
            self.util.msg_log_debug(u'before updateNetworkRequest')
            QgsApplication.authManager().updateNetworkRequest(
                req, self.settings.authcfg)
            self.util.msg_log_debug(u'before updateNetworkRequest')

        if self.reply is not None and self.reply.isRunning():
            self.reply.close()

        self.util.msg_log_debug(u'getting QgsNetworkAccessManager.instance()')
        #func = getattr(QgsNetworkAccessManager.instance(), method)
        #func = QgsNetworkAccessManager().get(req)

        #manager = QNetworkAccessManager()
        #event = QEventLoop()
        #response = manager.get(QNetworkRequest(QUrl(url)))
        #response.downloadProgress.connect(self.download_progress)
        #response.finished.connect(event.quit)
        #event.exec()
        #response_msg = response.readAll()
        ##response_msg = str(response_msg)
        #response_msg = str(response_msg, encoding='utf-8')
        ##response_msg = response_msg.decode('utf-8')
        #response.deleteLater()
        #self.util.msg_log_debug(u'response message:\n{} ...'.format(response_msg[:255]))
        #self.http_call_result.text = response_msg  # in Python3 all strings are unicode, so QString is not defined
        #return self.http_call_result

        # Calling the server ...
        self.util.msg_log_debug('before self.reply = func(req)')
        #self.reply = func(req)
        #self.reply = QgsNetworkAccessManager.instance().get(req)
        method_call = getattr(QgsNetworkAccessManager.instance(), method)
        self.reply = method_call(req)
        #self.reply.setReadBufferSize(1024*1024*1024)
        #self.reply.setReadBufferSize(1024 * 1024 * 1024 * 1024)
        self.reply.setReadBufferSize(0)
        self.util.msg_log_debug('after self.reply = func(req)')

        # Let's log the whole call for debugging purposes:
        if self.settings.debug:
            self.util.msg_log_debug("\nSending %s request to %s" %
                                    (method.upper(), req.url().toString()))
            headers = {
                str(h): str(req.rawHeader(h))
                for h in req.rawHeaderList()
            }
            for k, v in headers.items():
                try:
                    self.util.msg_log_debug("%s: %s" % (k, v))
                except:
                    self.util.msg_log_debug('error logging headers')

        if self.settings.authcfg:
            self.util.msg_log_debug("update reply w/ authcfg: {0}".format(
                self.settings.authcfg))
            QgsApplication.authManager().updateNetworkReply(
                self.reply, self.settings.authcfg)

        self.util.msg_log_debug('before connecting to events')

        # connect downloadProgress event
        try:
            self.reply.downloadProgress.connect(self.download_progress)
            #pass
        except:
            self.util.msg_log_error(
                'error connecting "downloadProgress" event')
            self.util.msg_log_last_exception()

        # connect reply finished event
        try:
            self.reply.finished.connect(self.reply_finished)
            #pass
        except:
            self.util.msg_log_error(
                'error connecting reply "finished" progress event')
            self.util.msg_log_last_exception()
        self.util.msg_log_debug('after connecting to events')

        # Call and block
        self.event_loop = QEventLoop()
        try:
            self.reply.finished.connect(self.event_loop.quit)
        except:
            self.util.msg_log_error(
                'error connecting reply "finished" progress event to event loop quit'
            )
            self.util.msg_log_last_exception()

        self.mb_downloaded = 0
        # Catch all exceptions (and clean up requests)
        self.event_loop.exec()

        # Let's log the whole response for debugging purposes:
        if self.settings.debug:
            self.util.msg_log_debug(
                u'\nGot response [{}/{}] ({} bytes) from:\n{}\nexception:{}'.
                format(self.http_call_result.status_code,
                       self.http_call_result.status_message,
                       len(self.http_call_result.text),
                       self.reply.url().toString(),
                       self.http_call_result.exception))
            headers = {
                str(h): str(self.reply.rawHeader(h))
                for h in self.reply.rawHeaderList()
            }
            for k, v in headers.items():
                self.util.msg_log_debug("%s: %s" % (k, v))
            self.util.msg_log_debug("Payload :\n%s ......" %
                                    self.http_call_result.text[:255])

        self.reply.close()
        self.util.msg_log_debug("Deleting reply ...")
        try:
            self.reply.deleteLater()
        except:
            self.util.msg_log_error('unexpected error deleting QNetworkReply')
            self.util.msg_log_last_exception()

        self.reply = None

        if self.http_call_result.exception is not None:
            self.util.msg_log_error('http_call_result.exception is not None')
            self.http_call_result.ok = False
            # raise self.http_call_result.exception
        return self.http_call_result