parse.c 2.81 KB
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <ctype.h>

#include "http/request_parser.h"
#include "interface/class.h"


#define REMAINS(pars,done) \
	((pars)->buffer_used - ((done) - (pars)->buffer))


static
inline
char *
httpRequestParserGetLine(char ** data)
{
	char * line_end = strstr(*data, "\r\n");
	char * ret      = *data;

	if (NULL == line_end) {
		return NULL;
	}

	*line_end = 0;
	*data = line_end + 2;

	return ret;
}

static
inline
void
httpRequestSkip(char ** data)
{
	for (; 0 != **data && ! isalpha(**data); (*data)++);
}

void httpRequestParserGetRequestLine(HttpRequest, char *);

void
httpRequestParserParse(HttpRequestParser this)
{
	static HttpRequest request  = NULL;
	static char *      data; // static pointer to unprocessed data
	char *             line;
	int                cont = 1;

	while(cont) {
		switch(this->state) {
			case HTTP_REQUEST_GARBAGE:
				data = this->buffer; // initialize static pointer
				httpRequestSkip(&data);
				request = new(HttpRequest);

				this->state = HTTP_REQUEST_START;
				break;

			case HTTP_REQUEST_START:
				if (NULL == (line = httpRequestParserGetLine(&data))) {
					cont = 0;
					break;
				}
				
				httpRequestParserGetRequestLine(request, line);

				this->state = HTTP_REQUEST_REQUEST_LINE_DONE;
				break;

			case HTTP_REQUEST_REQUEST_LINE_DONE:
				if (NULL == (line = httpRequestParserGetLine(&data))) {
					cont = 0;
					break;
				}

				if (0 == strlen(line)) {
					this->state = HTTP_REQUEST_HEADERS_DONE;
					break;
				}

				httpRequestParserGetHeader(request, line);
				break;

			case HTTP_REQUEST_HEADERS_DONE:
				httpHeaderSort(request->header, request->nheader);

				{
					char * nbody;

					if (0 == request->nbody) {
						nbody = httpHeaderGet(
								request->header,
								request->nheader,
								"Content-Length");

						if (NULL == nbody) {
							this->state = HTTP_REQUEST_DONE;
							break;
						}
						else {
							request->nbody = atoi(nbody);
						}
					}

					if (REMAINS(this, data) >= request->nbody) {
						request->body = calloc(1, request->nbody + 1);
						memcpy(request->body, data, request->nbody);
						data += request->nbody;
						this->state = HTTP_REQUEST_DONE;
					}
				}
					
				break;

			case HTTP_REQUEST_DONE:
				/**
				 * enqueue current request
				 */
				this->request_queue->requests[(this->request_queue->nrequests)++] =
					request;

				/**
				 * remove processed stuff from input buffer.
				 */
				memmove(this->buffer, data, REMAINS(this, data));

				this->buffer_used -= data - this->buffer;

				/**
				 * dont continue loop if input buffer is empty
				 */
				if (0 == this->buffer_used) {
					cont = 0;
				}

				/**
				 * prepare for next request
				 */
				this->state = HTTP_REQUEST_GARBAGE;

				break;

			default:
				break;
		}
	}
}

// vim: set ts=4 sw=4: