def generate_session_id(secret_key=settings.secret_key_bytes(), signed=settings.sign_sessions()):
    """Generate a random session ID.

    Typically, each browser tab connected to a Bokeh application
    has its own session ID.  In production deployments of a Bokeh
    app, session IDs should be random and unguessable - otherwise
    users of the app could interfere with one another.

    If session IDs are signed with a secret key, the server can
    verify that the generator of the session ID was "authorized"
    (the generator had to know the secret key). This can be used
    to have a separate process, such as another web application,
    which generates new sessions on a Bokeh server. This other
    process may require users to log in before redirecting them to
    the Bokeh server with a valid session ID, for example.

    Args:
        secret_key (str, optional) : Secret key (default: value of 'BOKEH_SECRET_KEY' env var)
        signed (bool, optional) : Whether to sign the session ID (default: value of
                                  'BOKEH_SIGN_SESSIONS' env var)

    """
    secret_key = _ensure_bytes(secret_key)
    if signed:
        # note: '-' can also be in the base64 encoded signature
        base_id = _get_random_string(secret_key=secret_key)
        return base_id + '-' + _signature(base_id, secret_key)
    else:
        return _get_random_string(secret_key=secret_key)
def check_session_id_signature(session_id, secret_key=settings.secret_key_bytes(),
                               signed=settings.sign_sessions()):
    """Check the signature of a session ID, returning True if it's valid.

    The server uses this function to check whether a session ID
    was generated with the correct secret key. If signed sessions are disabled,
    this function always returns True.

    Args:
        session_id (str) : The session ID to check
        secret_key (str, optional) : Secret key (default: value of 'BOKEH_SECRET_KEY' env var)
        signed (bool, optional) : Whether to check anything (default: value of
                                  'BOKEH_SIGN_SESSIONS' env var)

    """
    secret_key = _ensure_bytes(secret_key)
    if signed:
        pieces = session_id.split('-', 1)
        if len(pieces) != 2:
            return False
        base_id = pieces[0]
        provided_signature = pieces[1]
        expected_signature = _signature(base_id, secret_key)
        # hmac.compare_digest() uses a string compare algorithm that doesn't
        # short-circuit so we don't allow timing analysis
        # encode_utf8 is used to ensure that strings have same encoding
        return hmac.compare_digest(encode_utf8(expected_signature), encode_utf8(provided_signature))
    else:
        return True
def check_session_id_signature(session_id, secret_key=settings.secret_key_bytes(),
                               signed=settings.sign_sessions()):
    """Check the signature of a session ID, returning True if it's valid.

    The server uses this function to check whether a session ID
    was generated with the correct secret key. If signed sessions are disabled,
    this function always returns True.

    Args:
        session_id (str) : The session ID to check
        secret_key (str, optional) : Secret key (default: value of 'BOKEH_SECRET_KEY' env var)
        signed (bool, optional) : Whether to check anything (default: value of
                                  'BOKEH_SIGN_SESSIONS' env var)

    """
    secret_key = _ensure_bytes(secret_key)
    if signed:
        pieces = session_id.split('-', 1)
        if len(pieces) != 2:
            return False
        base_id = pieces[0]
        provided_signature = pieces[1]
        expected_signature = _signature(base_id, secret_key)
        # hmac.compare_digest() uses a string compare algorithm that doesn't
        # short-circuit so we don't allow timing analysis
        # encode_utf8 is used to ensure that strings have same encoding
        return hmac.compare_digest(encode_utf8(expected_signature), encode_utf8(provided_signature))
    else:
        return True
def generate_session_id(secret_key=settings.secret_key_bytes(), signed=settings.sign_sessions()):
    """Generate a random session ID.

    Typically, each browser tab connected to a Bokeh application
    has its own session ID.  In production deployments of a Bokeh
    app, session IDs should be random and unguessable - otherwise
    users of the app could interfere with one another.

    If session IDs are signed with a secret key, the server can
    verify that the generator of the session ID was "authorized"
    (the generator had to know the secret key). This can be used
    to have a separate process, such as another web application,
    which generates new sessions on a Bokeh server. This other
    process may require users to log in before redirecting them to
    the Bokeh server with a valid session ID, for example.

    Args:
        secret_key (str, optional) : Secret key (default: value of 'BOKEH_SECRET_KEY' env var)
        signed (bool, optional) : Whether to sign the session ID (default: value of
                                  'BOKEH_SIGN_SESSIONS' env var)

    """
    secret_key = _ensure_bytes(secret_key)
    if signed:
        # note: '-' can also be in the base64 encoded signature
        base_id = _get_random_string(secret_key=secret_key)
        return base_id + '-' + _signature(base_id, secret_key)
    else:
        return _get_random_string(secret_key=secret_key)
Exemple #5
0
def _get_random_string(length=36,
                       allowed_chars='abcdefghijklmnopqrstuvwxyz'
                       'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
                       secret_key=settings.secret_key_bytes()):
    """
    Return a securely generated random string.
    The default length of 12 with the a-z, A-Z, 0-9 character set returns
    a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
    """
    secret_key = _ensure_bytes(secret_key)
    _reseed_if_needed(using_sysrandom, secret_key)
    return ''.join(random.choice(allowed_chars) for i in range(length))
