package Cpanel::Easy::Utils::HttpdConf;

# cpanel - Cpanel/Easy/Utils/HttpdConf.pm         Copyright(c) 2014 cPanel, Inc.
#                                                           All rights Reserved.
# copyright@cpanel.net                                         http://cpanel.net
# This code is subject to the cPanel license. Unauthorized copying is prohibited

use strict;
use warnings;
no warnings qw(redefine);
use Cpanel::AdvConfig                     ();
use Cpanel::HttpUtils                     ();
use Cpanel::FileUtils                     ();
use Cpanel::Config                        ();
use Cpanel::Version                       ();
use File::Copy::Recursive                 ();
use Cpanel::SafeFile                      ();
use RcsRecord                             ();
use Cpanel::SafeRun                       ();
use Cpanel::EditHttpdconf                 ();
use Cpanel::AdvConfig::apache::directives ();

my $reset_statcache    = sub { return; };
my $reset_versioncache = sub { return; };
eval {
    require Cpanel::StatCache;
    if ( Cpanel::StatCache->can('clearcache') ) {
        $reset_statcache = sub { Cpanel::StatCache::clearcache(); };
    }
};
eval {
    require Cpanel::HttpUtils::Version;
    if ( Cpanel::HttpUtils::Version->can('clear_cache') ) {
        $reset_versioncache = sub { Cpanel::HttpUtils::Version::clear_cache(); };
    }
};

# Tests to see if we're upgrading from 2.2 to 2.4
# Relies on version of currently running Apache
sub is_upgrade_22_to_24 {
    my $self         = shift;
    my $wanted_httpd = shift;

    return undef if not $wanted_httpd;

    my $current_httpd = $self->_get_current_apache_version_key();

    if ( $current_httpd eq q{2_2} && $wanted_httpd eq q{2_4} ) {
        return 1;
    }
    return undef;
}

# Tests to see if we're downgrading from 2.4 to 2.2
# Relies on version of currently running Apache
sub is_downgrade_24_to_22 {
    my $self         = shift;
    my $wanted_httpd = shift;

    return undef if not $wanted_httpd;

    my $current_httpd = $self->_get_current_apache_version_key();
    if ( $current_httpd eq q{2_4} && $wanted_httpd eq q{2_2} ) {
        return 1;
    }
    return undef;
}

sub pre_build_config_setup {
    my ($self) = @_;
    return ( 1, 'ok' ) if $self->get_param('makecpphp');

    $self->add_non_apache_abspath_to_backup('');
    $self->add_non_apache_abspath_to_backup('');
    $self->add_non_apache_abspath_to_backup('');
    my $local_template_found = 0;
    for my $abspath (
        qw(
        /var/cpanel/conf/apache/main
        /var/cpanel/templates/apache1/main.local
        /var/cpanel/templates/apache2/main.local
        /var/cpanel/templates/apache1/main.default
        /var/cpanel/templates/apache2/main.default
        /var/cpanel/templates/apache1/vhost.local
        /var/cpanel/templates/apache2/vhost.local
        /var/cpanel/templates/apache1/vhost.default
        /var/cpanel/templates/apache2/vhost.default
        /var/cpanel/templates/apache1/ssl_vhost.local
        /var/cpanel/templates/apache2/ssl_vhost.local
        /var/cpanel/templates/apache1/ssl_vhost.default
        /var/cpanel/templates/apache2/ssl_vhost.default
        /usr/local/apache/conf/php.conf
        /usr/local/apache/conf/php.conf.cache
        )
      ) {

        if ( -e $abspath && $abspath =~ m{\.local$} ) {
            $self->print_alert_color( 'blue', q{Local template detected: [_1]}, $abspath );
            $local_template_found = 1;
        }

        $self->add_non_apache_abspath_to_backup($abspath);
    }
    if ( $local_template_found && !$self->{'_'}{'prefs'}{'move_broken_local_templates'} ) {
        $self->print_alert_color(
            'blue',
            qq{\nIf there are issues with your local templates you might be interested in setting the '[_1]' preference.\n},
            $self->{'prefs_details'}{'move_broken_local_templates'}{'name'},
        );
    }
    my @rc = $self->run_system_cmd_returnable( ['/usr/local/cpanel/bin/userdata_update'] );
    return @rc if !$rc[0];

    if ( -e $self->_get_main_httpd_conf() && -e $self->_get_main_httpd_bin() ) {
        return $self->run_system_cmd_returnable( [ '/usr/local/cpanel/bin/apache_conf_distiller', '--update' ] );
    }

    return ( 1, 'Ok' );
}

sub _get_httpd_version {
    shift;
    $reset_statcache->();
    return Cpanel::HttpUtils::get_httpd_version();
}

sub _get_current_apache_version_key {
    shift;
    $reset_statcache->();
    $reset_versioncache->();
    return Cpanel::HttpUtils::get_current_apache_version_key();
}

sub _httpd_is_running {
    shift;
    $reset_statcache->();
    return Cpanel::HttpUtils::httpd_is_running();
}

# for use in _post_restart_httpd_tests() tests:
sub get_localhost_uri {
    my ( $self, $uri, $dohttps, $alt_host, $alt_port ) = @_;

    my $host = $alt_host ? $alt_host : 'localhost';

    if ($dohttps) {
        my $port = defined $alt_port && int($alt_port) ? int($alt_port) : 443;
        require Net::SSLeay;
        $uri = "/$uri" if $uri !~ m{ \A [/] }xms;

        my ( $page, $response, %headers );
        eval {
            my $alarm = alarm(15);
            ( $page, $response, %headers ) = Net::SSLeay::get_https( $host, $port, $uri );
            alarm $alarm;
        };

        return wantarray ? ( $page, $response, \%headers ) : $page;
    }
    else {
        my $port = 80;
        if ( defined $alt_port && int($alt_port) ) {
            $port = int($alt_port);
        }
        elsif ( defined( $self->{'main_httpd_test_port'} ) ) {
            $port = $self->{'main_httpd_test_port'};
        }
        else {
            my $cpconf = Cpanel::Config::loadcpconf();
            if ( defined $cpconf->{'apache_port'} ) {
                my ($tmp_port) = reverse split /:/, $cpconf->{'apache_port'};
                if ( defined($tmp_port) && int($tmp_port) ) {
                    $port = int($tmp_port);
                }
            }
            $self->{'main_httpd_test_port'} = $port;
        }
        require Cpanel::HttpRequest;
        my $req = Cpanel::HttpRequest->new( 'hideOutput' => 1 );
        $uri = "/$uri" if $uri !~ m{ \A [/] }xms;
        return $req->request(
            'host'     => $host,
            'url'      => $uri,
            'protocol' => 1,
            'port'     => $port,
        );
    }
}

