#/*
# *  Copyright 2007-2008 hkrn <hikarin@users.sourceforge.jp>
# *
# *  Licensed under the Apache License, Version 2.0 (the "License");
# *  you may not use this file except in compliance with the License.
# *  You may obtain a copy of the License at
# *
# *      http://www.apache.org/licenses/LICENSE-2.0
# *
# *  Unless required by applicable law or agreed to in writing, software
# *  distributed under the License is distributed on an "AS IS" BASIS,
# *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# *  See the License for the specific language governing permissions and
# *  limitations under the License.
# */
#
# $Id: Request.pm 1645 2008-02-06 15:40:18Z hikarin $
#

package Img0ch::FCGI::Async::Request;

use strict;
use base qw(Img0ch::Request::Interface);
use CGI::Minimal qw(:preload);
use File::Temp qw();

BEGIN { $INC{'Img0ch/Request.pm'} = __FILE__ }

sub new {
    my ( $iClass, $r, $param_args ) = @_;
    CGI::Minimal::max_read_size(16777216);

    my $params = $r->params();
    my $q      = CGI::Minimal->new();
    my $buffer = $r->read_stdin( $params->{CONTENT_LENGTH} )
        || $params->{QUERY_STRING};

    my $content_type = $params->{'CONTENT_TYPE'} || '';
    if ( $content_type =~ m{\Amultipart/form-data; boundary=(.*)\z}i ) {
        my $boundary = $1;
        $q->_burst_multipart_buffer( $buffer, $boundary );
    }
    else {
        $q->_burst_URL_encoded_buffer( $buffer, '[&;]' );
    }
    $param_args and $q->param($param_args);

    bless {
        __cgi     => $q,
        __env     => $params,
        __cookie  => [],
        __header  => {},
        __request => $r
    }, $iClass;
}

sub DESTROY { $_[0]->{__cgi}->reset_globals(); return }

sub request { $_[0]->{__request} }

sub signature {
    my ( $iRequest, $module_type, $token_type ) = @_;
    my $sign = $iRequest->{__sign};
    if ( !$sign ) {
        $sign = $iRequest->SUPER::signature( 'FastCGI', $token_type );
        $iRequest->{__sign} = $sign;
    }
    return $sign;
}

*credit = \&signature;

sub init {
    my ( $iRequest, $iConfig ) = @_;
    my $ip = $iRequest->{__env}->{REMOTE_ADDR} || '0.0.0.0';
    $iRequest->SUPER::init( $iConfig, $ip, time(), 'FastCGI' );
    1;
}

sub param {
    my ( $iRequest, $key, $unescape ) = @_;
    my $q = $iRequest->{__cgi};
    $unescape ||= 0;

    if ( !wantarray ) {
        my $value = $q->param($key);
        if ( !$unescape ) {
            $value = Img0ch::Kernel::escape_html_entities($value);
        }
        return $value;
    }
    elsif ( wantarray and !$key ) {
        my @result = $q->param();
        return @result;
    }
    else {
        my @r = $q->param($key);
        return
            map { $unescape ? $_ : Img0ch::Kernel::escape_html_entities($_) }
            @r;
    }
}

sub rawdata { \$_[0]->{__cgi}->raw() }

sub get_header {
    my ( $iRequest, $key ) = @_;
    $key =~ tr/\-/_/;
    $key = 'HTTP_' . uc $key;
    return $iRequest->{__env}->{$key};
}

sub set_header {
    my ( $iRequest, $key, $value ) = @_;
    $key =~ tr/\-/_/;
    $key = 'HTTP_' . uc $key;
    $iRequest->{__header}->{$key} = $value;
    return;
}

sub request_by_post { $_[0]->{__env}->{REQUEST_METHOD} eq 'POST' ? 1 : 0 }

sub request_uri { $_[0]->{__env}->{REQUEST_URI} }

sub query { $_[0]->{__env}->{QUERY_STRING} }

