1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
|
#include <stdio.h>
#include <stdlib.h>
#include <stddef.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 Hoffmann <gerd@kraxel.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,"%s", 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;
}
|