Exemple #6
0
def _get_random_string(length=36,
                       allowed_chars='abcdefghijklmnopqrstuvwxyz'
                       'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
                       secret_key=settings.secret_key_bytes()):
    """
    Return a securely generated random string.
    The default length of 12 with the a-z, A-Z, 0-9 character set returns
    a 71-bit value. log_2((26+26+10)^12) =~ 71 bits
    """
    secret_key = _ensure_bytes(secret_key)
    _reseed_if_needed(using_sysrandom, secret_key)
    return ''.join(random.choice(allowed_chars) for i in range(length))
Exemple #7
0
def _get_random_string(length: int = 44,
                       allowed_chars: str = 'abcdefghijklmnopqrstuvwxyz'
                       'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789',
                       secret_key: Optional[bytes] = settings.secret_key_bytes()) -> str:
    """
    Return a securely generated random string.
    With the a-z, A-Z, 0-9 character set:
    Length 12 is a 71-bit value. log_2((26+26+10)^12) =~ 71
    Length 44 is a 261-bit value. log_2((26+26+10)^44) = 261
    """
    secret_key = _ensure_bytes(secret_key)
    _reseed_if_needed(using_sysrandom, secret_key)
    return ''.join(random.choice(allowed_chars) for _ in range(length))
Exemple #8
0
def generate_session_id(secret_key: Optional[bytes] = settings.secret_key_bytes(),
                        signed: bool = settings.sign_sessions()) -> str:
    ''' Generate a random session ID.

    Typically, each browser tab connected to a Bokeh application has its own
    session ID.  In production deployments of a Bokeh app, session IDs should be
    random and unguessable - otherwise users of the app could interfere with one
    another.
    '''
    session_id = _get_random_string()
    if signed:
        session_id = '.'.join([session_id, _signature(session_id, secret_key)])
    return session_id
Exemple #9
0
def check_token_signature(
    token: str,
    secret_key: Optional[bytes] = settings.secret_key_bytes(),
    signed: Optional[bool] = settings.sign_sessions()
) -> bool:
    """Check the signature of a token and the contained signature.

    The server uses this function to check whether a token and the
    contained session id was generated with the correct secret key.
    If signed sessions are disabled, this function always returns True.

    Args:
        token (str) :
            The token to check

        secret_key (str, optional) :
            Secret key (default: value of BOKEH_SECRET_KEY environment variable)

        signed (bool, optional) :
            Whether to check anything (default: value of BOKEH_SIGN_SESSIONS
            environment variable)

    Returns:
        bool

    """
    secret_key = _ensure_bytes(secret_key)
    if signed:
        token_pieces = token.split('.', 1)
        if len(token_pieces) != 2:
            return False
        base_token = token_pieces[0]
        provided_token_signature = token_pieces[1]
        expected_token_signature = _signature(base_token, secret_key)
        # hmac.compare_digest() uses a string compare algorithm that doesn't
        # short-circuit so we don't allow timing analysis
        token_valid = hmac.compare_digest(expected_token_signature,
                                          provided_token_signature)
        session_id = get_session_id(token)
        session_id_valid = check_session_id_signature(session_id, secret_key,
                                                      signed)
        return token_valid and session_id_valid
    return True
Exemple #10
0
def check_session_id_signature(session_id: str,
                               secret_key: Optional[bytes] = settings.secret_key_bytes(),
                               signed: Optional[bool] = settings.sign_sessions()) -> bool:
    """Check the signature of a session ID, returning True if it's valid.

    The server uses this function to check whether a session ID was generated
    with the correct secret key. If signed sessions are disabled, this function
    always returns True.
    """
    secret_key = _ensure_bytes(secret_key)
    if signed:
        id_pieces = session_id.split('.', 1)
        if len(id_pieces) != 2:
            return False
        provided_id_signature = id_pieces[1]
        expected_id_signature = _signature(id_pieces[0], secret_key)
        return hmac.compare_digest(
            expected_id_signature, provided_id_signature
        )
    return True
Exemple #11
0
def generate_jwt_token(
        session_id: str,
        secret_key: Optional[bytes] = settings.secret_key_bytes(),
        signed: bool = settings.sign_sessions(),
        extra_payload: Optional[Dict[str, Any]] = None,
        expiration: int = 300) -> str:
    """Generates a JWT token given a session_id and additional payload.

    Args:
        session_id (str):
            The session id to add to the token

        secret_key (str, optional) :
            Secret key (default: value of BOKEH_SECRET_KEY environment varariable)

        signed (bool, optional) :
            Whether to sign the session ID (default: value of BOKEH_SIGN_SESSIONS
            envronment varariable)

        extra_payload (dict, optional) :
            Extra key/value pairs to include in the Bokeh session token

        expiration (int, optional) :
            Expiration time

    Returns:
        str
    """
    now = calendar.timegm(dt.datetime.now().utctimetuple())
    payload = {'session_id': session_id, 'session_expiry': now + expiration}
    if extra_payload:
        if "session_id" in extra_payload:
            raise RuntimeError(
                "extra_payload for session tokens may not contain 'session_id'"
            )
        payload.update(extra_payload)
    token = _base64_encode(json.dumps(payload))
    secret_key = _ensure_bytes(secret_key)
    if not signed:
        return token
    return token + '.' + _signature(token, secret_key)