sub path_info {
    my ($iRequest) = @_;
    my $path_info = $iRequest->{__path_info};
    if ( !$path_info ) {
        $path_info = $iRequest->{__env}->{PATH_INFO} || '';
        $path_info =~ s{.*\.cgi/}{/}xms;
        $iRequest->{__path_info} = $path_info;
    }
    return $path_info;
}

sub is_uploadable {
    my ( $iRequest, $key ) = @_;
    my $q = $iRequest->{__cgi};
    $q->truncated()
        and
        Img0ch::Kernel->throw_exception('Cannot upload with truncated file');

    my $file = $q->param_filename($key) || return 0;
    my ( $fh, $filename ) = File::Temp::tempfile( UNLINK => 1 );
    binmode $fh;
    print {$fh} $q->param($key) or Img0ch::Kernel->throw_exception($!);
    close $fh or Img0ch::Kernel->throw_exception($!);

    $iRequest->{__file}  = $file;
    $iRequest->{__fsize} = -s $filename;
    $iRequest->{__tmp}   = $filename;
    return 1;
}

sub cookie {
    my ( $iRequest, $key, $hash ) = @_;
    my $q   = $iRequest->{__cgi};
    my $jar = $iRequest->{__cookie_jar};

    if ( !$jar ) {
        $jar = {};
        my @pairs = split /;\s?/,
            ( $iRequest->{__request}->param('HTTP_COOKIE') || '' );
        for my $pair (@pairs) {
            $pair =~ s/\A\s+//xms;
            $pair =~ s/\s+\z//xms;
            my ( $key, $value ) = split '=', $pair;
            $value or next;
            my @values = map { $q->url_decode($_) } split /[&;]/, $value;
            $key = $q->url_decode($key);
            $jar->{$key} = @values > 1 ? [@values] : $q->url_decode($value);
        }
        %{ $iRequest->{__cookie_jar} } = %$jar;
    }
    if ( ( ref $hash || '' ) eq 'HASH' ) {
        my $q       = $iRequest->{__cgi};
        my $value   = $q->url_encode( $hash->{value} || '' );
        my $path    = $hash->{path} || '/';
        my $expires = $iRequest->{__now} + ( $hash->{expires} || 2592000 );
        my $secure  = $hash->{secure} || 0;
        my @cookie  = ( $q->url_encode($key) . '=' . $value );
        push @cookie, "path=${path}";
        push @cookie, 'expires=' . $q->date_rfc1123($expires);
        $secure and push @cookie, "secure=${secure}";
        push @{ $iRequest->{__cookie} }, join( '; ', @cookie );
    }

    return $jar->{$key} || undef;
}

sub enable_compress {
    $_[0]->{__header}->{'content-encoding'} = 'gzip';
    return;
}

sub send_http_header {
    my ( $iRequest, $type, $charset ) = @_;
    my $request = $iRequest->{__request};
    $type ||= 'text/html';
    $charset = defined $charset ? $charset : 'Shift_JIS';

    my $header = $iRequest->{__header};
    while ( my ( $key, $value ) = each %$header ) {
        $request->print_stdout( ucfirst($key) . ": ${value}\r\n" );
    }
    map { $request->print_stdout("Set-Cookie: $_\r\n") }
        @{ $iRequest->{__cookie} || [] };

    my $ctype = "Content-Type: ${type}";
    ( index( $type, 'text/' ) == 0 ) and $ctype .= "; charset=${charset}";
    $request->print_stdout("$ctype\r\n\r\n");
    return;
}

sub print {
    my $iRequest = shift;
    my $request  = $iRequest->{__request};
    map { $request->print_stdout( ${$_} ) } @_;
    $request->print_stdout("\r\n");
    return;
}

package Img0ch::Request;

use strict;
@Img0ch::Request::ISA = qw(Img0ch::FCGI::Async::Request);

1;
__END__
