Default setup dont redirect STDERR
[catagits/HTTP-Request-AsCGI.git] / lib / HTTP / Request / AsCGI.pm
CommitLineData
b2e1304d 1package HTTP::Request::AsCGI;
2
3use strict;
4use warnings;
090cc060 5use bytes;
b2e1304d 6use base 'Class::Accessor::Fast';
7
8use Carp;
bd7813ac 9use IO::File;
b2e1304d 10
090cc060 11__PACKAGE__->mk_accessors(qw[ enviroment request stdin stdout stderr ]);
b2e1304d 12
13our $VERSION = 0.1;
14
15sub new {
16 my $class = shift;
17 my $request = shift;
18
19 my $self = {
20 request => $request,
21 restored => 0,
6f5fb9a7 22 setuped => 0,
bd7813ac 23 stdin => IO::File->new_tmpfile,
17b370b0 24 stdout => IO::File->new_tmpfile
b2e1304d 25 };
26
27 $self->{enviroment} = {
28 GATEWAY_INTERFACE => 'CGI/1.1',
29 HTTP_HOST => $request->uri->host_port,
090cc060 30 PATH_INFO => $request->uri->path,
b2e1304d 31 QUERY_STRING => $request->uri->query || '',
c1e07bf1 32 SCRIPT_NAME => '/',
b2e1304d 33 SERVER_NAME => $request->uri->host,
34 SERVER_PORT => $request->uri->port,
35 SERVER_PROTOCOL => $request->protocol || 'HTTP/1.1',
36 SERVER_SOFTWARE => __PACKAGE__ . "/" . $VERSION,
37 REMOTE_ADDR => '127.0.0.1',
38 REMOTE_HOST => 'localhost',
39 REMOTE_PORT => int( rand(64000) + 1000 ), # not in RFC 3875
40 REQUEST_URI => $request->uri->path || '/', # not in RFC 3875
41 REQUEST_METHOD => $request->method,
42 @_
43 };
44
45 foreach my $field ( $request->headers->header_field_names ) {
46
47 my $key = uc($field);
2aaf55bc 48 $key =~ tr/-/_/;
b2e1304d 49 $key = 'HTTP_' . $key unless $field =~ /^Content-(Length|Type)$/;
50
51 unless ( exists $self->{enviroment}->{$key} ) {
52 $self->{enviroment}->{$key} = $request->headers->header($field);
53 }
54 }
55
56 return $class->SUPER::new($self);
57}
58
59sub setup {
60 my $self = shift;
61
090cc060 62 $self->{restore}->{enviroment} = {%ENV};
b2e1304d 63
090cc060 64 open( $self->{restore}->{stdin}, '>&', STDIN->fileno )
65 or croak("Can't dup stdin: $!");
b2e1304d 66
090cc060 67 open( STDIN, '<&=', $self->stdin->fileno )
68 or croak("Can't open stdin: $!");
441eeb04 69
17b370b0 70 binmode( $self->stdin );
71 binmode( STDIN );
b2e1304d 72
73 if ( $self->request->content_length ) {
74
12852959 75 $self->stdin->syswrite( $self->request->content )
780060e5 76 or croak("Can't write request content to stdin handle: $!");
b2e1304d 77
12852959 78 $self->stdin->sysseek( 0, SEEK_SET )
780060e5 79 or croak("Can't seek stdin handle: $!");
b2e1304d 80 }
81
090cc060 82 if ( $self->stdout ) {
83 open( $self->{restore}->{stdout}, '>&', STDOUT->fileno )
84 or croak("Can't dup stdout: $!");
85
86 open( STDOUT, '>&=', $self->stdout->fileno )
87 or croak("Can't open stdout: $!");
441eeb04 88
17b370b0 89 binmode( $self->stdout );
90 binmode( STDOUT);
090cc060 91 }
92
93 if ( $self->stderr ) {
94 open( $self->{restore}->{stderr}, '>&', STDERR->fileno )
95 or croak("Can't dup stderr: $!");
96
97 open( STDERR, '>&=', $self->stderr->fileno )
98 or croak("Can't open stderr: $!");
441eeb04 99
17b370b0 100 binmode( $self->stderr );
101 binmode( STDERR );
090cc060 102 }
103
3cdea3c7 104 {
105 no warnings 'uninitialized';
106 %ENV = %{ $self->enviroment };
107 }
b2e1304d 108
6f5fb9a7 109 $self->{setuped}++;
b2e1304d 110
111 return $self;
112}
113
780060e5 114sub response {
115 my ( $self, $callback ) = @_;
116
117 return undef unless $self->{setuped};
118 return undef unless $self->{restored};
090cc060 119 return undef unless $self->{restore}->{stdout};
780060e5 120
121 require HTTP::Response;
122
123 my $message = undef;
124 my $position = $self->stdin->tell;
125
090cc060 126 $self->stdout->sysseek( 0, SEEK_SET )
780060e5 127 or croak("Can't seek stdin handle: $!");
128
129 while ( my $line = $self->stdout->getline ) {
130 $message .= $line;
131 last if $line =~ /^\x0d?\x0a$/;
132 }
133
134 unless ( $message =~ /^HTTP/ ) {
135 $message = "HTTP/1.1 200\x0d\x0a" . $message;
136 }
137
138 my $response = HTTP::Response->parse($message);
139
140 if ( my $code = $response->header('Status') ) {
141 $response->code($code);
142 }
143
144 $response->protocol( $self->request->protocol );
145 $response->headers->date( time() );
146
090cc060 147 if ($callback) {
780060e5 148 $response->content( sub {
149 if ( $self->stdout->read( my $buffer, 4096 ) ) {
150 return $buffer;
151 }
152 return undef;
090cc060 153 });
780060e5 154 }
155 else {
156 my $length = 0;
157 while ( $self->stdout->read( my $buffer, 4096 ) ) {
158 $length += length($buffer);
159 $response->add_content($buffer);
160 }
161 $response->content_length($length) unless $response->content_length;
162 }
163
090cc060 164 $self->stdout->sysseek( $position, SEEK_SET )
780060e5 165 or croak("Can't seek stdin handle: $!");
166
167 return $response;
168}
169
b2e1304d 170sub restore {
171 my $self = shift;
172
173 %ENV = %{ $self->{restore}->{enviroment} };
174
175 open( STDIN, '>&', $self->{restore}->{stdin} )
176 or croak("Can't restore stdin: $!");
177
780060e5 178 $self->stdin->sysseek( 0, SEEK_SET )
179 or croak("Can't seek stdin: $!");
12852959 180
090cc060 181 if ( $self->{restore}->{stdout} ) {
182 open( STDOUT, '>&', $self->{restore}->{stdout} )
183 or croak("Can't restore stdout: $!");
184
6f5fb9a7 185 $self->stdout->sysseek( 0, SEEK_SET )
186 or croak("Can't seek stdout: $!");
187 }
12852959 188
090cc060 189 if ( $self->{restore}->{stderr} ) {
190 open( STDERR, '>&', $self->{restore}->{stderr} )
191 or croak("Can't restore stderr: $!");
192
6f5fb9a7 193 $self->stderr->sysseek( 0, SEEK_SET )
194 or croak("Can't seek stderr: $!");
195 }
12852959 196
b2e1304d 197 $self->{restored}++;
090cc060 198
199 return $self;
b2e1304d 200}
201
202sub DESTROY {
203 my $self = shift;
6f5fb9a7 204 $self->restore if $self->{setuped} && !$self->{restored};
b2e1304d 205}
206
2071;
208
209__END__
210
211=head1 NAME
212
bd7813ac 213HTTP::Request::AsCGI - Setup a CGI enviroment from a HTTP::Request
b2e1304d 214
215=head1 SYNOPSIS
216
bd7813ac 217 use CGI;
218 use HTTP::Request;
219 use HTTP::Request::AsCGI;
220
221 my $request = HTTP::Request->new( GET => 'http://www.host.com/' );
222 my $stdout;
223
224 {
225 my $c = HTTP::Request::AsCGI->new($request)->setup;
226 my $q = CGI->new;
227
228 print $q->header,
229 $q->start_html('Hello World'),
230 $q->h1('Hello World'),
231 $q->end_html;
232
233 $stdout = $c->stdout;
234
235 # enviroment and descriptors will automatically be restored when $c is destructed.
236 }
237
bd7813ac 238 while ( my $line = $stdout->getline ) {
239 print $line;
240 }
241
b2e1304d 242=head1 DESCRIPTION
243
244=head1 METHODS
245
246=over 4
247
248=item new
249
bd7813ac 250=item enviroment
251
b2e1304d 252=item setup
253
254=item restore
255
256=item request
257
780060e5 258=item response
259
b2e1304d 260=item stdin
261
262=item stdout
263
264=item stderr
265
266=back
267
268=head1 BUGS
269
17b370b0 270=item THANKS TO
271
272Thomas L. Shinnick for his valuable win32 testing.
273
b2e1304d 274=head1 AUTHOR
275
276Christian Hansen, C<ch@ngmedia.com>
277
278=head1 LICENSE
279
280This library is free software. You can redistribute it and/or modify
281it under the same terms as perl itself.
282
283=cut