def process_get_call(self, url, url_query_items, timeout=None, report_url=True): """ Run a GET request and return reply data :param url: url for request :param url_query_items: :param timeout: in ms :param report_url: True if URL should be reported to feedback :return: response or error message in json format """ url_query = QUrl(url) if report_url: self.report_info('GET ' + url_query.toString()) if url_query_items: url_query.setQuery(url_query_items) request = QNetworkRequest(url_query) if self.connection.auth_cfg != '': request.setRawHeader("Accept".encode("utf-8"), "*/*".encode("utf-8")) if timeout is not None and "setTransferTimeout" in dir(request): request.setTransferTimeout(timeout) reply = self.network_access_manager.blockingGet( request, self.connection.auth_cfg, True, self.feedback) return self.process_qgs_reply(reply)
def executeHTTPQuery(self, method, path, callback, body, context={}, downloadProgressCallback=None, showProgress=True, ignoreErrors=False, progressText=None, timeout=5): """ Call the remote server :param method: HTTP method :param path: Remote path :param body: params to send (dictionary) :param callback: callback method to call when the server replies :param context: Pass a context to the response callback :param downloadProgressCallback: Callback called when received something, it can be an incomplete response :param showProgress: Display progress to the user :param progressText: Text display to user in progress dialog. None for auto generated :param ignoreErrors: Ignore connection error (usefull to not closing a connection when notification feed is broken) :param timeout: Delay in seconds before raising a timeout :returns: QNetworkReply """ try: ip = self._http_host.rsplit('%', 1)[0] ipaddress.IPv6Address(ip) # remove any scope ID # this is an IPv6 address, we must surround it with brackets to be used with QUrl. host = "[{}]".format(ip) except ipaddress.AddressValueError: host = self._http_host log.debug("{method} {protocol}://{host}:{port}/v1{path} {body}".format(method=method, protocol=self._scheme, host=host, port=self._http_port, path=path, body=body)) if self._user: url = QtCore.QUrl("{protocol}://{user}@{host}:{port}/v1{path}".format(protocol=self._scheme, user=self._user, host=host, port=self._http_port, path=path)) else: url = QtCore.QUrl("{protocol}://{host}:{port}/v1{path}".format(protocol=self._scheme, host=host, port=self._http_port, path=path)) request = self._request(url) request = self.addAuth(request) request.setRawHeader(b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode()) # By default QT doesn't support GET with body even if it's in the RFC that's why we need to use sendCustomRequest body = self._addBodyToRequest(body, request) response = self._network_manager.sendCustomRequest(request, method.encode(), body) context = copy.copy(context) context["query_id"] = str(uuid.uuid4()) response.finished.connect(qpartial(self._processResponse, response, callback, context, body, ignoreErrors)) if downloadProgressCallback is not None: response.downloadProgress.connect(qpartial(self._processDownloadProgress, response, downloadProgressCallback, context)) if showProgress: response.uploadProgress.connect(qpartial(self.notify_progress_upload, context["query_id"])) response.downloadProgress.connect(qpartial(self.notify_progress_download, context["query_id"])) # Should be the last operation otherwise we have race condition in Qt # where query start before finishing connect to everything self.notify_progress_start_query(context["query_id"], progressText, response) if timeout is not None: QtCore.QTimer.singleShot(timeout * 1000, qpartial(self._timeoutSlot, response)) return response
def addAuth(self, request): """ If require add basic auth header """ if self._user: auth_string = "{}:{}".format(self._user, self._password) auth_string = base64.b64encode(auth_string.encode("utf-8")) auth_string = "Basic {}".format(auth_string.decode()) request.setRawHeader("Authorization", auth_string) return request
def _addAuth(self, request): """ If require add basic auth header """ if self._user: auth_string = "{}:{}".format(self._user, self._password) auth_string = base64.b64encode(auth_string.encode("utf-8")) auth_string = "Basic {}".format(auth_string.decode()) request.setRawHeader(b"Authorization", auth_string.encode()) return request
def createRequest(self, operation, request, data): al1 = QtCore.QByteArray() al1.append("Accept-Language") al2 = QtCore.QByteArray() al2.append("en-US,en;q=0.5") request.setRawHeader(al1, al2) dnt1 = QtCore.QByteArray() dnt1.append("DNT") dnt2 = QtCore.QByteArray() dnt2.append("1") request.setRawHeader(dnt1, dnt2) return QtNetwork.QNetworkAccessManager.createRequest(self, operation, request, data)
def process_post_call(self, url, url_query_items, data, is_read_only=True, report_url=True): """ Run a POST request and return reply data :param url: url for request :param url_query_items: :param data: :param is_read_only: True if the request does not update data :param report_url: True if URL should be reported to feedback :return: response or error message in json format """ if self.connection.read_only and not is_read_only: return { "error": { "msg": "Graphium connection is set to read-only!" } } url_query = QUrl(url) if report_url: self.report_info('POST ' + url_query.toString()) if url_query_items: url_query.setQuery(url_query_items) # data_byte_array = json.dumps(data).encode('utf8') # data = QtCore.QByteArray( json.dumps( json_request ) ) data_byte_array = QJsonDocument.fromVariant(data) request = QNetworkRequest(url_query) if self.connection.auth_cfg != '': request.setRawHeader("Accept".encode("utf-8"), "*/*".encode("utf-8")) request.setHeader(QNetworkRequest.ContentTypeHeader, "application/json") reply = self.network_access_manager.blockingPost( request, data_byte_array.toJson(), self.connection.auth_cfg, True, self.feedback) return self.process_qgs_reply(reply)
def process_put_call(self, url, data=None, report_url=True): """ Run a PUT request and return reply data :param url: url for request :param data: :param report_url: True if URL should be reported to feedback :return: response or error message in json format """ if self.connection.read_only: return { "error": { "msg": "Graphium connection is set to read-only!" } } url_query = QUrl(url) if report_url: self.report_info('PUT ' + url_query.toString()) data_byte_array = QJsonDocument.fromVariant(data) request = QNetworkRequest(url_query) if self.connection.auth_cfg != '': self.auth = 0 config = QgsAuthMethodConfig() QgsApplication.authManager().loadAuthenticationConfig( self.connection.auth_cfg, config, True) concatenated = config.configMap( )['username'] + ":" + config.configMap()['password'] data = base64.encodebytes(concatenated.encode("utf-8")).replace( '\n'.encode("utf-8"), ''.encode("utf-8")) request.setRawHeader("Authorization".encode("utf-8"), ("Basic %s" % data).encode("utf-8")) request.setRawHeader("Accept".encode("utf-8"), "*/*".encode("utf-8")) loop = QEventLoop() # https://stackoverflow.com/a/46514984 reply = self.network_access_manager.put(request, data_byte_array.toJson()) reply.finished.connect(loop.quit) loop.exec_() return self.process_q_reply(reply)
def process_delete_call(self, url, report_url=True): """ Run a DELETE request and return reply data :param url: url for request :param report_url: True if URL should be reported to feedback :return: response or error message in json format """ if self.connection.read_only: return { "error": { "msg": "Graphium connection is set to read-only!" } } url_query = QUrl(url) if report_url: self.report_info('DELETE ' + url_query.toString()) request = QNetworkRequest(url_query) if self.connection.auth_cfg != '': self.auth = 0 config = QgsAuthMethodConfig() QgsApplication.authManager().loadAuthenticationConfig( self.connection.auth_cfg, config, True) concatenated = config.configMap( )['username'] + ":" + config.configMap()['password'] data = base64.encodebytes(concatenated.encode("utf-8")).replace( '\n'.encode("utf-8"), ''.encode("utf-8")) request.setRawHeader("Authorization".encode("utf-8"), ("Basic %s" % data).encode("utf-8")) request.setRawHeader("Accept".encode("utf-8"), "*/*".encode("utf-8")) loop = QEventLoop() reply = self.network_access_manager.deleteResource(request) reply.finished.connect(loop.quit) loop.exec_() return self.process_q_reply(reply)
def _addBodyToRequest(self, body, request): """ Add the require headers for sending the body. It detect the type of body for sending the corresponding headers and methods. :param body: The body :returns: The body compatible with Qt """ if body is None: return None if isinstance(body, dict): body = json.dumps(body) request.setRawHeader(b"Content-Type", b"application/json") request.setRawHeader(b"Content-Length", str(len(body)).encode()) data = QtCore.QByteArray(body.encode()) body = QtCore.QBuffer(self) body.setData(data) body.open(QtCore.QIODevice.ReadOnly) return body elif isinstance(body, pathlib.Path): body = QtCore.QFile(str(body), self) body.open(QtCore.QFile.ReadOnly) request.setRawHeader(b"Content-Type", b"application/octet-stream") # QT is smart and will compute the Content-Lenght for us return body else: return None
def _sendRequest(self, url, params, headers={}): if self.asynchonous: if self.reply is not None: self.reply.finished.disconnect(self.reply_finished) self.reply.abort() self.reply = None url = QUrl(url) urlQuery = QUrlQuery(url) for key, value in params.items(): urlQuery.addQueryItem(key, value) QgsLogger.debug('Request: {}'.format(url.toEncoded())) url.setQuery(urlQuery) request = QNetworkRequest(url) for key, value in headers.items(): request.setRawHeader(key, value) self.reply = QgsNetworkAccessManager.instance().get(request) else: url = url + '?' + urllib.parse.urlencode(params) response = urllib.request.urlopen(url) data = json.load(response) self.load_data(data)
def executeHTTPQuery(self, method, path, callback, body, context={}): """ Call the remote server :param method: HTTP method :param path: Remote path :param body: params to send (dictionary) :param callback: callback method to call when the server replies :param context: Pass a context to the response callback """ import copy context = copy.copy(context) context["query_id"] = str(uuid.uuid4()) self.notify_progress_start_query(context["query_id"]) log.debug("{method} {scheme}://{host}:{port}/v1{path} {body}".format(method=method, scheme=self.scheme, host=self.host, port=self.port, path=path, body=body)) url = QtCore.QUrl("{scheme}://{host}:{port}/v1{path}".format(scheme=self.scheme, host=self.host, port=self.port, path=path)) request = self._request(url) request = self.addAuth(request) request.setRawHeader("Content-Type", "application/json") request.setRawHeader("Content-Length", str(len(body))) request.setRawHeader("User-Agent", "GNS3 QT Client v{version}".format(version=__version__)) if method == "GET": response = self._network_manager.get(request) if method == "PUT": body = json.dumps(body) request.setRawHeader("Content-Type", "application/json") request.setRawHeader("Content-Length", str(len(body))) response = self._network_manager.put(request, body) if method == "POST": body = json.dumps(body) request.setRawHeader("Content-Type", "application/json") request.setRawHeader("Content-Length", str(len(body))) response = self._network_manager.post(request, body) if method == "DELETE": response = self._network_manager.deleteResource(request) if HTTPClient._progress_callback and HTTPClient._progress_callback.progress_dialog(): request_canceled = partial(self._requestCanceled, response, context) HTTPClient._progress_callback.progress_dialog().canceled.connect(request_canceled) response.finished.connect(partial(self._processResponse, response, callback, context))
def getSynchronous(self, method, endpoint, prefix="/v2", timeout=5): """ Synchronous check if a server is running :returns: Tuple (Status code, json of answer). Status 0 is a non HTTP error """ host = self._getHostForQuery() log.debug( "{method} {protocol}://{host}:{port}{prefix}{endpoint}".format( method=method, protocol=self._protocol, host=host, port=self._port, prefix=prefix, endpoint=endpoint)) if self._user: url = QtCore.QUrl( "{protocol}://{user}@{host}:{port}{prefix}{endpoint}".format( protocol=self._protocol, user=self._user, host=host, port=self._port, prefix=prefix, endpoint=endpoint)) else: url = QtCore.QUrl( "{protocol}://{host}:{port}{prefix}{endpoint}".format( protocol=self._protocol, host=host, port=self._port, prefix=prefix, endpoint=endpoint)) request = self._request(url) request = self._addAuth(request) request.setRawHeader( b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode()) try: response = self._network_manager.sendCustomRequest( request, method.encode()) except SystemError as e: log.error("Can't send query: {}".format(str(e))) return loop = QtCore.QEventLoop() response.finished.connect(loop.quit) if timeout is not None: QtCore.QTimer.singleShot( timeout * 1000, qpartial(self._timeoutSlot, response, timeout)) if not loop.isRunning(): loop.exec_() status = response.attribute( QtNetwork.QNetworkRequest.HttpStatusCodeAttribute) if response.error() != QtNetwork.QNetworkReply.NoError: log.debug("Error while connecting to local server {}".format( response.errorString())) return status, None else: content_type = response.header( QtNetwork.QNetworkRequest.ContentTypeHeader) if status == 200: if content_type == "application/json": content = bytes(response.readAll()) json_data = json.loads(content.decode("utf-8")) return status, json_data else: return status, None return 0, None
def _executeHTTPQuery(self, method, path, callback, body, context={}, downloadProgressCallback=None, showProgress=True, ignoreErrors=False, progressText=None, server=None, timeout=120, prefix="/v2", params={}, networkManager=None, eventsHandler=None, **kwargs): """ Call the remote server :param method: HTTP method :param path: Remote path :param body: params to send (dictionary) :param callback: callback method to call when the server replies :param context: Pass a context to the response callback :param downloadProgressCallback: Callback called when received something, it can be an incomplete response :param showProgress: Display progress to the user :param networkManager: The network manager to use. If None use default :param progressText: Text display to user in progress dialog. None for auto generated :param ignoreErrors: Ignore connection error (usefull to not closing a connection when notification feed is broken) :param server: The server where the query is executed :param timeout: Delay in seconds before raising a timeout :param eventsHandler: Handler receiving and triggering events like `updated`, `cancelled`. If not specified and showProgress is `True` then `ProgressDialog` receives them. :param params: Query arguments parameters :returns: QNetworkReply """ host = self._getHostForQuery() query_string = self._paramsToQueryString(params) log.debug( "{method} {protocol}://{host}:{port}{prefix}{path} {body}{query_string}" .format(method=method, protocol=self._protocol, host=host, port=self._port, path=path, body=body, prefix=prefix, query_string=query_string)) if self._user: url = QtCore.QUrl( "{protocol}://{user}@{host}:{port}{prefix}{path}{query_string}" .format(protocol=self._protocol, user=self._user, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string)) else: url = QtCore.QUrl( "{protocol}://{host}:{port}{prefix}{path}{query_string}". format(protocol=self._protocol, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string)) request = self._request(url) request = self._addAuth(request) request.setRawHeader( b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode()) # By default QT doesn't support GET with body even if it's in the RFC that's why we need to use sendCustomRequest body = self._addBodyToRequest(body, request) if not networkManager: networkManager = self._network_manager try: response = networkManager.sendCustomRequest( request, method.encode(), body) except SystemError as e: log.error("Can't send query: {}".format(str(e))) return context = copy.copy(context) context["query_id"] = str(uuid.uuid4()) response.finished.connect( qpartial(self._processResponse, response, server, callback, context, body, ignoreErrors)) response.error.connect( qpartial(self._processError, response, server, callback, context, body, ignoreErrors)) if downloadProgressCallback is not None: response.readyRead.connect( qpartial(self._readyReadySlot, response, downloadProgressCallback, context, server)) request_canceled = qpartial(self._requestCanceled, response, context) if eventsHandler is not None: eventsHandler.canceled.connect(request_canceled) elif not sip_is_deleted( HTTPClient._progress_callback ) and HTTPClient._progress_callback.progress_dialog(): HTTPClient._progress_callback.progress_dialog().canceled.connect( request_canceled) if showProgress: response.uploadProgress.connect( qpartial(self._notify_progress_upload, context["query_id"])) response.downloadProgress.connect( qpartial(self._notify_progress_download, context["query_id"])) # Should be the last operation otherwise we have race condition in Qt # where query start before finishing connect to everything self._notify_progress_start_query(context["query_id"], progressText, response) if timeout is not None: QtCore.QTimer.singleShot( timeout * 1000, qpartial(self._timeoutSlot, response, timeout)) return response
def _executeHTTPQuery(self, method, path, callback, body, context={}, downloadProgressCallback=None, showProgress=True, ignoreErrors=False, progressText=None, server=None, timeout=120, prefix="/v2", params={}, networkManager=None, eventsHandler=None, **kwargs): """ Call the remote server :param method: HTTP method :param path: Remote path :param body: params to send (dictionary) :param callback: callback method to call when the server replies :param context: Pass a context to the response callback :param downloadProgressCallback: Callback called when received something, it can be an incomplete response :param showProgress: Display progress to the user :param networkManager: The network manager to use. If None use default :param progressText: Text display to user in progress dialog. None for auto generated :param ignoreErrors: Ignore connection error (usefull to not closing a connection when notification feed is broken) :param server: The server where the query is executed :param timeout: Delay in seconds before raising a timeout :param eventsHandler: Handler receiving and triggering events like `updated`, `cancelled`. If not specified and showProgress is `True` then `ProgressDialog` receives them. :param params: Query arguments parameters :returns: QNetworkReply """ host = self._getHostForQuery() query_string = self._paramsToQueryString(params) log.debug("{method} {protocol}://{host}:{port}{prefix}{path} {body}{query_string}".format(method=method, protocol=self._protocol, host=host, port=self._port, path=path, body=body, prefix=prefix, query_string=query_string)) if self._user: url = QtCore.QUrl("{protocol}://{user}@{host}:{port}{prefix}{path}{query_string}".format(protocol=self._protocol, user=self._user, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string)) else: url = QtCore.QUrl("{protocol}://{host}:{port}{prefix}{path}{query_string}".format(protocol=self._protocol, host=host, port=self._port, path=path, prefix=prefix, query_string=query_string)) request = self._request(url) request = self._addAuth(request) request.setRawHeader(b"User-Agent", "GNS3 QT Client v{version}".format(version=__version__).encode()) # By default QT doesn't support GET with body even if it's in the RFC that's why we need to use sendCustomRequest body = self._addBodyToRequest(body, request) if not networkManager: networkManager = self._network_manager try: response = networkManager.sendCustomRequest(request, method.encode(), body) except SystemError as e: log.error("Can't send query: {}".format(str(e))) return context = copy.copy(context) context["query_id"] = str(uuid.uuid4()) response.finished.connect(qpartial(self._processResponse, response, server, callback, context, body, ignoreErrors)) response.error.connect(qpartial(self._processError, response, server, callback, context, body, ignoreErrors)) if downloadProgressCallback is not None: response.readyRead.connect(qpartial(self._readyReadySlot, response, downloadProgressCallback, context, server)) request_canceled = qpartial(self._requestCanceled, response, context) if eventsHandler is not None: eventsHandler.canceled.connect(request_canceled) elif not sip_is_deleted(HTTPClient._progress_callback) and HTTPClient._progress_callback.progress_dialog(): HTTPClient._progress_callback.progress_dialog().canceled.connect(request_canceled) if showProgress: response.uploadProgress.connect(qpartial(self._notify_progress_upload, context["query_id"])) response.downloadProgress.connect(qpartial(self._notify_progress_download, context["query_id"])) # Should be the last operation otherwise we have race condition in Qt # where query start before finishing connect to everything self._notify_progress_start_query(context["query_id"], progressText, response) if timeout is not None: QtCore.QTimer.singleShot(timeout * 1000, qpartial(self._timeoutSlot, response, timeout)) return response
def executeHTTPQuery(self, method, path, callback, body, context={}): """ Call the remote server :param method: HTTP method :param path: Remote path :param body: params to send (dictionary) :param callback: callback method to call when the server replies :param context: Pass a context to the response callback """ import copy context = copy.copy(context) context["query_id"] = str(uuid.uuid4()) self.notify_progress_start_query(context["query_id"]) log.debug("{method} {scheme}://{host}:{port}/v1{path} {body}".format(method=method, scheme=self.scheme, host=self.host, port=self.port, path=path, body=body)) url = QtCore.QUrl("{scheme}://{host}:{port}/v1{path}".format(scheme=self.scheme, host=self.host, port=self.port, path=path)) request = self._request(url) request.setRawHeader("Content-Type", "application/json") request.setRawHeader("Content-Length", str(len(body))) request.setRawHeader("User-Agent", "GNS3 QT Client v{version}".format(version=__version__)) if method == "GET": response = self._network_manager.get(request) if method == "PUT": body = json.dumps(body) request.setRawHeader("Content-Type", "application/json") request.setRawHeader("Content-Length", str(len(body))) response = self._network_manager.put(request, body) if method == "POST": body = json.dumps(body) request.setRawHeader("Content-Type", "application/json") request.setRawHeader("Content-Length", str(len(body))) response = self._network_manager.post(request, body) if method == "DELETE": response = self._network_manager.deleteResource(request) response.finished.connect(partial(self._processResponse, response, callback, context)) if HTTPClient._progress_callback and HTTPClient._progress_callback.progress_dialog(): request_canceled = partial(self._requestCanceled, response, context) HTTPClient._progress_callback.progress_dialog().canceled.connect(request_canceled)