Varie correzioni, completata revisione capitolo sull'I/O su file
[gapil.git] / sources / wwwd.c
index 9fceda5330c020cf5635f43f2a36bdb914e56b76..0b6dfde9a9be2ca3e0ba4d2dcf04ee149e530083 100644 (file)
  *
  * Usage: wwwd -h give all info
  *
- * $Id$ 
- *
  ****************************************************************/
 /* 
  * Include needed headers
  */
 #define _GNU_SOURCE
-#include <string.h>      /* error strings */
-#include <sys/types.h>   /* predefined types */
-#include <unistd.h>      /* include unix standard library */
-#include <arpa/inet.h>   /* IP addresses conversion utiliites */
-#include <sys/socket.h>  /* socket library */
-#include <stdio.h>      /* include standard I/O library */
-#include <time.h>
+#include <sys/types.h>   /* primitive system data types */
+#include <sys/stat.h>    /* file characteristics constants and functions */
+#include <stdlib.h>      /* C standard library */
+#include <stdio.h>      /* standard I/O library */
+#include <unistd.h>      /* unix standard library */
+#include <arpa/inet.h>   /* IP addresses conversion utilities */
+#include <sys/socket.h>  /* socket constants, types and functions */
+#include <time.h>        /* date and time constants, types and functions */
 #include <syslog.h>      /* syslog system functions */
-#include <signal.h>      /* signal functions */
-#include <errno.h>       /* error code */
-#include <stdlib.h>
+#include <signal.h>      /* signal constants, types and functions */
+#include <errno.h>       /* error definitions and routines */
+#include <string.h>      /* C strings library */
+#include <dirent.h>      /* directory operation constants and functions */
 
 #include "Gapil.h"
 
+/* 
+ * Function and globals definitions
+ */
 #define BACKLOG 10
 #define MAXLINE 256
 int demonize  = 1;  /* daemon use option: default is daemon */
 int debugging = 0;  /* debug info printing option: default is no debug */
+struct code_page {
+    char * code; 
+    char * name;
+    char * body;
+};
 
-/* Subroutines declaration */
 void usage(void);
 void ServPage(int sockfd);
 void PrintErr(char * error);
-void print_headers(FILE *file);
-void print_err404(FILE *file, char *filename);
-void print_err400(FILE *file, char *string);
-void print_err500(FILE *file, char *string);
+void print_headers(FILE *file, struct code_page code);
+void print_error(FILE *file, struct code_page page, char * string);
 
