#!/usr/bin/perl use strict; use warnings; use Cwd 'abs_path'; my $directory = '/var/nex'; # Read the request and sanitize the path my ($method, $path) = split(' ', ); $path =~ s|^/||; $path = 'index' if $path eq ''; $path =~ s|\.\.||g; # Prevent directory traversal # Special handling for favicon.ico if ($path eq 'favicon.ico') { serve_favicon(); exit; } # Serve the file if method is GET if ($method eq 'GET') { my $file_path = "$directory/$path"; $file_path =~ s|/$||; # Remove trailing slash if (-e $file_path && -f $file_path) { my $real_path = abs_path($file_path); if ($real_path !~ m|^$directory|) { print_error(403, "Forbidden"); } else { # If the file has an extension, serve it as text/plain if ($file_path =~ /\.[^\/]+$/ && $path ne 'favicon.ico') { serve_text_file($file_path); } else { serve_file($file_path); } } } else { print_error(404, "Not Found"); } } else { print_error(405, "Method Not Allowed"); } # Serve favicon.ico with the correct MIME type sub serve_favicon { my $favicon_path = "$directory/favicon.ico"; if (-e $favicon_path && -f $favicon_path) { open my $fh, '<', $favicon_path or die "Cannot open favicon.ico: $!"; binmode $fh; my $favicon_content = do { local $/; <$fh> }; print "HTTP/1.0 200 OK\r\nContent-Type: image/x-icon\r\n\r\n"; print $favicon_content; close $fh; } else { print_error(404, "Favicon Not Found"); } } # Serve plain text files (any file with an extension except favicon.ico) sub serve_text_file { my ($file_path) = @_; open my $fh, '<', $file_path or die "Cannot open file: $!"; my @lines = <$fh>; close $fh; print "HTTP/1.0 200 OK\r\nContent-Type: text/plain\r\n\r\n"; print @lines; } # Serve the file as HTML (for files without extensions) sub serve_file { my ($file_path) = @_; open my $fh, '<', $file_path or die "Cannot open file: $!"; my @lines = <$fh>; close $fh; my $title = extract_title(\@lines); my $content = process_lines(\@lines); print "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n"; print_html($title, $content); } # Extract title from the lines (3rd or 4th line) sub extract_title { my ($lines) = @_; return '' unless @$lines >= 4; return $lines->[2] if $lines->[3] =~ /^-+$/; return $lines->[3] if @$lines >= 5 && $lines->[4] =~ /^-+$/; return ''; } # Process lines: Convert markdown links and escape HTML sub process_lines { my ($lines) = @_; my $content = ''; for my $line (@$lines) { chomp $line; $line = escape_html($line) unless $line =~ /^=>\s+/; if ($line =~ /^=>\s+(.*?)(\s+.*)?$/) { my $text = $2 // ''; # Use empty string if $2 is undefined $content .= "$1$text\n"; } else { $content .= "$line\n"; } } return "
$content
"; } # Escape HTML special characters sub escape_html { my $string = shift; $string =~ s/&/&/g; $string =~ s//>/g; $string =~ s/"/"/g; $string =~ s/'/'/g; return $string; } # Print error messages for 404, 403, 405, etc. sub print_error { my ($code, $message) = @_; print "HTTP/1.0 $code $message\r\nContent-Type: text/html\r\n\r\n"; print "

$code $message

\r\n"; exit; } # Generate the HTML response sub print_html { my ($title, $content) = @_; print < Morena + $title $content END_HTML }