HttpHeaders use only stack variables
parent
50a9fe26eb
commit
ea4f370e77
|
@ -2,110 +2,79 @@
|
|||
#include "stdlib.h"
|
||||
#include "string.h"
|
||||
|
||||
#ifndef HTTPHEADERS_SIZE
|
||||
#define HTTPHEADERS_SIZE 20
|
||||
#endif
|
||||
|
||||
|
||||
HttpHeaders::HttpHeaders() : _n(0) {
|
||||
headers = (HttpHeaderNode*) malloc(sizeof(HttpHeaderNode) * HTTPHEADERS_SIZE);
|
||||
}
|
||||
|
||||
void HttpHeaders::set(const char * name, const char * value)
|
||||
{
|
||||
int name_len = strlen(name);
|
||||
int value_len = strlen(value);
|
||||
|
||||
for (int i = 0; i < count(); i++) {
|
||||
if (strcmp(name, headers[i].name) != 0)
|
||||
continue;
|
||||
headers[i].value = (char *) realloc(headers[i].value, value_len + 1);
|
||||
strcpy(headers[i].value, value);
|
||||
return;
|
||||
int i = indexof(name);
|
||||
if (i == -1) {
|
||||
i = _num++;
|
||||
strncpy(_headers[i].name, name, HTTPHEADERS_NAME_SZ -1);
|
||||
}
|
||||
|
||||
// Grow headers if needed
|
||||
if (_n && (_n % HTTPHEADERS_SIZE) == 0) {
|
||||
headers = (HttpHeaderNode*) realloc(headers, sizeof(HttpHeaderNode) * HTTPHEADERS_SIZE * (_n / HTTPHEADERS_SIZE + 1));
|
||||
}
|
||||
|
||||
headers[_n].name = (char *) malloc( name_len + 1);
|
||||
headers[_n].value = (char *) malloc( value_len + 1);
|
||||
strcpy(headers[_n].name, name);
|
||||
strcpy(headers[_n].value, value);
|
||||
_n++;
|
||||
strncpy(_headers[i].value, value, HTTPHEADERS_VALUE_SZ -1);
|
||||
}
|
||||
|
||||
void HttpHeaders::append(const char* name, const char* value) {
|
||||
|
||||
int name_len = strlen(name);
|
||||
int value_len = strlen(value);
|
||||
|
||||
// search for existing node with name and append value
|
||||
for (int i = 0; i < count(); i++) {
|
||||
if (strcmp(name, headers[i].name) != 0)
|
||||
continue;
|
||||
int old_value_len = strlen(headers[i].value);
|
||||
headers[i].value = (char *) realloc(headers[i].value, old_value_len + value_len + 3);
|
||||
strcpy(headers[i].value+old_value_len, ", ");
|
||||
strcpy(headers[i].value+old_value_len+2, value);
|
||||
return;
|
||||
}
|
||||
|
||||
// Grow headers if needed
|
||||
if (_n && (_n % HTTPHEADERS_SIZE) == 0) {
|
||||
headers = (HttpHeaderNode*) realloc(headers, sizeof(HttpHeaderNode) * HTTPHEADERS_SIZE * (_n / HTTPHEADERS_SIZE + 1));
|
||||
}
|
||||
|
||||
// create and store new node with name and value
|
||||
headers[_n].name = (char *) malloc(name_len + 1);
|
||||
headers[_n].value = (char *) malloc(value_len + 1);
|
||||
strcpy(headers[_n].name, name);
|
||||
strcpy(headers[_n].value, value);
|
||||
_n++;
|
||||
}
|
||||
|
||||
char* HttpHeaders::get(const char* name)
|
||||
void HttpHeaders::append(const char * name, const char * value)
|
||||
{
|
||||
for (int i = 0; i < count(); i++) {
|
||||
if (strcmp(name, headers[i].name) == 0)
|
||||
return headers[i].value;
|
||||
}
|
||||
return nullptr;
|
||||
int i = indexof(name);
|
||||
if (i == -1) return set(name, value);
|
||||
|
||||
int val_len = strlen(_headers[i].value);
|
||||
if (val_len == HTTPHEADERS_VALUE_SZ - 3) return;
|
||||
_headers[i].value[val_len++] = ',';
|
||||
_headers[i].value[val_len++] = ' ';
|
||||
strncpy(_headers[i].value + val_len, value, HTTPHEADERS_VALUE_SZ - val_len - 1);
|
||||
}
|
||||
|
||||
char* HttpHeaders::get(const char * name) // TODO make const
|
||||
{
|
||||
int i = indexof(name);
|
||||
if (i == -1) return nullptr;
|
||||
return _headers[i].value;
|
||||
}
|
||||
|
||||
bool HttpHeaders::has(const char* name)
|
||||
{
|
||||
for (int i = 0; i < count(); i++) {
|
||||
if (strcmp(name, headers[i].name) == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
return (indexof(name) != -1);
|
||||
}
|
||||
|
||||
int HttpHeaders::count()
|
||||
unsigned int HttpHeaders::count()
|
||||
{
|
||||
return _n;
|
||||
return _num;
|
||||
}
|
||||
|
||||
int HttpHeaders::length()
|
||||
unsigned int HttpHeaders::length()
|
||||
{
|
||||
int length = 0;
|
||||
for (int i = 0; i < count(); i++) {
|
||||
length += strlen(headers[i].name);
|
||||
length += strlen(headers[i].value);
|
||||
length += 4; // add ': ' and '\r\n'
|
||||
unsigned int len = 0;
|
||||
for (int i = 0; i < _num; i++) {
|
||||
len += strlen(_headers[i].name);
|
||||
len += strlen(_headers[i].value);
|
||||
}
|
||||
return length;
|
||||
len += 2*_num; // count the ': ' between name and value
|
||||
return len;
|
||||
}
|
||||
|
||||
HttpHeaders::~HttpHeaders() {
|
||||
for (int i = 0; i < count(); i++) {
|
||||
free(headers[i].name);
|
||||
free(headers[i].value);
|
||||
}
|
||||
if (headers) {
|
||||
free(headers);
|
||||
headers = nullptr;
|
||||
}
|
||||
void HttpHeaders::write(char * buff, int size)
|
||||
{
|
||||
// TODO: implement
|
||||
}
|
||||
|
||||
int HttpHeaders::indexof( const char * name)
|
||||
{
|
||||
for (int i = 0; i < _num; i++) {
|
||||
if (names_match(name, _headers[i].name)) return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool HttpHeaders::names_match(const char * a, const char * b)
|
||||
{
|
||||
char ac,bc;
|
||||
for (int i = 0; ac=a[i]; i++) {
|
||||
bc = b[i];
|
||||
if (ac == bc) continue;
|
||||
if (ac > 96 && ac < 123) ac -= 32;
|
||||
if (bc > 96 && bc < 123) bc -= 32;
|
||||
if (ac != bc) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,25 +1,40 @@
|
|||
#pragma once
|
||||
|
||||
typedef struct HttpHeaderNode
|
||||
{
|
||||
char* name;
|
||||
char* value;
|
||||
} HttpHeaderNode;
|
||||
#ifndef HTTPHEADERS_BUFFER
|
||||
#define HTTPHEADERS_BUFFER 256
|
||||
#endif
|
||||
|
||||
#ifndef HTTPHEADERS_NUM
|
||||
#define HTTPHEADERS_NUM 16
|
||||
#endif
|
||||
|
||||
#define HTTPHEADERS_NAME_SZ 24
|
||||
#define HTTPHEADERS_VALUE_SZ 104
|
||||
|
||||
struct HttpHeaderField {
|
||||
char name[HTTPHEADERS_NAME_SZ];
|
||||
char value[HTTPHEADERS_VALUE_SZ];
|
||||
};
|
||||
|
||||
class HttpHeaders {
|
||||
public:
|
||||
HttpHeaders();
|
||||
~HttpHeaders();
|
||||
HttpHeaders():
|
||||
_headers(),
|
||||
_num(0)
|
||||
{};
|
||||
|
||||
void set(const char * , const char *);
|
||||
void append(const char *, const char *);
|
||||
char* get(const char*);
|
||||
char* get(const char*); //TODO make const
|
||||
bool has(const char*);
|
||||
int count();
|
||||
int length();
|
||||
unsigned int count();
|
||||
unsigned int length();
|
||||
void write(char *, int);
|
||||
|
||||
private:
|
||||
int _n;
|
||||
HttpHeaderNode* headers;
|
||||
HttpHeaderField _headers[HTTPHEADERS_NUM];
|
||||
unsigned int _num;
|
||||
int indexof( const char *);
|
||||
bool names_match(const char *, const char *);
|
||||
};
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ TEST_CASE("Get and set headers","[HttpHeaders]"){
|
|||
|
||||
// Set 'foo: bar' and check it
|
||||
headers.set("foo","bar");
|
||||
CHECK(strcmp(headers.get("foo"),"bar") == 0);
|
||||
CHECK_THAT(headers.get("foo"), Equals("bar"));
|
||||
CHECK(headers.count() == 1);
|
||||
}
|
||||
|
||||
|
@ -50,24 +50,23 @@ TEST_CASE("Append empty header behaves like set","[HttpHeaders]")
|
|||
CHECK(headers.count() == 1);
|
||||
}
|
||||
|
||||
TEST_CASE("Force headers to grow","[HttpHeaders]") {
|
||||
TEST_CASE("Fill headers","[HttpHeaders]") {
|
||||
HttpHeaders headers;
|
||||
char name[8] = "";
|
||||
char name[HTTPHEADERS_NAME_SZ] = "";
|
||||
strcpy(name, "header");
|
||||
|
||||
for (int i = 0; i < 26; i++) {
|
||||
for (int i = 0; i < HTTPHEADERS_NUM; i++) {
|
||||
name[6] = 0x41 + i;
|
||||
headers.set(name,"Foo");
|
||||
REQUIRE(strcmp(headers.get(name),"Foo") == 0);
|
||||
REQUIRE_THAT(headers.get(name), Equals("Foo"));
|
||||
CHECK(headers.count() == (i+1) );
|
||||
}
|
||||
}
|
||||
|
||||
/* TODO: enable this test case while fixing header case sensitivity
|
||||
TEST_CASE("Header name is case insensitive","[HttpHeaders]") {
|
||||
HttpHeaders headers;
|
||||
|
||||
headers.set("Foo","bar");
|
||||
|
||||
CHECK(headers.has("foo"));
|
||||
}*/
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue