* Fixed and improved HTTP server logic.
authorUrban Wallasch <urban.wallasch@freenet.de>
Mon, 22 Jul 2019 05:07:11 +0000 (07:07 +0200)
committerUrban Wallasch <urban.wallasch@freenet.de>
Mon, 22 Jul 2019 05:07:11 +0000 (07:07 +0200)
* Added configuration and command line argument processing.
* Fixed and improved script in index.html page.
* Added plain.html page.

index.html
plain.html [new file with mode: 0644]
telehttpd.c

index 5c8c78bad7757d04639b693925f23ea8bfda22fc..4d7e61a810619fd5818a63aedccd94d999b25b47 100644 (file)
@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<meta charset="UTF-8">
 <style>
 html, body {
   width: 100%;
@@ -22,18 +23,17 @@ html, body {
 <div id="cctrl" class="speed">12</div>
 <script>
 function loadDoc() {
-  var xhttp = new XMLHttpRequest();
   xhttp.onreadystatechange = function() {
     if (this.readyState == 4 && this.status == 200) {
-      myObj = JSON.parse(this.responseText);
-      console.log(this.responseText);
-      document.getElementById("speed").innerHTML = Math.round(myObj.speed * 3.6);
-      document.getElementById("cctrl").innerHTML = Math.round(myObj.cctrl * 3.6);
+      tele = JSON.parse(this.responseText);
+      document.getElementById("speed").innerHTML = Math.round(tele.speed * 3.6);
+      document.getElementById("cctrl").innerHTML = Math.round(tele.cctrl * 3.6);
     }
   };
   xhttp.open("GET", "/json", true);
   xhttp.send();
 }
+var xhttp = new XMLHttpRequest();
 loadDoc();
 window.setInterval(loadDoc, 500);
 </script>
diff --git a/plain.html b/plain.html
new file mode 100644 (file)
index 0000000..ee5aa70
--- /dev/null
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="UTF-8">
+</head>
+<body>
+<pre>
+<div id="json">-</div>
+</pre>
+<script>
+function loadDoc() {
+  xhttp.onreadystatechange = function() {
+    if (this.readyState == 4 && this.status == 200) {
+      tele = JSON.parse(this.responseText);
+      document.getElementById("json").innerHTML = JSON.stringify(tele, null, 4);
+    }
+  };
+  xhttp.open("GET", "/json", true);
+  xhttp.send();
+}
+var xhttp = new XMLHttpRequest();
+loadDoc();
+window.setInterval(loadDoc, 500);
+</script>
+
+</body>
+</html>
index e31e62f591440a24b57ab231a61199d200de2609..4bf7e1091404148c483bf56d3dfd70f45d6a3c74 100644 (file)
 #include "log.h"
 #include "shmget.h"
 
+
+struct {
+    int port;
+    char *iface;
+    char *host;
+    char *origin;
+    char *idxfile;
+} cfg = {
+    8837,
+    "*",
+    "localhost",
+    "http://localhost",
+    "index.html",
+};
+
 static volatile int force_quit;
 
 static void handle_signal(int sig) {
@@ -56,79 +71,83 @@ static void write_telejson( int fd ) {
 
 static void respond(int fd, const char *req, int code) {
     char buf[4096];
-    char origin[256] = "http://localhost";
-    char host[256] = "localhost";
+    char origin[256];
+    char host[256];
     const char *s;
+
     switch (code) {
     case r_json:
     case r_index:
-        s = strstr(req, "Origin:");
-        if (s){
+        if ( NULL != (s = strstr(req, "Origin: ")) ) {
             s += 8; //strlen("Origin: ");
             const char *e = strstr(s, "\r\n");
             strncpy(origin, s, e-s);
         }
-        s = strstr(req, "Host:");
-        if (s){
+        else
+            strcpy(origin, cfg.origin);
+
+        if ( NULL != (s = strstr(req, "Host: ")) ) {
             s += 6;//strlen("Host: ");
             const char *e = strstr(s, "\r\n");
             strncpy(host, s, e-s);
         }
+        else
+            strcpy(host, cfg.host);
 
-        write(fd, buf, sprintf (buf, "HTTP/1.1 200 OK\r\n"));
-        write(fd, buf, sprintf (buf, "Host: %s\r\n", host));
         if (r_json == code){
-            write(fd, buf, sprintf (buf, "Access-Control-Allow-Origin: %s\r\n", origin));
-            write(fd, buf, sprintf (buf, "Content-type: text/json\r\n"));
-            write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+            write(fd, buf, sprintf(buf, "HTTP/1.1 200 OK\r\n"));
+            write(fd, buf, sprintf(buf, "Host: %s\r\n", host));
+            write(fd, buf, sprintf(buf, "Access-Control-Allow-Origin: %s\r\n", origin));
+            write(fd, buf, sprintf(buf, "Content-type: text/json\r\n"));
+            write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
             write_telejson(fd);
-        } else {
+        }
+        else {
             struct file_info_t fi;
-            if (0 == fserv_open_server("index.html", &fi)){
-                write(fd, buf, sprintf (buf, "Content-type: text/html\r\n"));
-                write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
+            if (0 == fserv_open_server(cfg.idxfile, &fi)){
+                write(fd, buf, sprintf(buf, "HTTP/1.1 200 OK\r\n"));
+                write(fd, buf, sprintf(buf, "Host: %s\r\n", host));
+                write(fd, buf, sprintf(buf, "Content-type: text/html\r\n"));
+                write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
                 fserv_sendfile(fd, &fi);
                 fserv_close(&fi);
-            } else {
-                write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
-                write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
-                write(fd, buf, sprintf (buf, "Tough luck"));
             }
+            else
+                goto SEND_404;
         }
         break;
     case r_none:
-        write(fd, buf, sprintf (buf, "HTTP/1.1 404 Not Found\r\n"));
-        write(fd, buf, sprintf (buf, "Host: localhost\r\n"));
-        write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
-        write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
-        write(fd, buf, sprintf (buf, "Fuck you 404!"));
+    SEND_404:
+        write(fd, buf, sprintf(buf, "HTTP/1.1 404 Not Found\r\n"));
+        write(fd, buf, sprintf(buf, "Host: localhost\r\n"));
+        write(fd, buf, sprintf(buf, "Content-type: text/plain\r\n"));
+        write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
+        write(fd, buf, sprintf(buf, "404 Not Found"));
         break;
     default:
-        write(fd, buf, sprintf (buf, "HTTP/1.1 500 Internal Server Error\r\n"));
-        write(fd, buf, sprintf (buf, "Host: localhost\r\n"));
-        write(fd, buf, sprintf (buf, "Content-type: text/plain\r\n"));
-        write(fd, buf, sprintf (buf, "Connection: close\r\n\r\n"));
-        write(fd, buf, sprintf (buf, "Fuck you 500!"));
+        write(fd, buf, sprintf(buf, "HTTP/1.1 500 Internal Server Error\r\n"));
+        write(fd, buf, sprintf(buf, "Host: localhost\r\n"));
+        write(fd, buf, sprintf(buf, "Content-type: text/plain\r\n"));
+        write(fd, buf, sprintf(buf, "Connection: close\r\n\r\n"));
+        write(fd, buf, sprintf(buf, "500 Internal Server Error"));
         break;
     }
 }
 
-static int receive(int fd, int timeout) {
+static int rcv_request(int sock, char *buf, size_t size, int timeout) {
+    int res = -1;
+    size_t total = 0;
+    ssize_t bread = 0;
     struct pollfd pe;
-    int res;
-    pe.fd = fd;
-    char buf[2048];
-    int bread, total;
 
-    total = 0;
-    *buf = 0;
+    pe.fd = sock;
     do {
         pe.events = POLLIN;
         pe.revents = 0;
         res = poll(&pe, 1, timeout);
         if ( 0 < res && pe.revents == POLLIN ) {
             errno = 0;
-            bread = read(fd, buf + total, sizeof buf - total);
+            bread = read(sock, buf + total, size - total);
             if ( 0 > bread ) {
                 switch (errno) {
                 case EAGAIN:
@@ -145,64 +164,101 @@ static int receive(int fd, int timeout) {
             }
             else {
                 total += bread;
-                buf[total] = 0;
-                if ( strstr(buf, "\r\n\r\n" ) ) {
-                    fprintf (stderr, "%s", buf);
-                    if (0 == strncmp(buf, "GET /json HTTP", 10))
-                        respond(fd, buf, r_json);
-                    else if (0 == strncmp(buf, "GET / HTTP", 10))
-                        respond(fd, buf, r_index);
-                    else
-                        respond(fd, NULL, r_none);
-                    *buf = 0;
+                if ( strstr(buf, "\r\n\r\n" ) )
                     res = 0;
-                }
             }
         }
         timeout = 200;
     } while ( 1 == res && pe.revents == POLLIN && !force_quit );
+    buf[total] = 0;
     return res;
 }
 
 static void *handle_conn( void *p ) {
     int sock = *(int*)p;
-    int err;
+    char buf[2048];
 
     DPRINT( "sock: %d\n", sock );
-    do {
-        err = receive(sock, 1000);
-    } while ( 0 < err && !force_quit );
+    if ( 0 == rcv_request(sock, buf, sizeof buf, 1000) ) {
+        DPRINT( "request:\n%s", buf);
+        if (0 == strncmp(buf, "GET /json HTTP", 10))
+            respond(sock, buf, r_json);
+        else if (0 == strncmp(buf, "GET / HTTP", 10))
+            respond(sock, buf, r_index);
+        else
+            respond(sock, NULL, r_none);
+    }
     net_close( sock );
-    return p;
+    free( p );
+    return NULL;
 }
 
 static int serve_http(void) {
     int as, ss;
+    int *ps;
     pthread_t tid;
     pthread_attr_t attr;
 
-    ss = net_open_server( 8837, "*" );
+    ss = net_open_server( cfg.port, cfg.iface );
     if ( ss < 0 ) {
         EPRINT( "net_open_server failed!\n" );
         return -1;
     }
 
     while ( !force_quit ) {
-        if ( (as = net_accept( ss )) > 0 ) {
+        if ( 0 < (as = net_accept( ss )) && NULL != (ps = malloc( sizeof *ps )) ) {
+            *ps = as;
             pthread_attr_init(&attr);
             pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
-            pthread_create(&tid, &attr, handle_conn, &as);
-            usleep (100);
+            pthread_create(&tid, &attr, handle_conn, ps);
         }
     }
 
     return 0;
 }
 
+static int config( int argc, char *argv[] ) {
+    int opt;
+    const char *ostr = "+b:h:i:o:p:";
+
+    while ( -1 != ( opt = getopt( argc, argv, ostr ) ) ) {
+        switch ( opt ) {
+        case 'b':
+            cfg.iface = optarg;
+            break;
+        case 'h':
+            cfg.host = optarg;
+            break;
+        case 'i':
+            cfg.idxfile = optarg;
+            break;
+        case 'o':
+            cfg.origin = optarg;
+            break;
+        case 'p':
+            cfg.port = strtol(optarg, NULL, 10);
+            break;
+        case ':':
+            EPRINT( "Missing argument for option '%c'\n", optopt );
+            return -1;
+            break;
+        case '?':
+        default:
+            EPRINT( "Unrecognized option '%c'\n", optopt );
+            return -1;
+            break;
+        }
+    }
+    return 0;
+}
+
 int main(int argc, char *argv[]) {
     signal(SIGTERM, handle_signal);
     signal(SIGINT,  handle_signal);
 
+    if ( 0 != config( argc, argv ) )
+        exit( EXIT_FAILURE);
+
     if ( 0 != init_shm() )
         exit( EXIT_FAILURE);
 
@@ -210,5 +266,4 @@ int main(int argc, char *argv[]) {
         exit( EXIT_FAILURE);
 
     exit( EXIT_SUCCESS );
-    (void)argc; (void)argv;
 }