commit:ec27db46cef1c4643087fa2eeaad2ca72228bc06
author:Chip Black
committer:Chip Black
date:Sat Jan 1 04:06:19 2011 -0600
parents:bd39b527b12337f388e45410b86d223d4cdb16b0
Add RSS CGI, also quite a lot of refactoring
diff --git a/Makefile b/Makefile
line changes: +17/-5
index 2e49315..640be85
--- 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
line changes: +33/-0
index 0000000..2f430b1
--- /dev/null
+++ b/cgi/canned_responses.c
@@ -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
line changes: +10/-0
index 0000000..84fd56a
--- /dev/null
+++ b/cgi/canned_responses.h
@@ -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 */

diff --git a/cgi/cgi_blerg.c b/cgi/cgi_blerg.c
line changes: +5/-29
index d0dcdba..2d48d82
--- a/cgi/cgi_blerg.c
+++ b/cgi/cgi_blerg.c
@@ -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
line changes: +93/-0
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");
+
+}

diff --git a/common/app.c b/common/app.c
line changes: +0/-29
index 9bc4e40..9d3e6cf
--- a/common/app.c
+++ b/common/app.c
@@ -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);
-}
-

diff --git a/common/app.h b/common/app.h
line changes: +0/-1
index 93dc8b4..e37b47a
--- a/common/app.h
+++ b/common/app.h
@@ -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
line changes: +35/-0
index 0000000..27456bf
--- /dev/null
+++ b/common/escapery.c
@@ -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
line changes: +7/-0
index 0000000..ae74226
--- /dev/null
+++ b/common/escapery.h
@@ -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
line changes: +34/-0
index 0000000..6b793ab
--- /dev/null
+++ b/common/json.c
@@ -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
line changes: +6/-0
index 0000000..61e396d
--- /dev/null
+++ b/common/json.h
@@ -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 */