httpRequest.c 7.38 KB
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>

#include "../../include/appConfig.h"
#include "../../include/httpRequest.h"
#include "../../include/client.h"

#define SPACE   0x20


char httpRequest[8][8] = {
    "OPTIONS",
    "GET",
    "HEAD",
    "POST",
    "PUT",
    "DELETE",
    "TRACE",
    "CONNECT"
};

/*
 * Gedanken zum request einlese:
 * der client liest stumpf daten, außerdem implementiert er eine Methode um die
 * erste Zeile aus dem readbuffer zu entfernen.
 * Des weiteren eine Methode getLine die NULL zurück gibt wenn noch keine Zeile
 * komplett ist, ansonsten einen Pointer auf diese.
 * Der servercode triggert das Daten lesen des client, versucht dann die erste
 * Zeile zu lesen und gibt diese im erfolgsfall an den httpCode weiter um
 * dann wenn dieser ein OK gibt die erste Zeile über den clientCode wieder zu entfernen.
 * Leere Zeile vor der request line werden ignoriert.
 * Ebenso leere Zailen nachdem der request komplett eingelesen ist.
 * Nachdem alle Header Zeile eingelesen wurden...d.H. sobald eine leere Header Zeile
 * gelesen wurde wird exakt bodyLength vom client versucht zu lesen...hierbei
 * können die Daten die von client kommen in den body buffer übertragen werden.
 * Dabei kann im client code der buffer immer entsprechend zurück gesetzt werden.
 */
int
httpHeaderGetLine(tHttpHeader * header, char ** buffer, unsigned int * readPos)
{
    return 1;
}

void
httpHeaderParseRequestLine(tHttpHeader * header, const char * line, unsigned int len)
{
}

int
httpHeaderIsComplete(tHttpHeader * header)
{
    if (NULL == header->req.method) {
        return 0;
    }

    return 1;
}

unsigned char
httpHeaderIsStarted(tHttpHeader * header) {
    return 1;
}

static void
httpRequestStrip(char ** buffer, unsigned int * readPos)
{
    char * end = *buffer;

    /* remove all surrounding CRLF */
    while (('\r' == *end || '\n' == *end) && *end) {
        end++;
    }

    if (end != *buffer) {
        memmove(*buffer, end, *readPos - (end - *buffer));
        memset(*buffer, 0, end - *buffer);

        *readPos -= (end - * buffer);
    }
}

int
httpHeaderGet(char ** buffer, unsigned int * readPos, tHttpHeader * request)
{
    char *       end = *buffer;
    unsigned int readPosNew;

    httpRequestStrip(buffer, readPos);
    end = strstr(*buffer, "\r\n\r\n");

    /* get header if not already read and complete */
    if (!httpHeaderIsComplete(request) && NULL != end) {
        /* get request line */
        char * methodEnd = strchr(*buffer, SPACE);
        char * uriEnd    = strchr(methodEnd + 1, SPACE);
        char * lineEnd   = strstr(*buffer, "\r\n");

        request->req.method      =
            calloc(methodEnd-*buffer+1, sizeof(char));
        request->req.requestUri  =
            calloc(uriEnd-methodEnd, sizeof(char));
        request->req.httpVersion =
            calloc(lineEnd-uriEnd, sizeof(char));

        sscanf(*buffer, "%s %s %s\r\n",
                request->req.method,
                request->req.requestUri,
                request->req.httpVersion);

        readPosNew = (*buffer + *readPos) - lineEnd - 2;
        memmove(*buffer, lineEnd + 2, readPosNew);
        memset(*buffer + readPosNew, 0, *readPos - readPosNew);
        *readPos   = readPosNew;

        /* get all header lines */
        do {
            char * keyEnd   = strchr(*buffer, ':');

            lineEnd = strstr(*buffer, "\r\n");

            if (lineEnd != *buffer) {
                tHttpHeaderLine * actHeader;
                char *            actKey = NULL;

                request->headersCount += 1;

                request->headers = realloc(request->headers,
                            request->headersCount * sizeof(tHttpHeaderLine));
                actHeader = &(request->headers[request->headersCount-1]);
                memset(actHeader, 0, sizeof(tHttpHeaderLine));

                actKey = actHeader->key = calloc(keyEnd-*buffer+1, sizeof(char));
                actHeader->value = calloc(lineEnd-keyEnd-1, sizeof(char));

                sscanf(*buffer, "%[^:]:%s\r\n",
                        actHeader->key, actHeader->value);
                //while (NULL != actKey && *actKey != '\0' && (*actKey = tolower(*(actKey++)))); // strtolower
                for (; NULL != actKey && *actKey != '\0'; actKey++) {
                    *actKey = tolower(*actKey);
                }

                if (0 == strncmp("content-length", actHeader->key, strlen(actHeader->key))) {
                    request->bodyLength = atoi(actHeader->value);
                }
            }

            readPosNew = (*buffer + *readPos) - lineEnd - 2;
            memmove(*buffer, lineEnd + 2, readPosNew);
            memset(*buffer + readPosNew, 0, *readPos - readPosNew);
            *readPos   = readPosNew;
        } while (lineEnd != *buffer);

        return request->bodyLength;
    }

    return 0;
}

int
getHttpRequest(char ** buffer, unsigned int * readPos, tHttpRequest * request)
{
    /* get body if header is read and body incomplete */
    if (request->header.bodyLength != request->length) {
        size_t size = MIN(
                request->header.bodyLength - request->length,
                *readPos);

        if (0 != size) {
            if (NULL == request->body) {
                request->body = calloc(request->header.bodyLength, sizeof(char));
            }

            memcpy(request->body + request->length, *buffer, size);
            memmove(*buffer, *buffer + size, *readPos - size);
            memset(*buffer + (*readPos - size), 0, size);
            *readPos -= size;
            request->length += size;
        }
    }

    return 0;
}

void
freeHttpHeader(tHttpHeader * header) {
    unsigned int i;

    if (NULL != header->req.method) {
        free(header->req.method);
    }
    if (NULL != header->req.requestUri) {
        free(header->req.requestUri);
    }
    if (NULL != header->req.httpVersion) {
        free(header->req.httpVersion);
    }

    for (i=0; i<header->headersCount; i++) {
        if (NULL != header->headers[i].key) {
            free(header->headers[i].key);
        }
        if (NULL != header->headers[i].value) {
            free(header->headers[i].value);
        }
    }

    if (NULL != header->headers) {
        free(header->headers);
    }

    memset (header, 0, sizeof (tHttpHeader));
}

void
freeHttpRequest(tHttpRequest * request) {
    unsigned int i;

    if (NULL != request->header.req.method) {
        free(request->header.req.method);
        request->header.req.method = NULL;
    }
    if (NULL != request->header.req.requestUri) {
        free(request->header.req.requestUri);
        request->header.req.requestUri = NULL;
    }
    if (NULL != request->header.req.httpVersion) {
        free(request->header.req.httpVersion);
        request->header.req.httpVersion = NULL;
    }

    for (i=0; i<request->header.headersCount; i++) {
        if (NULL != request->header.headers[i].key) {
            free(request->header.headers[i].key);
            request->header.headers[i].key = NULL;
        }
        if (NULL != request->header.headers[i].value) {
            free(request->header.headers[i].value);
            request->header.headers[i].value = NULL;
        }
    }

    if (NULL != request->header.headers) {
        free(request->header.headers);
        request->header.headers = NULL;
    }

    if (NULL != request->body) {
        free(request->body);
        request->body = NULL;
    }

    memset (request, 0, sizeof (tHttpRequest));
}