Wed, 27 Nov 2024 23:00:07 +0100
add TODO to use a future ucx feature
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2013 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 "../public/nsapi.h" //include "request.h" HttpParser* http_parser_new(HTTPRequest *request) { HttpParser *parser = calloc(1, sizeof(HttpParser)); parser->request = request; parser->state = 0; parser->start_line.ptr = (char*)request->netbuf->inbuf; parser->start_line.length = 0; parser->offset = 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; } } return -1; } int http_parser_validate(HttpParser *parser) { HTTPRequest *req = parser->request; if( !req->method.ptr || req->method.length == 0 || !req->uri.ptr || req->uri.length == 0 || !req->httpv.ptr || req->httpv.length == 0) { return 0; } return 1; } 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') { size_t lnlen = buf->pos - parser->offset + 1; if(lnlen <= 2) { if(lnlen == 1 || buf->inbuf[buf->pos-1] == '\r') { // skip empty line buf->pos++; parser->offset = buf->pos; return 1; } // insufficient chars for request, return error return 2; } if(buf->inbuf[buf->pos - 1] == '\r') { parser->start_line.length = lnlen - 1; } else { parser->start_line.length = lnlen; } parser->start_line.ptr = (char*)buf->inbuf + parser->offset; 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->name.length = 0; parser->value.ptr = NULL; parser->value.length = 0; 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; parser->name.length = buf->pos - parser->offset - 1; } 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->name.length != 0) { if(parser->value.ptr) { parser->value.length = (buf->inbuf + buf->pos - 1) - (unsigned char*)parser->value.ptr; if(buf->inbuf[buf->pos-2] == '\r') { parser->value.length--; } } else { parser->value.ptr = ""; } // add header header_add( parser->request->headers, parser->name, parser->value); } else { // error: no value return 2; } parser->name.ptr = NULL; parser->value.ptr = NULL; parser->name.length = 0; parser->value.length = 0; parser->wl = 1; } } } } int parse_request_line(HttpParser *parser) { cxmutstr 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; 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 && isspace(line.ptr[i])) { ns = 1; 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 && isspace(line.ptr[i])) { ns = 1; parser->request->httpv.length = i - s; } else if(ns) { if(line.ptr[i] > 32) { break; } } } return 0; }