Exemple #12
0
    def invoke(self, args):
        applications = build_single_handler_applications(args.files)

        log_level = getattr(logging, args.log_level.upper())
        logging.basicConfig(level=log_level)

        if len(applications) == 0:
            # create an empty application by default, typically used with output_server
            applications['/'] = Application()

        if args.keep_alive is not None:
            if args.keep_alive == 0:
                log.info("Keep-alive ping disabled")
            else:
                log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive)
            # rename to be compatible with Server
            args.keep_alive_milliseconds = args.keep_alive

        server_kwargs = { key: getattr(args, key) for key in ['port',
                                                              'address',
                                                              'allow_websocket_origin',
                                                              'host',
                                                              'prefix',
                                                              'develop',
                                                              'keep_alive_milliseconds',
                                                              'use_xheaders',
                                                            ]
                          if getattr(args, key, None) is not None }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError("argparse should have filtered out --session-ids mode " +
                               args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " +
                "the `bokeh secret` command can be used to generate a new key.")

        server = Server(applications, **server_kwargs)

        if args.show:
            # we have to defer opening in browser until we start up the server
            def show_callback():
                for route in applications.keys():
                    server.show(route)
            server.io_loop.add_callback(show_callback)

        if args.develop:
            log.info("Using develop mode (do not enable --develop in production)")

        address_string = ''
        if server.address is not None and server.address != '':
            address_string = ' address ' + server.address

        log.info("Starting Bokeh server on port %d%s with applications at paths %r",
                 server.port,
                 address_string,
                 sorted(applications.keys()))

        server.start()
Exemple #13
0
    def invoke(self, args: argparse.Namespace) -> None:
        '''

        '''
        basicConfig(format=args.log_format, filename=args.log_file)

        # This is a bit of a fudge. We want the default log level for non-server
        # cases to be None, i.e. we don't set a log level. But for the server we
        # do want to set the log level to INFO if nothing else overrides that.
        log_level = settings.py_log_level(args.log_level)
        if log_level is None:
            log_level = logging.INFO
        logging.getLogger('bokeh').setLevel(log_level)

        if args.use_config is not None:
            log.info("Using override config file: {}".format(args.use_config))
            settings.load_config(args.use_config)

        # protect this import inside a function so that "bokeh info" can work
        # even if Tornado is not installed
        from bokeh.server.server import Server

        files = []
        for f in args.files:
            if args.glob:
                files.extend(glob(f))
            else:
                files.append(f)

        argvs = {f: args.args for f in files}
        applications = build_single_handler_applications(files, argvs)

        if len(applications) == 0:
            # create an empty application by default
            applications['/'] = Application()

        # rename args to be compatible with Server
        if args.keep_alive is not None:
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        if args.mem_log_frequency is not None:
            args.mem_log_frequency_milliseconds = args.mem_log_frequency

        server_kwargs = {
            key: getattr(args, key)
            for key in [
                'port',
                'address',
                'allow_websocket_origin',
                'num_procs',
                'prefix',
                'index',
                'keep_alive_milliseconds',
                'check_unused_sessions_milliseconds',
                'unused_session_lifetime_milliseconds',
                'stats_log_frequency_milliseconds',
                'mem_log_frequency_milliseconds',
                'use_xheaders',
                'websocket_max_message_size',
                'include_cookies',
                'include_headers',
                'exclude_cookies',
                'exclude_headers',
                'session_token_expiration',
            ] if getattr(args, key, None) is not None
        }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['ssl_certfile'] = settings.ssl_certfile(
            getattr(args, 'ssl_certfile', None))
        server_kwargs['ssl_keyfile'] = settings.ssl_keyfile(
            getattr(args, 'ssl_keyfile', None))
        server_kwargs['ssl_password'] = settings.ssl_password()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError(
                "argparse should have filtered out --session-ids mode " +
                args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; "
                +
                "the `bokeh secret` command can be used to generate a new key."
                )

        auth_module_path = settings.auth_module(
            getattr(args, 'auth_module', None))
        if auth_module_path:
            server_kwargs['auth_provider'] = AuthModule(auth_module_path)
        else:
            server_kwargs['auth_provider'] = NullAuth()

        server_kwargs['xsrf_cookies'] = settings.xsrf_cookies(
            getattr(args, 'enable_xsrf_cookies', False))
        server_kwargs['cookie_secret'] = settings.cookie_secret(
            getattr(args, 'cookie_secret', None))
        server_kwargs['use_index'] = not args.disable_index
        server_kwargs['redirect_root'] = not args.disable_index_redirect
        server_kwargs['autoreload'] = args.dev is not None

        def find_autoreload_targets(app_path: str) -> None:
            path = os.path.abspath(app_path)
            if not os.path.isdir(path):
                return

            for path, subdirs, files in os.walk(path):
                for name in files:
                    if (fnmatch(name, '*.html') or fnmatch(name, '*.css')
                            or fnmatch(name, '*.yaml')):
                        log.info("Watching: " + os.path.join(path, name))
                        watch(os.path.join(path, name))

        def add_optional_autoreload_files(file_list: List[str]) -> None:
            for filen in file_list:
                if os.path.isdir(filen):
                    log.warning("Cannot watch directory " + filen)
                    continue
                log.info("Watching: " + filen)
                watch(filen)

        if server_kwargs['autoreload']:
            if len(applications.keys()) != 1:
                die("--dev can only support a single app.")
            if server_kwargs['num_procs'] != 1:
                log.info("Running in --dev mode. --num-procs is limited to 1.")
                server_kwargs['num_procs'] = 1

            find_autoreload_targets(args.files[0])
            add_optional_autoreload_files(args.dev)

        with report_server_init_errors(**server_kwargs):
            server = Server(applications, **server_kwargs)

            if args.show:

                # we have to defer opening in browser until we start up the server
                def show_callback() -> None:
                    for route in applications.keys():
                        server.show(route)

                server.io_loop.add_callback(show_callback)

            address_string = 'localhost'
            if server.address is not None and server.address != '':
                address_string = server.address

            for route in sorted(applications.keys()):
                url = "http://%s:%d%s%s" % (address_string, server.port,
                                            server.prefix, route)
                log.info("Bokeh app running at: %s" % url)

            log.info("Starting Bokeh server with process id: %d" % os.getpid())
            server.run_until_shutdown()
