|
server 0.0.1
basicserverinfrastructure
|
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: