mirror of https://github.com/jeelabs/esp-link.git
parent
5f56676e4b
commit
45a127523e
@ -0,0 +1,202 @@ |
||||
#!/usr/bin/perl |
||||
use strict; |
||||
|
||||
use IO::Socket::INET; |
||||
use Data::Dumper; |
||||
use File::Basename; |
||||
|
||||
# auto-flush on socket |
||||
$| = 1; |
||||
|
||||
# creating a listening socket |
||||
my $server = new IO::Socket::INET ( |
||||
LocalHost => '0.0.0.0', |
||||
LocalPort => '7777', |
||||
Proto => 'tcp', |
||||
Listen => 5, |
||||
Reuse => 1 |
||||
); |
||||
die "cannot create socket $!\n" unless $server; |
||||
print "server waiting for client connection on port 7777\n"; |
||||
|
||||
|
||||
my $client; |
||||
|
||||
while ($client = $server->accept()) |
||||
{ |
||||
my $pid ; |
||||
while (not defined ($pid = fork())) |
||||
{ |
||||
sleep 5; |
||||
} |
||||
if ($pid) |
||||
{ |
||||
close $client; # Only meaningful in the client |
||||
} |
||||
else |
||||
{ |
||||
$client->autoflush(1); # Always a good idea |
||||
close $server; |
||||
|
||||
my $httpReq = parse_http( $client ); |
||||
print Dumper($httpReq); |
||||
my $httpResp = process_http( $httpReq ); |
||||
print Dumper($httpResp); |
||||
|
||||
my $data = "HTTP/1.1 " . $httpResp->{code} . " " . $httpResp->{text} . "\r\n"; |
||||
|
||||
if( exists $httpResp->{fields} ) |
||||
{ |
||||
for my $key( keys %{$httpResp->{fields}} ) |
||||
{ |
||||
$data .= "$key: " . $httpResp->{fields}{$key} . "\r\n"; |
||||
} |
||||
} |
||||
$data .= "\r\n"; |
||||
if( exists $httpResp->{body} ) |
||||
{ |
||||
$data .= $httpResp->{body}; |
||||
} |
||||
|
||||
print "$data\n\n"; |
||||
$client->send($data); |
||||
|
||||
if( $httpResp->{done} ) |
||||
{ |
||||
# notify client that response has been sent |
||||
#shutdown($client, 1); |
||||
} |
||||
} |
||||
} |
||||
|
||||
exit(0); |
||||
|
||||
sub parse_http |
||||
{ |
||||
my ($client) = @_; |
||||
# read up to 1024 characters from the connected client |
||||
my $data = ""; |
||||
|
||||
do{ |
||||
my $buf = ""; |
||||
$client->recv($buf, 1024); |
||||
$data .= $buf; |
||||
}while( $data !~ /\r\n\r\n/s ); |
||||
#print "Query: $data\n"; |
||||
|
||||
my %resp; |
||||
|
||||
my @lines = split /\r\n/, $data; |
||||
my $head = shift @lines; |
||||
|
||||
if( $head =~ /(GET|POST) / ) |
||||
{ |
||||
$resp{method} = $1; |
||||
$head =~ s/(GET|POST) //; |
||||
if( $head =~ /^([^ ]+) HTTP\/\d\.\d/ ) |
||||
{ |
||||
$resp{url} = $1; |
||||
|
||||
my %fields; |
||||
while( my $arg = shift @lines ) |
||||
{ |
||||
if( $arg =~ /^([\w-]+): (.*)$/ ) |
||||
{ |
||||
$fields{$1} = $2; |
||||
} |
||||
} |
||||
$resp{fields} = \%fields; |
||||
} |
||||
else |
||||
{ |
||||
$resp{method} = 'ERROR'; |
||||
$resp{error} = 'Invalid HTTP request'; |
||||
} |
||||
} |
||||
else |
||||
{ |
||||
$resp{method} = 'ERROR'; |
||||
$resp{error} = 'Invalid HTTP request'; |
||||
} |
||||
|
||||
return \%resp; |
||||
} |
||||
|
||||
sub error_response |
||||
{ |
||||
my ($code, $msg) = @_; |
||||
|
||||
my %resp; |
||||
$resp{code} = $code; |
||||
$resp{text} = $msg; |
||||
$resp{fields} = {}; |
||||
$resp{done} = 1; |
||||
|
||||
return \%resp; |
||||
} |
||||
|
||||
sub slurp |
||||
{ |
||||
my ($file) = @_; |
||||
|
||||
open IF, "<", $file or die "Can't read file: $!"; |
||||
my @fc = <IF>; |
||||
close(IF); |
||||
my $cnt = join("", @fc); |
||||
return $cnt; |
||||
} |
||||
|
||||
sub process_http |
||||
{ |
||||
my ($httpReq) = @_; |
||||
if( $httpReq->{method} eq 'ERROR' ) |
||||
{ |
||||
return error_response(400, $httpReq->{error}); |
||||
} |
||||
|
||||
if( $httpReq->{method} eq 'GET' ) |
||||
{ |
||||
my $url = $httpReq->{url}; |
||||
$url =~ s/^\///; |
||||
|
||||
$url = "home.html" if ! $url; |
||||
|
||||
my $pth = dirname $0; |
||||
|
||||
if( -f "$pth/../html/$url" ) |
||||
{ |
||||
my $cnt = slurp( "$pth/../html/$url" ); |
||||
|
||||
if( $url =~ /\.html$/ ) |
||||
{ |
||||
my $prep = slurp( "$pth/../html/head-" ); |
||||
$cnt = "$prep$cnt"; |
||||
} |
||||
|
||||
my %resp; |
||||
$resp{code} = 200; |
||||
$resp{text} = "OK"; |
||||
$resp{done} = 1; |
||||
$resp{body} = $cnt; |
||||
|
||||
$resp{fields} = {}; |
||||
$resp{fields}{'Content-Length'} = length($cnt); |
||||
|
||||
$resp{fields}{'Content-Type'} = "text/html; charset=UTF-8" if( $url =~ /\.html$/ ); |
||||
$resp{fields}{'Content-Type'} = "text/css" if( $url =~ /\.css$/ ); |
||||
$resp{fields}{'Content-Type'} = "text/javascript" if( $url =~ /\.js$/ ); |
||||
$resp{fields}{'Content-Type'} = "image/gif" if( $url =~ /\.ico$/ ); |
||||
$resp{fields}{'Connection'} = 'close'; |
||||
|
||||
return \%resp; |
||||
} |
||||
else |
||||
{ |
||||
return error_response(404, "File not found"); |
||||
} |
||||
} |
||||
|
||||
# TODO |
||||
|
||||
return error_response(400, "Invalid HTTP request"); |
||||
} |
Loading…
Reference in new issue