Exemple #14
0
    def invoke(self, args):
        applications = build_single_handler_applications(args.files)

        log_level = getattr(logging, args.log_level.upper())
        logging.basicConfig(level=log_level)

        if len(applications) == 0:
            # create an empty application by default, typically used with output_server
            applications["/"] = Application()

        if args.keep_alive is not None:
            if args.keep_alive == 0:
                log.info("Keep-alive ping disabled")
            else:
                log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive)
            # rename to be compatible with Server
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            log.info("Check for unused sessions every %d milliseconds", args.check_unused_sessions)
            # rename to be compatible with Server
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            log.info("Unused sessions last for %d milliseconds", args.unused_session_lifetime)
            # rename to be compatible with Server
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            log.info("Log statistics every %d milliseconds", args.stats_log_frequency)
            # rename to be compatible with Server
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        server_kwargs = {
            key: getattr(args, key)
            for key in [
                "port",
                "address",
                "allow_websocket_origin",
                "host",
                "prefix",
                "develop",
                "keep_alive_milliseconds",
                "check_unused_sessions_milliseconds",
                "unused_session_lifetime_milliseconds",
                "stats_log_frequency_milliseconds",
                "use_xheaders",
            ]
            if getattr(args, key, None) is not None
        }

        server_kwargs["sign_sessions"] = settings.sign_sessions()
        server_kwargs["secret_key"] = settings.secret_key_bytes()
        server_kwargs["generate_session_ids"] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == "unsigned":
            server_kwargs["sign_sessions"] = False
        elif args.session_ids == "signed":
            server_kwargs["sign_sessions"] = True
        elif args.session_ids == "external-signed":
            server_kwargs["sign_sessions"] = True
            server_kwargs["generate_session_ids"] = False
        else:
            raise RuntimeError("argparse should have filtered out --session-ids mode " + args.session_ids)

        if server_kwargs["sign_sessions"] and not server_kwargs["secret_key"]:
            die(
                "To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; "
                + "the `bokeh secret` command can be used to generate a new key."
            )

        server = Server(applications, **server_kwargs)

        if args.show:
            # we have to defer opening in browser until we start up the server
            def show_callback():
                for route in applications.keys():
                    server.show(route)

            server.io_loop.add_callback(show_callback)

        if args.develop:
            log.info("Using develop mode (do not enable --develop in production)")

        address_string = ""
        if server.address is not None and server.address != "":
            address_string = " address " + server.address

        log.info(
            "Starting Bokeh server on port %d%s with applications at paths %r",
            server.port,
            address_string,
            sorted(applications.keys()),
        )

        server.start()
Exemple #15
0
    def invoke(self, args):
        argvs = { f : args.args for f in args.files}
        applications = build_single_handler_applications(args.files, argvs)

        log_level = getattr(logging, args.log_level.upper())
        logging.basicConfig(level=log_level, format=args.log_format)

        if len(applications) == 0:
            # create an empty application by default, typically used with output_server
            applications['/'] = Application()

        if args.keep_alive is not None:
            if args.keep_alive == 0:
                log.info("Keep-alive ping disabled")
            else:
                log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive)
            # rename to be compatible with Server
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            log.info("Check for unused sessions every %d milliseconds", args.check_unused_sessions)
            # rename to be compatible with Server
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            log.info("Unused sessions last for %d milliseconds", args.unused_session_lifetime)
            # rename to be compatible with Server
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            log.info("Log statistics every %d milliseconds", args.stats_log_frequency)
            # rename to be compatible with Server
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        server_kwargs = { key: getattr(args, key) for key in ['port',
                                                              'address',
                                                              'allow_websocket_origin',
                                                              'host',
                                                              'prefix',
                                                              'develop',
                                                              'keep_alive_milliseconds',
                                                              'check_unused_sessions_milliseconds',
                                                              'unused_session_lifetime_milliseconds',
                                                              'stats_log_frequency_milliseconds',
                                                              'use_xheaders',
                                                            ]
                          if getattr(args, key, None) is not None }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError("argparse should have filtered out --session-ids mode " +
                               args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " +
                "the `bokeh secret` command can be used to generate a new key.")

        server_kwargs['use_index'] = not args.disable_index

        server = Server(applications, **server_kwargs)

        if args.show:
            # we have to defer opening in browser until we start up the server
            def show_callback():
                for route in applications.keys():
                    server.show(route)
            server.io_loop.add_callback(show_callback)

        if args.develop:
            log.info("Using develop mode (do not enable --develop in production)")

        address_string = ''
        if server.address is not None and server.address != '':
            address_string = ' address ' + server.address

        log.info("Starting Bokeh server on port %d%s with applications at paths %r",
                 server.port,
                 address_string,
                 sorted(applications.keys()))

        log.info("Starting Bokeh server with process id: %d" % getpid())

        server.start()
