Пример #1
0
    def adapt_prepare(self):
        """Prepares the special trip parameters."""

        parsed = urlsplit(self.url)
        if parsed.scheme not in ('http', 'https'):
            raise ValueError('Unsupported url scheme: %s' % self.url)
        netloc = parsed.netloc
        if '@' in netloc:
            userpass, _, netloc = netloc.rpartition('@')
        self.host, self.port = split_host_and_port(netloc)
        if self.port is None:
            self.port = 443 if parsed.scheme == 'https' else 80

        self.af = AF_INET

        self.decompress = 'gzip' in \
            self.headers.get('Accept-Encoding', '')

        req_path = ((parsed.path or '/') +
            (('?' + parsed.query) if parsed.query else ''))
        self.start_line = RequestStartLine(self.method, req_path, '')

        self.headers = HTTPHeaders(self.headers)

        if 'Connection' not in self.headers:
            self.headers['Connection'] = 'close'
        if 'Host' not in self.headers:
            self.headers['Host'] = self.host
Пример #2
0
    def connect(self):
        logging.info('start connect to %s from %s:%d', self.request.uri,
                     self.request.connection.context.address[0],
                     self.request.connection.context.address[1])

        host, port = httputil.split_host_and_port(self.request.uri)
        self.start_tunnel(host, port)
Пример #3
0
 def __init__(self, io_loop, client, request, release_callback,
              final_callback, max_buffer_size, tcp_client,
              max_header_size, max_body_size):
     self.start_time = io_loop.time()
     self.io_loop = io_loop
     self.client = client
     self.request = request
     self.release_callback = release_callback
     self.final_callback = final_callback
     self.max_buffer_size = max_buffer_size
     self.tcp_client = tcp_client
     self.max_header_size = max_header_size
     self.max_body_size = max_body_size
     self.code = None
     self.headers = None
     self.chunks = []
     self._decompressor = None
     # Timeout handle returned by IOLoop.add_timeout
     self._timeout = None
     self._sockaddr = None
     with stack_context.ExceptionStackContext(self._handle_exception):
         self.parsed = urlparse.urlsplit(_unicode(self.request.url))
         af = socket.AF_UNSPEC
         netloc = self.parsed.netloc
         
         host, port = httputil.split_host_and_port(netloc)
         timeout = min(self.request.connect_timeout, self.request.request_timeout)
         if timeout:
             self._timeout = self.io_loop.add_timeout(
                 self.start_time + timeout,
                 stack_context.wrap(self._on_timeout))
         self.tcp_client.connect(host,port, af=af,
                                 max_buffer_size=self.max_buffer_size,
                                 callback=self._on_connect)
Пример #4
0
    def _transform_tornado_request(self, request):
        if isinstance(request, HTTPRequest):
            raise ValueError('param tRequest should be \
                HTTPRequest instance from tornado package.')

        # from tornado.simple_httpclient L214-L242
        self.parsed = urlparse.urlsplit(_unicode(self.request.url))
        if self.parsed.scheme not in ("http", "https"):
            raise ValueError("Unsupported url scheme: %s" %
                             self.request.url)
        # urlsplit results have hostname and port results, but they
        # didn't support ipv6 literals until python 2.7.
        netloc = self.parsed.netloc
        if "@" in netloc:
            userpass, _, netloc = netloc.rpartition("@")
        host, port = split_host_and_port(netloc)
        if port is None:
            port = 443 if self.parsed.scheme == "https" else 80
        if re.match(r'^\[.*\]$', host):
            # raw ipv6 addresses in urls are enclosed in brackets
            host = host[1:-1]
        self.parsed_hostname = host  # save final host for _on_connect

        if request.allow_ipv6 is False:
            af = AF_INET
        else:
            af = AF_UNSPEC

        ssl_options = self._get_ssl_options(self.parsed.scheme)

        timeout = min(self.request.connect_timeout, self.request.request_timeout)
        if timeout:
            self._timeout = self.io_loop.add_timeout(
                self.start_time + timeout,
                stack_context.wrap(functools.partial(self._on_timeout, "while connecting")))
