Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
 def f(request):
     raise aiohttp.HttpErrorException(401,
                                      headers=(('WWW-Authenticate',
                                                'Basic'), ))
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
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()