4 # openssl s_client -connect localhost:11211
6 # a test server for "New Gopher"
12 use File
::MimeInfo
; # CPAN
15 die "Usage: ./sslserver.pl CONFIG-FILE";
26 'TLSkey'=>'server.key',
27 'TLScert'=>'server.crt',
32 while (<$fh>) { my $line = $_;
33 if ($line =~ /^#/) { next; } #comments
34 $line =~ /(\S+)\s+(.+)/;
35 my ($key, $val) = ($1, $2);
36 if (exists $defaults{$key}) {
37 $defaults{$key} = $val;
39 warn "Unknown config entry '".$key."'";
43 if (!($defaults{'Root'} =~ /\/$/)) { $defaults{'Root'} .= '/'; }
47 my %config = read_config($ARGV[0]);
49 (my $server = new TLSGopher::server \%config)
51 die "unable to create socket: ", TLSGopher::server::errstr, "\n";
54 accept => \&cb_accept,
56 request => \&cb_request,
60 print "Waiting for connections.\n";
65 print "Connection accepted\n";
69 print "Connection closed\n\n";
73 my ($conn, $resp, $req) = @_;
75 my $selector = safer_selector($req->{selector});
77 print "Responding to request '$selector'\n";
79 my $path = $config{'Root
'} . $selector;
81 if (-e $path && !-r $path) {
82 respond_with_error($resp, "Access denied", "You requested '".$resp->{selector}."'");
89 print "Running script '$path'\n";
90 exec_cgi($path, $resp, $req);
93 print "Sending file '$path'\n";
95 my $mimetype = mimetype $path;
99 $resp->write($size."\t".$mimetype."\r\n");
100 $resp->read_from(*FILE);
105 print "Generating menu '$path'\n";
106 $resp->type('text
/x
-menu
');
107 $resp->write( ng_menu_from_dir($path) );
112 respond_with_error($resp, "File not found", "You requested '".$resp->{selector}."'");
117 my ($conn, $data, $n) = @_;
118 # print "RAW data being read: ($n) $data";
121 sub ng_menu_from_dir {
125 my @files = glob $path."/*";
126 $buf .= "i\tListing [".$path."]\r\n";
127 $buf .= "m\t..\t..\r\n";
128 my $l = length $path;
129 my $sl = length $config{'Root
'};
130 foreach my $file (@files) {
131 my $name = substr($file, $l + 1);
132 my $selector = substr($file, $sl);
134 if (-x $file) { $type = 's
'; }
135 if (-d $file) { $type = 'm
'; }
136 $buf .= $type."\t".$name."\t".$selector."\r\n";
142 my $selector = shift;
143 if (!defined $selector) { $selector = ''; }
144 # Make selector 'safe
' :(
145 $selector = '/'.$selector;
146 $selector =~ s/\/\.+//;
147 $selector =~ s/\.\///;
148 $selector =~ s/^\/+//;
149 $selector =~ s/\/$//;
151 $selector =~ s/\n//m;
155 sub respond_with_error {
158 $r->write("m\tReturn to root\t/\r\n");
160 print "Responding with error: " . $_[0]."\n";
163 $_[0]->write("i\t________________________________\r\n");
164 $_[0]->write("i\t_generated by_[blahblah uname]__\r\n");
168 my ($path, $resp, $req) = @_;
170 # use IO::Handle; # thousands of lines just for autoflush :-(
171 pipe(PARENT_RDR, CHILD_WTR); # XXX: check failure?
172 pipe(CHILD_RDR, PARENT_WTR); # XXX: check failure?
173 # CHILD_WTR->autoflush(1);
174 # PARENT_WTR->autoflush(1);
177 if (!defined $pid) { # Fork failed, return error
178 print "FAILED TO FORK, FATAL ERROR\n";
186 if ($pid == 0) { # Child
189 open STDOUT, '>&'.'PARENT_WTR
' || die "can't reopen stdout
\n";
190 open STDIN, '<&'.'PARENT_RDR' || die "can
't reopen stdin\n";
191 open STDERR, '> '.'/dev/null
' || die "can't reopen stderr
\n";
193 $ENV{"PATH_INFO
"} = $req->{selector}; # HTTP/1.1 compatibility
194 $ENV{"SELECTOR
"} = $req->{selector}; # varied old gopher compatibility
196 $ENV{"GOPHER_SELECTOR
"} = $req->{selector};
197 $ENV{"QUERY_STRING
"} = $req->{search};
198 $ENV{'CONTENT_SIZE'} = $req->{post_size};
199 $ENV{'CONTENT_TYPE'} = $req->{post_type};
200 $ENV{"SCRIPT_NAME
"} = $path;
206 $SIG{PIPE} = "IGNORE
";
207 # print "Forked a CHILD
\n";
210 $req->write_to(*CHILD_WTR);
212 $resp->read_from(*CHILD_RDR);
213 $resp->track_pid($pid); # Do not unqueue $resp until child process is finished