Пример #5
0
    def __init__(self, io_loop, client, request, release_callback,
                 final_callback, max_buffer_size, tcp_client, max_header_size,
                 max_body_size):
        self.start_time = io_loop.time()
        self.io_loop = io_loop
        self.client = client
        self.request = request
        self.release_callback = release_callback
        self.final_callback = final_callback
        self.max_buffer_size = max_buffer_size
        self.tcp_client = tcp_client
        self.max_header_size = max_header_size
        self.max_body_size = max_body_size
        self.code = None
        self.headers = None
        self.chunks = []
        self._decompressor = None
        # Timeout handle returned by IOLoop.add_timeout
        self._timeout = None
        self._sockaddr = None
        with stack_context.ExceptionStackContext(self._handle_exception):
            self.parsed = urlparse.urlsplit(_unicode(self.request.url))
            if self.parsed.scheme not in ("http", "https"):
                raise ValueError("Unsupported url scheme: %s" %
                                 self.request.url)
            # urlsplit results have hostname and port results, but they
            # didn't support ipv6 literals until python 2.7.
            netloc = self.parsed.netloc
            if "@" in netloc:
                userpass, _, netloc = netloc.rpartition("@")
            host, port = httputil.split_host_and_port(netloc)
            if port is None:
                port = 443 if self.parsed.scheme == "https" else 80
            if re.match(r'^\[.*\]$', host):
                # raw ipv6 addresses in urls are enclosed in brackets
                host = host[1:-1]
            self.parsed_hostname = host  # save final host for _on_connect

            if request.allow_ipv6 is False:
                af = socket.AF_INET
            else:
                af = socket.AF_UNSPEC

            ssl_options = self._get_ssl_options(self.parsed.scheme)

            timeout = min(self.request.connect_timeout,
                          self.request.request_timeout)
            if timeout:
                self._timeout = self.io_loop.add_timeout(
                    self.start_time + timeout,
                    stack_context.wrap(
                        functools.partial(self._on_timeout,
                                          "while connecting")))
            self.tcp_client.connect(host,
                                    port,
                                    af=af,
                                    ssl_options=ssl_options,
                                    max_buffer_size=self.max_buffer_size,
                                    callback=self._on_connect)
Пример #6
0
def get_host_and_port(url):
    """ Get host and port from url."""
    parsed = urlsplit(url)
    netloc = parsed.netloc
    if '@' in netloc:
        userpass, _, netloc = netloc.rpartition('@')
    host, port = split_host_and_port(netloc)
    if port is None:
        port = 443 if parsed.scheme == 'https' else 80
    return (host, port)
Пример #7
0
    def match(self, request: HTTPServerRequest) -> Optional[dict]:
        host, port = split_host_and_port(request.host)
        if (self.protocol is not None and request.protocol != self.protocol):
            return None
        if (self.host is not None and host != self.host):
            return None
        if (self.port is not None and
            (port or DEFAULT_PORTS.get(request.protocol, None)) != self.port):
            return None

        return {}
Пример #8
0
    def __init__(self, io_loop, client, request, release_callback,
                 final_callback, max_buffer_size, tcp_client,
                 max_header_size, max_body_size):
        self.start_time = io_loop.time()
        self.io_loop = io_loop
        self.client = client
        self.request = request
        self.release_callback = release_callback
        self.final_callback = final_callback
        self.max_buffer_size = max_buffer_size
        self.tcp_client = tcp_client
        self.max_header_size = max_header_size
        self.max_body_size = max_body_size
        self.code = None
        self.headers = None
        self.chunks = []
        self._decompressor = None
        # Timeout handle returned by IOLoop.add_timeout
        self._timeout = None
        self._sockaddr = None
        with stack_context.ExceptionStackContext(self._handle_exception):
            self.parsed = urlparse.urlsplit(_unicode(self.request.url))
            if self.parsed.scheme not in ("http", "https"):
                raise ValueError("Unsupported url scheme: %s" %
                                 self.request.url)
            # urlsplit results have hostname and port results, but they
            # didn't support ipv6 literals until python 2.7.
            netloc = self.parsed.netloc
            if "@" in netloc:
                userpass, _, netloc = netloc.rpartition("@")
            host, port = httputil.split_host_and_port(netloc)
            if port is None:
                port = 443 if self.parsed.scheme == "https" else 80
            if re.match(r'^\[.*\]$', host):
                # raw ipv6 addresses in urls are enclosed in brackets
                host = host[1:-1]
            self.parsed_hostname = host  # save final host for _on_connect

            if request.allow_ipv6 is False:
                af = socket.AF_INET
            else:
                af = socket.AF_UNSPEC

            ssl_options = self._get_ssl_options(self.parsed.scheme)

            timeout = min(self.request.connect_timeout, self.request.request_timeout)
            if timeout:
                self._timeout = self.io_loop.add_timeout(
                    self.start_time + timeout,
                    stack_context.wrap(self._on_timeout))
            self.tcp_client.connect(host, port, af=af,
                                    ssl_options=ssl_options,
                                    max_buffer_size=self.max_buffer_size,
                                    callback=self._on_connect)
Пример #9
0
 def _get_host_handlers(self, request):
     host = split_host_and_port(request.host.lower())[0]
     matches = []
     for pattern, handlers in self.handlers:
         if pattern.match(host):
             matches.extend(handlers)
     # Look for default host if not behind load balancer (for debugging)
     if not matches and "X-Real-Ip" not in request.headers:
         for pattern, handlers in self.handlers:
             if pattern.match(self.default_host):
                 matches.extend(handlers)
     return matches or None
