src/server/httpparser.c

changeset 1
3c066d52342d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/httpparser.c	Tue Sep 06 22:27:32 2011 +0200
@@ -0,0 +1,196 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2011 Olaf Wintermann. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ *   1. Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *
+ *   2. Redistributions in binary form must reproduce the above copyright
+ *      notice, this list of conditions and the following disclaimer in the
+ *      documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "httpparser.h"
+#include "nsapi.h"
+//include "request.h"
+
+
+HttpParser* http_parser_new(HTTPRequest *request) {
+    HttpParser *parser = malloc(sizeof(HttpParser));
+    parser->request = request;
+    
+    parser->state = 0;
+    parser->start_line.ptr = (char*)request->netbuf->inbuf;
+    parser->start_line.length = 0;
+
+    return parser;
+}
+
+void http_parser_free(HttpParser *parser) {
+    free(parser);
+}
+
+int http_parser_process(HttpParser *parser) {
+    switch(parser->state) {
+        case 0: {
+            int r = get_start_line(parser);
+            switch(r) {
+                case 0: break;
+                default: return r;
+            }
+            parse_request_line(parser);
+            parser->state++;
+        }
+        case 1: {
+            return http_parser_parse_header(parser);
+        }
+        case 2: {
+            return 0;
+        }
+    }
+}
+
+int get_start_line(HttpParser *parser) {
+    netbuf *buf = parser->request->netbuf;
+    while(buf->pos < buf->cursize) {
+        unsigned char c = buf->inbuf[buf->pos];
+        if(c == '\n') {
+            if(buf->pos <= 1) {
+                // insufficient chars for request, return error
+                return 2;
+            }
+            if(buf->inbuf[buf->pos - 1] == '\r') {
+                parser->start_line.length = buf->pos;
+            } else {
+                parser->start_line.length = buf->pos + 1;
+            }
+            parser->start_line.ptr = (char*)buf->inbuf;
+            buf->pos++;
+            return 0;
+        }
+        buf->pos++;
+    }
+    return 1;
+}
+
+int http_parser_parse_header(HttpParser *parser) {
+    netbuf *buf = parser->request->netbuf;
+
+    parser->offset = buf->pos; // line offset
+    parser->name.ptr = NULL;
+    parser->value.ptr = NULL;
+    while(1) {
+        if(buf->pos >= buf->cursize) {
+            return 1;
+        }
+        char c = (char)buf->inbuf[buf->pos++];
+
+        if(c > 32) {
+            parser->wl = 0;
+            if(c == ':' && parser->value.ptr == NULL) {
+                parser->name.ptr = (char*)buf->inbuf + parser->offset;
+                buf->inbuf[buf->pos-1] = 0;
+            } else if(parser->name.ptr != NULL && parser->value.ptr == NULL) {
+                parser->value.ptr = (char*)buf->inbuf + buf->pos - 1;
+            }
+        } else if(c == '\n') {
+            if(parser->wl) {
+                // line contains only white space -> end of request
+                parser->state++;
+                return 0;
+            } else {
+                parser->offset = buf->pos;
+                if(parser->value.ptr != NULL) {
+                    buf->inbuf[buf->pos-1] = 0;
+                    // add header
+                    header_add(
+                            parser->request->headers,
+                            parser->name.ptr,
+                            parser->value.ptr);
+                } else {
+                    // error: no value
+                    return 2;
+                }
+                parser->name.ptr = NULL;
+                parser->value.ptr = NULL;
+                parser->wl = 1;
+            }
+        }
+    }
+}
+
+int parse_request_line(HttpParser *parser) {
+    sstr_t line = parser->start_line;
+    parser->request->request_line = line;
+    
+    /*
+     * parse method, url and http version
+     */
+    
+    int i = 0;
+    int ns = 0;
+
+    parser->request->method.ptr = line.ptr;
+    for(;i<line.length;i++) {
+        if(!ns && line.ptr[i] == ' ') {
+            ns = 1;
+            //line.ptr[i] = 0; // TODO: remove
+            parser->request->method.length = i;
+        } else if(ns) {
+            if(line.ptr[i] != ' ') {
+                break;
+            }
+        }
+    }
+
+    parser->request->uri.ptr = line.ptr + i;
+    ns = 0;
+    int s = i;
+    for(;i<line.length;i++) {
+        if(!ns && line.ptr[i] < 33) {
+            ns = 1;
+            //line.ptr[i] = 0; // TODO: remove
+            parser->request->uri.length = i - s;
+        } else if(ns) {
+            if(line.ptr[i] > 32) {
+                break;
+            }
+        }
+    }
+
+    parser->request->httpv.ptr = line.ptr + i;
+    ns = 0;
+    s = i;
+    for(;i<line.length;i++) {
+        if(!ns && line.ptr[i] < 33) {
+            ns = 1;
+            //line.ptr[i] = 0; // TODO: remove
+            parser->request->httpv.length = i - s;
+        } else if(ns) {
+            if(line.ptr[i] > 32) {
+                break;
+            }
+        }
+    }
+
+    return 0;
+}

mercurial