server 0.0.1
basicserverinfrastructure

src/http/request_parser.c

Go to the documentation of this file.
00001 #include <stdlib.h>
00002 #include <string.h>
00003 #include <stdlib.h>
00004 #include <stdio.h>
00005 #include <unistd.h>
00006 #include <ctype.h>
00007 #include <sys/types.h>
00008 
00009 #include "class.h"
00010 #include "http/request_parser.h"
00011 #include "interface/class.h"
00012 #include "interface/stream_reader.h"
00013 #include "http/request.h"
00014 #include "http/request_queue.h"
00015 
00016 static
00017 void
00018 httpRequestParserParse(HttpRequestParser);
00019 
00020 static
00021 void
00022 ctor(void * _this, va_list * params)
00023 {
00024         HttpRequestParser this = _this;
00025 
00026         this->request_queue = new(HttpRequestQueue);
00027 
00028         this->buffer = malloc(HTTP_REQUEST_PARSER_READ_CHUNK);
00029         this->buffer[0] = 0;
00030 }
00031 
00032 static
00033 void
00034 dtor(void * _this)
00035 {
00036         HttpRequestParser this = _this;
00037 
00038         free(this->buffer);
00039         delete(&(this->request_queue));
00040 } 
00041 
00042 static
00043 void
00044 _clone(void * _this, void * _base)
00045 {
00046         HttpRequestParser this = _this;
00047         HttpRequestParser base = _base;
00048         size_t            chunks;
00049 
00053         this->request_queue = new(HttpRequestQueue);
00054         this->buffer_used   = base->buffer_used;
00055 
00056         chunks = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK;
00057         chunks++;
00058 
00059         this->buffer = malloc(chunks * HTTP_REQUEST_PARSER_READ_CHUNK);
00060         memcpy(this->buffer, base->buffer, this->buffer_used);
00061 }
00062 
00063 static
00064 size_t
00065 get_data(void * _this, int fd)
00066 {
00067         HttpRequestParser this = _this;
00068         size_t            remaining, chunks;
00069         char              buffer[1024];
00070 
00071         size_t size = read(fd, buffer, 1024);
00072 
00073         if (0 < size) {
00074                 remaining = this->buffer_used % HTTP_REQUEST_PARSER_READ_CHUNK;
00075                 chunks    = this->buffer_used / HTTP_REQUEST_PARSER_READ_CHUNK;
00076 
00085                 chunks++;
00086 
00087                 if (size >= remaining) {
00088                         this->buffer =
00089                                 realloc(this->buffer, chunks * HTTP_REQUEST_PARSER_READ_CHUNK);
00090                 }
00091 
00092                 memcpy(this->buffer + this->buffer_used, buffer, size);
00093                 this->buffer_used += size;
00094                 this->buffer[this->buffer_used] = 0;
00095 
00096                 httpRequestParserParse(this);
00097         }
00098 
00099         return size;
00100 }
00101 
00102 INIT_IFACE(Class, ctor, dtor, _clone);
00103 INIT_IFACE(StreamReader, get_data);
00104 CREATE_CLASS(HttpRequestParser, NULL, IFACE(Class), IFACE(StreamReader));
00105 
00106 static
00107 inline
00108 char *
00109 httpRequestLineGet(char ** data)
00110 {
00111         char * line_end = strstr(*data, "\r\n");
00112         char * ret      = *data;
00113 
00114         if (NULL == line_end) {
00115                 return NULL;
00116         }
00117 
00118         *line_end = 0;
00119         *data = line_end + 2;
00120 
00121         return ret;
00122 }
00123 
00124 static
00125 inline
00126 void
00127 httpRequestSkip(char ** data)
00128 {
00129         for (; 0 != **data && ! isalpha(**data); (*data)++);
00130 }
00131 
00132 static
00133 void
00134 httpRequestParserParse(HttpRequestParser this)
00135 {
00136         static HttpRequest request  = NULL;
00137         static char *      data; // static pointer to unprocessed data
00138         char *             line;
00139         int                cont = 1;
00140         static int         header_idx;
00141 
00142         while(cont) {
00143                 switch(this->state) {
00144                         case HTTP_REQUEST_GARBAGE:
00145                                 data = this->buffer; // initialize static pointer
00146                                 httpRequestSkip(&data);
00147                                 request = new(HttpRequest);
00148 
00149                                 this->state = HTTP_REQUEST_START;
00150                                 break;
00151 
00152                         case HTTP_REQUEST_START:
00153                                 if (NULL == (line = httpRequestLineGet(&data))) {
00154                                         cont = 0;
00155                                         break;
00156                                 }
00157                                 
00158                                 {
00159                                         char * delim = strchr(line, ' ');
00160 
00161                                         if (NULL != delim) {
00162                                                 *delim = 0;
00163                                                 request->method = malloc(strlen(line) + 1);
00164                                                 strcpy(request->method, line);
00165                                                 line = delim + 1;
00166 
00167                                                 for (; *line == ' ' && *line != 0; line++);
00168 
00169                                                 if (0 != *line) {
00170                                                         delim = strchr(line, ' ');
00171 
00172                                                         if (NULL != delim) {
00173                                                                 *delim = 0;
00174                                                                 request->uri = malloc(strlen(line) + 1);
00175                                                                 strcpy(request->uri, line);
00176                                                                 line = delim + 1;
00177 
00178                                                                 for (; *line == ' ' && *line != 0; line++);
00179 
00180                                                                 if (0 != *line) {
00181                                                                         request->http_version = malloc(strlen(line) + 1);
00182                                                                         strcpy(request->http_version, line);
00183                                                                 }
00184                                                         }
00185                                                 }
00186                                         }
00187                                 }
00188 
00189                                 header_idx = 0;
00190                                 this->state = HTTP_REQUEST_REQUEST_LINE_DONE;
00191                                 break;
00192 
00193                         case HTTP_REQUEST_REQUEST_LINE_DONE:
00194                                 if (NULL == (line = httpRequestLineGet(&data))) {
00195                                         cont = 0;
00196                                         break;
00197                                 }
00198 
00199                                 if (0 == strlen(line)) {
00200                                         this->state = HTTP_REQUEST_HEADERS_DONE;
00201                                         break;
00202                                 }
00203 
00204                                 {
00205                                         char * delim = strchr(line, ':');
00206 
00207                                         *delim = 0;
00208                                         (request->header)[header_idx].name = malloc(strlen(line) + 1);
00209                                         strcpy((request->header)[header_idx].name, line);
00210 
00211                                         line = delim + 1;
00212                                         for (; *line == ' ' && *line != 0; line++);
00213 
00214                                         (request->header)[header_idx].value = malloc(strlen(line) + 1);
00215                                         strcpy((request->header)[header_idx].value, line);
00216                                 }
00217 
00218                                 header_idx++;
00219                                 break;
00220 
00221                         case HTTP_REQUEST_HEADERS_DONE:
00225                                 this->state = HTTP_REQUEST_DONE;
00226                                 break;
00227 
00228                         case HTTP_REQUEST_DONE:
00232                                 this->request_queue->requests[(this->request_queue->nrequests)++] =
00233                                         request;
00234 
00238                                 memmove(this->buffer,
00239                                                 data,
00240                                                 this->buffer_used - (data - this->buffer) + 1);
00241 
00242                                 this->buffer_used -= data - this->buffer;
00243 
00247                                 if (0 == this->buffer_used) {
00248                                         cont = 0;
00249                                 }
00250 
00254                                 this->state = HTTP_REQUEST_GARBAGE;
00255 
00256                                 break;
00257 
00258                         default:
00259                                 break;
00260                 }
00261         }
00262 }
00263 
00264 // vim: set ts=4 sw=4:
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Defines