Пример #10
0
 def _get_host_handlers(self, request):
     host = split_host_and_port(request.host.lower())[0]
     matches = []
     for pattern, handlers in self.handlers:
         if pattern.match(host):
             matches.extend(handlers)
     # Look for default host if not behind load balancer (for debugging)
     if not matches and "X-Real-Ip" not in request.headers:
         for pattern, handlers in self.handlers:
             if pattern.match(self.default_host):
                 matches.extend(handlers)
     return matches or None
    def prepare_tornado_request(self, request):

        dataDict = {}
        for key in request.arguments:
            dataDict[key] = request.arguments[key][0].decode('utf-8')

        result = {
            'https': 'on' if request == 'https' else 'off',
            'http_host': split_host_and_port(request.host)[0],
            'script_name': request.path,
            'server_port': split_host_and_port(request.host)[1],
            'get_data': dataDict,
            'post_data': dataDict,
            'query_string': request.query
        }

        if self.force_https:
            result['https'] = self.force_https

        self.log.debug("The values used for the tornado request are: %r" %
                       result)

        return result
Пример #12
0
 async def CAPTCHA_check(self,CAPTCHA,request_params):
     try:
         client = tornado.httpclient.AsyncHTTPClient()
         request = { k:v for k,v in request_params.items() if (v != None) }
         request = copy.deepcopy(request)
         if "url_params" in request:
             request["url_params"] = { k:v.replace("__front_end_response__",CAPTCHA) for k,v in request["url_params"].items() }
             request["url"] = request["url"] + "?" + urlencode(request["url_params"])
             del request["url_params"]
         if "body_params" in request:
             request["body_params"] = { k:v.replace("__front_end_response__",CAPTCHA) for k,v in request["body_params"].items() }
             request["body"] = urlencode(request["body_params"])
             del request["body_params"]
         url = request["url"]
         del request["url"]
         if self.block_SSRF == True:
             parsed = urllib.parse.urlsplit(_unicode(url))
             if parsed.scheme not in ("http", "https"):
                 raise ValueError("Unsupported url scheme: %s" % url)
             netloc = parsed.netloc
             if "@" in netloc:
                 userpass, _, netloc = netloc.rpartition("@")
             host, port = httputil.split_host_and_port(netloc)
             if port is None:
                 port = 443 if parsed.scheme == "https" else 80
             if re.match(r"^\[.*\]$", host):
                 host = host[1:-1]
             host_ips = list(filter(lambda x:x[1]==socket.SOCK_STREAM,socket.getaddrinfo(host,port)))
             host_ips_global = list(filter(lambda x:ipaddress.ip_address(x[-1][0]).is_global,host_ips))
             host_ips_connectable = [x for x in host_ips_global if check_sock(x)]
             if len(host_ips_global) == 0:
                 raise self.generateError(400,"SSRF blocked","Request to local network are blocked due to SSRF protection enabled")
             if port not in self.block_SSRF_port_whitelist:
                 raise self.generateError(400,"SSRF blocked","Request port are not in block_SSRF_port_whitelist.")
             if len(host_ips_connectable) == 0:
                 raise self.generateError(500,"CAPTCHA API fetch error","Not connectable")
             if "follow_redirects" in request and request["follow_redirects"] == True:
                 raise self.generateError(400,"SSRF blocked","follow_redirects are not available if SSRF protection enabled")
             request["follow_redirects"] = False
             host_ip = host_ips_connectable[0]
             client = tornado.httpclient.AsyncHTTPClient(hostname_mapping={host:host_ip})
         response = await client.fetch(url,**request)
         self._CAPTCHA_api_response_example = response
         return response
     except Exception as e:
         raise self.generateError(400,"CAPTCHA API fetch error",e,error_url="https://www.tornadoweb.org/en/stable/httpclient.html#tornado.httpclient.AsyncHTTPClient.fetch")
Пример #13
0
 def get_sinatra_request(self, request: HTTPServerRequest):
     host, port = split_host_and_port(request.host)
     return {
         "env": {
             "PATH_INFO":
             request.path,
             "QUERY_STRING":
             request.query,
             "REMOTE_ADDR":
             request.remote_ip,
             "REMOTE_HOST":
             request.host,
             "REQUEST_METHOD":
             request.method,
             "REQUEST_URI":
             f"{request.protocol}://{request.host}{request.uri}",
             "SCRIPT_NAME":
             "",
             "SERVER_NAME":
             host,
             "SERVER_PORT":
             port,
             "SERVER_PROTOCOL":
             request.version,
             "HTTP_HOST":
             request.host,
             "HTTP_ACCEPT":
             "*/*",
             "HTTP_COOKIE":
             ";".join([v.OutputString() for v in request.cookies.values()]),
             "HTTPS":
             "on" if request.protocol == "https" else "off",
             "HTTP_VERSION":
             request.version,
             "REQUEST_PATH":
             request.path,
             "rack.input":
             request.body.decode("utf8"),
         }
     }
