-
Notifications
You must be signed in to change notification settings - Fork 11
/
thumbnail.cgi.c
126 lines (110 loc) · 3.47 KB
/
thumbnail.cgi.c
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;
}