write.c 3.32 KB
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "class.h"
#include "interface/class.h"
#include "http/message.h"
#include "http/response.h"
#include "http/response/writer.h"

#define MAX(x,y)	((x) > (y) ? (x) : (y))
#define _PSIZE(x)	(MAX((x),RESPONSE_WRITER_MAX_BUF))
#define PSIZE		_PSIZE(this->nheader+message->nbody)

ssize_t
httpResponseWriterWrite(HttpResponseWriter this, int fd)
{
	HttpMessageQueue respq     = this->response_queue;
	HttpMessage      message   = (HttpMessage)this->cur_response;
	ssize_t          processed = (message)? 1 : 0;
	int              cont      = 1;

	while (cont) {
		switch (this->state) {
			case HTTP_RESPONSE_GET:
				if (NULL == this->cur_response && 0 < respq->nmsgs) {
					message            = respq->msgs[0];
					this->cur_response = (HttpResponse)message;
					processed++;

					memmove(respq->msgs,
							&(respq->msgs[1]),
							sizeof(void*) * (--respq->nmsgs + 1));

					this->nbuffer = 0;
					this->written = 0;
					this->pstart  = 0;
					this->nheader = httpMessageHeaderSizeGet(message);
					this->pend    = this->nheader;
					this->pipe    = malloc(PSIZE);
					httpMessageHeaderToString(message, this->pipe);

					this->state = HTTP_RESPONSE_WRITE;
				}
				else {
					cont = 0;
				}
				break;

			case HTTP_RESPONSE_WRITE:
				/**
				 * read
				 */
				if (this->nbuffer < message->nbody) {
					size_t temp = 0;
					size_t rsize;

					this->pend = (PSIZE == this->pend)?
						0 : this->pend;

					rsize = (this->pstart <= this->pend)?
						PSIZE - this->pend :
						this->pstart - 1;

					switch (message->type) {
						case HTTP_MESSAGE_BUFFERED:
							temp = message->nbody - this->nbuffer;
							temp = (rsize<temp)?  rsize : temp;
							memcpy(
									&(this->pipe[this->pend]),
									&(message->body[this->nbuffer]),
									temp);
							break;

						case HTTP_MESSAGE_PIPED:
							temp = read(
									message->handle,
									&(this->pipe[this->pend]),
									rsize);
							break;
					}

					this->nbuffer += temp;
					this->pend    += temp;
				}

				/**
				 * write
				 */
				{
					size_t wsize;
					size_t temp;

					wsize = (this->pstart <= this->pend)?
						this->pend - this->pstart :
						PSIZE - this->pstart;

					temp = write(fd, &(this->pipe[this->pstart]), wsize);

					this->written += temp;
					this->pstart  += temp;

					this->pstart = (PSIZE == this->pstart)?
						0 : this->pstart;
				}

				if (this->written == message->nbody + this->nheader) {
					this->state = HTTP_RESPONSE_DONE;
				}
				else {
					cont = 0;
				}
				break;

			case HTTP_RESPONSE_DONE:
				if (HTTP_MESSAGE_PIPED == message->type) {
					close(message->handle);
				}

				free(this->pipe);

				this->nheader = 0;
				this->nbuffer = 0;
				this->written = 0;
				this->pstart  = 0;
				this->pend    = 0;

				if (! httpMessageHasKeepAlive(message)) {
					/**
					 * if the message did not have the keep-alive feature
					 * we don't care about further pipelined messages and
					 * return the to caller with a 0 indicating that the
					 * underlying connection should be closed.
					 */
					processed = 0;
					cont      = 0;
				}

				delete(&this->cur_response);

	 			this->state = HTTP_RESPONSE_GET;
				break;
		}
	}

	return processed;
}

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