sub _post_restart_httpd_tests {
    my ($self) = @_;

## Example of how to add a test from an opt mod step: ##
    #
    #    cp /ea3tests/foo.php -> htdocs/... or error out
    #
    #    push @{ $self->{'_'}{'post_httpd_restart_tests'} }, {
    #        'name'     => 'Name of test',
    #        'onlyonce' => 1, # set to true if you do not want it to run on the erstart after a failure restore, default is false
    #        'command'  => sub {
    #            my ($easy, $is_fatal_boolean_sr) = @_;
    #            my $content = $easy->get_localhost_uri( '/ea3tests/foo.php' );
    #
    #            if ( !$content ) {
    #              return(0, q{no content, better check that});
    #              # could not even get the rest through
    #            }
    #            elsif ( $content =~ $failure_regex ) {
    #                ${ $is_fatal_boolean_sr } = 1;
    #                return(0, q{totally failed, looks like we got source code instead of rendered PHP});
    #            }
    #            elsif ( $content =~ $success_regex ) {
    #                return(1, 'ok');
    #            }
    #            else {
    #                return(0, q{unknown result});
    #            }
    #        },
    #    };

    $self->hook_script('/usr/local/cpanel/scripts/before_httpd_restart_tests');
    local $| = 1;
    if ( exists $self->{'_'}{'post_httpd_restart_tests'} ) {
        if ( ref $self->{'_'}{'post_httpd_restart_tests'} eq 'ARRAY' ) {

            $self->{'ui_obj'}->output( $self, 0, q{-- Begin post apache restart tests --} );
            my $idx          = 0;
            my $tests_failed = 0;

            my $config = Cpanel::Config::loadcpconf();
            if (   ( exists $config->{'apache_port'} && $config->{'apache_port'} && $config->{'apache_port'} !~ m{^\d+$} && $config->{'apache_port'} !~ m{^0\.0\.0\.0\:\d+$} )
                || ( exists $config->{'apache_ssl_port'} && $config->{'apache_ssl_port'} && $config->{'apache_ssl_port'} !~ m{^\d+$} && $config->{'apache_ssl_port'} !~ m{^0\.0\.0\.0\:\d+$} ) ) {
                $self->print_alert_color(
                    'red',
                    q{'Skipping rest of tests: [_1]'},
                    $self->maketext(q{Tweak setting 'The port on which Apache listens' specifies a specific IP and prevents Apache from listening on all other IPs.}),
                );
                @{ $self->{'_'}{'post_httpd_restart_tests'} } = ();
            }

          TEST:
            for my $test ( @{ $self->{'_'}{'post_httpd_restart_tests'} } ) {
                $self->{'_'}{'post_httpd_restart_tests run'}{$idx}++;
                $idx++;

                if ( $test->{'onlyonce'} ) {
                    if ( exists $self->{'_'}{'post_httpd_restart_tests run'} && $self->{'_'}{'post_httpd_restart_tests run'}{$idx} > 1 ) {
                        next TEST;
                    }
                }

                $self->{'ui_obj'}->output( $self, 1, q{-- Begin test '[_1]' --}, $test->{'name'} );
                my $is_fatal = 0;
                my ( $rc, @msg ) = $test->{'command'}->( $self, \$is_fatal );

                if ($rc) {
                    $msg[0] eq 'skip' ? $self->print_alert(q{Test skipped ok}) : $self->print_alert(q{Test passed ok});
                }
                else {
                    $tests_failed = 1;
                    $self->print_alert(@msg);

                    $self->add_error_detail( '_post_restart_httpd_tests()', $test->{'name'}, $rc, @msg, );

                    if ($is_fatal) {
                        if ( $self->{'_'}{'prefs'}{'do_not_revert_on_test_failure'} ) {
                            $self->print_alert_color( 'yellow', q{Making fatal test not fatal as per 'do_not_revert_on_test_failure' flag.} );
                            next TEST;
                        }
                        else {
                            $self->{'_'}{'restore_backup'}++;
                            last TEST;
                        }
                    }
                }

                if ( !$test->{'does_check_httpd'} && $self->{'_'}{'prefs'}{'check_httpd_after_each_test'} ) {
                    if ( [ sort $self->{'pid_obj'}->get_pidof('/usr/local/apache/bin/httpd') ]->[0] ne $self->{'_'}{'post_httpd_restart_test_info'}{'pid'} ) {
                        $self->print_alert_color( 'red', q{No '[_1]' process found. Please check that '[_2]' is running.}, 'httpd', 'Apache' );
                        @{ $self->{'_'}{'post_httpd_restart_tests'} } = ();    # remove rest of tests
                        return ( 0, 'Skipping rest of tests: [_1]', 'httpd not running' );
                    }
                    else {
                        $self->print_alert( q{Post check of '[_1]' process Ok}, 'httpd' );
                    }
                }

                $self->{'ui_obj'}->output( $self, 1, q{-- End test '[_1]' --}, $test->{'name'} );
            }

            # if first test fails then $self->{'_'}{'post_httpd_restart_test_info'}{'pid'} will be false and this message already output
            if ( @{ $self->{'_'}{'post_httpd_restart_tests'} } && $self->{'_'}{'post_httpd_restart_test_info'}{'pid'} ) {
                if ( [ sort $self->{'pid_obj'}->get_pidof('/usr/local/apache/bin/httpd') ]->[0] ne $self->{'_'}{'post_httpd_restart_test_info'}{'pid'} ) {
                    $self->print_alert_color( 'red', q{No '[_1]' process found. Please check that '[_2]' is running.}, 'httpd', 'Apache' );
                }
                else {
                    $self->print_alert( q{Post check of '[_1]' process Ok}, 'httpd' );
                }
            }

            $self->{'ui_obj'}->output( $self, 0, q{-- End post apache restart tests --} );
            $self->print_to_log_and_screen("\n");
            if ($tests_failed) {
                my $report_only = 1;
                for my $log (qw(/usr/local/apache/logs/error_log /usr/local/apache/logs/suexec_log)) {
                    if ( !-f $log ) {
                        if ( $log eq '/usr/local/apache/logs/error_log' ) {
                            $self->print_alert( q{'[_1]' does not exist.}, $log );
                        }
                        next;
                    }
                    $self->tail_last_lines_of( $log, 20, $report_only );
                }
            }
        }
    }
    $self->hook_script('/usr/local/cpanel/scripts/after_httpd_restart_tests');
}

