/** * \file * * \author Georg Hopp * * \copyright * Copyright (C) 2012 Georg Hopp * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ #include <unistd.h> #include <sys/stat.h> #include "class.h" #include "interface/class.h" #include "http/message.h" #include "http/response.h" #include "http/response/writer.h" #include "cbuf.h" #define MIN(x,y) ((x) < (y) ? (x) : (y)) #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; int cont = 1; if (cbufIsLocked(this->buffer)) { if (FALSE == this->ourLock) return 0; } else { cbufLock(this->buffer); this->ourLock = TRUE; } 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; this->written = 0; this->nbody = 0; this->nheader = httpMessageHeaderSizeGet(message); httpMessageHeaderToString(message, cbufGetWrite(this->buffer)); cbufIncWrite(this->buffer, this->nheader); this->state = HTTP_RESPONSE_WRITE; } else { cbufRelease(this->buffer); this->ourLock = FALSE; cont = 0; } break; case HTTP_RESPONSE_WRITE: /** * read */ if (this->nbody < message->nbody) { size_t size = MIN( message->nbody - this->nbody, cbufGetFree(this->buffer)); switch (message->type) { case HTTP_MESSAGE_BUFFERED: cbufSetData(this->buffer, message->body + this->nbody, size); break; case HTTP_MESSAGE_PIPED: size = cbufRead(this->buffer, message->handle); break; default: return -1; } this->nbody += size; } /** * write */ { ssize_t written = cbufWrite(this->buffer, fd); if (0 <= written) { this->written += written; } else { return -1; } } 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); } this->state = HTTP_RESPONSE_GET; memmove(respq->msgs, &(respq->msgs[1]), sizeof(void*) * (--respq->nmsgs + 1)); if (! httpMessageHasKeepAlive(message)) { /** * if the message did not have the keep-alive feature * we don't care about further pipelined messages and * return to the caller with a -1 indicating that the * underlying connection should be closed. */ cbufRelease(this->buffer); this->ourLock = FALSE; delete(this->cur_response); return -1; } cbufRelease(this->buffer); this->ourLock = FALSE; delete(this->cur_response); break; } } return respq->nmsgs; } // vim: set ts=4 sw=4: