Browse Source

better response handling but still buggy with stream piping

master
Georg Hopp 14 years ago
parent
commit
1b7ef5030d
  1. 4
      include/http/message.h
  2. 6
      include/http/response.h
  3. 10
      include/http/response/writer.h
  4. 11
      src/Makefile.am
  5. 16
      src/http/message/header_size_get.c
  6. 28
      src/http/message/header_to_string.c
  7. 45
      src/http/request.c
  8. 47
      src/http/response.c
  9. 52
      src/http/response/image.c
  10. 58
      src/http/response/me.c
  11. 153
      src/http/response/writer/write.c
  12. 29
      src/interface/http_intro.c
  13. 79
      src/server/run.c

4
include/http/message.h

@ -21,7 +21,9 @@ CLASS(HttpMessage) {
int nbody; int nbody;
}; };
char httpMessageHasKeepAlive(HttpMessage);
char httpMessageHasKeepAlive(HttpMessage);
size_t httpMessageHeaderSizeGet(HttpMessage);
char * httpMessageHeaderToString(HttpMessage, char *);
#endif // __HTTP_MESSAGE__ #endif // __HTTP_MESSAGE__

6
include/http/response.h

@ -15,10 +15,10 @@ CLASS(HttpResponse) {
}; };
HttpResponse httpResponse404(); HttpResponse httpResponse404();
HttpResponse httpResponseMe();
HttpResponse httpResponseImage();
void httpResponseHeaderSet(HttpResponse, const char *, const char *);
size_t httpResponseSizeGet(HttpResponse);
char * httpResponseToString(HttpResponse, char *);
//void httpResponseHeaderSet(HttpResponse, const char *, const char *);
#endif /* __HTTP_RESPONSE_H__ */ #endif /* __HTTP_RESPONSE_H__ */

10
include/http/response/writer.h

@ -6,8 +6,8 @@
#include "http/message/queue.h" #include "http/message/queue.h"
typedef enum e_HttpResponseState { typedef enum e_HttpResponseState {
HTTP_RESPONSE_NO=0,
HTTP_RESPONSE_START,
HTTP_RESPONSE_GET=0,
HTTP_RESPONSE_HEADER,
HTTP_RESPONSE_PIPE, HTTP_RESPONSE_PIPE,
HTTP_RESPONSE_DONE HTTP_RESPONSE_DONE
} HttpResponseState; } HttpResponseState;
@ -17,9 +17,9 @@ CLASS(HttpResponseWriter) {
char pipe[1024]; char pipe[1024];
size_t nbuffer; size_t nbuffer;
size_t rpipe;
size_t wpipe;
char pipe_flip;
size_t written;
size_t pstart;
size_t pend;
HttpMessageQueue response_queue; HttpMessageQueue response_queue;
HttpResponse cur_response; HttpResponse cur_response;

11
src/Makefile.am

@ -2,15 +2,18 @@ ACLOCAL_AMFLAGS = -I m4
AUTOMAKE_OPTIONS = subdir-objects AUTOMAKE_OPTIONS = subdir-objects
IFACE = interface/class.c interface/stream_reader.c interface/logger.c \ IFACE = interface/class.c interface/stream_reader.c interface/logger.c \
interface/stream_writer.c
interface/stream_writer.c interface/http_intro.c
CLASS = class.c interface.c 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 http/message/has_keep_alive.c
MSG = http/message.c http/message/queue.c http/message/has_keep_alive.c \
http/message/header_size_get.c http/message/header_to_string.c
REQ = http/request.c REQ = http/request.c
RESP = http/response.c http/response/404.c http/response/size_get.c \
http/response/to_string.c
RESP = http/response.c \
http/response/404.c \
http/response/image.c \
http/response/me.c
WRITER = http/response/writer.c http/response/writer/write.c WRITER = http/response/writer.c http/response/writer/write.c
HEADER = http/header.c http/header/get.c http/header/add.c \ HEADER = http/header.c http/header/get.c http/header/add.c \
http/header/size_get.c http/header/to_string.c http/header/size_get.c http/header/to_string.c

16
src/http/response/size_get.c → src/http/message/header_size_get.c

@ -5,6 +5,7 @@
#include "http/message.h" #include "http/message.h"
#include "http/response.h" #include "http/response.h"
#include "http/header.h" #include "http/header.h"
#include "interface/http_intro.h"
static size_t size; static size_t size;
@ -19,24 +20,13 @@ addHeaderSize(const void * node, const VISIT which, const int depth)
} }
size_t size_t
httpResponseSizeGet(HttpResponse response)
httpMessageHeaderSizeGet(HttpMessage message)
{ {
HttpMessage message = (HttpMessage)response;
size = 0;
size += strlen(message->version) + 1;
size += 4; // for status
size += strlen(response->reason) + 2;
size = httpIntroSizeGet(message);
twalk(message->header, addHeaderSize); twalk(message->header, addHeaderSize);
size += 2; size += 2;
if (HTTP_MESSAGE_BUFFERED == message->type) {
size += message->nbody;
}
return size; return size;
} }

