Add RSS CGI, also quite a lot of refactoring
authorChip Black <bytex64@bytex64.net>
Sat, 1 Jan 2011 10:06:19 +0000 (04:06 -0600)
committerChip Black <bytex64@bytex64.net>
Sat, 1 Jan 2011 10:06:19 +0000 (04:06 -0600)
Makefile
cgi/canned_responses.c [new file with mode: 0644]
cgi/canned_responses.h [new file with mode: 0644]
cgi/cgi_blerg.c
cgi/rss.c [new file with mode: 0644]
common/app.c
common/app.h
common/escapery.c [new file with mode: 0644]
common/escapery.h [new file with mode: 0644]
common/json.c [new file with mode: 0644]
common/json.h [new file with mode: 0644]

index 2e49315..640be85 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,19 +1,22 @@
 CFLAGS ?= -g
-INCLUDES = -I. -Ifcgi -Idatabase -Icommon -Icgi-util-2.2.1 -Ilibmicrohttpd-0.9.3/src/include -Iyajl/build/yajl-1.0.11/include
+INCLUDES = -I. -Idatabase -Icommon -Iyajl/build/yajl-1.0.11/include
+HTTP_INCLUDES = -Ihttp -Ilibmicrohttpd-0.9.3/src/include
+CGI_INCLUDES = -Icgi -Icgi-util-2.2.1
 LDFLAGS ?=
 HTTP_LIBDIRS = -Llibmicrohttpd-0.9.3/src/daemon/.libs -Lyajl/build/yajl-1.0.11/lib
 CGI_LIBDIRS = -Lcgi-util-2.2.1 -Lyajl/build/yajl-1.0.11/lib
 
-targets = blerg.a blergtool http_blerg cgi_blerg
+targets = blerg.a blergtool http_blerg cgi_blerg rss
 blerg_a_objects = database/database.o database/tags.o database/util.o
 blergtool_objects = tools/blergtool.o blerg.a
-http_blerg_objects = http/http_blerg.o http/canned_responses.o common/app.o common/auth.o blerg.a
-cgi_blerg_objects = cgi/cgi_blerg.o common/app.o common/auth.o blerg.a
+rss_objects = cgi/rss.o cgi/canned_responses.o common/app.o common/escapery.o blerg.a
+http_blerg_objects = http/http_blerg.o http/canned_responses.o common/app.o common/json.o common/auth.o blerg.a
+cgi_blerg_objects = cgi/cgi_blerg.o cgi/canned_responses.o common/app.o common/json.o common/auth.o blerg.a
 
 all: $(targets)
 
 clean:
-       rm -f $(targets) $(blerg_a_objects) $(blergtool_objects) $(http_blerg_objects)
+       rm -f $(targets) $(blerg_a_objects) $(blergtool_objects) $(http_blerg_objects) $(cgi_blerg_objects) $(rss_objects)
 
 blerg.a: $(blerg_a_objects)
        ar rcu $@ $(blerg_a_objects)
@@ -27,5 +30,14 @@ http_blerg: $(http_blerg_objects)
 cgi_blerg: $(cgi_blerg_objects)
        gcc $(CGI_LIBDIRS) $(LDFLAGS) $(cgi_blerg_objects) -lcgi-util -lyajl_s -o $@
 
+rss: $(rss_objects)
+       gcc $(CGI_LIBDIRS) $(LDFLAGS) $(rss_objects) -lcgi-util -o $@
+
+http/%.o: http/%.c
+       gcc $(INCLUDES) $(HTTP_INCLUDES) $(CFLAGS) -c $< -o $@
+
+cgi/%.o: cgi/%.c
+       gcc $(INCLUDES) $(CGI_INCLUDES) $(CFLAGS) -c $< -o $@
+
 %.o: %.c
        gcc $(INCLUDES) $(CFLAGS) -c $< -o $@
diff --git a/cgi/canned_responses.c b/cgi/canned_responses.c
new file mode 100644 (file)
index 0000000..2f430b1
--- /dev/null
@@ -0,0 +1,33 @@
+#include <stdio.h>
+#include <string.h>
+#include "canned_responses.h"
+#include "app.h"
+
+void respond_simple_data(unsigned const char *data, int len) {
+       printf("Content-length: %d\r\n\r\n", len);
+       fwrite(data, len, 1, stdout);
+}
+
+void respond_404() {
+       printf("Status: 404 Not Found\r\n");
+       printf("Content-type: text/html\r\n");
+       printf("Content-length: %d\r\n\r\n", strlen(CONTENT_404));
+
+       printf(CONTENT_404);
+}
+
+void respond_405() {
+       printf("Status: 405 Method Not Allowed\r\n");
+       printf("Content-type: text/html\r\n");
+       printf("Content-length: %d\r\n\r\n", strlen(CONTENT_405));
+
+       printf(CONTENT_405);
+}
+
+void respond_JSON_Failure() {
+       respond_simple_data(JSON_FAILURE, strlen(JSON_FAILURE));
+}
+
+void respond_JSON_Success() {
+       respond_simple_data(JSON_SUCCESS, strlen(JSON_SUCCESS));
+}
diff --git a/cgi/canned_responses.h b/cgi/canned_responses.h
new file mode 100644 (file)
index 0000000..84fd56a
--- /dev/null
@@ -0,0 +1,10 @@
+#ifndef _CANNED_RESPONSES
+#define _CANNED_RESPONSES
+
+void respond_simple_data(unsigned const char *data, int len);
+void respond_404();
+void respond_405();
+void respond_JSON_Failure();
+void respond_JSON_Success();
+
+#endif /* _CANNED_RESPONSES */
index d0dcdba..2d48d82 100644 (file)
@@ -6,40 +6,12 @@
 #include "database.h"
 #include "tags.h"
 #include "auth.h"
