Example #1
0
        /// <summary>
        /// Restarts this instance
        /// </summary>
        /// <param name="address">The address to listen on</param>
        /// <param name="port">The port to listen on.</param>
        /// <param name="usessl">If set to <c>true</c> use ssl.</param>
        /// <param name="config">The server configuration.</param>
        public async Task RestartAsync(string address, int port, bool usessl, ServerConfig config)
        {
            if (RunnerTask != null)
            {
                await StopAsync();
            }

            m_token    = new CancellationTokenSource();
            Port       = port;
            Config     = config;
            UseSSL     = usessl;
            Address    = address;
            ShouldStop = false;

            if (Wrapper is ISelfListen isl && !isl.UseManagedListen)
            {
                isl.Bind(new IPEndPoint(ParseUtil.ParseIPAddress(address), port), config.SocketBacklog);
                RunnerTask = HttpServer.ListenToSocketAsync(
                    isl.ListenAsync,
                    usessl,
                    m_token.Token,
                    config,
                    (c, e, l) => ((ISelfListen)Wrapper).HandleRequest(c, e, l)
                    );
            }
Example #2
0
            /// <summary>
            /// Restarts this instance
            /// </summary>
            /// <param name="address">The address to listen on</param>
            /// <param name="port">The port to listen on.</param>
            /// <param name="usessl">If set to <c>true</c> use ssl.</param>
            /// <param name="config">The server configuration.</param>
            public async Task RestartAsync(IAppDomainWrappedRunner wrapper, string address, int port, bool usessl, ServerConfig config)
            {
                if (RunnerTask != null)
                {
                    await StopAsync();
                }

                m_token    = new CancellationTokenSource();
                Port       = port;
                Config     = config;
                UseSSL     = usessl;
                Wrapper    = wrapper;
                Address    = address;
                ShouldStop = false;

                RunnerTask = HttpServer.ListenToSocketAsync(
                    new IPEndPoint(ParseUtil.ParseIPAddress(address), port),
                    usessl,
                    m_token.Token,
                    config,
                    m_handler
                    );
            }
Example #3
0
 public static IPAddress ParseIpAddress(string text)
 {
     return(ParseUtil.ParseIPAddress(text));
 }
Example #4
0
        /// <summary>
        /// Creates a server configuration from a CLI config instance
        /// </summary>
        /// <returns>The server configuration.</returns>
        /// <param name="config">The CLI config instance.</param>
        public static ServerConfig ValidateConfig(CLIServerConfiguration config)
        {
            var cfg = CreateServerConfig(config);

            // Expose our configuration to allow modules to call back,
            // beware that these values should never be reported to the client
            // as there might be proxies in front which will make them useless
            // to clients not running on the local machine
            if (config.ListenHttp)
            {
                var parsedip = ParseUtil.ParseIPAddress(config.HttpAddress);
                var ip       = parsedip == IPAddress.Any ? "127.0.0.1" : parsedip.ToString();
                Environment.SetEnvironmentVariable("CEEN_SELF_HTTP_URL", "http://" + ip + ":" + config.HttpPort);
            }
            if (config.ListenHttps)
            {
                var parsedip = ParseUtil.ParseIPAddress(config.HttpsAddress);
                var ip       = parsedip == IPAddress.Any ? "127.0.0.1" : parsedip.ToString();
                Environment.SetEnvironmentVariable("CEEN_SELF_HTTPS_URL", "http://" + ip + ":" + config.HttpsPort);
            }

            if (config.AutoLoadAssemblies)
            {
                // Workaround for unittests not providing EntryAssembly
                var callingasm = Assembly.GetEntryAssembly();
                var callingdir = callingasm == null ? null : Path.GetDirectoryName(callingasm.Location);

                var paths = (config.Assemblypath ?? string.Empty)
                            .Split(new char[] { Path.PathSeparator }, StringSplitOptions.RemoveEmptyEntries)
                            .Union(new[] { config.Basepath, callingdir })
                            .Where(x => !string.IsNullOrWhiteSpace(x) && Directory.Exists(x))
                            .Distinct();

                foreach (var p in paths)
                {
                    foreach (var file in Directory.GetFiles(p, "*.*", SearchOption.TopDirectoryOnly))
                    {
                        if (file.EndsWith(".dll", StringComparison.OrdinalIgnoreCase) || file.EndsWith(".exe", StringComparison.OrdinalIgnoreCase))
                        {
                            try { Assembly.LoadFrom(file); }
                            catch { }
                        }
                    }
                }

                var ceenpath = Path.GetDirectoryName(typeof(CLIServerConfiguration).Assembly.Location);
                if (Directory.Exists(ceenpath))
                {
                    foreach (var dll in Directory.GetFiles(ceenpath, "Ceen.*.dll", SearchOption.TopDirectoryOnly))
                    {
                        try { Assembly.LoadFrom(dll); }
                        catch { }
                    }
                }
            }

            if (config.Loggers != null)
            {
                foreach (var logger in config.Loggers)
                {
                    var inst = CreateInstance(logger.Classname, logger.ConstructorArguments, typeof(ILogger));
                    if (logger.Options != null)
                    {
                        SetProperties(inst, logger.Options);
                    }

                    if (inst is ILoggerWithSetup mse)
                    {
                        mse.AfterConfigure();
                    }

                    cfg.AddLogger((ILogger)inst);
                }
            }

            if (config.Modules != null)
            {
                foreach (var module in config.Modules)
                {
                    object handler;
                    var    moduletype = ResolveType(module.Classname);
                    handler = CreateInstance(moduletype, module.ConstructorArguments, typeof(IModule));

                    if (module.Options != null)
                    {
                        SetProperties(handler, module.Options);
                    }

                    if (handler is IModuleWithSetup mse)
                    {
                        mse.AfterConfigure();
                    }


                    cfg.AddModule((IModule)handler);
                }
            }

            if (config.PostProcessors != null)
            {
                foreach (var postProcessor in config.PostProcessors)
                {
                    var inst = CreateInstance(postProcessor.Classname, postProcessor.ConstructorArguments, typeof(IPostProcessor));
                    if (postProcessor.Options != null)
                    {
                        SetProperties(inst, postProcessor.Options);
                    }

                    if (inst is IPostProcessorWithSetup mse)
                    {
                        mse.AfterConfigure();
                    }

                    cfg.AddPostProcessor((IPostProcessor)inst);
                }
            }


            if (config.Routes != null)
            {
                foreach (var route in config.Routes)
                {
                    // Check if this is a module
                    if (route.RoutePrefix != null)
                    {
                        object handler;
                        var    moduletype = ResolveType(route.Classname);
                        if (typeof(Ceen.Httpd.Handler.FileHandler).IsAssignableFrom(moduletype))
                        {
                            Func <IHttpRequest, string, string> mimehandler = null;
                            if (config.MimeTypes != null && config.MimeTypes.Count > 0)
                            {
                                string default_mimetype;
                                config.MimeTypes.TryGetValue("*", out default_mimetype);
                                if (string.IsNullOrWhiteSpace(default_mimetype))
                                {
                                    default_mimetype = null;
                                }

                                if (config.IgnoreDefaultMimeTypes)
                                {
                                    mimehandler = (req, mappedpath) =>
                                    {
                                        var    ext = Path.GetExtension(mappedpath).ToLowerInvariant();
                                        string mime;
                                        config.MimeTypes.TryGetValue(ext, out mime);
                                        if (default_mimetype != null && string.IsNullOrWhiteSpace(mime))
                                        {
                                            return(default_mimetype);
                                        }

                                        return(mime);
                                    };
                                }
                                else
                                {
                                    mimehandler = (req, mappedpath) =>
                                    {
                                        var    ext = Path.GetExtension(mappedpath).ToLowerInvariant();
                                        string mime;
                                        config.MimeTypes.TryGetValue(ext, out mime);
                                        if (!string.IsNullOrWhiteSpace(mime))
                                        {
                                            return(mime);
                                        }
                                        else if (default_mimetype != null && string.IsNullOrWhiteSpace(mime))
                                        {
                                            return(default_mimetype);
                                        }
                                        else
                                        {
                                            return(Ceen.Httpd.Handler.FileHandler.DefaultMimeTypes(mappedpath));
                                        }
                                    };
                                }
                            }
                            else if (config.IgnoreDefaultMimeTypes)
                            {
                                mimehandler = (req, path) => null;
                            }

                            handler = Activator.CreateInstance(
                                moduletype,
                                ExpandEnvironmentVariables(route.ConstructorArguments.First()),
                                mimehandler
                                );

                            if (config.IndexDocuments.Count != 0)
                            {
                                if (route.Options.ContainsKey(nameof(Handler.FileHandler.IndexDocuments)))
                                {
                                    throw new Exception($"Cannot use both the `Index` option and {nameof(Handler.FileHandler.IndexDocuments)} in the configuration for {moduletype.FullName}");
                                }
                                route.Options[nameof(Handler.FileHandler.IndexDocuments)] = string.Join(", ", config.IndexDocuments.Select(x => $"\"{x}\""));
                            }
                        }
                        else
                        {
                            handler = CreateInstance(moduletype, route.ConstructorArguments, typeof(IHttpModule));
                        }

                        if (route.Options != null)
                        {
                            SetProperties(handler, route.Options);
                        }

                        if (handler is IHttpModuleWithSetup mse)
                        {
                            mse.AfterConfigure();
                        }

                        if (string.IsNullOrWhiteSpace(route.RoutePrefix))
                        {
                            cfg.AddRoute((IHttpModule)handler);
                        }
                        else
                        {
                            cfg.AddRoute(route.RoutePrefix, (IHttpModule)handler);
                        }
                    }
                    else
                    {
                        var assembly = Assembly.Load(route.Assembly);
                        if (assembly == null)
                        {
                            throw new Exception($"Failed to find load assembly {route.Assembly}");
                        }

                        Type defaulttype = null;
                        if (!string.IsNullOrWhiteSpace(route.Classname))
                        {
                            defaulttype = assembly.GetType(route.Classname, false);
                            if (defaulttype == null)
                            {
                                throw new Exception($"Failed to find class {route.Classname} in {route.Assembly}");
                            }
                        }

                        var rt = new Ceen.Mvc.ControllerRouterConfig(defaulttype);
                        if (route.Options != null)
                        {
                            SetProperties(rt, route.Options);
                        }

                        cfg.AddRoute(new Ceen.Mvc.ControllerRouter(rt, assembly));
                    }
                }
            }

            return(cfg);
        }
Example #5
0
        /// <summary>
        /// Starts a runner instance
        /// </summary>
        /// <returns>The awaitable task.</returns>
        /// <param name="domain">The AppDomain to use.</param>
        /// <param name="config">The server configuration.</param>
        /// <param name="usessl">If set to <c>true</c> use ssl.</param>
        /// <param name="port">The port to listen on.</param>
        private async Task StartRunnerAsync(System.AppDomain domain, ServerConfig config, bool usessl, string address, int port)
        {
            var enabled = !string.IsNullOrWhiteSpace(address);

            // Ensure it parses
            ParseUtil.ParseIPAddress(address);

            var prev = m_handlers.Where(x => x.UseSSL == usessl).FirstOrDefault();

            if (enabled)
            {
                var addcrashhandler = true;
                var wrapper         = new AppDomainWrapper(domain);
                wrapper.SetupFromFile(usessl, m_path, config.Storage);
                if (prev == null)
                {
                    prev = new RunnerInstance(wrapper, address, port, usessl, config);
                    m_handlers.Add(prev);
                }
                else
                {
                    if (prev.RunnerTask.IsFaulted || prev.RunnerTask.IsCanceled || prev.RunnerTask.IsCompleted)
                    {
                        var cur = new RunnerInstance(wrapper, address, port, usessl, config);
                        m_handlers.Remove(prev);
                        m_handlers.Add(cur);

                        prev = cur;
                    }
                    else if (prev.Port != port || !string.Equals(prev.Address, address, StringComparison.Ordinal))
                    {
                        // Address or port change, start new listener first
                        var cur = new RunnerInstance(wrapper, address, port, usessl, config);

                        if (!prev.RunnerTask.IsFaulted)
                        {
                            await prev.StopAsync();
                        }

                        m_handlers.Remove(prev);
                        m_handlers.Add(cur);

                        prev = cur;
                    }
                    else if (prev.Config.SocketBacklog != config.SocketBacklog)
                    {
                        await prev.RestartAsync(wrapper, address, port, usessl, config);
                    }
                    else
                    {
                        addcrashhandler = false;   // We already have it
                        prev.Wrapper    = wrapper; // Assign the new wrapper
                    }
                }

                if (addcrashhandler)
                {
                    var dummy = prev.RunnerTask.ContinueWith(x =>
                    {
                        if (!prev.ShouldStop && InstanceCrashed != null)
                        {
                            InstanceCrashed(address, usessl, x.IsFaulted ? x.Exception : new Exception("Unexpected stop"));
                        }
                    });
                }
            }
            else if (prev != null)
            {
                await prev.StopAsync();

                m_handlers.Remove(prev);
            }
        }