Exemple #16
0
    def invoke(self, args):
        '''

        '''

        # protect this import inside a function so that "bokeh info" can work
        # even if Tornado is not installed
        from bokeh.server.server import Server

        argvs = { f : args.args for f in args.files}
        applications = build_single_handler_applications(args.files, argvs)

        log_level = getattr(logging, args.log_level.upper())
        basicConfig(level=log_level, format=args.log_format, filename=args.log_file)

        if len(applications) == 0:
            # create an empty application by default
            applications['/'] = Application()

        # rename args to be compatible with Server
        if args.keep_alive is not None:
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        if args.mem_log_frequency is not None:
            args.mem_log_frequency_milliseconds = args.mem_log_frequency

        server_kwargs = { key: getattr(args, key) for key in ['port',
                                                              'address',
                                                              'allow_websocket_origin',
                                                              'num_procs',
                                                              'prefix',
                                                              'keep_alive_milliseconds',
                                                              'check_unused_sessions_milliseconds',
                                                              'unused_session_lifetime_milliseconds',
                                                              'stats_log_frequency_milliseconds',
                                                              'mem_log_frequency_milliseconds',
                                                              'use_xheaders',
                                                              'websocket_max_message_size',
                                                            ]
                          if getattr(args, key, None) is not None }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError("argparse should have filtered out --session-ids mode " +
                               args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " +
                "the `bokeh secret` command can be used to generate a new key.")

        server_kwargs['use_index'] = not args.disable_index
        server_kwargs['redirect_root'] = not args.disable_index_redirect

        with report_server_init_errors(**server_kwargs):
            server = Server(applications, **server_kwargs)

            if args.show:
                # we have to defer opening in browser until we start up the server
                def show_callback():
                    for route in applications.keys():
                        server.show(route)
                server.io_loop.add_callback(show_callback)

            address_string = 'localhost'
            if server.address is not None and server.address != '':
                address_string = server.address

            for route in sorted(applications.keys()):
                url = "http://%s:%d%s%s" % (address_string, server.port, server.prefix, route)
                log.info("Bokeh app running at: %s" % url)

            log.info("Starting Bokeh server with process id: %d" % getpid())
            server.run_until_shutdown()
Exemple #17
0
    def invoke(self, args):
        '''

        '''

        # protect this import inside a function so that "bokeh info" can work
        # even if Tornado is not installed
        from bokeh.server.server import Server

        argvs = { f : args.args for f in args.files}
        applications = build_single_handler_applications(args.files, argvs)

        log_level = getattr(logging, args.log_level.upper())
        basicConfig(level=log_level, format=args.log_format, filename=args.log_file)

        if len(applications) == 0:
            # create an empty application by default
            applications['/'] = Application()

        # rename args to be compatible with Server
        if args.keep_alive is not None:
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        if args.mem_log_frequency is not None:
            args.mem_log_frequency_milliseconds = args.mem_log_frequency

        server_kwargs = { key: getattr(args, key) for key in ['port',
                                                              'address',
                                                              'allow_websocket_origin',
                                                              'num_procs',
                                                              'prefix',
                                                              'keep_alive_milliseconds',
                                                              'check_unused_sessions_milliseconds',
                                                              'unused_session_lifetime_milliseconds',
                                                              'stats_log_frequency_milliseconds',
                                                              'mem_log_frequency_milliseconds',
                                                              'use_xheaders',
                                                              'websocket_max_message_size',
                                                            ]
                          if getattr(args, key, None) is not None }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError("argparse should have filtered out --session-ids mode " +
                               args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " +
                "the `bokeh secret` command can be used to generate a new key.")

        server_kwargs['use_index'] = not args.disable_index
        server_kwargs['redirect_root'] = not args.disable_index_redirect
        server_kwargs['autoreload'] = args.dev is not None

        def find_autoreload_targets(app_path):
            path = os.path.abspath(app_path)
            if not os.path.isdir(path):
                return

            for path, subdirs, files in os.walk(path):
                for name in files:
                    if (fnmatch(name, '*.html') or
                        fnmatch(name, '*.css') or
                        fnmatch(name, '*.yaml')):
                        log.info("Watching: " + os.path.join(path, name))
                        watch(os.path.join(path, name))

        def add_optional_autoreload_files(file_list):
            for filen in file_list:
                if os.path.isdir(filen):
                    log.warning("Cannot watch directory " + filen)
                    continue
                log.info("Watching: " + filen)
                watch(filen)

        if server_kwargs['autoreload']:
            if len(applications.keys()) != 1:
                die("--dev can only support a single app.")
            if server_kwargs['num_procs'] != 1:
                log.info("Running in --dev mode. --num-procs is limited to 1.")
                server_kwargs['num_procs'] = 1

            find_autoreload_targets(args.files[0])
            add_optional_autoreload_files(args.dev)


        with report_server_init_errors(**server_kwargs):
            server = Server(applications, **server_kwargs)

            if args.show:
                # we have to defer opening in browser until we start up the server
                def show_callback():
                    for route in applications.keys():
                        server.show(route)
                server.io_loop.add_callback(show_callback)

            address_string = 'localhost'
            if server.address is not None and server.address != '':
                address_string = server.address

            for route in sorted(applications.keys()):
                url = "http://%s:%d%s%s" % (address_string, server.port, server.prefix, route)
                log.info("Bokeh app running at: %s" % url)

            log.info("Starting Bokeh server with process id: %d" % os.getpid())
            server.run_until_shutdown()