-/* Program beginning */
-int main(int argc, char *argv[])
+/*
+ * Main program
+ */int main(int argc, char *argv[])
 {
-/* 
- * Variables definition  
- */
+    /* 
    * Variables definition  
    */
     int list_fd, conn_fd;
-    int waiting = 0;
     int compat = 0;
     int reroot = 0;
+    int reuse = 1;
     char * rootdir;
     pid_t pid;
     struct sockaddr_in cli_add;
@@ -82,7 +88,7 @@ int main(int argc, char *argv[])
      */
     int i;
     opterr = 0;         /* don't want writing to stderr */
-    while ( (i = getopt(argc, argv, "hdicw:r:")) != -1) {
+    while ( (i = getopt(argc, argv, "hwdicr:")) != -1) {
        switch (i) {
        /* 
         * Handling options 
@@ -102,10 +108,9 @@ int main(int argc, char *argv[])
            debugging = 1;
            break;
        case 'w':
-           waiting = strtol(optarg, NULL, 10);
+           reuse = 0;
            break;
        case 'r':
-           printf("chroot\n");
            reroot = 1;
            rootdir = optarg;
            break;
@@ -130,12 +135,12 @@ int main(int argc, char *argv[])
        SignalRestart(SIGCHLD, HandSigCHLD);  /* restarting handler */
     }
     /* create and bind socket */
-    if ( (list_fd = sockbind2(argv[optind], "www", 6, SOCK_STREAM)) < 0) {
+    if ( (list_fd = sockbindopt(argv[optind], "www", 6, 
+                               SOCK_STREAM, reuse)) < 0) {
        return 1;
     }   
     /* chroot if requested */
     if (reroot) {
-       printf("chroot to %s\n", rootdir);
        if (chdir(rootdir)) {
            perror("Cannot find directory to chroot");
            exit(1);
@@ -166,7 +171,6 @@ int main(int argc, char *argv[])
        PrintErr("listen error");
        exit(1);
     }
-    if (waiting) sleep(waiting);
     /* handle echo to client */
     while (1) {
        /* accept connection */
@@ -217,12 +221,12 @@ void usage(void)
 {
     printf("Elementary echo server\n");
     printf("Usage:\n");
-    printf("  echod [-h] \n");
+    printf("  wwwd [-h] \n");
     printf("  -h          print this help\n");
     printf("  -d          write debug info\n");
     printf("  -i          use interactively\n");
     printf("  -c          disable BSD semantics\n");
-    printf("  -w N        wait N sec. before calling accept\n");
+    printf("  -r /path    chroot on /path\n");
     exit(1);
 }
 /*
@@ -234,16 +238,21 @@ void ServPage(int sockfd)
     char outbuf[1024];
     FILE *sock, *file;
     char *line, *copy, *method, *ptr, *filename, *version;
-    char *methods[] = { "GET", "PUT", NULL };
-    char *codes[] = {
-       "200 OK",
-       "400 Bad Request",
-       "404 Not Found",
-       "500 Internal Server Error",
-       NULL
+    char *methods[] = { "GET", "HEAD", NULL };
+    struct code_page codes[] = {
+       { "200", "OK", "%s"},
+       { "400", "Bad Request", 
+          "Your browser sent a request that this server could not understand."
+         "<P>The request line<P>%s<P> is invalid following the protocol<P>"}, 
+       { "404", "Not Found", 
+          "The requested URL %s was not found on this server.<P>"},
+       { "500", "Internal Server Error", 
+          "We got an error processing your request.<P>Error is: %s<P>"},
+       { "405", "Method Not Allowed", "Method %s not allowed.<P>"},
+       { "403", "Forbidden", "You cannot access %s.<P>"}
     };
     int nleft;
-    int i, j;
+    int i;
 
     sock = fdopen(sockfd, "w+");
     /* main loop, reading 0 char means client close connection */
@@ -255,21 +264,18 @@ void ServPage(int sockfd)
     /* parsing first line, getting method and filename */
     copy = strndupa(line, MAXLINE);
     if ((method = strtok_r(copy, " ", &ptr)) == NULL) {
-       fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
-       print_headers(sock);
-       print_err400(sock, line);
+       print_headers(sock, codes[1]);
+       print_error(sock, codes[1], line);
        return;
     }
     if ((filename = strtok_r(NULL, " ", &ptr)) == NULL) {
-       fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
-       print_headers(sock);
-       print_err400(sock, line);
+       print_headers(sock, codes[1]);
+       print_error(sock, codes[1], line);
        return;
     }
     if ((version = strtok_r(NULL, " ", &ptr)) == NULL) {
-       fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
-       print_headers(sock);
-       print_err400(sock, line);
+       print_headers(sock, codes[1]);
+       print_error(sock, codes[1], line);
        return;
     }
     i = 0;
@@ -280,9 +286,8 @@ void ServPage(int sockfd)
        i++;
     }
     if (i>=2) {
-       fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
-       print_headers(sock);
-       print_err400(sock, line);
+       print_headers(sock, codes[4]);
+       print_error(sock, codes[4], method);
        return;
     }
 
@@ -291,31 +296,30 @@ void ServPage(int sockfd)
     }
 
     if ( (file = fopen(filename, "r")) == NULL) {
-       fprintf(sock, "HTTP/1.0 %s\n", codes[2]);
-       print_headers(sock);
-       print_err404(sock, filename);
+       if ( (errno == EACCES)||(errno == EPERM) ) {
+           print_headers(sock, codes[5]);
+           print_error(sock, codes[5], filename);
+       } else {
+           print_headers(sock, codes[2]);
+           print_error(sock, codes[2], filename);
+       }
        return;
     }
-    fprintf(sock, "HTTP/1.0 %s\n", codes[0]);
-    print_headers(sock);
-
-    j = 0;
+    print_headers(sock, codes[0]);
     while (!feof(file)) {
        if ( (nleft = full_fread(file, outbuf, 1024)) != 0) {
            if (ferror(file)) {
-               fprintf(sock, "HTTP/1.0 %s\n", codes[3]);
-               print_headers(sock);
-               snprintf(buffer, MAXLINE, "reading %s", filename);
-               print_err500(sock, buffer);
+               strncpy(buffer, strerror(errno), MAXLINE);
+               print_headers(sock, codes[3]);
+               print_error(sock, codes[3], buffer);
                return;
            }
        }
        if (full_fwrite(sock, outbuf, 1024-nleft) != 0) {
            if (ferror(file)) {
-               fprintf(sock, "HTTP/1.0 %s\n", codes[3]);
-               print_headers(sock);
-               snprintf(buffer, MAXLINE, "writing");
-               print_err500(sock, buffer);
+               strncpy(buffer, strerror(errno), MAXLINE);
+               print_headers(sock, codes[3]);
+               print_error(sock, codes[3], buffer);
                return;
            }   
        }
@@ -337,10 +341,11 @@ void PrintErr(char * error)
     return;
 }
 
-void print_headers(FILE *file)
+void print_headers(FILE *file, struct code_page code)
 {
     time_t tempo;
 
+    fprintf(file, "HTTP/1.0 %s %s \n", code.code, code.name);
     time(&tempo);
     fprintf(file, "Date: %s", ctime(&tempo));
     fprintf(file, "Server: WWWd test server\n");
@@ -350,33 +355,13 @@ void print_headers(FILE *file)
     return;
 }
 
-void print_err404(FILE *file, char *filename)
-{
-    fprintf(file, "<HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD>\n");
-    fprintf(file, "<BODY><H1>Not Found</H1>\nThe requested ");
-    fprintf(file, "URL %s was not found on this server.<P><HR>", filename);
-    fprintf(file, "<ADDRESS>WWWd by Simone Piccardi</ADDRESS></BODY></HTML>");
-    return;
-}
-
-void print_err400(FILE *file, char *string)
+void print_error(FILE *file, struct code_page page, char * string)
 {
-    fprintf(file, "<HTML><HEAD><TITLE>404 Bad Request</TITLE></HEAD>\n");
-    fprintf(file, "<BODY><H1>Bad Request</H1>\n ");
-    fprintf(file, "Your browser sent a request that this server could not ");
-    fprintf(file, "understand.<P>The request line<P> %s <P>", string);
-    fprintf(file, "is invalid following the protocol<p><HR>");
-    fprintf(file, "<ADDRESS>WWWd by Simone Piccardi </ADDRESS></BODY></HTML>");
+    fprintf(file, "<HTML><HEAD><TITLE>%s %s</TITLE></HEAD>\n",
+           page.code, page.name);
+    fprintf(file, "<BODY><H1>%s</H1>\n", page.name);
+    fprintf(file, page.body, string);
+    fprintf(file, "<HR><ADDRESS>WWWd by S. Piccardi</ADDRESS></BODY></HTML>");
     return;
 }
 
-
-void print_err500(FILE *file, char *string)
-{
-    fprintf(file, "<HTML><HEAD><TITLE>500 Internal Server Error</TITLE>\n");
-    fprintf(file, "</HEAD><BODY><H1>Internal Server Error</H1>\n ");
-    fprintf(file, "We got an error processing your request.<P>");
-    fprintf(file, "Error is: %s <P><HR>\n", string);
-    fprintf(file, "<ADDRESS>WWWd by Simone Piccardi </ADDRESS></BODY></HTML>");
-    return;
-}