+#include "canned_responses.h"
 #include "app.h"
 #include "config.h"
 
 yajl_gen_config yajl_c = { 0, 0 };
 
-void respond_simple_data(unsigned const char *data, int len) {
-       printf("Content-length: %d\r\n\r\n", len);
-       fwrite(data, len, 1, stdout);
-}
-
-void respond_404() {
-       printf("Status: 404 Not Found\r\n");
-       printf("Content-type: text/html\r\n");
-       printf("Content-length: %d\r\n\r\n", strlen(CONTENT_404));
-
-       printf(CONTENT_404);
-}
-
-void respond_405() {
-       printf("Status: 405 Method Not Allowed\r\n");
-       printf("Content-type: text/html\r\n");
-       printf("Content-length: %d\r\n\r\n", strlen(CONTENT_405));
-
-       printf(CONTENT_405);
-}
-
-void respond_JSON_Failure() {
-       respond_simple_data(JSON_FAILURE, strlen(JSON_FAILURE));
-}
-
-void respond_JSON_Success() {
-       respond_simple_data(JSON_SUCCESS, strlen(JSON_SUCCESS));
-}
-
 void respond_for_range(struct blerg *b, uint64_t from, uint64_t to) {
        const unsigned char *ybuf;
        unsigned int len;
@@ -118,6 +90,10 @@ int main(int argc, char *argv[]) {
                exit(0);
        }
        request_method = getenv("REQUEST_METHOD");
+       if (request_method == NULL) {
+               fprintf(stderr, "Request method is null!?\n");
+               exit(0);
+       }
 
        if (strncmp(path, "/get", 4) == 0 && strlen(path) > 4) {
                if (strncmp(request_method, "GET", 4) != 0) {
diff --git a/cgi/rss.c b/cgi/rss.c
new file mode 100644 (file)
index 0000000..bd8a1d1
--- /dev/null
+++ b/cgi/rss.c
@@ -0,0 +1,93 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <cgi-util.h>
+#include "database.h"
+#include "escapery.h"
+#include "canned_responses.h"
+#include "app.h"
+
+int fprint_rss(FILE *f, const char *username) {
+       struct blerg *b = blerg_open(username);
+       uint64_t record_count = blerg_get_record_count(b);
+       uint64_t i = (record_count > 50 ? record_count - 50 : 0);
+       char *data;
+       char *tmp;
+       int len;
+
+       fprintf(f,
+               "<?xml version=\"1.0\" charset=\"utf8\">\n"
+               "<rss version=\"2.0\">\n"
+               "<channel>\n"
+               "<title>%s's bl&euml;rg</title>\n"
+               "<link>%s</link>\n"
+               "<description>%s</description>\n",
+               "bl&euml;rg",
+               "http://blerg.dominionfawesome.com/",
+               "Textual vomit"
+       );
+
+       while (i < record_count) {
+               blerg_fetch(b, i, &data, &len);
+               tmp = xml_escape_data(data, len);
+               fprintf(f,
+                       "<item>\n"
+                       "<description>%s</description>\n"
+                       "</item>\n",
+                       tmp
+               );
+               free(tmp);
+               free(data);
+               i++;
+       }
+       blerg_close(b);
+
+       fprintf(f,
+               "</channel>\n"
+               "</rss>\n"
+       );
+}
+
+int main (int argc, char *argv) {
+       char *path;
+       char *request_method;
+       int ret;
+       struct url_info info;
+
+       request_method = getenv("REQUEST_METHOD");
+       if (request_method == NULL) {
+               fprintf(stderr, "Request method is null!?\n");
+               exit(0);
+       }
+
+       if (strncmp(request_method, "GET", 4) != 0) {
+               respond_405();
+               exit(0);
+       }
+
+       path = getenv("PATH_INFO");
+       if (path == NULL) {
+               respond_404();
+               exit(0);
+       }
+
+       if (path[0] != '/') {
+               respond_404();
+               exit(0);
+       }
+
+       ret = parse_url_info(path + 1, &info);
+       if ((ret & URL_INFO_AUTHOR) == 0) {
+               respond_404();
+               exit(0);
+       }
+
+       if (!blerg_exists(info.author)) {
+               respond_404();
+               exit(0);
+       }
+
+       printf("Content-type: application/rss+xml\r\n\r\n");
+
+       fprint_rss(stdout, "chip");
+
+}
index 9bc4e40..9d3e6cf 100644 (file)
@@ -1,7 +1,6 @@
 #include <stdio.h>
 #include <string.h>
 #include <stdlib.h>
-#include <yajl/yajl_gen.h>
 #include "app.h"
 
 int parse_url_info(const char *url, struct url_info *info) {
@@ -48,31 +47,3 @@ uint64_t *make_sequential_list(uint64_t from, uint64_t to) {
 
        return list;
 }
-
-void json_generate_one_record(yajl_gen g, const char *author, struct blerg *b, uint64_t record) {
-       char *data;
-       char number[21];
-       int len;
-
-       if (!blerg_fetch(b, record, &data, &len)) {
-               fprintf(stderr, "Could not fetch record\n");
-               return;
-       }
-
-       yajl_gen_map_open(g);
-       if (author != NULL) {
-               yajl_gen_string(g, "author", 6);
-               yajl_gen_string(g, author, strlen(author));
-       }
-       yajl_gen_string(g, "record", 6);
-       snprintf(number, 21, "%llu", record);
-       yajl_gen_string(g, number, strlen(number));
-       yajl_gen_string(g, "timestamp", 9);
-       yajl_gen_integer(g, blerg_get_timestamp(b, record));
-       yajl_gen_string(g, "data", 4);
-       yajl_gen_string(g, data, len);
-       yajl_gen_map_close(g);
-
-       free(data);
-}
-
index 93dc8b4..e37b47a 100644 (file)
@@ -26,6 +26,5 @@ struct url_info {
 
 int parse_url_info(const char *url, struct url_info *info);
 uint64_t *make_sequential_list(uint64_t from, uint64_t to);
-void json_generate_one_record(yajl_gen g, const char *author, struct blerg *b, uint64_t record);
 
 #endif /* _APP_H */
diff --git a/common/escapery.c b/common/escapery.c
new file mode 100644 (file)
index 0000000..27456bf
--- /dev/null
@@ -0,0 +1,35 @@
+#include <string.h>
+#include <stdlib.h>
+#include "escapery.h"
+
+char *xml_escape(const char *str) {
+       return xml_escape_data(str, strlen(str));
+}
+
+char *xml_escape_data(const char *str, int len) {
+       char *r = malloc(len * 5 + 1);  /* Up to 5x the space if they're all &'s */
+       int i, j;
+
+       for (i = 0, j = 0; i < len; i++) {
+               switch(str[i]) {
+               case '<':
+                       memcpy(r + j, "&lt;", 4);
+                       j += 4;
+                       break;
+               case '>':
+                       memcpy(r + j, "&gt;", 4);
+                       j += 4;
+                       break;
+               case '&':
+                       memcpy(r + j, "&amp;", 5);
+                       j += 5;
+                       break;
+               default:
+                       r[j] = str[i];
+                       j += 1;
+               }
+       }
+       r[j] = 0;
+
+       return r;
+}
diff --git a/common/escapery.h b/common/escapery.h
new file mode 100644 (file)
index 0000000..ae74226
--- /dev/null
@@ -0,0 +1,7 @@
+#ifndef _ESCAPERY_H
+#define _ESCAPERY_H
+
+char *xml_escape(const char *str);
+char *xml_escape_data(const char *str, int len);
+
+#endif /* _ESCAPERY_H */
diff --git a/common/json.c b/common/json.c
new file mode 100644 (file)
index 0000000..6b793ab
--- /dev/null
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <yajl/yajl_gen.h>
+#include "database.h"
+#include "json.h"
+
+void json_generate_one_record(yajl_gen g, const char *author, struct blerg *b, uint64_t record) {
+       char *data;
+       char number[21];
+       int len;
+
+       if (!blerg_fetch(b, record, &data, &len)) {
+               fprintf(stderr, "Could not fetch record\n");
+               return;
+       }
+
+       yajl_gen_map_open(g);
+       if (author != NULL) {
+               yajl_gen_string(g, "author", 6);
+               yajl_gen_string(g, author, strlen(author));
+       }
+       yajl_gen_string(g, "record", 6);
+       snprintf(number, 21, "%llu", record);
+       yajl_gen_string(g, number, strlen(number));
+       yajl_gen_string(g, "timestamp", 9);
+       yajl_gen_integer(g, blerg_get_timestamp(b, record));
+       yajl_gen_string(g, "data", 4);
+       yajl_gen_string(g, data, len);
+       yajl_gen_map_close(g);
+
+       free(data);
+}
+
diff --git a/common/json.h b/common/json.h
new file mode 100644 (file)
index 0000000..61e396d
--- /dev/null
@@ -0,0 +1,6 @@
+#ifndef _JSON_H
+#define _JSON_H
+
+void json_generate_one_record(yajl_gen g, const char *author, struct blerg *b, uint64_t record);
+
+#endif /* _JSON_H */