sub _convert_acceptmutex_to_mutex_directive {
    my ( $self, $apache_conf ) = @_;

    $apache_conf = $self->_get_main_httpd_conf() unless ($apache_conf);
    return if ( !-e $apache_conf );

    if ( !$self->{'trying_previous_httpd_conf'} && $self->{'new_httpd_vers'} ge '2_4' ) {
        my $conf_backup = $self->{'_'}{'httpd.conf-make_install_backup'};
        my @directives  = $self->_get_lines_by_directive_name_in_conf(
            $conf_backup,
            'AcceptMutex',
        );

        if ( scalar @directives <= 0 ) {

            # if there is no AcceptMutex directive, add 'AcceptMutex default' by default.
            push @directives, "AcceptMutex default\n";
        }

        my $add_item = 0;
        my @directive_set;
        foreach my $mpm_type ( 'prefork.c', 'worker.c', 'itk.c' ) {
            push @directive_set, "<IfModule $mpm_type>\n";
            my $directive_value;
            foreach my $line (@directives) {
                if ( $line =~ $Cpanel::AdvConfig::apache::directives::directive_match ) {
                    my $directive       = lc $1;
                    my $directive_value = $2;
                    chomp $directive_value;
                    if ( my @values = $directive_value =~ m/^$Cpanel::AdvConfig::apache::directives::items{$directive}{'value'}$/ ) {
                        my $value         = lc( shift @values );
                        my $mutex_dirname = 'Mutex';
                        my $mutex_name    = 'mpm-accept';
                        my $mechanism;
                        if ( $value eq 'fcntl' || $value eq 'flock' || $value eq 'file' ) {
                            $mechanism = "$value:/usr/local/apache/logs";
                        }
                        else {
                            $mechanism = $value;
                        }
                        my $format_dir = sprintf( "%s %s %s\n", $mutex_dirname, $mechanism, $mutex_name );
                        push @directive_set, $format_dir;
                        $add_item = 1;
                    }
                }
            }
            push @directive_set, "</IfModule>\n";
        }

        if ($add_item) {
            $self->_add_lines_after_directive_name_to_conf(
                $apache_conf,
                '',
                @directive_set
            );
        }
    }
    return 1;
}

sub _get_lines_by_directive_name_in_conf {
    my ( $self, $file, $directive_name ) = @_;
    $file = $self->_get_main_httpd_conf() unless ($file);

    return if ( !-e $file );
    return if ( length($directive_name) <= 0 );

    my @directive_lines;
    my $rc;
    $rc = Cpanel::SafeFile::safe_readwrite(
        $file,
        sub {
            my ( $rw_fh, $safe_replace_content_coderef ) = @_;
            my $lines = '';
            while ( my $line = <$rw_fh> ) {
                $lines = $lines . $line;
                next if ( $line =~ m{\\$} );

                $lines =~ s{[\\][\n]}{}g;
                if ( $lines =~ m{^\s*$directive_name\s+}i ) {
                    push @directive_lines, $lines;
                }
                $lines = '';
            }
        },
    );

    return @directive_lines;
}

sub _add_lines_after_directive_name_to_conf {
    my ( $self, $file, $directive_name, @dir_lines ) = @_;
    $file = $self->_get_main_httpd_conf() unless ($file);

    return if ( !-e $file );
    return if ( scalar @dir_lines <= 0 );

    my @directive_lines;
    my $check_directive = 0;
    $check_directive = 1 if ( length($directive_name) > 0 );
    my $rc;
    $rc = Cpanel::SafeFile::safe_readwrite(
        $file,
        sub {
            my ( $rw_fh, $safe_replace_content_coderef ) = @_;

            my @new_content;
            my $messages;
            my $lines = '';
            while ( my $line = <$rw_fh> ) {
                $lines = $lines . $line;
                next if ( $line =~ m{\\$} );

                $lines =~ s{[\\][\n]}{}g;
                if ( $check_directive && $lines =~ m{^\s*$directive_name\s+}i ) {
                    push @new_content, $lines;
                    push @new_content, @dir_lines;
                    $lines = '';
                    next;
                }
                push @new_content, $lines;
                $lines = '';
            }
            push @new_content, @dir_lines if ( !$check_directive );

            $messages = sprintf( "%s", join( '', @dir_lines ) );
            return ($messages) if $safe_replace_content_coderef->( $rw_fh, \@new_content );
        },
    );

    if ($rc) {
        $self->print_to_log_and_screen("Added to httpd.conf\n $rc") if ($rc);
        return 1;
    }
    return;
}

sub _get_badconf_whm_url {
    my ($self) = @_;
}

sub _get_main_httpd_confdir {
    my $self  = shift;
    my $apdir = $self->{'base_dir'};
    return sprintf( '%s/conf', $apdir );
}

sub _get_main_httpd_bindir {
    my $self  = shift;
    my $apdir = $self->{'base_dir'};
    return sprintf( '%s/bin', $apdir );
}

sub _get_main_httpd_moddir {
    my $self = shift;
    return sprintf( '%s/%s', $self->{'base_dir'}, 'modules' );
}

sub _get_main_httpd_conf {
    my $self = shift;
    return sprintf( '%s/httpd.conf', $self->_get_main_httpd_confdir() );
}

sub _get_main_httpd_bin {
    my $self = shift;
    return sprintf( '%s/httpd', $self->_get_main_httpd_bindir() );
    return '/usr/local/apache/bin/httpd';
}

sub _get_main_apxs_bin {
    my $self = shift;
    return sprintf( '%s/apxs', $self->_get_main_httpd_bindir() );
}

sub _check_config {
    my ( $self, $level ) = @_;
    return Cpanel::AdvConfig::check_config(
        {
            'service' => 'apache',
            'level'   => $level,
        }
    );
}