Пример #14
0
def request_environment(request):
    # This creates a WSGI environ dictionary from a Tornado request.

    environ = {}

    environ['REQUEST_URI'] = request.uri
    environ['QUERY_STRING'] = request.query
    environ['REQUEST_METHOD'] = request.method

    for header, value in request.headers.items():
        if header in ['Content-Type', 'Content-Length']:
            wsgi_name = header.replace('-', '_').upper()
        else:
            wsgi_name = 'HTTP_' + header.replace('-', '_').upper()
        environ[wsgi_name] = value

    from tornado.httputil import split_host_and_port
    port = split_host_and_port(request.host.lower())[1]
    if port:
        environ['SERVER_PORT'] = port

    return environ
Пример #15
0
def request_environment(request):
    # This creates a WSGI environ dictionary from a Tornado request.

    environ = {}

    environ['REQUEST_URI'] = request.uri
    environ['QUERY_STRING'] = request.query
    environ['REQUEST_METHOD'] = request.method

    for header, value in request.headers.items():
        if header in ['Content-Type', 'Content-Length']:
            wsgi_name = header.replace('-', '_').upper()
        else:
            wsgi_name = 'HTTP_' + header.replace('-', '_').upper()
        environ[wsgi_name] = value

    from tornado.httputil import split_host_and_port
    port = split_host_and_port(request.host.lower())[1]
    if port:
        environ['SERVER_PORT'] = port

    return environ
def _getHostSubDomain(cls):
    """
    returns the subdomain portion of the request hostname

    eg something.copyrighthub.org would return "something"
    """
    subDomain = ""

    host = cls.request.headers.get('Host')

    host, port = httputil.split_host_and_port(host)

    # get the subdomain part
    hostparts = host.split('.')

    # match subdomain, but only if not in list of ignore_subdomains
    if len(hostparts) == 3:
        if not hostparts[0] in options.ignored_subdomains   \
                and hostparts[1] == 'copyrighthub'          \
                and hostparts[2] == 'org':
            subDomain = hostparts[0]

    return subDomain
Пример #17
0
 def get_sinatra_request(request: HTTPServerRequest):
     host, port = split_host_and_port(request.host)
     return {"env": {
         "PATH_INFO": request.path,
         "QUERY_STRING": request.query,
         "REMOTE_ADDR": request.remote_ip,
         "REMOTE_HOST": request.host,
         "REQUEST_METHOD": request.method,
         "REQUEST_URI": f"{request.protocol}://{request.host}{request.uri}",
         "SCRIPT_NAME": "",
         "SERVER_NAME": host,
         "SERVER_PORT": port,
         "SERVER_PROTOCOL": request.version,
         "HTTP_HOST": request.host,
         "HTTP_ACCEPT": "*/*",
         "HTTP_COOKIE": ";".join([
             v.OutputString() for v in request.cookies.values()
         ]),
         "HTTPS": "on" if request.protocol == "https" else "off",
         "HTTP_VERSION": request.version,
         "REQUEST_PATH": request.path,
         "rack.input": request.body.decode("utf8"),
     }}
Пример #18
0
    def _get_host(self):
        from tornado import httputil

        return httputil.split_host_and_port(self.request.host)[0]
