예제 #1
0
        private static bool BindCertificate(HttpServerConfiguration <TAccount> config)
        {
            AssemblyPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
            Port         = config.Port.ToString();
            IpAddress    = "0.0.0.0";

            BindingParams bindingParams;

            switch (config.CertificateBindType)
            {
            case BindType.CertificateThumbprint:
                bindingParams = new CertificateThumbprintBindingParams(config.CertificateThumbprint);
                break;

            case BindType.SubjectName:
                bindingParams = new CertificateSubjectnameParams(config.SubjectName, config.AllowGeneratedCertificates);
                break;

            case BindType.FromFile:
                bindingParams = new CertificateFileBindingParams(config.CertificateFilename, null);
                break;

            default:
                return(false);
            }

            var result = Binder.Bind(AssemblyPath, IpAddress, Port, config.CertificateBindType, bindingParams);

            if (result.Status != BindingStatus.Ok)
            {
                LogMessage(LogLevel.Warning, result.Reason ?? "Binding failed");
                return(false);
            }
            return(true);
        }
예제 #2
0
        private static void ConfigureResponseBuilding(HttpServerConfiguration <TAccount> configuration)
        {
            if (configuration.LogBodyReplacePatterns != null)
            {
                ResponseFactory.LogBodyReplacePatterns.AddRange(configuration.LogBodyReplacePatterns);
            }
            if (configuration.LogProhibitedHeaders != null)
            {
                ResponseFactory.LogProhibitedHeaders.AddRange(configuration.LogProhibitedHeaders);
            }

            ResponseFactory.NonSerializableTypes = configuration.NonSerializableTypes;
            ResponseFactory.SetBodyEncoders(configuration.BodyEncoders);
            ResponseFactory.LogResponseBodies     = configuration.LogResponseBodies;
            ResponseFactory.RequestTracingEnabled = configuration.RequestTracingEnabled;
            ResponseFactory.ResponseBodyLogLimit  = configuration.ResponseBodyLogLimit;
            CommonHelper.SetSerializationLimitations(configuration.RequestBodyLogLimit,
                                                     configuration.LogProhibitedQueryParams,
                                                     configuration.LogProhibitedHeaders,
                                                     configuration.BodyEncoders.First(be => be.IsDefault).Encoding);

            if (configuration.ServerName != null)
            {
                ResponseFactory.SetCommonHeaders(new Dictionary <string, string> {
                    { "Server", configuration.ServerName }
                });
            }
        }
예제 #3
0
 private static void PrepareStatistics(HttpServerConfiguration <TAccount> configuration)
 {
     _statisticsController = configuration.StatisticsEnabled
         ? new StatisticsController <TAccount>(new ServerStatistics <TAccount>(
                                                   configuration.CriticalMemoryValue,
                                                   configuration.MemoryAlarmStrategy),
                                               configuration.StatisticsAuthorizer)
         : new StatisticsController <TAccount>(null, null);
 }
예제 #4
0
        private static void StartListenerThread(HttpServerConfiguration <TAccount> configuration)
        {
            var protocolString = configuration.Protocol == Protocol.Http ? "http" : "https";

            ServicePointManager.DefaultConnectionLimit = 1000;

            _requestExecutonBlock = new ActionBlock <HttpListenerContext>(HandleRequestAsync, new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = configuration.MaxConcurrentRequests > 0 ? configuration.MaxConcurrentRequests : -1,
                BoundedCapacity        = configuration.MaxRequestQueue > 0 ? configuration.MaxRequestQueue : -1
            });

            _serviceUnavailabeBlock = new ActionBlock <HttpListenerContext>((Action <HttpListenerContext>)ReportServiceUnavailable, new ExecutionDataflowBlockOptions
            {
                MaxDegreeOfParallelism = 1
            });

            _listener = new HttpListener();
            _listener.Prefixes.Add($"{protocolString}://+:{configuration.Port}/");
            _listener.IgnoreWriteExceptions = true;
            _listener.Start();
            _listenerThread = new Thread(() =>
            {
                LogMessage(LogLevel.Info, "Server listener thread started");
                LogMessage(LogLevel.Info, $"Started listening port {configuration.Port}");
                while (true)
                {
                    try
                    {
                        var context = _listener.GetContext();
                        LogDebug($"Client connected: {context.Request.RemoteEndPoint}");
                        if (!_requestExecutonBlock.Post(context))
                        {
                            _serviceUnavailabeBlock.Post(context);
                        }
                    }
                    catch (ThreadAbortException)
                    {
                        LogMessage(LogLevel.Info, "Server listener thread stopped");
                        break;
                    }
                    catch (Exception ex)
                    {
                        LogException(LogLevel.Error, ex);
                    }
                }
            });

            _listenerThread.Start();
            _serverAddress = $"{protocolString}://{configuration.SubjectName}:{configuration.Port}/";
        }