sub _generate_config {
    my ( $self, $level ) = @_;
    my $now = time;

    # SSL configuration items handled via template
    my $apache_conf = $self->_get_main_httpd_conf();
    if ( defined $self->{'_'}{'httpd.conf-template_generated'} && -e $self->{'_'}{'httpd.conf-template_generated'} ) {
        unlink $self->{'_'}{'httpd.conf-template_generated'};
    }
    $self->{'_'}{'httpd.conf-template_generated'} = $apache_conf . '.' . $now;

    my @stripped = $self->strip_from_httpconf( '<IfModule mod_ssl.c>', '<IfDefine SSL>', '<IfModule ssl_module>', 'Listen' );
    return @stripped if !$stripped[0];

    # ErrorDocument settings needs .shtml
    Cpanel::EditHttpdconf::edit_httpdconf(
        sub {
            my ( $rw_fh, $safe_replace_content_coderef ) = @_;
            my $edited = 0;
            my $in_htdocs_directory;
            my $did_options = 0;
            my @new_content;

            while ( my $line = readline($rw_fh) ) {

                if ( $line =~ m{\A \s* [<] Directory \s+ \S? /usr/local/apache/htdocs [/]? \S? \s* [>] }ixms ) {
                    $in_htdocs_directory = 1;
                }
                elsif ($in_htdocs_directory) {
                    if ( $line =~ m{ \A \s* [<] [/] Directory [>] \s* \z}ixms ) {
                        if ( !$did_options ) {
                            push @new_content, "    Options Includes Indexes FollowSymLinks MultiViews\n";
                            $edited = 1;
                        }

                        $did_options         = 0;
                        $in_htdocs_directory = 0;
                    }
                    elsif ( $line =~ m{ \A (\s*) Options \s+ (.*) \z }ixms ) {
                        my $indent = $1;
                        my $value  = $2;
                        my $good   = 0;
                        $did_options = 1;

                        for my $ent ( split( /\s+/, $value ) ) {
                            $ent =~ s{^(?:\+|\-)}{}g;
                            if ( $ent =~ m{^All$}i || $ent =~ m{^Includes$}i || $ent =~ m{^IncludesNoExec$}i ) {
                                $good++;
                            }
                        }

                        if ( !$good ) {
                            $line   = $indent . 'Options Includes ' . $value;
                            $edited = 1;
                        }
                    }
                }
                push @new_content, $line;
            }

            if ( !defined $in_htdocs_directory ) {
                push @new_content, <<'END_DEFAULT';
<Directory "/usr/local/apache/htdocs">
    Options Includes Indexes FollowSymLinks MultiViews
    AllowOverride None
    Order allow,deny
    Allow from all
</Directory>
END_DEFAULT
                $edited = 1;
            }

            if ($edited) {
                return ("Edited by $0") if $safe_replace_content_coderef->( $rw_fh, \@new_content );
            }

            return;
        },
    );

    # Set Allow, Deny to cPanel defaults
    my @rv = $self->_check_slashdir_directives();
    return @rv if !$rv[0];

    # Preemptive distillation, to ensure that templates for the
    # (possibly new) Apache version are available when cPanel goes to
    # add aliases in the next step.  Trying to enclose this within
    # checks to the is_upgrade_22_to_24 and is_downgrade_24_to_22
    # functions fails because the "old" version that the functions are
    # extracting is equal to the new version that's being built.
    my @preemptive = $self->run_system_cmd_returnable( [ '/usr/local/cpanel/bin/apache_conf_distiller', '--update', '--main', '--reset' ] );
    return @preemptive if !$preemptive[0];

    # Add cPanel Aliases
    if ( -x '/usr/local/cpanel/scripts/check_cpanel_apache_aliases' ) {
        my @cpanel_aliases = $self->run_system_cmd_returnable( [ '/usr/local/cpanel/scripts/check_cpanel_apache_aliases', '--no-restart' ] );
        return @cpanel_aliases if !$cpanel_aliases[0];
    }

    # Remove all PHP configuration other than Include
    @rv = $self->strip_php_directives();
    return @rv if !$rv[0];

    @rv = $self->setup_php_include();
    return @rv if !$rv[0];

    # Case#59540: mod_qos requires MaxClients in httpd.conf
    @rv = $self->_check_for_mod_qos();
    return @rv if !$rv[0];

    # Case 62475: disabled sslcompression for older versions of apache
    @rv = $self->_strip_sslcompression_from_httpd();
    return @rv if !$rv[0];

    if ( -e '/usr/local/cpanel/bin/update_php_mime_types' && !-e '/var/cpanel/easy_skip_update_php_mime_types' ) {
        my $cpconf = Cpanel::Config::loadcpconf();
        my $recurse = exists $cpconf->{'htaccess_check_recurse'} ? int( $cpconf->{'htaccess_check_recurse'} ) : 2;
        $recurse = 2 unless ( $recurse <= 100 && $recurse >= 0 );
        @rv = $self->run_system_cmd_returnable( [ '/usr/local/cpanel/bin/update_php_mime_types --recurse=' . $recurse ] );
    }

    # If EA upgrades from earlier apache version to apache 2.4,
    # ‘AcceptMutex’ directive needs to be transferred to Mutex mpm-accept directive enclosed with ifmodule directive.
    if ( !$self->{'trying_previous_httpd_conf'} && $self->{'new_httpd_vers'} ge '2_4' ) {
        $self->_convert_acceptmutex_to_mutex_directive($apache_conf);
    }

    # Parse new config and register
    my @distiller = $self->run_system_cmd_returnable( [ '/usr/local/cpanel/bin/apache_conf_distiller', '--update', '--main', '--reset' ] );
    return @distiller if !$distiller[0];

    if ( !-e '/var/cpanel/conf/apache/success' || ( stat(_) )[9] < ( time - 10 ) ) {
        return ( 0, q{Failed to distill '[_1]'}, $apache_conf );
    }

    # Generate new full configuration
    my ( $returnval, $message ) = Cpanel::AdvConfig::generate_config_file( { 'service' => 'apache', '_target_conf_file' => $apache_conf . '.' . $now } );    # Force doesn't do anything yet
    if ( !$returnval ) {
        unlink $apache_conf . '.' . $now;

        my $conf = Cpanel::AdvConfig::apache::get_config();
        if ( !exists $conf->{'_use_target_version'} || !defined $conf->{'_use_target_version'} ) {
            $conf->{'_use_target_version'} = '';
        }

        if ( Cpanel::Template->can('get_template_file') ) {
            my $local_check = Cpanel::Template::get_template_file( 'apache' . $conf->{'_use_target_version'} );
            if ( $local_check =~ m{local$} ) {
                if ( $Cpanel::Template::VERSION > 1.4 && $Cpanel::AdvConfig::VERSION > 1.2 ) {
                    $self->print_alert_color( 'blue', q{Failed to build '[_1]' from local template, retrying with default template: [_2]}, $apache_conf, $message );

                    if ( $self->{'_'}{'prefs'}{'move_broken_local_templates'} ) {
                        $self->print_alert_color( 'blue', q{Moving '[_1]' to '[_2]' as per your preferences}, $local_check, "$local_check.broken" );
                        Cpanel::FileUtils::safemv( $local_check, "$local_check.broken" )
                          or $self->print_alert_color( 'red', q{'[_1]' did not return true}, "safecopy($local_check, $local_check.broken)" );
                    }

                    ( $returnval, $message ) = Cpanel::AdvConfig::generate_config_file( { 'skip_local' => 1, 'service' => 'apache', '_target_conf_file' => $apache_conf . '.' . $now } );    # Force doesn't do anything yet
                    if ( !$returnval ) {
                        unlink $apache_conf . '.' . $now;
                        return ( 0, q{Failed to build '[_1]': [_2]}, $apache_conf, $message );
                    }
                }
                else {
                    $self->print_alert_color( 'blue', q{'local' template in use, try moving '[_1]' to '[_1].broken' }, $local_check );
                }
            }
        }

        if ( !$returnval ) {
            return ( 0, q{Failed to build '[_1]': [_2]}, $apache_conf, $message );
        }
    }
    chmod 0600, $apache_conf . '.' . $now;
    chmod 0600, $apache_conf;
    chmod 0400, $apache_conf . ',v' if ( -e $apache_conf . ',v' );

    if ( $self->get_param('simulate-failed-confgen') ) {
        return ( 0, q{Simulating configuration generation failure as per 'simulate-failed-confgen' flag} );
    }

    # Check configuration syntax
    ( $returnval, $message ) = Cpanel::AdvConfig::apache::check_syntax( $apache_conf . '.' . $now );
    if ( !$returnval ) {

        my $conf = Cpanel::AdvConfig::apache::get_config();
        if ( !exists $conf->{'_use_target_version'} || !defined $conf->{'_use_target_version'} ) {
            $conf->{'_use_target_version'} = '';
        }

        if ( Cpanel::Template->can('get_template_file') ) {
            my $local_check = Cpanel::Template::get_template_file( 'apache' . $conf->{'_use_target_version'} );
            if ( $local_check =~ m{local$} ) {
                if ( $Cpanel::Template::VERSION > 1.4 && $Cpanel::AdvConfig::VERSION > 1.2 ) {
                    $self->print_alert_color(
                        'blue',       q{Failed to generate a syntactically correct Apache configuration ([_1]) from local template, retrying with default template: [_2]},
                        $apache_conf, $message
                    );

                    if ( $self->{'_'}{'prefs'}{'move_broken_local_templates'} ) {
                        $self->print_alert_color( 'blue', q{Moving '[_1]' to '[_2]' as per your preferences}, $local_check, "$local_check.broken" );
                        Cpanel::FileUtils::safemv( $local_check, "$local_check.broken" )
                          or $self->print_alert_color( 'red', q{'[_1]' did not return true}, "safecopy($local_check, $local_check.broken)" );
                    }

                    my ( $returnval_c, $message_c ) = Cpanel::AdvConfig::generate_config_file( { 'skip_local' => 1, 'service' => 'apache', '_target_conf_file' => $apache_conf . '.' . $now } );    # Force doesn't do anything yet
                    if ( !$returnval_c ) {
                        unlink $apache_conf . '.' . $now;
                        return ( 0, q{Failed to build '[_1]': [_2]}, $apache_conf, $message_c );
                    }
                    else {
                        chmod 0600, $apache_conf . '.' . $now;
                        chmod 0600, $apache_conf;
                        chmod 0400, $apache_conf . ',v' if ( -e $apache_conf . ',v' );

                        ( $returnval, $message ) = Cpanel::AdvConfig::apache::check_syntax( $apache_conf . '.' . $now );
                        if ( !$returnval ) {
                            return ( 0, "Failed to generate a syntactically correct Apache configuration ([_1]):\n[_2]", $apache_conf . '.' . $now, $message );
                        }
                    }
                }
                else {
                    $self->print_alert_color( 'blue', q{'local' template in use, try moving '[_1]' to '[_1].broken' }, $local_check );
                }
            }
        }

        if ( !$returnval ) {
            return ( 0, "Failed to generate a syntactically correct Apache configuration ([_1]):\n[_2]", $apache_conf . '.' . $now, $message );
        }
    }

    unlink $apache_conf . '.easyapache_save';
    rename $apache_conf, $apache_conf . '.easyapache_save';
    rename $apache_conf . '.' . $now, $apache_conf;
    unlink $apache_conf . '.datastore';    # Just in case

    RcsRecord::rcsrecord( $apache_conf, 'End build_apache_conf' );

    $self->run_commands('post-confgen-pre-restart-commands');

    return ( 1, 'succeeded' );
}