Пример #19
0
    async def get(self, path=None):
        # if the handler got a notebook_path argument, always serve that
        notebook_path = self.notebook_path or path
        if self.notebook_path and path:  # when we are in single notebook mode but have a path
            self.redirect_to_file(path)
            return

        if self.voila_configuration.enable_nbextensions:
            # generate a list of nbextensions that are enabled for the classical notebook
            # a template can use that to load classical notebook extensions, but does not have to
            notebook_config = self.config_manager.get('notebook')
            # except for the widget extension itself, since Voilà has its own
            load_extensions = notebook_config.get('load_extensions', {})
            if 'jupyter-js-widgets/extension' in load_extensions:
                load_extensions['jupyter-js-widgets/extension'] = False
            if 'voila/extension' in load_extensions:
                load_extensions['voila/extension'] = False
            nbextensions = [
                name for name, enabled in load_extensions.items() if enabled
            ]
        else:
            nbextensions = []

        notebook = await self.load_notebook(notebook_path)
        if not notebook:
            return
        self.cwd = os.path.dirname(notebook_path)

        path, basename = os.path.split(notebook_path)
        notebook_name = os.path.splitext(basename)[0]

        # Adding request uri to kernel env
        self.kernel_env = os.environ.copy()
        self.kernel_env['SCRIPT_NAME'] = self.request.path
        self.kernel_env[
            'PATH_INFO'] = ''  # would be /foo/bar if voila.ipynb/foo/bar was supported
        self.kernel_env['QUERY_STRING'] = str(self.request.query)
        self.kernel_env['SERVER_SOFTWARE'] = 'voila/{}'.format(__version__)
        self.kernel_env['SERVER_PROTOCOL'] = str(self.request.version)
        host, port = split_host_and_port(self.request.host.lower())
        self.kernel_env['SERVER_PORT'] = str(port) if port else ''
        self.kernel_env['SERVER_NAME'] = host

        # we can override the template via notebook metadata or a query parameter
        template_override = None
        if 'voila' in notebook.metadata and self.voila_configuration.allow_template_override in [
                'YES', 'NOTEBOOK'
        ]:
            template_override = notebook.metadata['voila'].get('template')
        if self.voila_configuration.allow_template_override == 'YES':
            template_override = self.get_argument("voila-template",
                                                  template_override)
        if template_override:
            self.template_paths = collect_template_paths(
                ['voila', 'nbconvert'], template_override)
        template_name = template_override or self.voila_configuration.template

        theme = self.voila_configuration.theme
        if 'voila' in notebook.metadata and self.voila_configuration.allow_theme_override in [
                'YES', 'NOTEBOOK'
        ]:
            theme = notebook.metadata['voila'].get('theme', theme)
        if self.voila_configuration.allow_theme_override == 'YES':
            theme = self.get_argument("voila-theme", theme)

        # render notebook to html
        resources = {
            'base_url': self.base_url,
            'nbextensions': nbextensions,
            'theme': theme,
            'template': template_name,
            'metadata': {
                'name': notebook_name
            }
        }

        # include potential extra resources
        extra_resources = self.voila_configuration.config.VoilaConfiguration.resources
        # if no resources get configured from neither the CLI nor a config file,
        # extra_resources is a traitlets.config.loader.LazyConfigValue object
        # This seems to only happy with the notebook server and traitlets 5
        # Note that we use string checking for backward compatibility
        if 'DeferredConfigString' in str(type(extra_resources)):
            from .configuration import VoilaConfiguration
            extra_resources = VoilaConfiguration.resources.from_string(
                extra_resources)
        if not isinstance(extra_resources, dict):
            extra_resources = extra_resources.to_dict()
        if extra_resources:
            recursive_update(resources, extra_resources)

        self.exporter = VoilaExporter(
            template_paths=self.template_paths,
            template_name=template_name,
            config=self.traitlet_config,
            contents_manager=self.contents_manager,  # for the image inlining
            theme=theme,  # we now have the theme in two places
            base_url=self.base_url,
        )
        if self.voila_configuration.strip_sources:
            self.exporter.exclude_input = True
            self.exporter.exclude_output_prompt = True
            self.exporter.exclude_input_prompt = True

        # These functions allow the start of a kernel and execution of the notebook after (parts of) the template
        # has been rendered and send to the client to allow progressive rendering.
        # Template should first call kernel_start, and then decide to use notebook_execute
        # or cell_generator to implement progressive cell rendering
        extra_context = {
            'kernel_start': self._jinja_kernel_start,
            'cell_generator': self._jinja_cell_generator,
            'notebook_execute': self._jinja_notebook_execute,
        }

        # Compose reply
        self.set_header('Content-Type', 'text/html')
        self.set_header('Cache-Control', 'no-cache, no-store, must-revalidate')
        self.set_header('Pragma', 'no-cache')
        self.set_header('Expires', '0')
        # render notebook in snippets, and flush them out to the browser can render progresssively
        async for html_snippet, resources in self.exporter.generate_from_notebook_node(
            notebook, resources=resources, extra_context=extra_context):
            self.write(html_snippet)
            self.flush(
            )  # we may not want to consider not flusing after each snippet, but add an explicit flush function to the jinja context
            # yield  # give control back to tornado's IO loop, so it can handle static files or other requests
        self.flush()