예제 #5
0
        private static bool StartFileProcessing(HttpServerConfiguration <TAccount> configuration)
        {
            _fileRequestController = new FileRequestController <TAccount>();

            return(_fileRequestController.Start(new FileRequestControllerConfiguration <TAccount>
            {
                FilesEnabled = configuration.FilesEnabled,
                FilesBaseUri = configuration.FilesBaseUri,
                ExistingFilesPreprocessingFrequency = configuration.ExistingFilesPreprocessingFrequency,
                FaviconPath = configuration.FaviconPath,
                FilesAuthorizer = configuration.FilesAuthorizer,
                FileSections = configuration.FileSections,
                FilesLocation = configuration.FilesLocation,
                FilesNeedAuthorization = configuration.FilesNeedAuthorization,
                FilesPreprocessingEnabled = configuration.FilesPreprocessingEnabled,
                FilesCompressionEnabled = configuration.FilesCompressionEnabled,
                FilesPreprocessorThreads = configuration.FilesPreprocessorThreads
            },
                                                _statisticsController.Statistics));
        }
예제 #6
0
        private static void StartServices(HttpServerConfiguration <TAccount> configuration)
        {
            ServiceUris.AddRange(configuration.GetReservedUris());
            if (ServiceUris.Any())
            {
                LogDebug($"Reserved sections:\n{string.Join("\n", ServiceUris)}");
            }

            ServiceRequestProcessors.Add(_optionsController);
            if (configuration.FilesEnabled)
            {
                ServiceRequestProcessors.Add(_fileRequestController);
            }
            if (configuration.StatisticsEnabled)
            {
                ServiceRequestProcessors.Add(_statisticsController);
            }
            ServiceRequestProcessors.Add(_pingController);
            if (configuration.ConfigurationViewEnabled)
            {
                ServiceRequestProcessors.Add(_configurationController);
            }
            ServiceRequestProcessors.Add(_authentificationController);
        }
예제 #7
0
        public static ServerStartStatus Start(HttpServerConfiguration <TAccount> configuration)
        {
            if (_started)
            {
                LogMessage(LogLevel.Warning, "Server is already running");
                return(ServerStartStatus.AlreadyStarted);
            }
            lock (OperationLock)
            {
                if (_operationInProgress)
                {
                    LogMessage(LogLevel.Info, "Cannot start now, operation in progress");
                    return(ServerStartStatus.AlreadyStarted);
                }
                _operationInProgress = true;
            }
            if (configuration == null || !configuration.IsEnough())
            {
                return(ServerStartStatus.BadParameters);
            }

            DebugLogsEnabled      = configuration.DebugLogsEnabled;
            RequestTracingEnabled = configuration.RequestTracingEnabled;

            try
            {
                PrepareStatistics(configuration);

                _optionsController = new OptionsController <TAccount>(InnerRequestProcessors);
                _pingController    = new PingController();

                _configurationController = new ConfigurationController <TAccount>(configuration);

                Protocol    = configuration.Protocol;
                _authorizer = configuration.Authorizer;
                _authentificationController = new AuthentificationController(configuration.Authentificator);

                ConfigureResponseBuilding(configuration);

                if (configuration.FilesEnabled)
                {
                    if (!StartFileProcessing(configuration))
                    {
                        return(ServerStartStatus.BadParameters);
                    }
                }

                _requestMaxServeTime = configuration.RequestMaxServeTime;

                if (Protocol == Protocol.Https)
                {
                    if (!BindCertificate(configuration))
                    {
                        LogMessage(LogLevel.Warning, "Binding failed");
                        return(ServerStartStatus.BindingError);
                    }
                }

                StartListenerThread(configuration);
                StartServices(configuration);
                _started = true;

                return(ServerStartStatus.Ok);
            }
            catch (SocketException)
            {
                LogMessage(LogLevel.Critical, $"Error binding to port {configuration.Port}. Is it in use?");
                _fileRequestController?.Stop();
                return(ServerStartStatus.BindingError);
            }
            catch (Exception ex)
            {
                LogException(LogLevel.Critical, ex);
                _fileRequestController?.Stop();
                return(ServerStartStatus.UnknownError);
            }
            finally
            {
                lock (OperationLock)
                {
                    _operationInProgress = false;
                }
            }
        }