Browse Source

first working version of content delivery from file....very crude... @TODO: rewrite complete response handline.

master
Georg Hopp 14 years ago
parent
commit
0fba746fe2
  1. BIN
      assets/waldschrat.jpg
  2. 8
      include/http/message.h
  3. 2
      include/http/request.h
  4. 2
      include/http/response/writer.h
  5. 4
      src/Makefile.am
  6. 4
      src/http/message.c
  7. 3
      src/http/message/has_keep_alive.c
  8. 4
      src/http/request/parser/get_body.c
  9. 8
      src/http/response/404.c
  10. 2
      src/http/response/to_string.c
  11. 100
      src/http/response/writer/write.c
  12. 101
      src/server/run.c

BIN
assets/waldschrat.jpg

After

Width: 250  |  Height: 250  |  Size: 78 KiB

8
include/http/message.h

@ -16,13 +16,13 @@ CLASS(HttpMessage) {
HttpHeader header; HttpHeader header;
HttpMessageType type; HttpMessageType type;
union {
char * buffer;
int handle;
} body;
int handle;
char * body;
int nbody; int nbody;
}; };
char httpMessageHasKeepAlive(HttpMessage);
#endif // __HTTP_MESSAGE__ #endif // __HTTP_MESSAGE__
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

2
include/http/request.h

@ -11,8 +11,6 @@ CLASS(HttpRequest) {
char * uri; char * uri;
}; };
char httpRequestHasKeepAlive(HttpRequest);
#endif /* __HTTP_REQUEST_H__ */ #endif /* __HTTP_REQUEST_H__ */
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

2
include/http/response/writer.h

@ -27,7 +27,7 @@ CLASS(HttpResponseWriter) {
HttpResponseState state; HttpResponseState state;
}; };
size_t httpResponseWriterWrite(HttpResponseWriter, int);
HttpResponse httpResponseWriterWrite(HttpResponseWriter, int);
#endif // __HTTP_RESPONSE_WRITER_H__ #endif // __HTTP_RESPONSE_WRITER_H__

4
src/Makefile.am

@ -7,8 +7,8 @@ CLASS = class.c interface.c
SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c SOCKET = socket.c socket/accept.c socket/connect.c socket/listen.c
SERVER = server.c server/run.c server/close_conn.c SERVER = server.c server/run.c server/close_conn.c
LOGGER = logger.c logger/stderr.c logger/syslog.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 \ RESP = http/response.c http/response/404.c http/response/size_get.c \
http/response/to_string.c http/response/to_string.c
WRITER = http/response/writer.c http/response/writer/write.c WRITER = http/response/writer.c http/response/writer/write.c

4
src/http/message.c

