aboutsummaryrefslogtreecommitdiffstats
path: root/thumbnail.cgi.c
diff options
context:
space:
mode:
Diffstat (limited to 'thumbnail.cgi.c')
-rw-r--r--thumbnail.cgi.c125
1 files changed, 125 insertions, 0 deletions
diff --git a/thumbnail.cgi.c b/thumbnail.cgi.c
new file mode 100644
index 0000000..a4ba3c8
--- /dev/null
+++ b/thumbnail.cgi.c
@@ -0,0 +1,125 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <libexif/exif-data.h>
+
+/* -------------------------------------------------------------------------- */
+
+static const char *shellhelp =
+ "\n"
+ "This is a cgi script. It doesn't do any useful (beside printing this text)\n"
+ "when started from the shell prompt, it is supposed to be started by your\n"
+ "web server\n";
+
+static const char *description =
+ "\n"
+ "The script deliveres the EXIF thumbnail of JPEG images to the web browser.\n"
+ "It will lookup the path passed via path info below your document root, i.e.\n"
+ "a request like this ...\n"
+ "\n"
+ " http://your.server/cgi-bin/thumbnail.cgi/path/file.jpg\n"
+ "\n"
+ "... will make the script send the thumbnail of the file ...\n"
+ "\n"
+ " %s/path/file.jpg\n"
+ "\n"
+ "to the client\n"
+ "\n"
+ "Security note: The script refuses paths containing \"..\" to avoid breaking\n"
+ "out of the document root. There are no other checks through, so it will\n"
+ "deliver thumbnails for any JPEG image below below your document root which\n"
+ "it is allowed to open by unix file permissions.\n"
+ "\n"
+ "(c) 2004 Gerd Knorr <kraxel@bytesex.org> [SUSE Labs]\n"
+ "\n";
+
+/* -------------------------------------------------------------------------- */
+
+static void panic(int code, char *message)
+{
+ printf("Status: %d %s\n"
+ "Content-Type: text/plain\n"
+ "\n"
+ "ERROR: %s\n",
+ code, message, message);
+ fflush(stdout);
+ exit(1);
+}
+
+static void dump_thumbnail(char *filename)
+{
+ char *cached;
+ char mtime[64];
+ struct stat st;
+ struct tm *tm;
+ ExifData *ed = NULL;
+
+ if (-1 == stat(filename,&st))
+ panic(404,"can't stat file");
+ tm = gmtime(&st.st_mtime);
+ strftime(mtime,sizeof(mtime),"%a, %d %b %Y %H:%M:%S GMT",tm);
+ cached = getenv("HTTP_IF_MODIFIED_SINCE");
+ if (NULL != cached && 0 == strcmp(cached,mtime)) {
+ /* shortcut -- browser has a up-to-date copy */
+ printf("Status: 304 Image not modified\n"
+ "\n");
+ fflush(stdout);
+ return;
+ }
+
+ ed = exif_data_new_from_file(filename);
+ if (!ed)
+ panic(500,"file has no exif data\n");
+ if (!ed->data)
+ panic(500,"no exif thumbnail present");
+ if (ed->data[0] != 0xff || ed->data[1] != 0xd8)
+ panic(500,"exif thumbnail has no jpeg magic");
+
+
+ printf("Status: 200 Thumbnail follows\n"
+ "Content-Type: image/jpeg\n"
+ "Content-Length: %d\n"
+ "Last-modified: %s\n"
+ "\n",
+ ed->size,mtime);
+ fwrite(ed->data,ed->size,1,stdout);
+ fflush(stdout);
+}
+
+/* -------------------------------------------------------------------------- */
+
+int main(int argc, char *argv[])
+{
+ char filename[1024];
+ char *document_root;
+ char *path_info;
+
+ if (NULL == getenv("GATEWAY_INTERFACE")) {
+ fprintf(stderr,shellhelp);
+ fprintf(stderr,description,"$DOCUMENT_ROOT");
+ exit(1);
+ }
+
+ document_root = getenv("DOCUMENT_ROOT");
+ if (NULL == document_root)
+ panic(500,"DOCUMENT_ROOT unset");
+
+ path_info = getenv("PATH_INFO");
+ if (NULL == path_info || 0 == strlen(path_info)) {
+ printf("Content-type: text/plain\n"
+ "\n");
+ printf(description,document_root);
+ fflush(stdout);
+ return 0;
+ }
+
+ if (NULL != strstr(path_info,".."))
+ panic(403,"\"..\" not allowed in path");
+ snprintf(filename,sizeof(filename),"%s/%s",document_root,path_info);
+ dump_thumbnail(filename);
+ return 0;
+}