Permalink
Browse files

build (more?) standard-compliant HTTP responses.

Proper HTTP responses need headers, not just a dump
of the content spit back on the client.
  • Loading branch information...
1 parent b9fe92f commit d5b0ab2da32a51bc9ba56b81605d11dddbab0d92 @mojaves committed May 26, 2012
Showing with 105 additions and 7 deletions.
  1. +100 −7 src/craneweb.c
  2. +3 −0 src/craneweb.h
  3. +2 −0 tests/build_craneweb_private_h.py
View
@@ -4,6 +4,7 @@
* ZLIB licensed.
*/
+#include <time.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
@@ -87,7 +88,7 @@ const char *CRW_version_string(void)
/* what's worse? duplicating the information or using a static buffer?
choose your destiny.
*/
- return "craneweb v0.2.0.1";
+ return "craneweb/0.2.0.1";
}
/*** instance (0) *********************************************************/
@@ -624,6 +625,31 @@ enum {
CRW_RESPONSE_DEFAULT_BODY_LEN = 1024
};
+typedef struct crwhttpstatus_ CRW_HTTPStatus;
+struct crwhttpstatus_ {
+ int status_code;
+ const char *status_description;
+};
+
+static const CRW_HTTPStatus HTTPStatuses[] = {
+ { 200, "OK" },
+ { 0, NULL }
+};
+
+CRW_PRIVATE
+const char *CRW_http_status_description(int status_code)
+{
+ const char *desc = NULL;
+ int j = 0;
+ for (j = 0; !desc && HTTPStatuses[j].status_code; j++) {
+ if (HTTPStatuses[j].status_code == status_code) {
+ desc = HTTPStatuses[j].status_description;
+ }
+ }
+ return desc;
+}
+
+
struct crwresponse_ {
int status_code;
list headers;
@@ -636,7 +662,7 @@ CRW_Response *CRW_response_new(CRW_Instance *inst)
CRW_Response *res = NULL;
res = calloc(1, sizeof(CRW_Response));
if (res) {
- res->status_code = 200; /* FIXME */
+ res->status_code = 200; /* FIXME: magic? number */
list_init(&res->headers, free);
res->body = sb_new_with_size(CRW_RESPONSE_DEFAULT_BODY_LEN);
if (!res->body) {
@@ -656,6 +682,23 @@ void CRW_response_del(CRW_Response *res)
free(res);
}
+CRW_PRIVATE
+int CRW_is_valid_status_code(int status_code)
+{
+ return 1; /* FIXME */
+}
+
+int CRW_response_status_code(CRW_Response *res, int status_code)
+{
+ int err = -1;
+ if (res && CRW_is_valid_status_code(status_code)) {
+ res->status_code = status_code;
+ err = 0;
+ }
+ return err;
+}
+
+
int CRW_response_add_header(CRW_Response *res,
const char *name, const char *value)
{
@@ -664,7 +707,7 @@ int CRW_response_add_header(CRW_Response *res,
char hdrbuf[CRW_RESPONSE_DEFAULT_BODY_LEN] = { '\0' };
char *pc = NULL;
snprintf(hdrbuf, sizeof(hdrbuf), "%s%s%s\r\n",
- name, (value) ?":" :"", value);
+ name, (value) ?": " :"", value);
pc = strdup(hdrbuf);
if (pc) {
list_element *tail = list_tail(&(res->headers));
@@ -1583,20 +1626,70 @@ static int CRW_server_adapter_mongoose_build(CRW_ServerAdapter *serv,
return err;
}
+CRW_PRIVATE
+int CRW_server_adapter_mongoose_send_http_head_base(struct mg_connection *conn,
+ CRW_Response *res)
+{
+ time_t now = time(NULL);
+ struct tm tmdesc;
+ char datebuf[256] = { '\0' }; /* FIXME */
+ mg_printf(conn, "HTTP/1.0 %i %s\r\n",
+ res->status_code,
+ CRW_http_status_description(res->status_code));
+ mg_printf(conn, "Server: %s (generic)\r\n",
+ CRW_version_string());
+ gmtime_r(&now, &tmdesc);
+ strftime(datebuf, sizeof(datebuf), "%a, %d %b %Y %T", &tmdesc);
+ mg_printf(conn, "Date: %s GMT\r\n", datebuf);
+ mg_printf(conn, "Content-Type: text/html; charset=UTF-8\r\n"); /* FIXME */
+ mg_printf(conn, "Content-Length: %i\r\n", res->body->pos + 2); /* FIXME */
+ return 0;
+}
-static int CRW_server_adapter_mongoose_send(CRW_ServerAdapter *serv,
- struct mg_connection *conn,
- CRW_Response *res)
+CRW_PRIVATE
+int CRW_server_adapter_mongoose_send_http_head_user(struct mg_connection *conn,
+ CRW_Response *res)
+{
+ /* TODO: overwritten headers */
+ list_element *elem = NULL;
+ for (elem = list_head(&res->headers); elem; elem = list_next(elem)) {
+ mg_printf(conn, "%s\r\n", (const char *)list_data(elem));
+ }
+ return 0;
+}
+
+CRW_PRIVATE
+int CRW_server_adapter_mongoose_send_http_blank(struct mg_connection *conn,
+ CRW_Response *res)
+{
+ mg_write(conn, "\r\n", 2); /* FIXME */
+ return 0;
+}
+
+CRW_PRIVATE
+int CRW_server_adapter_mongoose_send_http_body(struct mg_connection *conn,
+ CRW_Response *res)
{
if (res->path) {
mg_send_file(conn, res->path);
} else {
- /* FIXME*/
mg_write(conn, res->body->cstr, res->body->pos);
}
return 0;
}
+static int CRW_server_adapter_mongoose_send(CRW_ServerAdapter *serv,
+ struct mg_connection *conn,
+ CRW_Response *res)
+{
+ CRW_server_adapter_mongoose_send_http_head_base(conn, res);
+ CRW_server_adapter_mongoose_send_http_head_user(conn, res);
+ CRW_server_adapter_mongoose_send_http_blank(conn, res);
+ CRW_server_adapter_mongoose_send_http_body(conn, res);
+ CRW_server_adapter_mongoose_send_http_blank(conn, res);
+ return 0;
+}
+
static void *CRW_mongoose_event_handler(enum mg_event event,
struct mg_connection *conn,
View
@@ -356,6 +356,9 @@ CRW_Response *CRW_response_new(CRW_Instance *inst);
*/
void CRW_response_del(CRW_Response *res);
+/** FIXME */
+int CRW_response_status_code(CRW_Response *res, int status_code);
+
/** \fn CRW_response_add_header
\brief adds an HTTP header to a CRW_Response.
@@ -28,6 +28,8 @@ def write_header(protos, fdst):
"typedef struct crwroutescanner_ CRW_RouteScanner;\n",
"typedef struct crwparameters_ CRW_Parameters;\n",
"\n",
+ "struct mg_connection;\n",
+ "\n",
"" ]
footer = [ "\n" ,
"#endif /* CRANEWEB_PRIVATE_H */",

0 comments on commit d5b0ab2

Please sign in to comment.