@ -43,11 +43,11 @@ dtor(void * _this)
switch (this->type) { switch (this->type) {
case HTTP_MESSAGE_BUFFERED: case HTTP_MESSAGE_BUFFERED:
_free((void **)&((this->body).buffer));
_free((void **)&(this->body));
break; break;
case HTTP_MESSAGE_PIPED: case HTTP_MESSAGE_PIPED:
close((this->body).handle);
if (2 < this->handle) close(this->handle);
break; break;
default: default:

3
src/http/request/has_keep_alive.c → src/http/message/has_keep_alive.c

@ -7,9 +7,8 @@
char char
httpRequestHasKeepAlive(HttpRequest request)
httpMessageHasKeepAlive(HttpMessage message)
{ {
HttpMessage message = (HttpMessage)request;
char * header; char * header;
char * header_ptr; char * header_ptr;

4
src/http/request/parser/get_body.c

@ -26,8 +26,8 @@ httpRequestParserGetBody(HttpRequestParser this)
} }
if (REMAINS(this) >= message->nbody) { 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, this->cur_data,
message->nbody); message->nbody);
this->cur_data += message->nbody; this->cur_data += message->nbody;

8
src/http/response/404.c

@ -37,10 +37,10 @@ httpResponse404()
httpHeaderAdd(&(message->header), httpHeaderAdd(&(message->header),
new(HttpHeader, "Server", "testserver")); 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); sprintf(buffer, "%d", message->nbody);
httpHeaderAdd(&(message->header), httpHeaderAdd(&(message->header),

2
src/http/response/to_string.c

@ -49,7 +49,7 @@ httpResponseToString(HttpResponse response, char * _string)
*string++ = '\n'; *string++ = '\n';
if (HTTP_MESSAGE_BUFFERED == message->type) { if (HTTP_MESSAGE_BUFFERED == message->type) {
memcpy(string, (message->body).buffer, message->nbody);
memcpy(string, message->body, message->nbody);
} }
return string; return string;

100
src/http/response/writer/write.c

@ -1,26 +1,31 @@
#include <stdio.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
#include "http/response.h" #include "http/response.h"
#include "http/response/writer.h" #include "http/response/writer.h"
size_t
HttpResponse
httpResponseWriterWrite(HttpResponseWriter this, int fd) httpResponseWriterWrite(HttpResponseWriter this, int fd)
{ {
HttpMessageQueue respq = this->response_queue; HttpMessageQueue respq = this->response_queue;
int cont = 1; int cont = 1;
size_t written = 0;
HttpResponse retval = NULL;
while (cont) { while (cont) {
switch (this->state) { switch (this->state) {
case HTTP_RESPONSE_NO: case HTTP_RESPONSE_NO:
if (NULL == this->cur_response && 0 < respq->nmsgs) { 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; this->state = HTTP_RESPONSE_START;
} }
else { else {
@ -29,51 +34,86 @@ httpResponseWriterWrite(HttpResponseWriter this, int fd)
break; break;
case HTTP_RESPONSE_START: 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; this->state = HTTP_RESPONSE_DONE;
} }
else { else {
this->state = HTTP_RESPONSE_PIPE;
cont = 0;
} }
} }
else {
this->nbuffer -= written;
memmove(this->buffer, this->buffer + written, this->nbuffer);
cont = 0;
}
} }
break; break;
case HTTP_RESPONSE_PIPE:
break;
case HTTP_RESPONSE_DONE: 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; break;
} }
} }
return written;
return retval;
} }
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

101
src/server/run.c

@ -6,6 +6,9 @@
#include <ctype.h> #include <ctype.h>
#include <time.h> #include <time.h>
#include <errno.h> #include <errno.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "server.h" #include "server.h"
#include "socket.h" #include "socket.h"
@ -114,16 +117,78 @@ serverRun(Server this)
* @TODO: for now simply remove request and send not found. * @TODO: for now simply remove request and send not found.
* Make this sane. * 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[] =
"<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n"
"<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\"\n"
" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">\n"
"<html xmlns=\"http://www.w3.org/1999/xhtml\" xml:lang=\"en\" lang=\"en\">\n"
"<head><title>200 - OK</title></head>"
"<body><h1>200 - OK</h1>"
"<img src=\"http://localhost:11212/image/\" /></body>"
"</html>";
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( httpHeaderAdd(
&(response->header), &(response->header),
new(HttpHeader, "Connection", "Keep-Alive")); new(HttpHeader, "Connection", "Keep-Alive"));
} }
else { else {
(this->conns)[fd].keep_alive = 0;
httpHeaderAdd( httpHeaderAdd(
&(response->header), &(response->header),
new(HttpHeader, "Connection", "Close")); new(HttpHeader, "Connection", "Close"));
@ -145,18 +210,32 @@ serverRun(Server this)
* handle writes * handle writes
*/ */
if (0 != ((this->fds)[i].revents & POLLOUT) && 0 < nwrites) { if (0 != ((this->fds)[i].revents & POLLOUT) && 0 < nwrites) {
int size;
HttpResponseWriter writer =
(HttpResponseWriter)(this->conns)[fd].writer;
HttpMessage message;
events--; events--;
nwrites--; 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);
} }
} }
} }

Loading…
Cancel
Save