Exemple #18
0
    def __init__(self, applications, prefix, hosts,
                 extra_websocket_origins,
                 io_loop=None,
                 extra_patterns=None,
                 secret_key=settings.secret_key_bytes(),
                 sign_sessions=settings.sign_sessions(),
                 generate_session_ids=True,
                 # heroku, nginx default to 60s timeout, so well less than that
                 keep_alive_milliseconds=37000,
                 # how often to check for unused sessions
                 check_unused_sessions_milliseconds=17000,
                 # how long unused sessions last
                 unused_session_lifetime_milliseconds=60*30*1000,
                 # how often to log stats
                 stats_log_frequency_milliseconds=15000,
                 develop=False):

        self._prefix = prefix

        if io_loop is None:
            io_loop = IOLoop.current()
        self._loop = io_loop

        if keep_alive_milliseconds < 0:
            # 0 means "disable"
            raise ValueError("keep_alive_milliseconds must be >= 0")

        self._hosts = set(hosts)
        self._websocket_origins = self._hosts | set(extra_websocket_origins)
        self._resources = {}
        self._develop = develop
        self._secret_key = secret_key
        self._sign_sessions = sign_sessions
        self._generate_session_ids = generate_session_ids

        log.debug("Allowed Host headers: %r", list(self._hosts))
        log.debug("These host origins can connect to the websocket: %r", list(self._websocket_origins))

        # Wrap applications in ApplicationContext
        self._applications = dict()
        for k,v in applications.items():
            self._applications[k] = ApplicationContext(v, self._develop, self._loop)

        extra_patterns = extra_patterns or []
        all_patterns = []
        for key in applications:
            app_patterns = []
            for p in per_app_patterns:
                if key == "/":
                    route = p[0]
                else:
                    route = key + p[0]
                route = self._prefix + route
                app_patterns.append((route, p[1], { "application_context" : self._applications[key] }))

            websocket_path = None
            for r in app_patterns:
                if r[0].endswith("/ws"):
                    websocket_path = r[0]
            if not websocket_path:
                raise RuntimeError("Couldn't find websocket path")
            for r in app_patterns:
                r[2]["bokeh_websocket_path"] = websocket_path

            all_patterns.extend(app_patterns)

        for p in extra_patterns + toplevel_patterns:
            prefixed_pat = (self._prefix+p[0],) + p[1:]
            all_patterns.append(prefixed_pat)

        for pat in all_patterns:
            _whitelist(pat[1])

        log.debug("Patterns are: %r", all_patterns)

        super(BokehTornado, self).__init__(all_patterns)

        self._clients = set()
        self._executor = ProcessPoolExecutor(max_workers=4)
        self._loop.add_callback(self._start_async)
        self._stats_job = PeriodicCallback(self.log_stats,
                                           stats_log_frequency_milliseconds,
                                           io_loop=self._loop)
        self._unused_session_linger_seconds = unused_session_lifetime_milliseconds
        self._cleanup_job = PeriodicCallback(self.cleanup_sessions,
                                             check_unused_sessions_milliseconds,
                                             io_loop=self._loop)

        if keep_alive_milliseconds > 0:
            self._ping_job = PeriodicCallback(self.keep_alive, keep_alive_milliseconds, io_loop=self._loop)
        else:
            self._ping_job = None
Exemple #19
0
    def __init__(self, applications, prefix, hosts,
                 extra_websocket_origins,
                 io_loop=None,
                 extra_patterns=None,
                 secret_key=settings.secret_key_bytes(),
                 sign_sessions=settings.sign_sessions(),
                 generate_session_ids=True,
                 # heroku, nginx default to 60s timeout, so well less than that
                 keep_alive_milliseconds=37000,
                 # how often to check for unused sessions
                 check_unused_sessions_milliseconds=17000,
                 # how long unused sessions last
                 unused_session_lifetime_milliseconds=15000,
                 # how often to log stats
                 stats_log_frequency_milliseconds=15000,
                 use_index=True,
                 redirect_root=True):

        self._prefix = prefix
        self.use_index = use_index

        if keep_alive_milliseconds < 0:
            # 0 means "disable"
            raise ValueError("keep_alive_milliseconds must be >= 0")

        if check_unused_sessions_milliseconds <= 0:
            raise ValueError("check_unused_sessions_milliseconds must be > 0")

        if unused_session_lifetime_milliseconds <= 0:
            raise ValueError("check_unused_sessions_milliseconds must be > 0")

        if stats_log_frequency_milliseconds <= 0:
            raise ValueError("stats_log_frequency_milliseconds must be > 0")

        self._hosts = set(hosts)
        self._websocket_origins = self._hosts | set(extra_websocket_origins)
        self._resources = {}
        self._secret_key = secret_key
        self._sign_sessions = sign_sessions
        self._generate_session_ids = generate_session_ids

        log.debug("Allowed Host headers: %r", list(self._hosts))
        log.debug("These host origins can connect to the websocket: %r", list(self._websocket_origins))

        # Wrap applications in ApplicationContext
        self._applications = dict()
        for k,v in applications.items():
            self._applications[k] = ApplicationContext(v)

        extra_patterns = extra_patterns or []
        all_patterns = []
        for key, app in applications.items():
            app_patterns = []
            for p in per_app_patterns:
                if key == "/":
                    route = p[0]
                else:
                    route = key + p[0]
                route = self._prefix + route
                app_patterns.append((route, p[1], { "application_context" : self._applications[key] }))

            websocket_path = None
            for r in app_patterns:
                if r[0].endswith("/ws"):
                    websocket_path = r[0]
            if not websocket_path:
                raise RuntimeError("Couldn't find websocket path")
            for r in app_patterns:
                r[2]["bokeh_websocket_path"] = websocket_path

            all_patterns.extend(app_patterns)

            # add a per-app static path if requested by the application
            if app.static_path is not None:
                if key == "/":
                    route = "/static/(.*)"
                else:
                    route = key + "/static/(.*)"
                route = self._prefix + route
                all_patterns.append((route, StaticFileHandler, { "path" : app.static_path }))

        for p in extra_patterns + toplevel_patterns:
            if p[1] == RootHandler:
                if self.use_index:
                    data = {"applications": self._applications,
                            "prefix": self._prefix,
                            "use_redirect": redirect_root}
                    prefixed_pat = (self._prefix + p[0],) + p[1:] + (data,)
                    all_patterns.append(prefixed_pat)
            else:
                prefixed_pat = (self._prefix + p[0],) + p[1:]
                all_patterns.append(prefixed_pat)

        for pat in all_patterns:
            _whitelist(pat[1])

        log.debug("Patterns are:")
        for line in pformat(all_patterns, width=60).split("\n"):
            log.debug("  " + line)

        super(BokehTornado, self).__init__(all_patterns)