Пример #20
0
    async def run(self) -> None:
        try:
            self.parsed = urllib.parse.urlsplit(_unicode(self.request.url))
            if self.parsed.scheme not in ("http", "https"):
                raise ValueError("Unsupported url scheme: %s" %
                                 self.request.url)
            # urlsplit results have hostname and port results, but they
            # didn't support ipv6 literals until python 2.7.
            netloc = self.parsed.netloc
            if "@" in netloc:
                userpass, _, netloc = netloc.rpartition("@")
            host, port = httputil.split_host_and_port(netloc)
            if port is None:
                port = 443 if self.parsed.scheme == "https" else 80
            if re.match(r"^\[.*\]$", host):
                # raw ipv6 addresses in urls are enclosed in brackets
                host = host[1:-1]
            self.parsed_hostname = host  # save final host for _on_connect

            if self.request.allow_ipv6 is False:
                af = socket.AF_INET
            else:
                af = socket.AF_UNSPEC

            ssl_options = self._get_ssl_options(self.parsed.scheme)

            source_ip = None
            if self.request.network_interface:
                if is_valid_ip(self.request.network_interface):
                    source_ip = self.request.network_interface
                else:
                    raise ValueError(
                        "Unrecognized IPv4 or IPv6 address for network_interface, got %r"
                        % (self.request.network_interface, ))

            timeout = min(self.request.connect_timeout,
                          self.request.request_timeout)
            if timeout:
                self._timeout = self.io_loop.add_timeout(
                    self.start_time + timeout,
                    functools.partial(self._on_timeout, "while connecting"),
                )
                stream = await self.tcp_client.connect(
                    host,
                    port,
                    af=af,
                    ssl_options=ssl_options,
                    max_buffer_size=self.max_buffer_size,
                    source_ip=source_ip,
                )

                if self.final_callback is None:
                    # final_callback is cleared if we've hit our timeout.
                    stream.close()
                    return
                self.stream = stream
                self.stream.set_close_callback(self.on_connection_close)
                self._remove_timeout()
                if self.final_callback is None:
                    return
                if self.request.request_timeout:
                    self._timeout = self.io_loop.add_timeout(
                        self.start_time + self.request.request_timeout,
                        functools.partial(self._on_timeout, "during request"),
                    )
                if (self.request.method not in self._SUPPORTED_METHODS
                        and not self.request.allow_nonstandard_methods):
                    raise KeyError("unknown method %s" % self.request.method)
                for key in (
                        "proxy_host",
                        "proxy_port",
                        "proxy_username",
                        "proxy_password",
                        "proxy_auth_mode",
                ):
                    if getattr(self.request, key, None):
                        raise NotImplementedError("%s not supported" % key)
                if "Connection" not in self.request.headers:
                    self.request.headers["Connection"] = "close"
                if "Host" not in self.request.headers:
                    if "@" in self.parsed.netloc:
                        self.request.headers[
                            "Host"] = self.parsed.netloc.rpartition("@")[-1]
                    else:
                        self.request.headers["Host"] = self.parsed.netloc
                username, password = None, None
                if self.parsed.username is not None:
                    username, password = self.parsed.username, self.parsed.password
                elif self.request.auth_username is not None:
                    username = self.request.auth_username
                    password = self.request.auth_password or ""
                if username is not None:
                    assert password is not None
                    if self.request.auth_mode not in (None, "basic"):
                        raise ValueError("unsupported auth_mode %s",
                                         self.request.auth_mode)
                    self.request.headers[
                        "Authorization"] = "Basic " + _unicode(
                            base64.b64encode(
                                httputil.encode_username_password(
                                    username, password)))
                if self.request.user_agent:
                    self.request.headers[
                        "User-Agent"] = self.request.user_agent
                if not self.request.allow_nonstandard_methods:
                    # Some HTTP methods nearly always have bodies while others
                    # almost never do. Fail in this case unless the user has
                    # opted out of sanity checks with allow_nonstandard_methods.
                    body_expected = self.request.method in ("POST", "PATCH",
                                                            "PUT")
                    body_present = (self.request.body is not None
                                    or self.request.body_producer is not None)
                    if (body_expected
                            and not body_present) or (body_present
                                                      and not body_expected):
                        raise ValueError(
                            "Body must %sbe None for method %s (unless "
                            "allow_nonstandard_methods is true)" %
                            ("not " if body_expected else "",
                             self.request.method))
                if self.request.expect_100_continue:
                    self.request.headers["Expect"] = "100-continue"
                if self.request.body is not None:
                    # When body_producer is used the caller is responsible for
                    # setting Content-Length (or else chunked encoding will be used).
                    self.request.headers["Content-Length"] = str(
                        len(self.request.body))
                if (self.request.method == "POST"
                        and "Content-Type" not in self.request.headers):
                    self.request.headers[
                        "Content-Type"] = "application/x-www-form-urlencoded"
                if self.request.decompress_response:
                    self.request.headers["Accept-Encoding"] = "gzip"
                req_path = (self.parsed.path or "/") + (
                    ("?" + self.parsed.query) if self.parsed.query else "")
                self.connection = self._create_connection(stream)
                start_line = httputil.RequestStartLine(self.request.method,
                                                       req_path, "")
                self.connection.write_headers(start_line, self.request.headers)
                if self.request.expect_100_continue:
                    await self.connection.read_response(self)
                else:
                    await self._write_body(True)
        except Exception:
            if not self._handle_exception(*sys.exc_info()):
                raise
Пример #21
0
    def _get_host(self):
        from tornado import httputil

        return httputil.split_host_and_port(self.request.host)[0]