# Ensure <Directory "/"> has a default allow style policy, as opposed to the
# default default deny.
sub _check_slashdir_directives {

    # Adapted from the old /usr/local/cpanel/scripts/checkallowoverride script
    my ( $self, @files ) = @_;

    if ( !@files ) {
        @files = ( $self->_get_main_httpd_conf() );
        push @files, $self->{'_'}{'httpd.conf-make_install_created'} if ( -e $self->{'_'}{'httpd.conf-make_install_created'} );
    }

    my @warnings;
    for my $httpdconf (@files) {
        my $needs_update = 0;

        my $httpd_fh = IO::Handle->new();
        my $hlock = Cpanel::SafeFile::safeopen( $httpd_fh, '<', $httpdconf );
        if ( !$hlock ) {
            push @warnings, "Could not read from $httpdconf";
            next;
        }

        my $inslashdir = 0;
        while ( my $line = <$httpd_fh> ) {
            if ( $line =~ m{^\s*<Directory\s+"?/"?\s*>}i ) {
                $inslashdir = 1;
            }
            elsif ( $line =~ m{^\s*</Directory}i ) {
                $inslashdir = 0;
            }
            elsif ( $inslashdir && $line =~ m/^\s*(?:order|deny|allowoverride\s+none|options\s+(?:none|follow)|require\s+all\s+denied)/i ) {
                $needs_update = 1;
                last;
            }
        }
        Cpanel::SafeFile::safeclose( $httpd_fh, $hlock );

        next if !$needs_update;

        RcsRecord::rcsrecord( $httpdconf, 'check_slashdir_directives BEGIN' );

        $hlock = Cpanel::SafeFile::safeopen( $httpd_fh, '+<', $httpdconf );
        if ( !$hlock ) {
            push @warnings, "Could not edit $httpdconf";
            next;
        }

        $inslashdir = 0;
        my @CFILE;

        # Apache 2.4 default conf doesn't have an 'Options' directive.  We
        # need to add this for backwards-compatibility
        my $found_options = 0;
        while ( my $line = <$httpd_fh> ) {
            if ( $line =~ m{^\s*<Directory\s+"?/"?>}i ) {
                $inslashdir = 1;
            }
            elsif ( $line =~ m{^\s*</Directory}i ) {
                push @CFILE, "    Options All\n" unless $found_options;
                $inslashdir = 0;
            }
            elsif ($inslashdir) {
                if ( $line =~ m/^(\s*)AllowOverride\s+none\b/i ) {
                    push @CFILE, $1 . "AllowOverride All\n";
                    next;
                }
                elsif ( $line =~ m/^(\s*)Options\s+(?:none|follow)/i ) {
                    push @CFILE, $1 . "Options All\n";
                    $found_options = 1;
                    next;
                }
                elsif ( $line =~ m/^\s*(?:Order|Deny|Require)\b/i ) {

                    # Remove this line
                    next;
                }
            }

            push @CFILE, $line;
        }

        seek( $httpd_fh, 0, 0 );
        print {$httpd_fh} @CFILE;
        truncate( $httpd_fh, tell($httpd_fh) );

        Cpanel::SafeFile::safeclose( $httpd_fh, $hlock );

        RcsRecord::rcsrecord( $httpdconf, 'check_slashdir_directives END' );
    }

    if (@warnings) {
        return wantarray ? ( 0, @warnings ) : 0;
    }

    return 1;
}