28
src/http/response/to_string.c → src/http/message/header_to_string.c

@ -4,6 +4,7 @@
#include "http/response.h" #include "http/response.h"
#include "http/header.h" #include "http/header.h"
#include "interface/http_intro.h"
static char * string; static char * string;
@ -18,40 +19,17 @@ addHeaderString(const void * node, const VISIT which, const int depth)
} }
char * char *
httpResponseToString(HttpResponse response, char * _string)
httpMessageHeaderToString(HttpMessage response, char * _string)
{ {
HttpMessage message = (HttpMessage)response; HttpMessage message = (HttpMessage)response;
char status[4];
string = _string;
snprintf(status, 4, "%d", response->status);
strcpy(string, message->version);
string += strlen(string);
*string++ = ' ';
strcpy(string, status);
string += strlen(string);
*string++ = ' ';
strcpy(string, response->reason);
string += strlen(string);
*string++ = '\r';
*string++ = '\n';
string = httpIntroToString(response, _string);
twalk(message->header, addHeaderString); twalk(message->header, addHeaderString);
*string++ = '\r'; *string++ = '\r';
*string++ = '\n'; *string++ = '\n';
if (HTTP_MESSAGE_BUFFERED == message->type) {
memcpy(string, message->body, message->nbody);
}
return string; return string;
} }

45
src/http/request.c

@ -1,8 +1,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
#include "interface/http_intro.h"
#include "http/request.h" #include "http/request.h"
#include "message/helper.c" #include "message/helper.c"
@ -24,7 +27,47 @@ dtor(void * _this)
PARENTCALL(_this, Class, dtor); PARENTCALL(_this, Class, dtor);
} }
static
size_t
sizeGet(void * _this)
{
HttpRequest this = _this;
size_t size = 0;
size += strlen(this->method) + 1;
size += strlen(this->uri) + 1;
size += strlen(((HttpMessage)this)->version) + 2;
return size;
}
static
char *
toString(void * _this, char * string)
{
HttpRequest this = _this;
strcpy(string, this->method);
string += strlen(string);
*string++ = ' ';
strcpy(string, this->uri);
string += strlen(string);
*string++ = ' ';
strcpy(string, ((HttpMessage)this)->version);
string += strlen(string);
*string++ = '\r';
*string++ = '\n';
return string;
}
INIT_IFACE(Class, ctor, dtor, NULL); INIT_IFACE(Class, ctor, dtor, NULL);
CREATE_CLASS(HttpRequest, HttpMessage, IFACE(Class));
INIT_IFACE(HttpIntro, sizeGet, toString);
CREATE_CLASS(HttpRequest,
HttpMessage,
IFACE(Class),
IFACE(HttpIntro));
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

47
src/http/response.c

@ -1,8 +1,12 @@
#include <stdlib.h> #include <stdlib.h>
#include <stdarg.h> #include <stdarg.h>
#include <string.h>
#include <sys/types.h>
#include <stdio.h>
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
#include "interface/http_intro.h"
#include "http/response.h" #include "http/response.h"
#include "message/helper.c" #include "message/helper.c"
@ -35,7 +39,48 @@ dtor(void * _this)
PARENTCALL(_this, Class, dtor); PARENTCALL(_this, Class, dtor);
} }
static
size_t
sizeGet(void * _this)
{
HttpResponse this = _this;
size_t size = 0;
size += strlen(((HttpMessage)this)->version) + 1;
size += 3 + 1; // for status
size += strlen(this->reason) + 2;
return size;
}
static
char *
toString(void * _this, char * string)
{
HttpResponse this = _this;
strcpy(string, ((HttpMessage)this)->version);
string += strlen(string);
*string++ = ' ';
snprintf(string, 4, "%d", this->status);
string += strlen(string);
*string++ = ' ';
strcpy(string, this->reason);
string += strlen(string);
*string++ = '\r';
*string++ = '\n';
return string;
}
INIT_IFACE(Class, ctor, dtor, NULL); INIT_IFACE(Class, ctor, dtor, NULL);
CREATE_CLASS(HttpResponse, HttpMessage, IFACE(Class));
INIT_IFACE(HttpIntro, sizeGet, toString);
CREATE_CLASS(
HttpResponse,
HttpMessage,
IFACE(Class),
IFACE(HttpIntro));
// vim: set ts=4 sw=4: // vim: set ts=4 sw=4:

