UNIXworkcode

1 /* 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. 3 * 4 * Copyright 2013 Olaf Wintermann. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26 * POSSIBILITY OF SUCH DAMAGE. 27 */ 28 29 #include <stdio.h> 30 #include <stdlib.h> 31 32 #include "httpparser.h" 33 #include "../public/nsapi.h" 34 //include "request.h" 35 36 37 HttpParser* http_parser_new(HTTPRequest *request) { 38 HttpParser *parser = calloc(1, sizeof(HttpParser)); 39 parser->request = request; 40 41 parser->state = 0; 42 parser->start_line.ptr = (char*)request->netbuf->inbuf; 43 parser->start_line.length = 0; 44 45 parser->offset = 0; 46 47 return parser; 48 } 49 50 void http_parser_free(HttpParser *parser) { 51 free(parser); 52 } 53 54 int http_parser_process(HttpParser *parser) { 55 switch(parser->state) { 56 case 0: { 57 int r = get_start_line(parser); 58 switch(r) { 59 case 0: break; 60 default: return r; 61 } 62 parse_request_line(parser); 63 parser->state++; 64 } 65 case 1: { 66 return http_parser_parse_header(parser); 67 } 68 case 2: { 69 return 0; 70 } 71 } 72 return -1; 73 } 74 75 int http_parser_validate(HttpParser *parser) { 76 HTTPRequest *req = parser->request; 77 if( 78 !req->method.ptr || req->method.length == 0 79 || !req->uri.ptr || req->uri.length == 0 80 || !req->httpv.ptr || req->httpv.length == 0) 81 { 82 return 0; 83 } 84 return 1; 85 } 86 87 int get_start_line(HttpParser *parser) { 88 netbuf *buf = parser->request->netbuf; 89 while(buf->pos < buf->cursize) { 90 unsigned char c = buf->inbuf[buf->pos]; 91 if(c == '\n') { 92 size_t lnlen = buf->pos - parser->offset + 1; 93 if(lnlen <= 2) { 94 if(lnlen == 1 || buf->inbuf[buf->pos-1] == '\r') { 95 // skip empty line 96 buf->pos++; 97 parser->offset = buf->pos; 98 return 1; 99 } 100 // insufficient chars for request, return error 101 return 2; 102 } 103 if(buf->inbuf[buf->pos - 1] == '\r') { 104 parser->start_line.length = lnlen - 1; 105 } else { 106 parser->start_line.length = lnlen; 107 } 108 parser->start_line.ptr = (char*)buf->inbuf + parser->offset; 109 buf->pos++; 110 return 0; 111 } 112 buf->pos++; 113 } 114 return 1; 115 } 116 117 int http_parser_parse_header(HttpParser *parser) { 118 netbuf *buf = parser->request->netbuf; 119 120 parser->offset = buf->pos; // line offset 121 parser->name.ptr = NULL; 122 parser->name.length = 0; 123 parser->value.ptr = NULL; 124 parser->value.length = 0; 125 while(1) { 126 if(buf->pos >= buf->cursize) { 127 return 1; 128 } 129 char c = (char)buf->inbuf[buf->pos++]; 130 131 if(c > 32) { 132 parser->wl = 0; 133 if(c == ':' && parser->value.ptr == NULL) { 134 parser->name.ptr = (char*)buf->inbuf + parser->offset; 135 parser->name.length = buf->pos - parser->offset - 1; 136 } else if(parser->name.ptr != NULL && parser->value.ptr == NULL) { 137 parser->value.ptr = (char*)buf->inbuf + buf->pos - 1; 138 } 139 } else if(c == '\n') { 140 if(parser->wl) { 141 // line contains only white space -> end of request 142 parser->state++; 143 return 0; 144 } else { 145 parser->offset = buf->pos; 146 if(parser->name.length != 0) { 147 if(parser->value.ptr) { 148 parser->value.length = (buf->inbuf + buf->pos - 1) 149 - (unsigned char*)parser->value.ptr; 150 if(buf->inbuf[buf->pos-2] == '\r') { 151 parser->value.length--; 152 } 153 } else { 154 parser->value.ptr = ""; 155 } 156 // add header 157 header_add( 158 parser->request->headers, 159 parser->name, 160 parser->value); 161 } else { 162 // error: no value 163 return 2; 164 } 165 parser->name.ptr = NULL; 166 parser->value.ptr = NULL; 167 parser->name.length = 0; 168 parser->value.length = 0; 169 parser->wl = 1; 170 } 171 } 172 } 173 } 174 175 int parse_request_line(HttpParser *parser) { 176 cxmutstr line = parser->start_line; 177 parser->request->request_line = line; 178 179 /* 180 * parse method, url and http version 181 */ 182 183 int i = 0; 184 int ns = 0; 185 186 parser->request->method.ptr = line.ptr; 187 for(;i<line.length;i++) { 188 if(!ns && line.ptr[i] == ' ') { 189 ns = 1; 190 parser->request->method.length = i; 191 } else if(ns) { 192 if(line.ptr[i] != ' ') { 193 break; 194 } 195 } 196 } 197 198 parser->request->uri.ptr = line.ptr + i; 199 ns = 0; 200 int s = i; 201 for(;i<line.length;i++) { 202 if(!ns && isspace(line.ptr[i])) { 203 ns = 1; 204 parser->request->uri.length = i - s; 205 } else if(ns) { 206 if(line.ptr[i] > 32) { 207 break; 208 } 209 } 210 } 211 212 parser->request->httpv.ptr = line.ptr + i; 213 ns = 0; 214 s = i; 215 for(;i<line.length;i++) { 216 if(!ns && isspace(line.ptr[i])) { 217 ns = 1; 218 parser->request->httpv.length = i - s; 219 } else if(ns) { 220 if(line.ptr[i] > 32) { 221 break; 222 } 223 } 224 } 225 226 return 0; 227 } 228