sub _httpd_conf_syntax_check_cmd {
    my ( $self, $file ) = @_;
    $file = $self->_get_main_httpd_conf() if !$file || !-e $file;

    return ( 0, q{'[_1]' does not exist}, $file ) if !-e $file;

    no warnings;

    open( OLDOUT_B, '>&STDOUT' ) or die "Can't dup STDOUT: $!";
    open( OLDERR_B, '>&STDERR' ) or die "Can't dup STDERR: $!";

    open( STDOUT, '>/dev/null' ) or die "Cant send STDOUT to /dev/null: $!";
    open( STDERR, '>/dev/null' ) or die "Cant send STDERR to /dev/null: $!";

    my @rc = $self->run_system_cmd_returnable( [ $self->_get_main_httpd_bin(), qw(-t -f), $file ] );

    open( STDOUT, '>&OLDOUT_B' ) or die "Can't restore OLDOUT_B: $!";
    open( STDERR, '>&OLDERR_B' ) or die "Can't restore OLDERR_B: $!";

    return @rc if !$rc[0];
    return ( 0, q{Syntax check failed on '[_1]'}, $file ) if $self->{'last_run_system_cmd'} !~ m{Syntax OK};
    return @rc;
}

sub restart_httpd {
    my ( $self, $settings ) = @_;
    $settings = {} if !defined $settings || ref $settings ne 'HASH';

    $self->print_alert( q{Restarting '[_1]' ...}, 'httpd' );

    # case 4423:
    if ( $self->{'ui_obj'}->can('httpd_whm_proxy_helper') ) {
        if ( $self->{'ui_obj'}->httpd_whm_proxy_helper( $self, { 'action' => 'return_is_proxy_boolean' } ) ) {
            $self->{'ui_obj'}->httpd_whm_proxy_helper( $self, { 'action' => 'print_message' } );
        }
    }

    $self->set_infinite_memory_limits();    # safe to remove once safeparestart() is really safe
    my ( $status, $message ) = Cpanel::HttpUtils::safeaprestart(1);
    if ( !$status ) {
        $self->print_alert('Failed to restart Apache.');
        $self->print_alert($message) if $message;

        if ( $settings->{'on_failure_add_error_detail'} ) {
            my $rc = exists $settings->{'error_detail_rc'} ? int( $settings->{'error_detail_rc'} ) : $status;
            my ( $pkg, $mth ) = ref $settings->{'caller_ar'} eq 'ARRAY' ? ( @{ $settings->{'caller_ar'} } )[ 0, 3 ] : ( caller(1) )[ 0, 3 ];
            $self->add_error_detail( $pkg, $mth, $rc, "safeaprestart() returned false: $message" );
        }
    }
    else {
        $self->print_alert( q{'[_1]' restart complete.}, 'httpd' );
    }

    return $status;
}

sub post_httpd_conf_handler {
    my ($self) = @_;
    return if $self->get_param('makecpphp');

    # add_error_detail() if problems

    $self->_rebuild_globalcache();

    my ( $rc, @text ) = ( 0, q{Could not generate valid configuration} );
    $self->print_alert(q{Resetting Apache configuration to default.}) if !$self->{'trying_previous_httpd_conf'};
    ( $rc, @text ) = $self->_generate_config();
    if ( !$rc && $self->{'trying_previous_httpd_conf'} ) {
        my $conf     = $self->_get_main_httpd_conf();
        my $alt_conf = $self->{'_'}{'httpd.conf-make_install_created'};
        if ( -e $alt_conf ) {
            $self->print_alert(q{Failed to utilize existing Apache configuration file. Resetting Apache configuration to default.});

            unlink $conf;
            File::Copy::Recursive::fcopy( $alt_conf, $conf );
            ( $rc, @text ) = $self->_generate_config();
        }
    }

    if ($rc) {
        if ( !$self->restart_httpd( { 'on_failure_add_error_detail' => 1 }, 'caller_ar' => [ caller(1) ], 'error_detail_rc' => $rc, ) ) {

            $self->{'ui_obj'}->pstconf_isbad( $self, $rc );    # no @text since its probably 'succeeded' or other positive msg from _generate_config()

            my $std_port = $self->get_std_httpd_port();
            my $ssl_port = $self->get_ssl_httpd_port();
            my $lsof     = Cpanel::SafeRun::findbin( 'lsof', 'path' => [qw( /bin /sbin /usr/sbin /usr/local/sbin /usr/bin /usr/local/bin )] ) || 'lsof';
            $self->output_system_cmd( [ $lsof, '-n', "-iTCP:$std_port", "-iTCP:$ssl_port" ] );    # case 4355, semi-tmp

            my $netstat = Cpanel::SafeRun::findbin( 'netstat', 'path' => [qw( /bin /sbin /usr/sbin /usr/local/sbin /usr/bin /usr/local/bin )] ) || 'netstat';

            # Yes, command as a single string (IE one item array ref) so that the pipe will work
            $self->output_system_cmd( ["$netstat -a -n --tcp | grep LISTEN"] );                   # case 4382
        }
        else {
            $self->_post_restart_httpd_tests();
            Cpanel::FileUtils::touchfile('/var/cpanel/use_apache_conf');
        }
    }
    else {
        $self->{'conf_gen_failed'}++;
        my ( $pkg, $mth ) = ( caller(1) )[ 0, 3 ];
        $self->add_error_detail( $pkg, $mth, $rc, @text );
        $self->{'ui_obj'}->pstconf_isbad( $self, $rc, @text );
    }
}

sub dotso_exists {
    my ( $self, $dotso ) = @_;

    my $apv = $self->_get_current_apache_version_key();
    return if !$apv;
    my $so = sprintf( '%s/%s', $self->_get_main_httpd_moddir(), $dotso );

    return ( -e $so ? 1 : undef );
}

