Guest User

httpd

a guest
Jan 9th, 2016
200
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 6 4.77 KB | None | 0 0
  1. #!/usr/bin/env perl6
  2.  
  3. my $port = 3333;
  4. my $keepalive_timeout = 15;
  5. my $keepalive_max = 100;
  6.  
  7. #use DateTime::Format::W3CDTF; # Doesn't compile 2016-01-08
  8.  
  9.  
  10. class Header {
  11.   has %!headers = ();
  12.  
  13.   method set(Str $key, Str $value) {
  14.     %!headers{$key} = $value;
  15.   }
  16.  
  17.   method send(IO::Socket $socket) {
  18.     my $raw = "";
  19.     for keys %!headers -> $key {
  20.       say "SENT> $key: %!headers{$key}";
  21.       $raw ~= "$key: %!headers{$key}\n";
  22.     }
  23.     #say "";
  24.     $raw ~= "\n";
  25.     #say $!content;
  26.     $socket.write(:bin, $raw.encode('ISO-8859-1'));
  27.   }
  28. }
  29.  
  30. class Response {
  31.   has $.status is rw = 500;
  32.   has $.message is rw = 'Server Error';
  33.   has $.header = Header.new();
  34.   has $.content is rw = '';
  35.  
  36.   method send(IO::Socket $socket) {
  37.     $!header.set( 'Content-Length', $!content.chars.Str );
  38.     say "SENT> HTTP1/1 $.status $.message";
  39.     $socket.write(:bin, "HTTP1/1 $.status $.message\n".encode('ISO-8859-1'));
  40.     $!header.send($socket);
  41.     $socket.write(:bin, $!content.encode('ISO-8859-1'));
  42.   }
  43. }
  44.  
  45.  
  46. my $http_server = IO::Socket::INET.new(
  47.   :listen,
  48.   :localport($port),
  49.   :reuse-address
  50. );
  51. say "listening on tcp/$port";
  52.  
  53.  
  54. sub formatter (DateTime $dt) {
  55.   say "Formatter called with $dt";
  56.   return "huh?";
  57. }
  58.  
  59. # TCP connect loop
  60. loop {
  61.   my $client = $http_server.accept;
  62.   say "\nclient connected: ";
  63.  
  64.   # HTTP request loop
  65.   loop {
  66.     my %request = ( headers => {} );
  67.  
  68.     # Get current date/time
  69. #    my $now = DateTime::Format::W3CDTF.new.format(DateTime.now());
  70.     my @weekdays = < Mon Tue Wed Thu Fri Sat Sun >;
  71.     my @months = < Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec >;
  72.     my $now = DateTime.now( :formatter({ sprintf("%s, %02d %s %04d %02d:%02d:%02d %04d",
  73.     @weekdays[.day-of-week -1], .day-of-month, @months[.month -1], .year, .hour, .minute, .second, .offset-in-hours*100) }) );
  74.  
  75.     # Get first line of request
  76.     say "waiting for first line";
  77.     my $first_line = $client.get();
  78.     last unless $first_line;
  79.     %request{<method uri protocol>} = $first_line.split(/\s/);
  80.     say "\nmethod=%request{'method'}, uri=%request{'uri'}, protocol=%request{'protocol'}";
  81.  
  82.     # Get request headers
  83.     say "receiving headers";
  84.     while my $line = $client.get() {
  85.       $line.chomp;
  86.       last unless $line; # End of headers
  87.       %request{'headers'}.push($line.split(/\:\s/, 2));
  88.       say "RECV> " ~ $line;
  89.     }
  90.     say "end of headers";
  91.  
  92.     # Dump request hash for debugging
  93.     say %request.perl;
  94.  
  95.     # Get request data (if any, check Content-Length header? FIXME)
  96.     if (%request{'method'} ~~ /:i ^POST$/ && %request{'headers'}.{'Content-Length'}) {
  97.       say "get request content";
  98.       %request{'content'} = Buf.new;
  99.       my $wanted = %request{'headers'}.{'Content-Length'};
  100.       my $bufsiz = 4096;
  101.       while $wanted {
  102.         # Read $wanted bytes from client, limited to $bufsiz
  103.         my $buffer = $client.read(:bin, $wanted > $bufsiz ?? $bufsiz !! $wanted);
  104.         $wanted -= $buffer.elems;
  105.         %request{'content'} ~= $buffer;
  106.         die "Got excess data? (wanted=$wanted)" if $wanted < 0; # Should be impossible
  107.       }
  108.       say "received " ~ %request{'content'}.elems ~ " bytes of request content";
  109.     }
  110.  
  111.     # Keep-alive requested?
  112.     #%request{'keep-alive'} = %request{'headers'}.{'Connection'} ~~ /:i^keep\-alive$/;
  113.  
  114.     my $response = Response.new();
  115.  
  116.     $response.status = 200;
  117.     $response.message = 'OK';
  118.  
  119.     $response.header.set('Server', 'Atlas/4.0.0alpha');
  120.     $response.header.set('Content-Type','text/html; charset=UTF-8');
  121.     $response.header.set('Cache-Control', 'no-cache');
  122.     $response.header.set('Connection', ' keep-alive') if %request{'keep-alive'};
  123.     $response.header.set('Date', $now.Str);
  124.  
  125.     $response.content = "<html><body><form method='post' enctype='multipart/form-data'><input type='file' name='file' value='file'><input type='submit' name='key1' value='value1'></form></body></html>\n";
  126.  
  127.     $response.send($client);
  128.  
  129.     # Keep-alive
  130.     last unless %request{'keep-alive'};
  131.   }
  132.  
  133.   say "closing connection";
  134.   $client.close;
  135. }
  136.  
  137.  
  138.  
  139. =finish
  140.  
  141. == Sample request
  142.  
  143. GET / HTTP/1.1
  144. Host: localhost:3333
  145. User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:42.0) Gecko/20100101
  146. Firefox/42.0
  147. Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
  148. Accept-Language: en-US,en;q=0.5
  149. Accept-Encoding: gzip, deflate
  150. Connection: keep-alive
  151. Cache-Control: max-age=0
  152.  
  153.  
  154. == Sample response
  155.  
  156. HTTP1/1 200 OK
  157. Content-Length: 176
  158. Content-Type: text/html; charset=UTF-8
  159. Server: Atlas/4.0.0alpha
  160. Cache-Control: no-cache
  161. Date: Sat, 09 Jan 2016 20:01:45 0100
  162.  
  163. <html><body><form method='post' enctype='multipart/form-data'><input type='file' name='file' value='file'><input type='submit' name='key1' value='value1'></form></body></html>
Advertisement
Add Comment
Please, Sign In to add comment