#! /usr/bin/awk -f # HTTP-SERVER - HTTP server in AWK # Copyright (C) 2007 Matous Jan Fialka # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the Free # Software Foundation, either version 3 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for # more details. # # You should have received a copy of the GNU General Public License along with # this program. If not, see . # CONFIGURATION BEGIN { directory_index = "index.html"; content_types = "/etc/mime.types"; default_content_type = "text/plain"; syslog_program = "/usr/bin/logger"; syslog_tag = "HAWK"; syslog_priority = "user"; syslog_default_facility = "info"; default_domain = "domain.tld"; server_status[200] = "OK"; server_status[400] = "Bad Request"; server_status[403] = "Forbidden"; server_status[404] = "Not Found"; server_status[405] = "Method Not Allowed"; server_status[500] = "Internal Server Error"; server_status[505] = "HTTP Version Not Supported"; server_status_document[200] = "200.html"; server_status_document[400] = "400.html"; server_status_document[403] = "403.html"; server_status_document[404] = "404.html"; server_status_document[405] = "405.html"; server_status_document[500] = "500.html"; server_status_document[505] = "505.html"; } # DEFAULT VIRTUAL HOSTS BEGIN { server_name[default_domain] = default_domain; server_root[default_domain] = "/var/www/htdocs"; server_name["error"] = default_domain; server_root["error"] = server_root[default_domain] "/errors"; } # VIRTUAL HOSTS BEGIN { server_name["example.tld"] = "example.tld"; server_root["example.tld"] = "/var/www/example.tld/www"; server_name["www.example.tld"] = "www.example.tld"; server_root["www.example.tld"] = "/var/www/example.tld/www"; } # ENVIRONMENT BEGIN { environment["remote_ip"] = ENVIRON["TCPREMOTEIP"]; environment["remote_port"] = ENVIRON["TCPREMOTEPORT"]; if ("TCPREMOTEHOST" in ENVIRON) environment["remote_host"] = ENVIRON["TCPREMOTEHOST"]; else environment["remote_host"] = environment["remote_ip"]; } # RUNTIME SETTINGS BEGIN { IGNORECASE = 1; } # MAIN PROGRAM { sub(/\r$/, ""); } /^$/ { if (proceed_request) exit; next; } { request = $0; request_method = $1; request_uri = $2; request_protocol = $3; request_trash = $4; proceed_request = 1; } # PROCEED REQUEST END { IGNORECASE = 0; syslog(request, "info"); if (!request_uri) error(400); if (request_trash) error(400); if (request_protocol !~ /^HTTP\/1\.[01]$/) error(505); file = uri_file(request_uri); if (request_method == "GET") method_get(request_uri, file); else if (request_method == "HEAD") method_head(request_uri, file); else error(405); } # FUNCTIONS function uri_file(uri, doc_root, file) { if((environment["remote_host"] in server_root) || (substr(match(environment["remote_host"], /:/), 1, RSTART - 1) in \ server_root)) doc_root = server_root[environment["remote_host"]]; else doc_root = server_root[default_domain]; file = uri; if (file ~ /\/\.\./) error(403); if (file ~ /\/\.[^\/]*$/) error(403); if (file ~ /^\//) { if (match(file, /\?.*$/)) file = substr(uri, 1, RSTART - 1); if (file ~ /\/$/) file = file directory_index; return(doc_root file); } else error(403) } function method_get(uri, file) { send_head(uri, file); send_body(uri, file); } function method_head(uri, file) { send_body(uri, file); } function send_head(uri, file, code, content_type) { if (file_exists(file) < 0) { if (fatal_error) fatal(); error(404); } if (!code) code = 200; match(file, /\.[^.]+$/); content_type = get_content_type(substr(file, RSTART + 1)); if(content_type == "") content_type = default_content_type; print "HTTP/1.0 " code " " server_status[code] "\r"; print "Content-Type: " content_type "\r"; print "\r"; } function send_body(uri, file) { while (getline < file > 0) print; close(file); } function error(code, error_doc) { fatal_error = 1; error_doc = server_root["error"] "/" server_status_document[code]; send_head(uri, error_doc, code); if (request_method == "HEAD") send_body(uri, error_doc); syslog(code " " (ERRNO ? ERRNO : server_status[code]), "err"); exit(code); } function fatal() { print "HTTP/1.0 500 " server_status[500] "\r" print "Content-Type: text/plain\r" print "\r" print server_status[500] "\r" syslog(ERRNO, "crit") exit(500) } function get_content_type(ext, s, a, i, r) { while (getline s < content_types > 0) { if (/^[ \t]*#/) continue; i = split(s, a); while (--i > 1) { if (a[i] == ext) { r = a[1]; break; } } } close(content_types); return((r == "") ? default_content_type : r); } function file_exists(file_name, r, s) { r = getline s < file_name; close(file_name); return(r); } function syslog(message, facility) { if (facility == "") facility = syslog_default_facility; system(syslog_program " -t " syslog_tag " -p " syslog_priority "." \ facility " " message); }