def handle_request(self, message, payload): print('method = {!r}; path = {!r}; version = {!r}'.format( message.method, message.path, message.version)) path = message.path if (not (path.isprintable() and path.startswith('/')) or '/.' in path): print('bad path', repr(path)) path = None else: path = '.' + path if not os.path.exists(path): print('no file', repr(path)) path = None else: isdir = os.path.isdir(path) if not path: raise aiohttp.HttpErrorException(404) headers = email.message.Message() for hdr, val in message.headers: print(hdr, val) headers.add_header(hdr, val) if isdir and not path.endswith('/'): path = path + '/' raise aiohttp.HttpErrorException(302, headers=(('URI', path), ('Location', path))) response = aiohttp.Response(self.writer, 200, http_version=message.version) response.add_header('Transfer-Encoding', 'chunked') # content encoding accept_encoding = headers.get('accept-encoding', '').lower() if 'deflate' in accept_encoding: response.add_header('Content-Encoding', 'deflate') response.add_compression_filter('deflate') elif 'gzip' in accept_encoding: response.add_header('Content-Encoding', 'gzip') response.add_compression_filter('gzip') response.add_chunking_filter(1025) if isdir: response.add_header('Content-type', 'text/html') response.send_headers() response.write(b'<ul>\r\n') for name in sorted(os.listdir(path)): if name.isprintable() and not name.startswith('.'): try: bname = name.encode('ascii') except UnicodeError: pass else: if os.path.isdir(os.path.join(path, name)): response.write(b'<li><a href="' + bname + b'/">' + bname + b'/</a></li>\r\n') else: response.write(b'<li><a href="' + bname + b'">' + bname + b'</a></li>\r\n') response.write(b'</ul>') else: response.add_header('Content-type', 'text/plain') response.send_headers() try: with open(path, 'rb') as fp: chunk = fp.read(8196) while chunk: response.write(chunk) chunk = fp.read(8196) except OSError: response.write(b'Cannot open') yield from response.write_eof() if response.keep_alive(): self.keep_alive(True)
def f(request): raise aiohttp.HttpErrorException(401, headers=(('WWW-Authenticate', 'Basic'), ))
def dispatch(self, request): path = request.path method = request.method allowed_methods = set() check_cors = False if method == 'OPTIONS' and self.cors_enabled: check_cors = True method = request.headers.get('ACCESS-CONTROL-REQUEST-METHOD') if not method: raise errors.RESTError(404, "Not Found") for entry in self._urls: match = entry.regex.match(path) if match is None: continue if entry.method != method: allowed_methods.add(entry.method) elif check_cors and entry.check_cors: headers = tuple( self._make_cors_headers(request, entry.cors_options)) raise errors.HttpCorsOptions(headers) else: break else: if allowed_methods: allow = ', '.join(sorted(allowed_methods)) # add log raise errors.RESTError(405, "Not Allowed", json_body={'allowed_methods': allow}, headers=(('Allow', allow), )) else: # add log raise errors.RESTError(404, "Not Found") if self.cors_enabled and entry.check_cors: headers = tuple( self._make_cors_headers(request, entry.cors_options)) request.response.headers.extend(headers) handler = entry.handler status_code = getattr(handler, 'status_code', 200) sig = inspect.signature(handler) kwargs = match.groupdict() if entry.use_request: assert entry.use_request not in kwargs, (entry.use_request, kwargs) kwargs[entry.use_request] = request try: args, kwargs, ret_ann = self.construct_args(sig, kwargs) if asyncio.iscoroutinefunction(handler): ret = yield from handler(*args, **kwargs) else: ret = handler(*args, **kwargs) if ret_ann is not None: ret = ret_ann(ret) except aiohttp.HttpException as exc: raise except Exception as exc: # add log about error raise aiohttp.HttpErrorException(500, "Internal Server Error") from exc else: return json.dumps(ret), status_code
def _download(url, target=None, resume=True, progress=None, **kwargs): if not target: target = io.BytesIO() elif not hasattr(target, 'write'): target = open(target, 'ab+' if resume else 'wb') try: headers = kwargs.setdefault('headers', {}) if resume: pos = target.seek(0, io.SEEK_END) if pos > 0: headers['Range'] = 'bytes={}-'.format(pos) expected_pos = pos else: target.seek(0, io.SEEK_SET) target.truncate() expected_pos = 0 log.info('fetching %s', url) method = kwargs.pop('method', 'GET') response = yield from aiohttp.request(method, url, **kwargs) if response.status >= 300: raise aiohttp.HttpErrorException(response.status) # See if server responded with Content-Range header. m = re.search(r'bytes +(\d+).*/(\d+|\*)', response.headers.get('content-range', '')) if m: pos, size = m.groups() pos = int(pos) if progress: if size != '*': progress.set(pos=pos, max=int(size)) else: progress.set(pos=pos) if pos < expected_pos: target.seek(pos, io.SEEK_SET) target.truncate() else: if expected_pos > 0: # Server didn't respond with a Content-Range header and we are # trying to resume. We have to assume the server doesn't support # resume, but we should restart the request without a Range # request header. Simulate a range not satisfiable error. raise aiohttp.HttpErrorException(416) if progress: progress.set( max=int(response.headers.get('content-length', 0))) while True: try: chunk = yield from response.content.read() if not chunk: break if progress: progress.update(diff=len(chunk)) except aiohttp.EofStream: break target.write(chunk) if isinstance(target, io.BytesIO): return response.status, target.getvalue() else: return response.status, response finally: if not isinstance(target, io.BytesIO): target.close()