sub ensure_loadmodule_in_httpdconf {
    my ( $self, $name, $dotso ) = @_;
    return ( 0, 'Invalid arguments' ) if $name !~ m{ \A \w+ \z }xms || $dotso !~ m{ \A (?: \w+ [.] )+ so \z }xms;

    my @files = ( $self->_get_main_httpd_conf() );
    push @files, $self->{'_'}{'httpd.conf-make_install_created'} if ( -e $self->{'_'}{'httpd.conf-make_install_created'} );

    my $sodir = $self->_get_main_httpd_moddir();

    foreach my $file (@files) {
        open my $http_conf_fh, '<', $file || return ( 0, q{Could not open '[_1]' for reading: [_2]}, $file, $! );
        my $content = join( '', <$http_conf_fh> );
        close $http_conf_fh;
        unless ( $content =~ s/^\s*#?\s*LoadModule\s+${name}_module\s+(libexec|modules)\/$dotso\s*$/LoadModule ${name}_module $1\/$dotso/im ) {
            $content = "LoadModule ${name}_module $sodir/$dotso\n" . $content;
        }
        open $http_conf_fh, '>', $file || return ( 0, q{Could not open '[_1]' for writing: [_2]}, $file, $! );
        print $http_conf_fh $content;
        close $http_conf_fh;
    }

    return ( 1, 'Ok' );
}

sub strip_from_httpconf {
    my ( $self, @strip ) = @_;

    return ( 0, 'Invalid arguments' ) if @strip == 0;

    my @files = ( $self->_get_main_httpd_conf() );
    push @files, $self->{'_'}{'httpd.conf-make_install_created'} if ( defined $self->{'_'}{'httpd.conf-make_install_created'} && -e $self->{'_'}{'httpd.conf-make_install_created'} );

    foreach my $file (@files) {
        my ( $rc, @text ) = $self->strip_apache_directive( $file, @strip );
        if ( !$rc ) {
            return ( $rc, @text );
        }
    }

    return ( 1, 'ok' );
}