Пример #22
0
    def run(self):
        try:
            self.parsed = urlparse.urlsplit(_unicode(self.request.url))
            if self.parsed.scheme not in ("http", "https"):
                raise ValueError("Unsupported url scheme: %s" %
                                 self.request.url)
            # urlsplit results have hostname and port results, but they
            # didn't support ipv6 literals until python 2.7.
            netloc = self.parsed.netloc
            if "@" in netloc:
                userpass, _, netloc = netloc.rpartition("@")
            host, port = httputil.split_host_and_port(netloc)
            if port is None:
                port = 443 if self.parsed.scheme == "https" else 80
            if re.match(r'^\[.*\]$', host):
                # raw ipv6 addresses in urls are enclosed in brackets
                host = host[1:-1]
            self.parsed_hostname = host  # save final host for _on_connect

            if self.request.allow_ipv6 is False:
                af = socket.AF_INET
            else:
                af = socket.AF_UNSPEC

            ssl_options = self._get_ssl_options(self.parsed.scheme)

            timeout = min(self.request.connect_timeout, self.request.request_timeout)
            if timeout:
                self._timeout = self.io_loop.add_timeout(
                    self.start_time + timeout,
                    stack_context.wrap(functools.partial(self._on_timeout, "while connecting")))
                stream = yield self.tcp_client.connect(
                    host, port, af=af,
                    ssl_options=ssl_options,
                    max_buffer_size=self.max_buffer_size)

                if self.final_callback is None:
                    # final_callback is cleared if we've hit our timeout.
                    stream.close()
                    return
                self.stream = stream
                self.stream.set_close_callback(self.on_connection_close)
                self._remove_timeout()
                if self.final_callback is None:
                    return
                if self.request.request_timeout:
                    self._timeout = self.io_loop.add_timeout(
                        self.start_time + self.request.request_timeout,
                        stack_context.wrap(functools.partial(self._on_timeout, "during request")))
                if (self.request.method not in self._SUPPORTED_METHODS and
                        not self.request.allow_nonstandard_methods):
                    raise KeyError("unknown method %s" % self.request.method)
                for key in ('network_interface',
                            'proxy_host', 'proxy_port',
                            'proxy_username', 'proxy_password',
                            'proxy_auth_mode'):
                    if getattr(self.request, key, None):
                        raise NotImplementedError('%s not supported' % key)
                if "Connection" not in self.request.headers:
                    self.request.headers["Connection"] = "close"
                if "Host" not in self.request.headers:
                    if '@' in self.parsed.netloc:
                        self.request.headers["Host"] = self.parsed.netloc.rpartition('@')[-1]
                    else:
                        self.request.headers["Host"] = self.parsed.netloc
                username, password = None, None
                if self.parsed.username is not None:
                    username, password = self.parsed.username, self.parsed.password
                elif self.request.auth_username is not None:
                    username = self.request.auth_username
                    password = self.request.auth_password or ''
                if username is not None:
                    if self.request.auth_mode not in (None, "basic"):
                        raise ValueError("unsupported auth_mode %s",
                                         self.request.auth_mode)
                    self.request.headers["Authorization"] = (
                        b"Basic " + base64.b64encode(
                            httputil.encode_username_password(username, password)))
                if self.request.user_agent:
                    self.request.headers["User-Agent"] = self.request.user_agent
                if not self.request.allow_nonstandard_methods:
                    # Some HTTP methods nearly always have bodies while others
                    # almost never do. Fail in this case unless the user has
                    # opted out of sanity checks with allow_nonstandard_methods.
                    body_expected = self.request.method in ("POST", "PATCH", "PUT")
                    body_present = (self.request.body is not None or
                                    self.request.body_producer is not None)
                    if ((body_expected and not body_present) or
                            (body_present and not body_expected)):
                        raise ValueError(
                            'Body must %sbe None for method %s (unless '
                            'allow_nonstandard_methods is true)' %
                            ('not ' if body_expected else '', self.request.method))
                if self.request.expect_100_continue:
                    self.request.headers["Expect"] = "100-continue"
                if self.request.body is not None:
                    # When body_producer is used the caller is responsible for
                    # setting Content-Length (or else chunked encoding will be used).
                    self.request.headers["Content-Length"] = str(len(
                        self.request.body))
                if (self.request.method == "POST" and
                        "Content-Type" not in self.request.headers):
                    self.request.headers["Content-Type"] = "application/x-www-form-urlencoded"
                if self.request.decompress_response:
                    self.request.headers["Accept-Encoding"] = "gzip"
                req_path = ((self.parsed.path or '/') +
                            (('?' + self.parsed.query) if self.parsed.query else ''))
                self.connection = self._create_connection(stream)
                start_line = httputil.RequestStartLine(self.request.method,
                                                       req_path, '')
                self.connection.write_headers(start_line, self.request.headers)
                if self.request.expect_100_continue:
                    yield self.connection.read_response(self)
                else:
                    yield self._write_body(True)
        except Exception:
            if not self._handle_exception(*sys.exc_info()):
                raise
