parse.c 2.79 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) \
	((pars)->buffer_used - ((pars)->cur_data - (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
httpRequestParserParse(HttpRequestParser this)
{
	char *             line;
	int                cont = 1;

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

				this->state = HTTP_REQUEST_START;
				break;

			case HTTP_REQUEST_START:
				if (NULL == (line = httpRequestParserGetLine(&(this->cur_data)))) {
					cont = 0;
					break;
				}
				
				httpRequestParserGetRequestLine(this->cur_request, line);

				this->state = HTTP_REQUEST_REQUEST_LINE_DONE;
				break;

			case HTTP_REQUEST_REQUEST_LINE_DONE:
				if (NULL == (line = httpRequestParserGetLine(&(this->cur_data)))) {
					cont = 0;
					break;
				}

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

				httpRequestParserGetHeader(this->cur_request, line);
				break;

			case HTTP_REQUEST_HEADERS_DONE:
				{
					char * nbody;

					if (0 == this->cur_request->nbody) {
						nbody = httpHeaderGet(
								&(this->cur_request->header),
								"Content-Length");

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

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

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

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

				this->buffer_used -= this->cur_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: