diff --git a/assets/waldschrat.jpg b/assets/waldschrat.jpg new file mode 100644 index 0000000..880d014 Binary files /dev/null and b/assets/waldschrat.jpg differ diff --git a/include/http/message.h b/include/http/message.h index 8b3459d..fa89b34 100644 --- a/include/http/message.h +++ b/include/http/message.h @@ -16,13 +16,13 @@ CLASS(HttpMessage) { HttpHeader header; HttpMessageType type; - union { - char * buffer; - int handle; - } body; + int handle; + char * body; int nbody; }; +char httpMessageHasKeepAlive(HttpMessage); + #endif // __HTTP_MESSAGE__ // vim: set ts=4 sw=4: diff --git a/include/http/request.h b/include/http/request.h index 79c346d..a0472ab 100644 --- a/include/http/request.h +++ b/include/http/request.h @@ -11,8 +11,6 @@ CLASS(HttpRequest) { char * uri; }; -char httpRequestHasKeepAlive(HttpRequest); - #endif /* __HTTP_REQUEST_H__ */ // vim: set ts=4 sw=4: diff --git a/include/http/response/writer.h b/include/http/response/writer.h index 31aa3d5..cfec228 100644 --- a/include/http/response/writer.h +++ b/include/http/response/writer.h @@ -27,7 +27,7 @@ CLASS(HttpResponseWriter) { HttpResponseState state; }; -size_t httpResponseWriterWrite(HttpResponseWriter, int); +HttpResponse httpResponseWriterWrite(HttpResponseWriter, int); #endif // __HTTP_RESPONSE_WRITER_H__ diff --git a/src/Makefile.am b/src/Makefile.am index 17b90e7..0275541 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -7,8 +7,8 @@ CLASS = class.c interface.c SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c SERVER = server.c server/run.c server/close_conn.c LOGGER = logger.c logger/stderr.c logger/syslog.c -MSG = http/message.c http/message/queue.c -REQ = http/request.c http/request/has_keep_alive.c +MSG = http/message.c http/message/queue.c http/message/has_keep_alive.c +REQ = http/request.c RESP = http/response.c http/response/404.c http/response/size_get.c \ http/response/to_string.c WRITER = http/response/writer.c http/response/writer/write.c diff --git a/src/http/message.c b/src/http/message.c index 5f4f1f3..c9a76a9 100644 --- a/src/http/message.c +++ b/src/http/message.c @@ -43,11 +43,11 @@ dtor(void * _this) switch (this->type) { case HTTP_MESSAGE_BUFFERED: - _free((void **)&((this->body).buffer)); + _free((void **)&(this->body)); break; case HTTP_MESSAGE_PIPED: - close((this->body).handle); + if (2 < this->handle) close(this->handle); break; default: diff --git a/src/http/request/has_keep_alive.c b/src/http/message/has_keep_alive.c similarity index 83% rename from src/http/request/has_keep_alive.c rename to src/http/message/has_keep_alive.c index e34f852..eb53474 100644 --- a/src/http/request/has_keep_alive.c +++ b/src/http/message/has_keep_alive.c @@ -7,9 +7,8 @@ char -httpRequestHasKeepAlive(HttpRequest request) +httpMessageHasKeepAlive(HttpMessage message) { - HttpMessage message = (HttpMessage)request; char * header; char * header_ptr; diff --git a/src/http/request/parser/get_body.c b/src/http/request/parser/get_body.c index 81fc8da..71d5b31 100644 --- a/src/http/request/parser/get_body.c +++ b/src/http/request/parser/get_body.c @@ -26,8 +26,8 @@ httpRequestParserGetBody(HttpRequestParser this) } if (REMAINS(this) >= message->nbody) { - (message->body).buffer = calloc(1, message->nbody + 1); - memcpy((message->body).buffer, + message->body = calloc(1, message->nbody + 1); + memcpy(message->body, this->cur_data, message->nbody); this->cur_data += message->nbody; diff --git a/src/http/response/404.c b/src/http/response/404.c index ed4e457..f59df29 100644 --- a/src/http/response/404.c +++ b/src/http/response/404.c @@ -37,10 +37,10 @@ httpResponse404() httpHeaderAdd(&(message->header), new(HttpHeader, "Server", "testserver")); - message->type = HTTP_MESSAGE_BUFFERED; - message->nbody = sizeof(RESP_DATA) - 1; - (message->body).buffer = calloc(1, sizeof(RESP_DATA)); - strcpy((message->body).buffer, RESP_DATA); + message->type = HTTP_MESSAGE_BUFFERED; + message->nbody = sizeof(RESP_DATA) - 1; + message->body = calloc(1, sizeof(RESP_DATA)); + strcpy(message->body, RESP_DATA); sprintf(buffer, "%d", message->nbody); httpHeaderAdd(&(message->header), diff --git a/src/http/response/to_string.c b/src/http/response/to_string.c index 770c18f..2f4571d 100644 --- a/src/http/response/to_string.c +++ b/src/http/response/to_string.c @@ -49,7 +49,7 @@ httpResponseToString(HttpResponse response, char * _string) *string++ = '\n'; if (HTTP_MESSAGE_BUFFERED == message->type) { - memcpy(string, (message->body).buffer, message->nbody); + memcpy(string, message->body, message->nbody); } return string; diff --git a/src/http/response/writer/write.c b/src/http/response/writer/write.c index a3dda7e..bf4fd8d 100644 --- a/src/http/response/writer/write.c +++ b/src/http/response/writer/write.c @@ -1,26 +1,31 @@ +#include #include #include #include #include +#include +#include #include "class.h" #include "interface/class.h" #include "http/response.h" #include "http/response/writer.h" -size_t +HttpResponse httpResponseWriterWrite(HttpResponseWriter this, int fd) { HttpMessageQueue respq = this->response_queue; int cont = 1; - size_t written = 0; + HttpResponse retval = NULL; while (cont) { switch (this->state) { case HTTP_RESPONSE_NO: if (NULL == this->cur_response && 0 < respq->nmsgs) { - this->cur_response = (HttpResponse)respq->msgs[0]; - memmove(respq->msgs, &(respq->msgs[1]), --respq->nmsgs); + retval = this->cur_response = (HttpResponse)respq->msgs[0]; + memmove(respq->msgs, + &(respq->msgs[1]), + sizeof(void*) * (--respq->nmsgs + 1)); this->state = HTTP_RESPONSE_START; } else { @@ -29,51 +34,86 @@ httpResponseWriterWrite(HttpResponseWriter this, int fd) break; case HTTP_RESPONSE_START: - if (NULL == this->buffer) { - this->nbuffer = httpResponseSizeGet(this->cur_response); - this->buffer = calloc(1, this->nbuffer); - httpResponseToString(this->cur_response, this->buffer); + if (HTTP_MESSAGE_PIPED == + ((HttpMessage)(this->cur_response))->type) { + struct stat st; + HttpMessage message = (HttpMessage)this->cur_response; + char buffer[200]; + + message->handle = + open("./assets/waldschrat.jpg", O_RDONLY); + fstat(message->handle, &st); + message->nbody = st.st_size; + + sprintf(buffer, "%d", message->nbody); + httpHeaderAdd(&(message->header), + new(HttpHeader, "Content-Length", buffer)); + } + + this->state = HTTP_RESPONSE_PIPE; + break; + + case HTTP_RESPONSE_PIPE: { - written = write(fd, this->buffer, this->nbuffer); + HttpMessage message = (HttpMessage)(this->cur_response); + size_t headsize = httpResponseSizeGet(this->cur_response); + + this->buffer = malloc(headsize + message->nbody); + httpResponseToString(this->cur_response, this->buffer); + this->rpipe = headsize; - if (-1 == written) { - free (this->buffer); - this->buffer = NULL; - return written; + if (HTTP_MESSAGE_PIPED == message->type && + 0 != message->handle) { + char * data = &(this->buffer[headsize]); + size_t togo = message->nbody; + + size_t rsize = read(message->handle, data, togo); + + while (rsize < togo) { + data += rsize; + togo -= rsize; + rsize = read(message->handle, data, togo); + } + + this->wpipe = 0; + this->rpipe += message->nbody; + close(message->handle); + message->handle = 0; } - if (written == this->nbuffer) { - if (HTTP_MESSAGE_BUFFERED == - ((HttpMessage)(this->cur_response))->type) { + { + char * data = &(this->buffer[this->wpipe]); + size_t written; + + written = write(fd, data, this->rpipe - this->wpipe); + data += written; + this->wpipe += written; + + if (this->rpipe == this->wpipe) { + this->rpipe = 0; + this->wpipe = 0; + free (this->buffer); + this->buffer = NULL; this->state = HTTP_RESPONSE_DONE; } else { - this->state = HTTP_RESPONSE_PIPE; + cont = 0; } } - else { - this->nbuffer -= written; - memmove(this->buffer, this->buffer + written, this->nbuffer); - cont = 0; - } } break; - case HTTP_RESPONSE_PIPE: - break; - case HTTP_RESPONSE_DONE: - free (this->buffer); - this->buffer = NULL; - delete(&(this->cur_response)); - this->state = HTTP_RESPONSE_NO; + this->state = HTTP_RESPONSE_NO; + this->cur_response = NULL; + cont = 0; break; } } - return written; + return retval; } // vim: set ts=4 sw=4: diff --git a/src/server/run.c b/src/server/run.c index c9069c0..17f0173 100644 --- a/src/server/run.c +++ b/src/server/run.c @@ -6,6 +6,9 @@ #include #include #include +#include +#include +#include #include "server.h" #include "socket.h" @@ -114,16 +117,78 @@ serverRun(Server this) * @TODO: for now simply remove request and send not found. * Make this sane. */ - HttpMessage response = (HttpMessage)httpResponse404(); + HttpRequest request = (HttpRequest)(reqq->msgs[j]); + HttpMessage response = NULL; + + if (0 == strcmp("GET", request->method) && + 0 == strcmp("/me/", request->uri)) { + const char foo[] = + "\n" + "\n" + "\n" + "200 - OK" + "

200 - OK

" + "" + ""; + char buffer[200]; + time_t t; + struct tm * tmp; + + response = (HttpMessage)new(HttpResponse, "HTTP/1.1", 200, "OK"); + + httpHeaderAdd(&(response->header), + new(HttpHeader, "Content-Type", "text/html")); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Server", "testserver")); + + response->type = HTTP_MESSAGE_BUFFERED; + response->nbody = sizeof(foo) - 1; + response->body = calloc(1, sizeof(foo)); + strcpy(response->body, foo); + + sprintf(buffer, "%d", response->nbody); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Content-Length", buffer)); + + t = time(NULL); + tmp = localtime(&t); + strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Date", buffer)); + } + else if (0 == strcmp("GET", request->method) && + 0 == strcmp("/image/", request->uri)) { + char buffer[200]; + time_t t; + struct tm * tmp; + + response = (HttpMessage)new( + HttpResponse, "HTTP/1.1", 200, "OK"); + + httpHeaderAdd(&(response->header), + new(HttpHeader, "Content-Type", "image/jpeg")); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Server", "testserver")); + + response->type = HTTP_MESSAGE_PIPED; + + t = time(NULL); + tmp = localtime(&t); + strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp); + httpHeaderAdd(&(response->header), + new(HttpHeader, "Date", buffer)); + } + else { + response = (HttpMessage)httpResponse404(); + } - if (httpRequestHasKeepAlive((HttpRequest)reqq->msgs[j])) { - (this->conns)[fd].keep_alive = 1; + if (httpMessageHasKeepAlive(reqq->msgs[j])) { httpHeaderAdd( &(response->header), new(HttpHeader, "Connection", "Keep-Alive")); } else { - (this->conns)[fd].keep_alive = 0; httpHeaderAdd( &(response->header), new(HttpHeader, "Connection", "Close")); @@ -145,18 +210,32 @@ serverRun(Server this) * handle writes */ if (0 != ((this->fds)[i].revents & POLLOUT) && 0 < nwrites) { - int size; + HttpResponseWriter writer = + (HttpResponseWriter)(this->conns)[fd].writer; + HttpMessage message; events--; nwrites--; - size = streamWriterWrite((this->conns)[fd].writer, fd); + message = (HttpMessage)streamWriterWrite(writer, fd); - if ((this->conns)[fd].keep_alive) { - (this->fds)[i].events &= ~POLLOUT; - } - else { - serverCloseConn(this, i); + while (NULL != message) { + if (writer->state == HTTP_RESPONSE_NO) { + if (httpMessageHasKeepAlive(message)) { + delete(&message); + if (0 == writer->response_queue->nmsgs) { + (this->fds)[i].events &= ~POLLOUT; + break; + } + } + else { + delete(&message); + serverCloseConn(this, i); + break; + } + } + + message = (HttpMessage)streamWriterWrite(writer, fd); } } }