blob: 78a43bd7564fbc41d8d6aa93e7abccaa405b90c5 [file] [log] [blame] [raw]
#define _GNU_SOURCE
#include "http-request.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
// we declare because we need them... implementation comes later.
static struct HttpRequest* request_new(void);
static void request_clear(struct HttpRequest* self);
static void request_destroy(struct HttpRequest* self);
static void request_first(struct HttpRequest* self);
static int request_next(struct HttpRequest* self);
static int request_find(struct HttpRequest* self, char* const name);
static char* request_name(struct HttpRequest* self);
static char* request_value(struct HttpRequest* self);
static int request_is_request(struct HttpRequest* self);
const struct HttpRequestClass HttpRequest = {
// retures an new heap allocated request object
.create = request_new,
// releases the resources used by a request object and keeps it's memory.
.clear = request_clear,
// releases the resources used by a request object and frees it's memory.
.destroy = request_destroy,
// validated that this is a request object
.is_request = request_is_request,
// Header handling
/// restarts the header itteration
.first = request_first,
/// moves to the next header. returns 0 if the end of the list was
/// reached.
.next = request_next,
/// finds a specific header matching the requested string.
/// all headers are lower-case, so the string should be lower case.
/// returns 0 if the header couldn't be found.
.find = request_find,
/// returns the name of the current header in the itteration cycle.
.name = request_name,
/// returns the value of the current header in the itteration cycle.
.value = request_value,
};
////////////////
// The Request object implementation
// The constructor
static struct HttpRequest* request_new(void) {
struct HttpRequest* req = calloc(sizeof(struct HttpRequest), 1);
req->private.is_request = request_is_request;
return req;
}
// the destructor
static void request_destroy(struct HttpRequest* self) {
if (!self || !self->server)
return;
if (self->body_file)
fclose(self->body_file);
self->server = 0;
free(self);
}
// resetting the request
static void request_clear(struct HttpRequest* self) {
if (!self || !self->server)
return;
if (self->body_file)
fclose(self->body_file);
self->method = 0;
self->path = 0;
self->query = 0;
self->version = 0;
self->host = 0;
self->content_length = 0;
self->content_type = 0;
self->upgrade = 0;
self->body_str = 0;
self->body_file = NULL;
self->private.header_hash = 0;
self->private.pos = 0;
self->private.max = 0;
self->private.bd_rcved = 0;
}
// validating a request object
static int request_is_request(struct HttpRequest* self) {
return (self && (self->private.is_request == request_is_request));
}
// implement the following request handlers:
static void request_first(struct HttpRequest* self) {
self->private.pos = 0;
};
static int request_next(struct HttpRequest* self) {
// repeat the following 2 times, as it's a name + value pair
for (int i = 0; i < 2; i++) {
// move over characters
while (self->private.pos < self->private.max &&
self->private.header_hash[self->private.pos])
self->private.pos++;
// move over NULL
while (self->private.pos < self->private.max &&
!self->private.header_hash[self->private.pos])
self->private.pos++;
}
if (self->private.pos == self->private.max)
return 0;
return 1;
}
static int request_find(struct HttpRequest* self, char* const name) {
self->private.pos = 0;
do {
if (!strcasecmp(self->private.header_hash + self->private.pos, name))
return 1;
} while (request_next(self));
return 0;
}
static char* request_name(struct HttpRequest* self) {
if (!self->private.header_hash[self->private.pos])
return NULL;
return self->private.header_hash + self->private.pos;
};
static char* request_value(struct HttpRequest* self) {
if (!self->private.header_hash[self->private.pos])
return NULL;
int pos = self->private.pos;
// move over characters
while (pos < self->private.max && self->private.header_hash[pos])
pos++;
// move over NULL
while (pos < self->private.max && !self->private.header_hash[pos])
pos++;
if (self->private.pos == self->private.max)
return 0;
return self->private.header_hash + pos;
};