package Cpanel::Easy::Apache::Fastcgi;

# cpanel - Cpanel/Easy/Apache/Fastcgi.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 Cpanel::SafeFile ();
use IO::Handle       ();

my $version = q{2.3.9};

our $easyconfig = {
    'name'     => qq{Mod FastCGI v$version},
    'note'     => 'FastCGI support for the Apache web server.',
    'url'      => 'http://httpd.apache.org/mod_fcgid/',
    'version'  => $version,
    'hastargz' => 1,
    'src_cd2'  => 'mod_fcgid',

    'modself' => sub {
        my ( $easy, $self_hr, $profile_hr ) = @_;

        # FastCGI is incompatible with mod_ruid2
        if ( $profile_hr->{'Cpanel::Easy::ModRuid2'} ) {
            $self_hr->{'skip'} = 1;
        }
    },

    # Built as loadable module to avoid running buildconf in the apache source and
    # creating additional headaches
    'dryrun' => {
        '0' => {
            'name'    => 'Store FCGID working directory',
            'command' => sub {
                my ($self) = @_;
                $self->{'_'}{'fcgid_dir'} = $self->cwd();
                return ( 1, 'Ok' );
            },
        },
        '1' => {
            'name'    => 'Patch mod_fcgid',
            'command' => sub {
                my $self = shift;
                if ( opendir my $patch_dh, '../mod_fcgid_patches' ) {
                    my @patches = readdir($patch_dh);
                    closedir $patch_dh;
                    foreach my $patch ( sort @patches ) {
                        next if ( $patch =~ /^\.+$/ );
                        my @return = $self->apply_patch( '../mod_fcgid_patches/' . $patch );
                        return (@return) unless ( $return[0] );
                    }
                }
                return ( 1, 'Ok' );
            },
        },
    },
    'step' => {
        '0' => {
            'name'    => 'Create task list to do after apache is built',
            'command' => sub {
                my ($self) = @_;
                my $post_apache = {
                    'step' => {
                        '8.01' => {
                            'name'    => 'configuring mod_fcgid',
                            'command' => sub {
                                my ($self) = @_;

                                my $start = $self->cwd();
                                chdir $self->{'_'}{'fcgid_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'fcgid_dir'}, $! );

                                local $ENV{'APXS'} = '/usr/local/apache/bin/apxs';
                                my @return = $self->run_system_cmd_returnable( ['./configure.apxs'] );

                                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                                return @return;
                            },
                        },
                        '8.1' => {
                            'name'    => 'APXSing mod_fcgid into apache - make',
                            'command' => sub {
                                my ($self) = @_;
                                my $start = $self->cwd();
                                chdir $self->{'_'}{'fcgid_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'fcgid_dir'}, $! );

                                my @return = $self->run_system_cmd_returnable( ['make'] );

                                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                                return @return;
                            },
                        },
                        '8.2' => {
                            'name'    => 'APXSing mod_fcgid into apache - make install',
                            'command' => sub {
                                my ($self) = @_;
                                my $start = $self->cwd();
                                chdir $self->{'_'}{'fcgid_dir'} or return ( 0, q{Could not chdir into '[_1]: [_2]'}, $self->{'_'}{'fcgid_dir'}, $! );

                                my @return = $self->run_system_cmd_returnable( [qw(make install)] );

                                chdir $start or return ( 0, q{Could not chdir back into '[_1]': [_2]}, $start, $! );
                                return @return;

                            },
                        },
                        '8.3' => {
                            'name'    => 'Configuring mod_fcgid in /usr/local/apache/conf/includes/pre_virtualhost_global.conf',
                            'command' => sub {
                                my ($self) = @_;

                                my $max_request = 1073741824;
                                my $new_block   = <<"END_MOD_FCGID";
<IfModule mod_fcgid.c>
    FcgidMaxRequestLen %d
</IfModule>

END_MOD_FCGID
                                my $global_includes_dir = '/usr/local/apache/conf/includes';
                                my $file                = $global_includes_dir . '/pre_virtualhost_global.conf';

                                if ( !-d $global_includes_dir ) {
                                    mkdir $global_includes_dir, 0755;
                                    if ( !-d $global_includes_dir ) {
                                        return ( 0, q{Failed to create directory '[_1]': [_2]}, $global_includes_dir, $! );
                                    }
                                }

                                # Clean up old <IfModule mod_fcgid> blocks from pre_main_global.conf
                                my $old_file = $global_includes_dir . '/pre_main_global.conf';
                                if ( -e $old_file && !-z _ ) {
                                    my $httpd_fh = IO::Handle->new();
                                    my $httplock = Cpanel::SafeFile::safeopen( $httpd_fh, '+<', $old_file );
                                    if ( !$httplock ) {
                                        return ( 0, q{Could not open() file '[_1]' for writing: [_2]}, $old_file, $! );
                                    }

                                    my $in_fcgid = 0;
                                    my @lines;
                                    while ( my $line = readline($httpd_fh) ) {
                                        if ( !$in_fcgid && $line =~ m/^\s*<ifmodule\s*mod_fcgid/i ) {
                                            $in_fcgid = 1;
                                        }
                                        elsif ( $in_fcgid && $line =~ m{^\s*</ifmodule>}i ) {
                                            $in_fcgid = 0;
                                        }
                                        elsif ( $line =~ m/^\s*(?:Fcgid)?MaxRequestLen\s*(\d*)\s*$/i ) {
                                            $max_request = $1;
                                        }
                                        elsif ( !$in_fcgid ) {
                                            push @lines, $line;
                                        }
                                    }

                                    seek( $httpd_fh, 0, 0 );

                                    my $lines = join( '', @lines );
                                    if ( $lines !~ m{\A\s*\z} ) {
                                        print {$httpd_fh} $lines;
                                    }

                                    truncate( $httpd_fh, tell($httpd_fh) );
                                    Cpanel::SafeFile::safeclose( $httpd_fh, $httplock );

                                    unlink $old_file if -z $old_file;
                                }

                                # Set up the pre_virtualhost_global.conf
                                if ( !-e $file || -z _ ) {
                                    my $orig_umask = umask(0177);
                                    if ( open my $inc_fh, '>', $file ) {
                                        printf {$inc_fh} $new_block, $max_request;
                                        close $inc_fh;
                                        umask($orig_umask);
                                        return ( 1, 'Ok' );
                                    }
                                    else {
                                        umask($orig_umask);
                                        return ( 0, q{Could not open() file '[_1]' for writing: [_2]}, $file, $! );
                                    }

                                }
                                else {
                                    my $httpd_fh = IO::Handle->new();
                                    my $httplock = Cpanel::SafeFile::safeopen( $httpd_fh, '+<', $file );
                                    if ( !$httplock ) {
                                        return ( 0, q{Could not open() file '[_1]' for writing: [_2]}, $file, $! );
                                    }

                                    my $found_maxreq_len = 0;
                                    my @CONFFILE;
                                    while ( my $line = readline($httpd_fh) ) {
                                        if ( $line =~ m/^\s*FcgidMaxRequestLen\s*(\d*)\s*$/i ) {
                                            $found_maxreq_len = 1;
                                        }
                                        elsif ( $line =~ m/^\s*MaxRequestLen\s*(\d*)\s*$/i ) {
                                            $max_request = $1;
                                            next;
                                        }
                                        push @CONFFILE, $line;
                                    }

                                    seek( $httpd_fh, 0, 0 );

                                    if ( !$found_maxreq_len ) {
                                        printf {$httpd_fh} $new_block, $max_request;
                                    }

                                    print {$httpd_fh} @CONFFILE;
                                    truncate( $httpd_fh, tell($httpd_fh) );
                                    Cpanel::SafeFile::safeclose( $httpd_fh, $httplock );
                                }

                                return ( 1, 'Ok' );
                            },
                        },
                    },
                };

                my $ap_ns = 'Cpanel::Easy::Apache::';
                $ap_ns .= $self->{'working_profile'}{'Apache'}{'version'};
                return $self->add_to_modify_later_queue( $ap_ns, $post_apache );
            },
        },
    },
};

1;
