基于socket编写的httpserver(perl版本200行代码)

实现的功能有:1、获取静态资源

       2、目录下文件列表的显示

       3、/xxx/yyy.do请求的解析

       4、404、500错误处理

code:

  

  1 #!/usr/bin/env perl
  2 #tcp_socket_server.pl
  3 
  4 use warnings;
  5 use Socket;
  6 use Cwd;
  7 use POSIX qw(strftime);
  8 use File::Spec;
  9 my $port = 8080;     #port
 10 my $root = getcwd;
 11 my %request;         #save headers
 12 my $mime;
 13 my %mime = (
 14     "text" => "text/plain",
 15     "html" => "text/html",
 16     "css"  => "text/css",
 17     "js"   => "application/javascript",
 18     "json" => "application/json"
 19 );
 20 my $quit = 0;
 21 $SIG{INT} = $SIG{TERM} = sub {
 22     $quit++;
 23     exit(0);
 24 };
 25 
 26 sub main {
 27     my $argstr = join( " ", @ARGV );    #server -p8080 -r /home/toor
 28     $argstr = " $argstr ";
 29     if ( $argstr =~ /\s-h\s/ ) {
 30         print "usage:\n";
 31         print "      perl server.pl -p8080 -r /home/toor/webapp\n";
 32         exit(0);
 33     }
 34     if ( $argstr =~ /\s-p\s*(\d{2,5})\s/ ) {
 35         $port = $1;
 36     }
 37     if ( $argstr =~ /\s-r\s?(\S+)\s/ ) {
 38         $root = $1;
 39     }
 40     socket( server_socket, AF_INET, SOCK_STREAM, getprotobyname('tcp') )
 41         or die "Socket $!\n";
 42     setsockopt( server_socket, SOL_SOCKET, SO_REUSEADDR, 1 )
 43         or die "Can't set SO_REUSADDR: $!";
 44     my $my_addr = sockaddr_in( $port, INADDR_ANY );
 45 
 46     bind( server_socket, $my_addr ) or die "Bind $!\n";
 47 
 48     listen( server_socket, 5 ) || die "Listen $!\n";
 49 
 50     print "http server start in http://127.0.0.1:/$port\n";
 51     while ( !$quit ) {
 52         accept( client_socket, server_socket ) || die "Accept $!\n";
 53         defined( $pid = fork ) || die "Fork: $!\n";
 54         if ( $pid == 0 ) {
 55             &accept_request(client_socket);
 56             exit(0);
 57         }
 58         else {
 59             close(client_socket);
 60         }
 61     }
 62 
 63 }
 64 
 65 sub accept_request {    # handle a request
 66                                       # my $socket = shift;
 67     &parse_headers(client_socket);    #parse
 68     my $uri = $request{'uri'};
 69     if(!$uri){
 70         close(client_socket);
 71         return;
 72     }
 73     $now = strftime( "%Y-%m-%d %H:%M:%S", localtime );#my $now = `date`; # $now =~ s/\n//;
 74     print "$now $request{'method'} $uri\n";
 75     $uri =~ s/(\?.*)// if($uri=~/\?.*/);
 76     if ( $uri =~ /\w+\.html$/ ) {
 77         $mime = $mime{'html'};
 78     }
 79     elsif ( $uri =~ /\w+\.css$/ ) {
 80         $mime = $mime{"css"};
 81     }
 82     elsif ( $uri =~ /\w+\.js$/ ) {
 83         $mime = $mime{"js"};
 84     }
 85     elsif ( $uri =~ /\w+\.json$/ ) {
 86         $mime = $mime{"json"};
 87     }
 88     elsif ( $uri =~ /\w+\.do$/ ) {
 89         $mime = $mime{"json"};
 90         my $prefix;
 91         my $suffix = $uri;
 92         my $refer  = $request{'$Referer'};
 93         if ( $refer && $refer =~ /htmls(\/.*\/)\w+\.html/ ) {
 94             $prefix = "/data$1";
 95             $suffix =~ s/\/(\w+)\.do/$1.json/;
 96             $uri = "$prefix$suffix";
 97         }
 98         else {
 99             resp_error( 500, "Bad Request" );
100             close(client_socket);
101             exit(1);
102         }
103     }
104     else {
105         $mime = "text/html";
106     }
107     my $filename = File::Spec->catfile( $root, $uri );
108     if ( -e -f $filename ) {
109         send_success($filename);
110     }
111     elsif ( -e -d $filename ) {
112         if ( -e -f "$filename/index.html" ) {
113             send_success("$filename/index.html");
114         }
115         else {
116             resp_filelist($filename);
117         }
118     }
119     else {
120         resp_error( 404, "Not Found" );
121     }
122     close(client_socket);
123 }
124 
125 sub parse_headers {
126 
127     # my ($socket) = @_;    #client socket
128     my $content = "";
129     while (1) {
130         my $buffer;
131         my $flag = sysread( client_socket, $buffer, 1024 );
132         $content .= $buffer;
133         last if ( $flag < 1024 );
134     }
135     if ( $content =~ m/^(.*)\s(\/.*)\s(HTTP\/\d\.\d)/ ) {
136         $request{'method'}   = $1;
137         $request{'uri'}      = $2;
138         $request{'protocol'} = $3;
139     }
140     my @header = split( /\n/, $content );
141     foreach (@header) {
142         if (/^([^()<>\@,;:\\"\/\[\]?={} \t]+):\s*(.*)/i) {
143             $request{$1} = $2;
144         }
145     }
146 }
147 
148 sub resp_headers {
149     print client_socket "HTTP/1.0 200 OK\n";
150     print client_socket "Content-Type: $mime;charset: utf-8\n";
151     print client_socket "Date: $now\n";
152     print client_socket "Server: xyserver\n";
153     print client_socket "\n";
154 }
155 
156 sub resp_filelist {
157     my ($directory) = shift;
158     opendir( DIR, $directory ) or die "cannot open $directory:$!";
159     resp_headers();
160     ( my $shortdir = $directory ) =~ s{$root}{};
161     print client_socket
162         "<html><head><title>Index of ./</title></head><body><h1>Directory:$shortdir</h1><table border='0'><tbody>";
163     print client_socket
164         "<tr><td><a href='../'>Parent Directory</a></td><td></td><td></td></tr>";
165     foreach ( sort readdir DIR ) {
166         next if (/^\./);
167         my @info = stat("$directory/$_");
168         ( my $href = "$shortdir/$_" ) =~ s/\/\//\//g;
169         $href = "$href/" if ( -d "$directory/$_" );
170         my $size = $info[7];
171         my $mtime = strftime( "%Y-%m-%d %H:%M:%S", localtime( $info[9] ) );
172         $href=~ s/\/\//\//g;
173         print client_socket
174             "<tr><td><a href='$href'>$_</a></td><td style='text-align:right'>$size  bytes</td><td> $mtime</td></tr>";
175     }
176     closedir DIR;
177     print client_socket "</tbody></table></body></html>";
178 }
179 
180 sub resp_error {    #status, message
181     my ( $status, $error ) = @_;
182     print client_socket "HTTP/1.0 $status $error\n";
183     print client_socket "Content-Type: text/html;charset: utf-8\n";
184     print client_socket "Date: $now\n";
185     print client_socket "Server: xyserver\n";
186     print client_socket "\n";
187     print client_socket
188         "<html><head><title>Http Error</title></head><body><h2>Http Error...</h2><p>errror status:$status</p><pre>error message:$error</pre><hr><i><small>Powered by javaway</i></body></html>";
189 }
190 
191 sub send_success {
192     my $filename = shift;
193     resp_headers();
194     open FILE, "<$filename"
195         or die "cannot open $filename:$!";
196     foreach (<FILE>) {
197         print client_socket $_;
198     }
199 }
200 
201 main();

github:https://github.com/x373241884y/HttpServer/tree/master/perl

posted @ 2016-03-04 21:39  徐徐徐徐徐徐  阅读(112)  评论(0)    收藏  举报