sub strip_apache_directive {
    my ( $self, $file, @directives ) = @_;

    unless ($file) {
        $file = $self->_get_main_httpd_conf();
    }
    if ( !-e $file ) {
        return ( 0, "Could not find $file" );
    }

    my %matching;
    foreach my $directive (@directives) {
        my @parts = split /\s+/, $directive;
        my $match;
        if ( scalar @parts > 1 ) {
            $match = join '\s+', @parts[ 1 .. $#parts ];
        }
        else {
            $match = $directive;
        }
        $matching{ $parts[0] }{$match} = $directive;
    }
    if ( !scalar keys %matching ) {
        return ( 0, "No directives specified" );
    }
    my $start_match = join '|', map { quotemeta } ( keys %matching );

    my $httpc = IO::Handle->new();
    my $hlock = Cpanel::SafeFile::safeopen( $httpc, '+<', $file );
    if ( !$hlock ) {
        return ( 0, "Could not edit $file" );
    }

    my @in_section;
    my $needs_rewrite;
    my @httpdconf;

  LINE:
    while ( my $line = <$httpc> ) {
        if (@in_section) {
            if ( $line =~ m/^\s*<\// && $line =~ m/^\s*<\/$in_section[-1]/ ) {
                pop @in_section;
            }
            elsif ( $line =~ m/^\s*($start_match)\s*/ ) {
                my $directive = $1;
                if ( $directive =~ m/^</ ) {
                    $directive =~ s/^<//;
                    push @in_section, $directive;
                }
            }
            $needs_rewrite = 1;
            next LINE;
        }
        if ( $line =~ m/^\s*($start_match)\s*/ ) {
            my $directive = $1;
            foreach my $match ( keys %{ $matching{$directive} } ) {
                if ( $line =~ m/\s*\Q$match\E/ ) {
                    if ( $directive =~ m/^</ ) {
                        $directive =~ s/^<//;
                        push @in_section, $directive;
                    }
                    $needs_rewrite = 1;
                    next LINE;
                }
            }
        }
        push @httpdconf, $line;
    }

    if ( !$needs_rewrite ) {
        Cpanel::SafeFile::safeclose( $httpc, $hlock );
        return ( 1, 'ok' );
    }

    print "Updating Apache configuration\n";

    seek( $httpc, 0, 0 );
    print $httpc join( '', @httpdconf );
    truncate( $httpc, tell($httpc) );

    Cpanel::SafeFile::safeclose( $httpc, $hlock );

    return ( 1, 'ok' );
}

sub include_directive_handler {
    my ( $self, $setup_hr ) = @_;

    my $new_line = qq/Include "$setup_hr->{'include_path'}"/;

    return ( 0, 'Invalid arguments' )
      if !$setup_hr->{'include_path'}
      || $setup_hr->{'include_path'} =~ m{ \s }xms;

    $setup_hr->{'no_strip'} = $setup_hr->{'no_strip'} ? 1 : 0;

    $self->strip_from_httpconf($new_line);

    my ($file) = reverse split /\//, $setup_hr->{'include_path'};
    return $self->add_after_mod_or_end(
        {
            %{$setup_hr},
            'new_line'  => $new_line . "\n",
            'rcsrecord' => 'added $file Include',
        }
    );
}

sub add_after_mod_or_end {
    my ( $self, $setup_hr ) = @_;

    return ( 0, 'Invalid arguments' )
      if ( ref $setup_hr->{'addmodule'} ne 'Regexp' && $setup_hr->{'addmodule'} !~ m{ \A \w+ \z }xms )
      || ( ref $setup_hr->{'loadmodule'} ne 'Regexp' && $setup_hr->{'loadmodule'} !~ m{ \A \w+ \z }xms )
      || !$setup_hr->{'new_line'};

    $setup_hr->{'rcsrecord'} = '0E0' if !defined $setup_hr->{'rcsrecord'};

    my @files = ( $self->_get_main_httpd_conf() );
    push @files, $self->{'_'}{'httpd.conf-make_install_created'} if ( -e $self->{'_'}{'httpd.conf-make_install_created'} );

    my $rc;
    foreach my $file (@files) {
        $rc = Cpanel::SafeFile::safe_readwrite(
            $file,
            sub {
                my ( $rw_fh, $safe_replace_content_coderef ) = @_;

                # TODO: 'the last matching' logic

                my @httpdconf;
                my $have_addmodule  = 0;
                my $have_loadmodule = 0;

              AM_LINE:
                while ( my $line = <$rw_fh> ) {
                    chomp $line;
                    $line .= "\n";    # FB 127757
                    push @httpdconf, $line;

                    if ( $line =~ m/AddModule\s+mod_$setup_hr->{'addmodule'}/ ) {
                        push @httpdconf, $setup_hr->{'new_line'} if !$have_addmodule;
                        $have_addmodule++;
                    }
                }

                if ( !$have_addmodule ) {
                    @httpdconf = ();
                    seek( $rw_fh, 0, 0 );

                  LM_LINE:
                    while ( my $line = <$rw_fh> ) {
                        chomp $line;
                        $line .= "\n";    # FB 127757
                        push @httpdconf, $line;

                        if ( $line =~ m/LoadModule\s+$setup_hr->{'loadmodule'}/ ) {
                            push @httpdconf, $setup_hr->{'new_line'} if !$have_loadmodule;
                            $have_loadmodule++;
                        }
                    }
                }

                if ( !$have_addmodule && !$have_loadmodule ) {
                    push @httpdconf, $setup_hr->{'new_line'};
                }

                return $setup_hr->{'rcsrecord'} if $safe_replace_content_coderef->( $rw_fh, \@httpdconf );
                return;
            },
        );
        last unless $rc;
    }

    return ( 0, q{'[_1]' did not return true}, 'Cpanel::SafeFile::safe_readwrite' ) if !$rc;
    return ( 1, 'ok' );
}

# If we're preserving the old httpd.conf we need to make certain at least one LoadModule line appears
# in it so that aspx will function correctly.  This will get stripped later when the distill/rebuild process completes.
sub ensure_loadmodule_exists {
    my $self            = shift;
    my $httpd_conf_file = $self->_get_main_httpd_conf();
    return unless ( -e $httpd_conf_file );
    open my $httpd_conf_fh, '+<', $httpd_conf_file || return;
    my @httpd_conf = <$httpd_conf_fh>;
    unless ( grep( /^\s*\#*\s*LoadModule/i, @httpd_conf ) ) {
        unshift @httpd_conf, "\n#LoadModule dummy_module /usr/local/apache/modules/mod_dummy.so\n";
        seek( $httpd_conf_fh, 0, 0 );
        print $httpd_conf_fh @httpd_conf;
        truncate( $httpd_conf_fh, tell($httpd_conf_fh) );
    }
    close $httpd_conf_fh;
}

sub proxydomains_configuration {
    my $self   = shift;
    my $cpconf = Cpanel::Config::loadcpconf();

    # Check if proxydomains have never been configured
    if ( -e '/usr/local/cpanel/scripts/proxydomains' && !-e '/var/cpanel/version/proxydomains' && !-e '/var/cpanel/version/proxydomains2' ) {
        if ( !defined $cpconf->{'proxysubdomains'} && !defined $cpconf->{'proxysubdomainsfornewaccounts'} && !defined $cpconf->{'proxysubdomainsoverride'} ) {
            $self->print_alert('Proxy subdomains have not been configured.  Enabling now.');
            $cpconf->{'proxysubdomains'}               = 1;
            $cpconf->{'proxysubdomainsfornewaccounts'} = 1;
            $cpconf->{'proxysubdomainsoverride'}       = 1;
            Cpanel::Config::savecpconf($cpconf);
            if ( open my $flag_fh, '>', '/var/cpanel/version/proxydomains' ) {
                print $flag_fh time;
                close $flag_fh;
            }
            if ( -e '/usr/local/cpanel/scripts/checkwebdiskproxydomains' && open my $new_flag_fh, '>', '/var/cpanel/version/proxydomains2' ) {
                print $new_flag_fh time;
                close $new_flag_fh;
            }
            $self->print_alert('Adding proxy subdomain DNS records to all accounts.  This may take several minutes.');
            $self->run_system_cmd( [ '/usr/local/cpanel/scripts/proxydomains', 'add' ] );
        }
    }

    # If proxy domains have been configured and are enabled, update for webdisk
    if ( defined $cpconf->{'proxysubdomains'} && $cpconf->{'proxysubdomains'} && -e '/usr/local/cpanel/scripts/checkwebdiskproxydomains' && !-e '/var/cpanel/version/proxydomains2' ) {
        $self->print_alert('Adding webdisk proxy subdomain DNS record to all accounts.  This may take several minutes.');
        $self->run_system_cmd( [ '/usr/local/cpanel/scripts/proxydomains', '--subdomain=webdisk', 'add' ] );
        if ( open my $new_flag_fh, '>', '/var/cpanel/version/proxydomains2' ) {
            print $new_flag_fh time;
            close $new_flag_fh;
        }
    }
    return ( 1, 'Ok' );
}

sub _rebuild_globalcache {
    my $self = shift;
    if ( -x '/usr/local/cpanel/bin/build_global_cache' ) {
        $self->run_system_cmd( ['/usr/local/cpanel/bin/build_global_cache'] );
    }
}

sub _check_for_mod_qos {
    my ($self) = @_;

    # Stop here if ModQos is not selected
    return ( 1, 'ok' ) if ( !$self->get_ns_value_from_profile( 'Cpanel::Easy::ModQos', $self->{'working_profile'} ) );
    my $apv = $self->_get_current_apache_version_key();
    return ( 1, 'ok' ) if !$apv;

    # Add 'MaxClients' in httpd.conf only if it does not exist.
    my $directive = $apv lt '2_4' ? 'MaxClients' : 'MaxRequestWorkers';

    Cpanel::EditHttpdconf::edit_httpdconf(
        sub {
            my ( $rw_fh, $safe_replace_content_coderef ) = @_;
            my @new_content;
            my $need_edit = 1;
            while ( my $line = readline($rw_fh) ) {
                push @new_content, $line;
                if ( $line =~ m{^\s*(?:MaxClients|MaxRequestWorkers)\s+}i ) {
                    $need_edit = 0;
                    last;
                }

                # The setting needs to be placed in the Apache Global Configuration
                if ( $line =~ m{^\s*#\s+These\s+can\s+be\s+set\s+in\s+WHM\s+under\s+\'Apache\s+Global\s+Configuration\'}i ) {
                    push @new_content, "$directive 150\n";
                }
            }
            if ($need_edit) {
                $self->print_alert(q{Updating Apache configuration for ModQos});
                return ("Edited Apache configuration for ModQos") if $safe_replace_content_coderef->( $rw_fh, \@new_content );
            }
            return;
        },
    ) || return ( 0, 'Failed to update httpd.conf for mod_qos' );

    return ( 1, 'ok' );
}

# The SSLCompression directive was added to Apache 2.2.23 (patched), Apache 2.2.24, and
# Apache 2.4.  Since it was not backported to older versions of Apache, this routine
# examines the current Apache version and ensures that the directive is removed if
# an incompatible version is found.
sub _strip_sslcompression_from_httpd {
    my $self    = shift;
    my $version = $self->_get_current_apache_version_key();
    my @rc      = ( 1, 'Ok' );

    if ( $version le '2_2' ) {
        @rc = $self->strip_from_httpconf('SSLCompression');
    }

    return @rc;
}

1;