52
src/http/response/image.c

@ -0,0 +1,52 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "class.h"
#include "interface/class.h"
#include "http/response.h"
#include "http/message.h"
#include "http/header.h"
HttpResponse
httpResponseImage()
{
time_t t;
struct tm * tmp;
char buffer[200];
struct stat st;
HttpResponse response;
HttpMessage message;
response = new(HttpResponse, "HTTP/1.1", 200, "OK");
message = (HttpMessage)response;
httpHeaderAdd(&(message->header),
new(HttpHeader, "Content-Type", "image/jpeg"));
httpHeaderAdd(&(message->header),
new(HttpHeader, "Server", "testserver"));
message->type = HTTP_MESSAGE_PIPED;
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));
t = time(NULL);
tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpHeaderAdd(&(message->header),
new(HttpHeader, "Date", buffer));
return response;
}
// vim: set ts=4 sw=4:

58
src/http/response/me.c

@ -0,0 +1,58 @@
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>
#include "class.h"
#include "interface/class.h"
#include "http/response.h"
#include "http/message.h"
#include "http/header.h"
#define RESP_DATA "<?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=\"/image/\" /></body>" \
"</html>"
HttpResponse
httpResponseMe()
{
time_t t;
struct tm * tmp;
char buffer[200];
HttpResponse response;
HttpMessage message;
response = new(HttpResponse, "HTTP/1.1", 200, "OK");
message = (HttpMessage)response;
httpHeaderAdd(&(message->header),
new(HttpHeader, "Content-Type", "text/html"));
httpHeaderAdd(&(message->header),
new(HttpHeader, "Server", "testserver"));
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),
new(HttpHeader, "Content-Length", buffer));
t = time(NULL);
tmp = localtime(&t);
strftime(buffer, sizeof(buffer), "%a, %d %b %Y %T %Z", tmp);
httpHeaderAdd(&(message->header),
new(HttpHeader, "Date", buffer));
return response;
}
// vim: set ts=4 sw=4:

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