Exemple #20
0
    def invoke(self, args):
        argvs = { f : args.args for f in args.files}
        applications = build_single_handler_applications(args.files, argvs)

        log_level = getattr(logging, args.log_level.upper())
        logging.basicConfig(level=log_level, format=args.log_format)

        if len(applications) == 0:
            # create an empty application by default, typically used with output_server
            applications['/'] = Application()

        if args.keep_alive is not None:
            if args.keep_alive == 0:
                log.info("Keep-alive ping disabled")
            else:
                log.info("Keep-alive ping configured every %d milliseconds", args.keep_alive)
            # rename to be compatible with Server
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            log.info("Check for unused sessions every %d milliseconds", args.check_unused_sessions)
            # rename to be compatible with Server
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            log.info("Unused sessions last for %d milliseconds", args.unused_session_lifetime)
            # rename to be compatible with Server
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            log.info("Log statistics every %d milliseconds", args.stats_log_frequency)
            # rename to be compatible with Server
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        server_kwargs = { key: getattr(args, key) for key in ['port',
                                                              'address',
                                                              'allow_websocket_origin',
                                                              'host',
                                                              'num_procs',
                                                              'prefix',
                                                              'develop',
                                                              'keep_alive_milliseconds',
                                                              'check_unused_sessions_milliseconds',
                                                              'unused_session_lifetime_milliseconds',
                                                              'stats_log_frequency_milliseconds',
                                                              'use_xheaders',
                                                            ]
                          if getattr(args, key, None) is not None }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError("argparse should have filtered out --session-ids mode " +
                               args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; " +
                "the `bokeh secret` command can be used to generate a new key.")

        server_kwargs['use_index'] = not args.disable_index
        server_kwargs['redirect_root'] = not args.disable_index_redirect

        server = Server(applications, **server_kwargs)

        if args.show:
            # we have to defer opening in browser until we start up the server
            def show_callback():
                for route in applications.keys():
                    server.show(route)
            server.io_loop.add_callback(show_callback)

        if args.develop:
            log.info("Using develop mode (do not enable --develop in production)")

        address_string = ''
        if server.address is not None and server.address != '':
            address_string = ' address ' + server.address

        log.info("Starting Bokeh server on port %d%s with applications at paths %r",
                 server.port,
                 address_string,
                 sorted(applications.keys()))

        log.info("Starting Bokeh server with process id: %d" % getpid())

        event_handler = LoggingEventHandler()
        observer = Observer()
        path = r'C:\Users\jhu\Desktop'
        observer.schedule(event_handler, path, recursive=False)
        observer.start()
        server.start()
Exemple #21
0
    def invoke(self, args):
        argvs = {f: args.args for f in args.files}
        applications = build_single_handler_applications(args.files, argvs)

        log_level = getattr(logging, args.log_level.upper())
        basicConfig(level=log_level, format=args.log_format)

        # This should remain here until --host is removed entirely
        _fixup_deprecated_host_args(args)

        if len(applications) == 0:
            # create an empty application by default
            applications['/'] = Application()

        if args.keep_alive is not None:
            if args.keep_alive == 0:
                log.info("Keep-alive ping disabled")
            else:
                log.info("Keep-alive ping configured every %d milliseconds",
                         args.keep_alive)
            # rename to be compatible with Server
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            log.info("Check for unused sessions every %d milliseconds",
                     args.check_unused_sessions)
            # rename to be compatible with Server
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            log.info("Unused sessions last for %d milliseconds",
                     args.unused_session_lifetime)
            # rename to be compatible with Server
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            log.info("Log statistics every %d milliseconds",
                     args.stats_log_frequency)
            # rename to be compatible with Server
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        server_kwargs = {
            key: getattr(args, key)
            for key in [
                'port',
                'address',
                'allow_websocket_origin',
                'num_procs',
                'prefix',
                'keep_alive_milliseconds',
                'check_unused_sessions_milliseconds',
                'unused_session_lifetime_milliseconds',
                'stats_log_frequency_milliseconds',
                'use_xheaders',
            ] if getattr(args, key, None) is not None
        }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError(
                "argparse should have filtered out --session-ids mode " +
                args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; "
                +
                "the `bokeh secret` command can be used to generate a new key."
                )

        server_kwargs['use_index'] = not args.disable_index
        server_kwargs['redirect_root'] = not args.disable_index_redirect

        with report_server_init_errors(**server_kwargs):
            server = Server(applications, **server_kwargs)

            if args.show:
                # we have to defer opening in browser until we start up the server
                def show_callback():
                    for route in applications.keys():
                        server.show(route)

                server.io_loop.add_callback(show_callback)

            address_string = 'localhost'
            if server.address is not None and server.address != '':
                address_string = server.address

            for route in sorted(applications.keys()):
                url = "http://%s:%d%s%s" % (address_string, server.port,
                                            server.prefix, route)
                log.info("Bokeh app running at: %s" % url)

            log.info("Starting Bokeh server with process id: %d" % getpid())
            server.run_until_shutdown()