Пример #23
0
    async def get_generator(self, path=None):
        # if the handler got a notebook_path argument, always serve that
        notebook_path = self.notebook_path or path

        if (self.notebook_path and
                path):  # when we are in single notebook mode but have a path
            self.redirect_to_file(path)
            return
        cwd = os.path.dirname(notebook_path)

        # Adding request uri to kernel env
        kernel_env = os.environ.copy()
        kernel_env[ENV_VARIABLE.SCRIPT_NAME] = self.request.path
        kernel_env[
            ENV_VARIABLE.
            PATH_INFO] = ''  # would be /foo/bar if voila.ipynb/foo/bar was supported
        kernel_env[ENV_VARIABLE.QUERY_STRING] = str(self.request.query)
        kernel_env[ENV_VARIABLE.SERVER_SOFTWARE] = 'voila/{}'.format(
            __version__)
        kernel_env[ENV_VARIABLE.SERVER_PROTOCOL] = str(self.request.version)
        host, port = split_host_and_port(self.request.host.lower())
        kernel_env[ENV_VARIABLE.SERVER_PORT] = str(port) if port else ''
        kernel_env[ENV_VARIABLE.SERVER_NAME] = host
        # Add HTTP Headers as env vars following rfc3875#section-4.1.18
        if len(self.voila_configuration.http_header_envs) > 0:
            for header_name in self.request.headers:
                config_headers_lower = [
                    header.lower()
                    for header in self.voila_configuration.http_header_envs
                ]
                # Use case insensitive comparison of header names as per rfc2616#section-4.2
                if header_name.lower() in config_headers_lower:
                    env_name = f'HTTP_{header_name.upper().replace("-", "_")}'
                    kernel_env[env_name] = self.request.headers.get(
                        header_name)

        template_arg = self.get_argument("voila-template", None)
        theme_arg = self.get_argument("voila-theme", None)

        # Compose reply
        self.set_header('Content-Type', 'text/html')
        self.set_header('Cache-Control', 'no-cache, no-store, must-revalidate')
        self.set_header('Pragma', 'no-cache')
        self.set_header('Expires', '0')

        try:
            current_notebook_data: Dict = self.kernel_manager.notebook_data.get(
                notebook_path, {})
            pool_size: int = self.kernel_manager.get_pool_size(notebook_path)
        except AttributeError:
            # For server extenstion case.
            current_notebook_data = {}
            pool_size = 0
        # Check if the conditions for using pre-heated kernel are satisfied.
        if self.should_use_rendered_notebook(
                current_notebook_data,
                pool_size,
                template_arg,
                theme_arg,
                self.request.arguments,
        ):
            # Get the pre-rendered content of notebook, the result can be all rendered cells
            # of the notebook or some rendred cells and a generator which can be used by this
            # handler to continue rendering calls.

            render_task, rendered_cache, kernel_id = await self.kernel_manager.get_rendered_notebook(
                notebook_name=notebook_path, )

            QueryStringSocketHandler.send_updates({
                'kernel_id': kernel_id,
                'payload': self.request.query
            })
            # Send rendered cell to frontend
            if len(rendered_cache) > 0:
                yield ''.join(rendered_cache)

            # Wait for current running cell finish and send this cell to
            # frontend.
            rendered, rendering = await render_task
            if len(rendered) > len(rendered_cache):
                html_snippet = ''.join(rendered[len(rendered_cache):])
                yield html_snippet

            # Continue render cell from generator.
            async for html_snippet, _ in rendering:
                yield html_snippet

        else:
            # All kernels are used or pre-heated kernel is disabled, start a normal kernel.
            supported_file_extensions = ['.ipynb']
            supported_file_extensions.extend([
                x.lower() for x in
                self.voila_configuration.extension_language_mapping.keys()
            ])
            file_extenstion = Path(notebook_path).suffix.lower()
            if file_extenstion not in supported_file_extensions:
                self.redirect_to_file(path)
                return

            gen = NotebookRenderer(
                voila_configuration=self.voila_configuration,
                traitlet_config=self.traitlet_config,
                notebook_path=notebook_path,
                template_paths=self.template_paths,
                config_manager=self.config_manager,
                contents_manager=self.contents_manager,
                base_url=self.base_url,
                kernel_spec_manager=self.kernel_spec_manager,
            )

            await gen.initialize(template=template_arg, theme=theme_arg)

            def time_out():
                """If not done within the timeout, we send a heartbeat
                this is fundamentally to avoid browser/proxy read-timeouts, but
                can be used in a template to give feedback to a user
                """

                return '<script>voila_heartbeat()</script>\n'

            kernel_env[ENV_VARIABLE.VOILA_PREHEAT] = 'False'
            kernel_env[ENV_VARIABLE.VOILA_BASE_URL] = self.base_url
            kernel_id = await ensure_async((self.kernel_manager.start_kernel(
                kernel_name=gen.notebook.metadata.kernelspec.name,
                path=cwd,
                env=kernel_env,
            )))
            kernel_future = self.kernel_manager.get_kernel(kernel_id)
            queue = asyncio.Queue()

            async def put_html():
                async for html_snippet, _ in gen.generate_content_generator(
                        kernel_id, kernel_future):
                    await queue.put(html_snippet)

                await queue.put(None)

            asyncio.ensure_future(put_html())

            # If not done within the timeout, we send a heartbeat
            # this is fundamentally to avoid browser/proxy read-timeouts, but
            # can be used in a template to give feedback to a user
            while True:
                try:
                    html_snippet = await asyncio.wait_for(
                        queue.get(),
                        self.voila_configuration.http_keep_alive_timeout)
                except asyncio.TimeoutError:
                    yield time_out()
                else:
                    if html_snippet is None:
                        break
                    yield html_snippet