@ -8,6 +8,7 @@
#include "class.h" #include "class.h"
#include "interface/class.h" #include "interface/class.h"
#include "http/message.h"
#include "http/response.h" #include "http/response.h"
#include "http/response/writer.h" #include "http/response/writer.h"
@ -15,98 +16,124 @@ HttpResponse
httpResponseWriterWrite(HttpResponseWriter this, int fd) httpResponseWriterWrite(HttpResponseWriter this, int fd)
{ {
HttpMessageQueue respq = this->response_queue; HttpMessageQueue respq = this->response_queue;
HttpResponse retval = this->cur_response;
HttpMessage message = (HttpMessage)this->cur_response;
int cont = 1; int cont = 1;
HttpResponse retval = NULL;
while (cont) { while (cont) {
switch (this->state) { switch (this->state) {
case HTTP_RESPONSE_NO:
case HTTP_RESPONSE_GET:
if (NULL == this->cur_response && 0 < respq->nmsgs) { if (NULL == this->cur_response && 0 < respq->nmsgs) {
retval = this->cur_response = (HttpResponse)respq->msgs[0];
message = respq->msgs[0];
retval = this->cur_response = (HttpResponse)message;
memmove(respq->msgs, memmove(respq->msgs,
&(respq->msgs[1]), &(respq->msgs[1]),
sizeof(void*) * (--respq->nmsgs + 1)); sizeof(void*) * (--respq->nmsgs + 1));
this->state = HTTP_RESPONSE_START;
this->nbuffer = httpMessageHeaderSizeGet(message);
this->buffer = malloc(this->nbuffer);
this->written = 0;
httpMessageHeaderToString(message, this->buffer);
this->state = HTTP_RESPONSE_HEADER;
} }
else { else {
cont = 0; cont = 0;
} }
break; break;
case HTTP_RESPONSE_START:
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));
case HTTP_RESPONSE_HEADER:
this->written += write(
fd,
&(this->buffer[this->written]),
this->nbuffer - this->written);
if (this->written == this->nbuffer) {
free(this->buffer);
this->buffer = NULL;
this->nbuffer = 0;
this->written = 0;
this->pstart = 0;
this->pend = 0;
this->state = HTTP_RESPONSE_PIPE;
}
else {
cont = 0;
} }
this->state = HTTP_RESPONSE_PIPE;
break; break;
case HTTP_RESPONSE_PIPE: case HTTP_RESPONSE_PIPE:
{
HttpMessage message = (HttpMessage)(this->cur_response);
size_t headsize = httpResponseSizeGet(this->cur_response);
switch (message->type) {
case HTTP_MESSAGE_BUFFERED:
this->written += write(
fd,
&(message->body[this->written]),
message->nbody - this->written);
break;
case HTTP_MESSAGE_PIPED:
/**
* read
*/
if (this->nbuffer < message->nbody) {
size_t rsize;
size_t temp;
this->pend = (1024 == this->pend)?
0 : this->pend;
rsize = (this->pstart <= this->pend)?
1024 - this->pend : this->pstart - 1;
temp = read(
message->handle,
&(this->pipe[this->pend]),
rsize);
this->nbuffer += temp;
this->pend += temp;
}
this->buffer = malloc(headsize + message->nbody);
httpResponseToString(this->cur_response, this->buffer);
this->rpipe = headsize;
/**
* write
*/
{
size_t wsize;
size_t temp;
if (HTTP_MESSAGE_PIPED == message->type &&
0 != message->handle) {
char * data = &(this->buffer[headsize]);
size_t togo = message->nbody;
wsize = (this->pstart <= this->pend)?
this->pend - this->pstart : 1024 - this->pstart;
size_t rsize = read(message->handle, data, togo);
temp = write(fd, &(this->pipe[this->pstart]), wsize);
while (rsize < togo) {
data += rsize;
togo -= rsize;
rsize = read(message->handle, data, togo);
this->written += temp;
this->pstart += temp;
} }
break;
this->wpipe = 0;
this->rpipe += message->nbody;
close(message->handle);
message->handle = 0;
}
{
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 {
cont = 0;
}
}
default:
break;
}
if (this->written == message->nbody) {
this->nbuffer = 0;
this->written = 0;
this->pstart = 0;
this->pend = 0;
this->state = HTTP_RESPONSE_DONE;
}
else {
cont = 0;
} }
break; break;
case HTTP_RESPONSE_DONE: case HTTP_RESPONSE_DONE:
this->state = HTTP_RESPONSE_NO;
this->cur_response = NULL; this->cur_response = NULL;
this->state = HTTP_RESPONSE_GET;
cont = 0; cont = 0;
break; break;

29
src/interface/http_intro.c

@ -0,0 +1,29 @@
#include "class.h"
#include "interface/http_intro.h"
const struct interface i_HttpIntro = {
"httpIntro",
2
};
size_t
httpIntroSizeGet(void * object)
{
size_t ret;
RETCALL(object, HttpIntro, sizeGet, ret);
return ret;
}
char *
httpIntroToString(void * object, char * string)
{
char * ret;
RETCALL(object, HttpIntro, toString, ret, string);
return ret;
}
// vim: set ts=4 sw=4:

79
src/server/run.c

@ -122,62 +122,11 @@ serverRun(Server this)
if (0 == strcmp("GET", request->method) && if (0 == strcmp("GET", request->method) &&
0 == strcmp("/me/", request->uri)) { 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=\"/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));
response = (HttpMessage)httpResponseMe();
} }
else if (0 == strcmp("GET", request->method) && else if (0 == strcmp("GET", request->method) &&
0 == strcmp("/image/", request->uri)) { 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));
response = (HttpMessage)httpResponseImage();
} }
else { else {
response = (HttpMessage)httpResponse404(); response = (HttpMessage)httpResponse404();
@ -217,25 +166,17 @@ serverRun(Server this)
events--; events--;
nwrites--; nwrites--;
message = (HttpMessage)streamWriterWrite(writer, fd);
message = streamWriterWrite(writer, fd);
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;
}
if (NULL != message && writer->state == HTTP_RESPONSE_GET) {
if (httpMessageHasKeepAlive(message)) {
(this->fds)[i].events &= ~POLLOUT;
}
else {
serverCloseConn(this, i);
} }
message = (HttpMessage)streamWriterWrite(writer, fd);
delete(&message);
} }
} }
} }

Loading…
Cancel
Save