Exemple #22
0
    def invoke(self, args):
        '''

        '''

        # protect this import inside a function so that "bokeh info" can work
        # even if Tornado is not installed
        from bokeh.server.server import Server

        argvs = {f: args.args for f in args.files}
        applications = build_single_handler_applications(args.files, argvs)

        log_level = getattr(logging, args.log_level.upper())
        basicConfig(level=log_level,
                    format=args.log_format,
                    filename=args.log_file)

        if len(applications) == 0:
            # create an empty application by default
            applications['/'] = Application()

        # rename args to be compatible with Server
        if args.keep_alive is not None:
            args.keep_alive_milliseconds = args.keep_alive

        if args.check_unused_sessions is not None:
            args.check_unused_sessions_milliseconds = args.check_unused_sessions

        if args.unused_session_lifetime is not None:
            args.unused_session_lifetime_milliseconds = args.unused_session_lifetime

        if args.stats_log_frequency is not None:
            args.stats_log_frequency_milliseconds = args.stats_log_frequency

        if args.mem_log_frequency is not None:
            args.mem_log_frequency_milliseconds = args.mem_log_frequency

        server_kwargs = {
            key: getattr(args, key)
            for key in [
                'port',
                'address',
                'allow_websocket_origin',
                'num_procs',
                'prefix',
                'index',
                'keep_alive_milliseconds',
                'check_unused_sessions_milliseconds',
                'unused_session_lifetime_milliseconds',
                'stats_log_frequency_milliseconds',
                'mem_log_frequency_milliseconds',
                'use_xheaders',
                'websocket_max_message_size',
            ] if getattr(args, key, None) is not None
        }

        server_kwargs['sign_sessions'] = settings.sign_sessions()
        server_kwargs['secret_key'] = settings.secret_key_bytes()
        server_kwargs['generate_session_ids'] = True
        if args.session_ids is None:
            # no --session-ids means use the env vars
            pass
        elif args.session_ids == 'unsigned':
            server_kwargs['sign_sessions'] = False
        elif args.session_ids == 'signed':
            server_kwargs['sign_sessions'] = True
        elif args.session_ids == 'external-signed':
            server_kwargs['sign_sessions'] = True
            server_kwargs['generate_session_ids'] = False
        else:
            raise RuntimeError(
                "argparse should have filtered out --session-ids mode " +
                args.session_ids)

        if server_kwargs['sign_sessions'] and not server_kwargs['secret_key']:
            die("To sign sessions, the BOKEH_SECRET_KEY environment variable must be set; "
                +
                "the `bokeh secret` command can be used to generate a new key."
                )

        server_kwargs['use_index'] = not args.disable_index
        server_kwargs['redirect_root'] = not args.disable_index_redirect
        server_kwargs['autoreload'] = args.dev is not None

        def find_autoreload_targets(app_path):
            path = os.path.abspath(app_path)
            if not os.path.isdir(path):
                return

            for path, subdirs, files in os.walk(path):
                for name in files:
                    if (fnmatch(name, '*.html') or fnmatch(name, '*.css')
                            or fnmatch(name, '*.yaml')):
                        log.info("Watching: " + os.path.join(path, name))
                        watch(os.path.join(path, name))

        def add_optional_autoreload_files(file_list):
            for filen in file_list:
                if os.path.isdir(filen):
                    log.warning("Cannot watch directory " + filen)
                    continue
                log.info("Watching: " + filen)
                watch(filen)

        if server_kwargs['autoreload']:
            if len(applications.keys()) != 1:
                die("--dev can only support a single app.")
            if server_kwargs['num_procs'] != 1:
                log.info("Running in --dev mode. --num-procs is limited to 1.")
                server_kwargs['num_procs'] = 1

            find_autoreload_targets(args.files[0])
            add_optional_autoreload_files(args.dev)

        with report_server_init_errors(**server_kwargs):
            server = Server(applications, **server_kwargs)

            if args.show:
                # we have to defer opening in browser until we start up the server
                def show_callback():
                    for route in applications.keys():
                        server.show(route)

                server.io_loop.add_callback(show_callback)

            address_string = 'localhost'
            if server.address is not None and server.address != '':
                address_string = server.address

            for route in sorted(applications.keys()):
                url = "http://%s:%d%s%s" % (address_string, server.port,
                                            server.prefix, route)
                log.info("Bokeh app running at: %s" % url)

            log.info("Starting Bokeh server with process id: %d" % os.getpid())
            server.run_until_shutdown()