def run(self): # setup progress handler self.byteUpdate = time.time() self.recvTotal = 0 def recvEvent(bytes): self.recvTotal += bytes self.recv.emit() addHook("httpRecv", recvEvent) client = AnkiRequestsClient() try: resp = client.get(aqt.appShared + "download/%s?v=2.1" % self.code) if resp.status_code == 200: data = client.streamContent(resp) elif resp.status_code in (403, 404): self.error = _( "Invalid code, or add-on not available for your version of Anki." ) return else: self.error = _("Unexpected response code: %s" % resp.status_code) return except Exception as e: self.error = _( "Please check your internet connection.") + "\n\n" + str(e) return finally: remHook("httpRecv", recvEvent) self.fname = re.match("attachment; filename=(.+)", resp.headers['content-disposition']).group(1) self.data = data
def run(self): # setup progress handler self.byteUpdate = time.time() self.recvTotal = 0 def recvEvent(bytes): self.recvTotal += bytes self.recv.emit() addHook("httpRecv", recvEvent) client = AnkiRequestsClient() try: resp = client.get(aqt.appShared + "download/%d" % self.code) if resp.status_code == 200: data = client.streamContent(resp) elif resp.status_code in (403, 404): self.error = _("Invalid code") return else: self.error = _("Error downloading: %s" % resp.status_code) return except Exception as e: exc = traceback.format_exc() try: self.error = str(e[0]) except: self.error = str(exc) return finally: remHook("httpRecv", recvEvent) self.fname = re.match("attachment; filename=(.+)", resp.headers['content-disposition']).group(1) self.data = data
def download(url): contents = None client = AnkiRequestsClient() client.timeout = URL_TIMEOUT resp = client.get(url) if resp.status_code == 200: contents = client.streamContent(resp) return (resp.status_code, contents)
def _getRemoteDirectoryListing(self): client = AnkiRequestsClient() resp = client.get(self._api_url + "?format=JSON") if resp.status_code != 200: raise Exception("Unexpected response code: {}".format( resp.status_code)) # Strip 5-byte prefix that's used for XSSI prevention: json_content = resp.text[5:] entries = json.loads(json_content)["entries"] return entries
def net_headers(self, url, headers=None): """Returns the headers for a URL.""" self._logger.debug("GET %s for headers", url) self._netops += 1 client = AnkiRequestsClient() response = client.get(url, headers=headers) return response.headers
def getImageFromUrl(url): URL_TIMEOUT = 5 if anki == "set": client = AnkiRequestsClient() client.timeout = URL_TIMEOUT resp = client.get(url) content = client.streamContent(resp) else: resp = requests.get(url, timeout=URL_TIMEOUT) content = resp.content return content
def _retrieveURL(self, url): "Download file into media folder and return local filename or None." # urllib doesn't understand percent-escaped utf8, but requires things like # '#' to be escaped. url = urllib.parse.unquote(url) if url.lower().startswith("file://"): url = url.replace("%", "%25") url = url.replace("#", "%23") local = True else: local = False # fetch it into a temporary folder self.mw.progress.start(immediate=not local, parent=self.parentWindow) ct = None try: if local: req = urllib.request.Request( url, None, {"User-Agent": "Mozilla/5.0 (compatible; Anki)"}) filecontents = urllib.request.urlopen(req).read() else: reqs = AnkiRequestsClient() reqs.timeout = 30 r = reqs.get(url) if r.status_code != 200: showWarning( _("Unexpected response code: %s") % r.status_code) return filecontents = r.content ct = r.headers.get("content-type") except urllib.error.URLError as e: showWarning(_("An error occurred while opening %s") % e) return except requests.exceptions.RequestException as e: showWarning(_("An error occurred while opening %s") % e) return finally: self.mw.progress.finish() # strip off any query string url = re.sub(r"\?.*?$", "", url) path = urllib.parse.unquote(url) return self.mw.col.media.writeData(path, filecontents, typeHint=ct)
def checkForUpdates(self): client = AnkiRequestsClient() # get mod times self.mw.progress.start(immediate=True) try: # ..of enabled items downloaded from ankiweb addons = [] for dir in self.managedAddons(): meta = self.addonMeta(dir) if not meta.get("disabled"): addons.append(dir) mods = [] while addons: chunk = addons[:25] del addons[:25] mods.extend(self._getModTimes(client, chunk)) return self._updatedIds(mods) finally: self.mw.progress.finish()
def _importNetResource(self, url, protocal=''): try: reqs = AnkiRequestsClient() reqs.timeout = 30 r = reqs.get(protocal + url) if r.status_code != 200: if protocal: #retry with http instead of https return self._importNetResource('http:' + url) aqt.utils.showWarning( _("Unexpected response code: %s") % r.status_code) return return r except urllib.error.URLError as e: if protocal: #retry with http instead of https return self._importNetResource('http:' + url) aqt.utils.showWarning(_("An error occurred while opening %s") % e) return except requests.exceptions.RequestException as e: aqt.utils.showWarning( _("An error occurred while requesting %s") % e) return
def net_stream(self, targets, require=None, method='GET', awesome_ua=False, add_padding=False, custom_quoter=None, custom_headers=None, allow_redirects=True): """ Returns the raw payload string from the specified target(s). If multiple targets are specified, their resulting payloads are glued together. Each "target" is a bare URL string or a tuple containing an address and a dict for what to tack onto the query string. Finally, a require dict may be passed to enforce a Content-Type using key 'mime' and/or a minimum payload size using key 'size'. If using multiple targets, these requirements apply to each response. The underlying library here already understands how to search the environment for proxy settings (e.g. HTTP_PROXY), so we do not need to do anything extra for that. If add_padding is True, then some additional null padding will be added onto the stream returned. This is helpful for some web services that sometimes return MP3s that `mplayer` clips early. To prevent redirects one can set allow_redirects to False. """ assert method in ['GET', 'POST'], "method must be GET or POST" from urllib.parse import quote targets = targets if isinstance(targets, list) else [targets] targets = [ (target, None) if isinstance(target, str) else ( target[0], '&'.join( '='.join([ key, ( custom_quoter[key] if (custom_quoter and key in custom_quoter) else quote )( str(val), safe='', ), ]) for key, val in list(target[1].items()) ), ) for target in targets ] require = require or {} payloads = [] client = AnkiRequestsClient() for number, (url, params) in enumerate(targets, 1): desc = "web request" if len(targets) == 1 \ else "web request (%d of %d)" % (number, len(targets)) self._logger.debug("%s %s%s%s for %s", method, url, "?" if params else "", params or "", desc) headers = {'User-Agent': (self.ecosystem.agent if awesome_ua else DEFAULT_UA)} if custom_headers: headers.update(custom_headers) self._netops += 1 if method == 'GET': request_url = ('?'.join([url, params]) if params else url) self._logger.debug('request made: ' + repr((method, request_url, headers))) response = client.get(request_url, headers) else: from io import BytesIO self._logger.debug('request made: ' + repr((method, url, headers, (params if params else '')))) # note that this method of AnkiRequestsClient must take IO streams, not strings response = client.post(url, BytesIO((params if params else '').encode()), headers) if not response: raise IOError("No response for %s" % desc) if response.status_code != 200: value_error = ValueError( "Got %d status for %s" % (response.status_code, desc) ) try: value_error.payload = response.content response.close() except Exception: pass raise value_error got_mime = response.headers['Content-Type'] simplified_mime = self.parse_mime_type(got_mime) #self._logger.debug('response got: ' + str(response.content)) if 'mime' in require and require['mime'] != simplified_mime: value_error = ValueError( f"Request got {got_mime} Content-Type for {desc};" f" wanted {require['mime']}" ) value_error.got_mime = got_mime value_error.wanted_mime = require['mime'] raise value_error if not allow_redirects and response.url != url: raise ValueError("Request has been redirected") payload = response.content response.close() if 'size' in require and len(payload) < require['size']: raise self.TinyDownloadError( "Request got %d-byte stream for %s; wanted %d+ bytes" % (len(payload), desc, require['size']) ) payloads.append(payload) if add_padding: payloads.append(PADDING) return b''.join(payloads)