Added simple IO test
[catagits/HTTP-Request-AsCGI.git] / lib / HTTP / Request / AsCGI.pm
1 package HTTP::Request::AsCGI;
2
3 use strict;
4 use warnings;
5 use base 'Class::Accessor::Fast';
6
7 use Carp;
8 use IO::File;
9
10 __PACKAGE__->mk_accessors( qw[ enviroment request stdin stdout stderr ] );
11
12 our $VERSION = 0.1;
13
14 sub new {
15     my $class   = shift;
16     my $request = shift;
17
18     my $self = {
19         request  => $request,
20         restored => 0,
21         stdin    => IO::File->new_tmpfile,
22         stdout   => IO::File->new_tmpfile,
23         stderr   => IO::File->new_tmpfile
24     };
25
26     $self->{enviroment} = {
27         GATEWAY_INTERFACE => 'CGI/1.1',
28         HTTP_HOST         => $request->uri->host_port,
29         QUERY_STRING      => $request->uri->query || '',
30         SCRIPT_NAME       => $request->uri->path || '/',
31         SERVER_NAME       => $request->uri->host,
32         SERVER_PORT       => $request->uri->port,
33         SERVER_PROTOCOL   => $request->protocol || 'HTTP/1.1',
34         SERVER_SOFTWARE   => __PACKAGE__ . "/" . $VERSION,
35         REMOTE_ADDR       => '127.0.0.1',
36         REMOTE_HOST       => 'localhost',
37         REMOTE_PORT       => int( rand(64000) + 1000 ),        # not in RFC 3875
38         REQUEST_URI       => $request->uri->path || '/',       # not in RFC 3875
39         REQUEST_METHOD    => $request->method,
40         @_
41     };
42
43     foreach my $field ( $request->headers->header_field_names ) {
44
45         my $key = uc($field);
46         $key =~ tr/_/-/;
47         $key = 'HTTP_' . $key unless $field =~ /^Content-(Length|Type)$/;
48
49         unless ( exists $self->{enviroment}->{$key} ) {
50             $self->{enviroment}->{$key} = $request->headers->header($field);
51         }
52     }
53
54     return $class->SUPER::new($self);
55 }
56
57 sub setup {
58     my $self = shift;
59
60     open( my $stdin, '>&', STDIN->fileno )
61       or croak("Can't dup stdin: $!");
62
63     open( my $stdout, '>&', STDOUT->fileno )
64       or croak("Can't dup stdout: $!");
65
66     open( my $stderr, '>&', STDERR->fileno )
67       or croak("Can't dup stderr: $!");
68
69     $self->{restore} = {
70         stdin      => $stdin,
71         stdout     => $stdout,
72         stderr     => $stderr,
73         enviroment => {%ENV}
74     };
75
76     if ( $self->request->content_length ) {
77
78         $self->stdin->syswrite( $self->request->content )
79           or croak("Can't write content to stdin: $!");
80
81         $self->stdin->sysseek( 0, SEEK_SET )
82           or croak("Can't seek stdin: $!");
83     }
84
85     %ENV = %{ $self->enviroment };
86
87     open( STDIN, '<&=', $self->stdin->fileno )
88       or croak("Can't open stdin: $!");
89
90     open( STDOUT, '>&=', $self->stdout->fileno )
91       or croak("Can't open stdout: $!");
92
93     open( STDERR, '>&=', $self->stderr->fileno )
94       or croak("Can't open stderr: $!");
95
96     return $self;
97 }
98
99 sub restore {
100     my $self = shift;
101
102     %ENV = %{ $self->{restore}->{enviroment} };
103
104     open( STDIN, '>&', $self->{restore}->{stdin} )
105       or croak("Can't restore stdin: $!");
106
107     open( STDOUT, '>&', $self->{restore}->{stdout} )
108       or croak("Can't restore stdout: $!");
109
110     open( STDERR, '>&', $self->{restore}->{stderr} )
111       or croak("Can't restore stderr: $!");
112
113     $self->stdin->sysseek( 0, SEEK_SET )
114       or croak("Can't seek stdin: $!");
115
116     $self->stdout->sysseek( 0, SEEK_SET )
117       or croak("Can't seek stdout: $!");
118
119     $self->stderr->sysseek( 0, SEEK_SET )
120       or croak("Can't seek stderr: $!");
121
122     $self->{restored}++;
123 }
124
125 sub DESTROY {
126     my $self = shift;
127     $self->restore unless $self->{restored};
128 }
129
130 1;
131
132 __END__
133
134 =head1 NAME
135
136 HTTP::Request::AsCGI - Setup a CGI enviroment from a HTTP::Request
137
138 =head1 SYNOPSIS
139
140     use CGI;
141     use HTTP::Request;
142     use HTTP::Request::AsCGI;
143     
144     my $request = HTTP::Request->new( GET => 'http://www.host.com/' );
145     my $stdout;
146     
147     {
148         my $c = HTTP::Request::AsCGI->new($request)->setup;
149         my $q = CGI->new;
150         
151         print $q->header,
152               $q->start_html('Hello World'),
153               $q->h1('Hello World'),
154               $q->end_html;
155         
156         $stdout = $c->stdout;
157         
158         # enviroment and descriptors will automatically be restored when $c is destructed.
159     }
160     
161     while ( my $line = $stdout->getline ) {
162         print $line;
163     }
164     
165 =head1 DESCRIPTION
166
167 =head1 METHODS
168
169 =over 4 
170
171 =item new
172
173 =item enviroment
174
175 =item setup
176
177 =item restore
178
179 =item request
180
181 =item stdin
182
183 =item stdout
184
185 =item stderr
186
187 =back
188
189 =head1 BUGS
190
191 =head1 AUTHOR
192
193 Christian Hansen, C<ch@ngmedia.com>
194
195 =head1 LICENSE
196
197 This library is free software. You can redistribute it and/or modify 
198 it under the same terms as perl itself.
199
200 =cut