Use SOCK_SEQPACKET between processes to ensure EOF receipt. Probably only works on...
[ashd.git] / src / htparser.c
index 3a788ac..1a45ea1 100644 (file)
@@ -31,6 +31,7 @@
 #include <utils.h>
 #include <mt.h>
 #include <log.h>
+#include <req.h>
 
 #define EV_READ 1
 #define EV_WRITE 2
@@ -115,6 +116,134 @@ static int listensock6(int port)
     return(fd);
 }
 
+static size_t readhead(int fd, struct charbuf *buf)
+{
+    int nl;
+    size_t off;
+    
+    int get1(void)
+    {
+       int ret;
+       
+       while(!(off < buf->d)) {
+           sizebuf(*buf, buf->d + 1024);
+           ret = recv(fd, buf->b + buf->d, buf->s - buf->d, MSG_DONTWAIT);
+           if(ret <= 0) {
+               if((ret < 0) && (errno == EAGAIN)) {
+                   block(fd, EV_READ);
+                   continue;
+               }
+               return(-1);
+           }
+           buf->d += ret;
+       }
+       return(buf->b[off++]);
+    }
+
+    nl = 0;
+    off = 0;
+    while(1) {
+       switch(get1()) {
+       case '\n':
+           if(nl)
+               return(off);
+           nl = 1;
+           break;
+       case '\r':
+           break;
+       case -1:
+           return(-1);
+       default:
+           nl = 0;
+           break;
+       }
+    }
+}
+
+#define SKIPNL(ptr) ({                         \
+           int __buf__;                        \
+           if(*(ptr) == '\r')                  \
+               *((ptr)++) = 0;                 \
+           if(*(ptr) != '\n') {                \
+               __buf__ = 0;                    \
+           } else {                            \
+               *((ptr)++) = 0;                 \
+               __buf__ = 1;                    \
+           }                                   \
+           __buf__;})
+static struct htreq *parseraw(char *buf)
+{
+    char *p, *p2, *nl;
+    char *method, *url, *ver;
+    struct htreq *req;
+    
+    if((nl = strchr(buf, '\n')) == NULL)
+       return(NULL);
+    if(((p = strchr(buf, ' ')) == NULL) || (p > nl))
+       return(NULL);
+    method = buf;
+    *(p++) = 0;
+    if(((p2 = strchr(p, ' ')) == NULL) || (p2 > nl))
+       return(NULL);
+    url = p;
+    p = p2;
+    *(p++) = 0;
+    if(strncmp(p, "HTTP/", 5))
+       return(NULL);
+    ver = (p += 5);
+    for(; ((*p >= '0') && (*p <= '9')) || (*p == '.'); p++);
+    if(!SKIPNL(p))
+       return(NULL);
+
+    req = mkreq(method, url, ver);
+    while(1) {
+       if(SKIPNL(p)) {
+           if(*p)
+               goto fail;
+           break;
+       }
+       if((nl = strchr(p, '\n')) == NULL)
+           goto fail;
+       if(((p2 = strchr(p, ':')) == NULL) || (p2 > nl))
+           goto fail;
+       *(p2++) = 0;
+       for(; (*p2 == ' ') || (*p2 == '\t'); p2++);
+       for(nl = p2; (*nl != '\r') && (*nl != '\n'); nl++);
+       if(!SKIPNL(nl))
+           goto fail;
+       reqappheader(req, p, p2);
+       p = nl;
+    }
+    return(req);
+    
+fail:
+    freereq(req);
+    return(NULL);
+}
+
+static void serve(struct muth *muth, va_list args)
+{
+    vavar(int, fd);
+    struct charbuf buf;
+    struct htreq *req;
+    size_t headoff;
+    
+    bufinit(buf);
+    while(1) {
+       buf.d = 0;
+       if((headoff = readhead(fd, &buf)) < 0)
+           goto out;
+       if((req = parseraw(buf.b)) == NULL)
+           goto out;
+       printf("\"%s\", \"%s\", \"%s\", \"%s\"\n", req->method, req->url, req->ver, getheader(req, "host"));
+       freereq(req);
+    }
+    
+out:
+    buffree(buf);
+    close(fd);
+}
+
 static void listenloop(struct muth *muth, va_list args)
 {
     vavar(int, ss);
@@ -126,10 +255,15 @@ static void listenloop(struct muth *muth, va_list args)
        namelen = sizeof(name);
        block(ss, EV_READ);
        ns = accept(ss, (struct sockaddr *)&name, &namelen);
-       block(ns, EV_WRITE);
-       write(ns, "test\n", 5);
-       close(ns);
+       if(ns < 0) {
+           flog(LOG_ERR, "accept: %s", strerror(errno));
+           goto out;
+       }
+       mustart(serve, ns);
     }
+    
+out:
+    close(ss);
 }
 
 static void ioloop(void)
@@ -140,7 +274,7 @@ static void ioloop(void)
     int maxfd;
     int ev;
     
-    while(1) {
+    while(blockers != NULL) {
        FD_ZERO(&rfds);
        FD_ZERO(&wfds);
        FD_ZERO(&efds);
@@ -172,7 +306,8 @@ static void ioloop(void)
                ev |= EV_WRITE;
            if(FD_ISSET(bl->fd, &efds))
                ev = -1;
-           resume(bl->th, ev);
+           if(ev != 0)
+               resume(bl->th, ev);
        }
     }
 }