#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ctype.h>
#include <fcall.h>
#include <libsec.h>
#include "httpd.h"
#include "httpsrv.h"
enum {
Tpl = 7, // # thumbnails per line
Lpp = 4, // # thumbnails lines per page
Twid = 100, // thumbnail width (pixels)
Downwid = 16, // width of down arrow on directories
// file types in directory scan
Tdull = 0, // boring file
Tdir, // real directory
Tphoto, // virtual dir from photosrv
Timage // image (known extension)
};
Hio *hout;
static Hio houtb;
static HConnect *connect;
static int vermaj;
static char *Magic = "exif is over-complex";
static char *Imgexts[] = { ".jpg", ".gif", ".png" };
char *Strapcolor = "#EFFFEF"; // acme title bar green
char *Rulercolor = "#428a42"; // acme ruler green
char *Textcolor = "black";
char *Bodycolor = "white";
/*********************************************************/
char *
path2text(char *path)
{
int i;
char *p, *s, *text;
if((s = strrchr(path, '/')) == nil)
s = path;
else
s++;
text = strdup(s);
if((p = strrchr(text, '.')) != nil)
for(i = 0; i < nelem(Imgexts); i++)
if(cistrcmp(p, Imgexts[i]) == 0){
*p = 0;
break;
}
if(isalpha(*text))
*text = toupper(*text);
return text;
}
char *
path2parent(char *path)
{
char *p, *parent;
parent = strdup(path);
if(strcmp(parent, "/") == 0)
return parent;
if((p = strrchr(parent, '/')) != nil){
if(p != parent)
p[0] = 0;
else
p[1] = 0;
}
return parent;
}
char *
mkuri(char *fmt, ...)
{
va_list a;
char *r, *w, *p, *s, *t;
va_start(a, fmt);
s = vsmprint(fmt, a);
va_end(a);
// strip duplicate slashes
p = "";
for(w = r = s; *r; r++){
*w = *r;
if(*p == '/' && *w == '/')
continue;
p = w++;
}
*w = 0;
t = smprint("%U", s);
free(s);
return t;
}
int
filetype(Dir *d)
{
int i;
char *p;
DigestState *ds;
uchar hash[SHA1dlen];
char muid[SHA1dlen*2];
ds = sha1((uchar *)Magic, strlen(Magic), nil, nil);
sha1((uchar *)d->name, strlen(d->name), hash, ds);
snprint(muid, sizeof(muid), "%.*[", 8, hash);
if(strcmp(muid, d->muid) == 0)
return Tphoto;
if((p = strrchr(d->name, '.')) != nil)
for(i = 0; i < nelem(Imgexts); i++)
if(cistrcmp(p, Imgexts[i]) == 0)
return Timage;
if((d->mode & DMDIR) == 0)
return Tdull;
return Tdir;
}
/*********************************************************/
/*
* couldn't open a file
* figure out why and return and error message
*/
static int
notfound(char *path)
{
connect->xferbuf[0] = 0;
errstr(connect->xferbuf, sizeof connect->xferbuf);
if(strstr(connect->xferbuf, "file does not exist") != nil)
return hfail(connect, HNotFound, path);
if(strstr(connect->xferbuf, "permission denied") != nil)
return hfail(connect, HUnauth, path);
return hfail(connect, HNotFound, path);
}
static void
prelude(char *title, char *icon)
{
if (vermaj) {
hokheaders(connect);
hprint(hout, "Content-type: text/html\n");
hprint(hout, "\n");
}
hprint(hout, "\n");
hprint(hout, "<html>\n");
hprint(hout, "<head>\n");
hprint(hout, "<title>%s</title>\n", title);
if(icon)
hprint(hout, " <link rel='SHORTCUT ICON' href='%s'>\n", icon);
hprint(hout, "</head>\n");
hprint(hout, "<body text='%s' bgcolor='%s' topmargin='0' "
"leftmargin='0' marginwidth='0' marginheight='0'>\n", Textcolor, Bodycolor);
/*
* A crude attempt at stopping people from snatching our pictures
* doesn't really work but discourages the dull masses.
*/
hprint(hout, "\n");
hprint(hout, "<meta http-equiv='imagetoolbar' content='false'>\n");
hprint(hout, "<div>\n");
hprint(hout, "<script type='text/javascript' language=JavaScript>\n");
hprint(hout, "var message='© Copyright, all rights reserved';\n");
hprint(hout, "function click(e) {\n");
hprint(hout, " if (document.all) {\n");
hprint(hout, " if (event.button == 2) {\n");
hprint(hout, " alert(message);\n");
hprint(hout, " return false;\n");
hprint(hout, " }\n");
hprint(hout, " }\n");
hprint(hout, " if (document.layers) {\n");
hprint(hout, " if (e.which == 3) {\n");
hprint(hout, " alert(message);\n");
hprint(hout, " return false;\n");
hprint(hout, " }\n");
hprint(hout, " }\n");
hprint(hout, " }\n");
hprint(hout, " if (document.layers) {\n");
hprint(hout, " document.captureEvents(Event.MOUSEDOWN);\n");
hprint(hout, " }\n");
hprint(hout, " document.onmousedown=click;\n");
hprint(hout, "</script>\n");
hprint(hout, "</div>\n");
}
static void
prologue(void)
{
hprint(hout, "</body>\n");
hprint(hout, "</html>\n");
}
static void
framenav(char *path, char *names[3], int page, int npages)
{
char *title, *uri;
hprint(hout, "\n");
hprint(hout, "<table frame='below' rules='none' border='2' bordercolor='%s'"
"bgcolor='%s' width='100%%' >\n", Rulercolor, Strapcolor);
hprint(hout, " <tr height='34'>\n");
title = path2text(path);
hprint(hout, " <td>\n");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='5'>\n");
hprint(hout, " %s\n", title);
hprint(hout, " </font>\n");
hprint(hout, " </td>\n");
free(title);
hprint(hout, " <td align='right' >\n");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
hprint(hout, " %d/%d\n", page, npages);
hprint(hout, " </font>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td align='right' width='34' >\n");
if(names[0]){
uri = mkuri("/magic/webphoto?frame=%s/%s", path, names[0]);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='Previous' "
"src='/nav/left-arrow.gif' />\n");
hprint(hout, " </a>\n");
free(uri);
}
else
hprint(hout, " \n");
hprint(hout, " </td>\n");
uri = mkuri("/magic/webphoto?dir=%s", path);
hprint(hout, " <td align='right' width='34' >\n");
hprint(hout, " <a href='%H?page=%d'>\n", uri, (page + ((Tpl * Lpp)-1)) /(Tpl * Lpp));
hprint(hout, " <img border='0' alt='Index' src='/nav/up-arrow.gif' />\n");
hprint(hout, " </a>\n");
hprint(hout, " </td>\n");
free(uri);
hprint(hout, " <td align='right' width='34' >\n");
if(names[2]){
uri = mkuri("/magic/webphoto?frame=%s/%s", path, names[2]);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='Next' "
"src='/nav/right-arrow.gif' />\n");
hprint(hout, " </a>\n");
free(uri);
}
else
hprint(hout, " \n");
hprint(hout, " </td>\n");
hprint(hout, " </tr>\n");
hprint(hout, "</table>\n");
hprint(hout, "<br>\n");
}
static void
doframe(char *path, char *file, int type)
{
char *p, *name, *alt, *uri, *nuri;
/* top edge of drop shadow */
hprint(hout, "\n");
hprint(hout, "<center>\n");
hprint(hout, "<table summary='' border='0' cellspacing='0' cellpadding='0'>\n");
hprint(hout, "<tr>\n");
hprint(hout, " <td width='30'>\n");
hprint(hout, " <p><img src='/nav/top-left.gif' "
"width='30' height='30' align='bottom'></p>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td align='bottom' background='/nav/top-edge.gif' >\n");
hprint(hout, " <p> </p>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td width='30'>\n");
hprint(hout, " <p><img src='/nav/top-right.gif' "
"width='30' height='30' align='bottom'></p>\n");
hprint(hout, " </td>\n");
hprint(hout, "</tr>\n");
alt = "Click for metadata";
name = path2text(file);
if(type == Tphoto){
if((p = strrchr(file, '.')) == nil)
p = "";
uri = mkuri("/magic/webphoto?image=%s/%s/fullsize%s", path, file, p);
}
else
uri = mkuri("/magic/webphoto?image=%s/%s", path, file);
nuri = mkuri("/magic/webphoto?metadata=%s/%s", path, file);
/* image and sides of drop shadow */
hprint(hout, "\n");
hprint(hout, "<tr>\n");
hprint(hout, " <td background='/nav/left-edge.gif' width='30'>\n");
hprint(hout, " <p> </p>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td>\n");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' color='black'>\n");
hprint(hout, " <a href='%H'><img src='%H' alt='%s' border='0'></a>\n", nuri, uri, alt);
hprint(hout, " </font>\n");
hprint(hout, " <br>\n");
hprint(hout, " <p align='left'>");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
hprint(hout, " %s", name);
hprint(hout, " </font>\n");
hprint(hout, " </p>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td background='/nav/right-edge.gif' width='30'>\n");
hprint(hout, " <p align='right'> </p>\n");
hprint(hout, " </td>\n");
hprint(hout, "</tr>\n");
free(name);
free(uri);
free(nuri);
/* bottom edge of drop shadow */
hprint(hout, "\n");
hprint(hout, "<tr>\n");
hprint(hout, " <td width='30' height='30'>\n");
hprint(hout, " <p><img src='/nav/bottom-left.gif' "
"width='30' height='30' align='bottom'></p>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td align='center' valign='bottom' "
"background='/nav/bottom-edge.gif' height='30'>\n");
hprint(hout, " <p> </p>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td width='30' height='30'>\n");
hprint(hout, " <p align='right'><img src='/nav/bottom-right.gif' "
"width='30' height='30' align='bottom'></p>\n");
hprint(hout, " </td>\n");
hprint(hout, "</tr>\n");
hprint(hout, "</table>\n");
hprint(hout, "</center>\n");
}
char *
probedir(char *path, char *dir)
{
Dir *d;
int i, type, n, fd;
char *p, *fn, *first;
fn = smprint("%s/%s", path, dir);
if((fd = open(fn, OREAD)) == -1){
free(fn);
return nil;
}
if((n = dirreadall(fd, &d)) < 1){
free(fn);
close(fd);
return nil;
}
type = -1;
for(i = 0; i < n; i++){
type = filetype(&d[i]);
if(type == Tphoto || type == Timage)
break;
}
if(i < n){
if(type == Tphoto){
if((p = strrchr(d[i].name, '.')) == nil)
p = "";
first = mkuri("/magic/webphoto?thumb=%s/%s/%s/thumbnail%s", path, dir, d[i].name, p);
}
else
first = mkuri("/magic/webphoto?thumb=%s/%s/%s", path, dir, d[i].name);
}
else
first = mkuri("/nav/query.jpg");
free(d);
free(fn);
return first;
}
void
dodir(char *path, char **files, int *types)
{
int i;
char *p, *alt, *name, *img, *uri, *nuri;
hprint(hout, "<table border='0' cellspacing='8' cellpadding='8'>\n");
hprint(hout, "<font face='ARIAL, HELVETICA, GENEVA' size='2'>");
hprint(hout, "<tr>\n");
hprint(hout, " <td align='center' width='50'>\n");
hprint(hout, " </td>\n");
for(i = 0; i < Tpl; i++){
if(files[i] == nil)
continue;
hprint(hout, " <td align='center' valign='middle'>\n");
name = path2text(files[i]);
switch(types[i]){
case Tdir:
alt = "Click for album contents";
if((img = probedir(path, files[i])) == nil)
img = strdup("/nav/query.jpg");
uri = mkuri("/magic/webphoto?dir=%s/%s", path, files[i]);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='%s' width='%d' "
"src='%s' /><br>%s\n", alt, Twid, img, name);
hprint(hout, " <img border='0' alt='%s' width='%d' "
"src='/nav/down-arrow.gif' />\n", name, Downwid);
hprint(hout, " </a>\n");
free(uri);
break;
case Timage:
alt = "Click for larger image";
uri = mkuri("/magic/webphoto?frame=%s/%s", path, files[i]);
nuri = mkuri("/magic/webphoto?thumb=%s/%s", path, files[i]);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='%s' width='%d' src='%H' /><br>%s",
alt, Twid, nuri, name);
hprint(hout, " </a>\n");
free(uri);
free(nuri);
break;
case Tphoto:
alt = "Click for larger image";
if((p = strrchr(files[i], '.')) == nil)
p = "";
uri = mkuri("/magic/webphoto?frame=%s/%s", path, files[i]);
nuri = mkuri("/magic/webphoto?image=%s/%s/thumbnail%s", path, files[i], p);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='%s' width='%d' src='%H' /><br>%s",
alt, Twid, nuri, name);
hprint(hout, " </a>\n");
free(uri);
free(nuri);
break;
default:
alt = "Unknown";
uri = mkuri("/magic/webphoto?image=%s/%s", path, files[i]);
hprint(hout, " <a href='%H'>", uri);
hprint(hout, " <img border='0' alt='%s' width='%d' src='/nav/query.jpg'/><br>%s",
alt, Twid, name);
hprint(hout, " </a>\n");
free(uri);
break;
}
hprint(hout, " </td>\n");
free(name);
}
hprint(hout, " <td align='center' width='50'>\n");
hprint(hout, " </td>\n");
hprint(hout, "</tr>\n");
hprint(hout, "</font>");
hprint(hout, "</table>\n");
}
static void
dirnav(char *path, char *parent, int page, int npages)
{
char *title, *uri;
hprint(hout, "\n");
hprint(hout, "\n");
hprint(hout, "<table border='2' frame='below' rules='none' bordercolor='%s'"
"bgcolor='%s' width='100%%' >\n", Rulercolor, Strapcolor);
hprint(hout, " <tr height='34'>\n");
title = path2text(path);
hprint(hout, " <td>\n");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='5'>\n");
hprint(hout, " %s\n", title);
hprint(hout, " </font>\n");
hprint(hout, " </td>\n");
free(title);
hprint(hout, " <td align='right' >\n");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
hprint(hout, " %d/%d\n", page, npages);
hprint(hout, " </font>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td align='right' width='34' >\n");
if(page > 1){
uri = mkuri("/magic/webphoto?dir=%s", path);
hprint(hout, " <a href='%H?page=%d'>\n", uri, page-1);
hprint(hout, " <img border='0' alt='Previous' "
"src='/nav/left-arrow.gif' />\n");
hprint(hout, " </a>\n");
free(uri);
}
else
hprint(hout, " \n");
hprint(hout, " </td>\n");
hprint(hout, " <td align='right' width='34' >\n");
uri = mkuri("/magic/webphoto?dir=%s", parent);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='Index' src='/nav/up-arrow.gif' />\n");
hprint(hout, " </a>\n");
free(uri);
hprint(hout, " </td>\n");
hprint(hout, " <td align='right' width='34' >\n");
if(page < npages){
uri = mkuri("/magic/webphoto?dir=%s", path);
hprint(hout, " <a href='%H?page=%d'>\n", uri, page+1);
hprint(hout, " <img border='0' alt='Next'"
"src='/nav/right-arrow.gif' />\n");
hprint(hout, " </a>\n");
free(uri);
}
else
hprint(hout, " \n");
hprint(hout, " </tr>\n");
hprint(hout, "</table>\n");
hprint(hout, "<br>\n");
}
/*************************************************/
int
frame(char *path)
{
Dir *d;
int i, n, tot, idx, fd, t, types[3];
char *title, *file, *names[3];
if((file = strrchr(path, '/')) == nil){
hfail(connect, HBadReq);
exits("missing slash");
}
if(file == path){ // root dir is special
file++;
path = "/";
}
else{
*file++ = 0;
}
if((fd = open(path, OREAD)) == -1){
notfound(path);
exits("not found");
}
if((n = dirreadall(fd, &d)) < 1){
notfound(path);
exits("not found");
}
title = path2text(path);
prelude(title, "/favicon.ico");
free(title);
tot = 0;
for(i = 0; i < n; i++)
switch(filetype(&d[i])){
case Tphoto:
case Timage:
tot++;
}
idx = 0;
memset(types, 0, sizeof(types));
memset(names, 0, sizeof(names));
for(i = 0; i < n; i++){
t = filetype(&d[i]);
if(t != Timage && t != Tphoto)
continue;
types[2] = t;
names[2] = d[i].name;
if(names[1] && strcmp(names[1], file) == 0){
framenav(path, names, idx, tot);
doframe(path, names[1], types[1]);
break;
}
memcpy(types, &types[1], sizeof(types) - sizeof(types[0]));
memcpy(names, &names[1], sizeof(names) - sizeof(names[0]));
names[2] = nil;
types[2] = 0;
idx++;
}
if(i >= n && names[1] && strcmp(names[1], file) == 0){
framenav(path, names, idx, tot);
doframe(path, names[1], types[1]);
}
prologue();
close(fd);
free(d);
return 0;
}
void
dir(char *path)
{
Dir *d;
char *str, *title, *parent, *names[Tpl];
int i, j, n, fd, page, npages, types[Tpl];
page = 1;
if((str = strchr(path, '?')) != 0){
*str++ = 0;
if(strncmp(str, "page=", 5) != 0){
hfail(connect, HSyntax);
exits("request syntax");
}
str = hurlunesc(connect, str+5);
page = atoi(str);
}
if((fd = open(path, OREAD)) == -1){
notfound(path);
exits("not found");
}
if((n = dirreadall(fd, &d)) == -1){
notfound(path);
exits("not found");
}
npages = (n + ((Tpl * Lpp)-1)) /(Tpl * Lpp);
if(page < 1 || page > npages){
hfail(connect, HBadReq);
exits("bad request");
}
title = path2text(path);
prelude(title, "/favicon.ico");
free(title);
parent = path2parent(path);
dirnav(path, parent, page, npages);
free(parent);
for(i = (page-1)*Tpl*Lpp; i < n && i < page*Tpl*Lpp;){
memset(names, 0, sizeof(names));
memset(types, 0, sizeof(types));
for(j = 0; j < Tpl && i < n; i++){
names[j] = d[i].name;
types[j] = filetype(&d[i]);
if(types[j] == Tdull)
continue;
j++;
}
dodir(path, names, types);
}
prologue();
close(fd);
free(d);
}
void
image(char *path)
{
int fd;
Dir *d;
if((fd = open(path, OREAD)) == -1){
notfound(path);
exits("not found");
}
if((d = dirstat(path)) == nil){
notfound(path);
exits("not found");
}
/* generate mime type from file extension in request */
connect->req.uri = connect->req.search;
sendfd(connect, fd, d, nil, nil);
}
void
metadata(char *path)
{
Dir *d;
Biobuf *bp;
int type, lines;
char *p, *q;
char *alt, *title, *parent, *uri, *meta;
if((d = dirstat(path)) == nil){
notfound(path);
exits("not found");
}
type = filetype(d);
free(d);
alt = "Full size image";
title = path2text(path);
parent = path2parent(path);
prelude(title, "/favicon.ico");
/* navigation bar */
hprint(hout, "\n");
hprint(hout, "<table frame='below' rules='none' border='2' bordercolor='%s'"
"bgcolor='%s' width='100%%' >\n", Rulercolor, Strapcolor);
hprint(hout, " <tr height='34'>\n");
hprint(hout, " <td>\n");
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='5'>\n");
hprint(hout, " %H\n", title);
hprint(hout, " </font>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td width='34'>\n");
hprint(hout, " </td>\n");
hprint(hout, " <td align='right' width='34'>\n");
uri = mkuri("/magic/webphoto?frame=%s", path);
hprint(hout, " <a href='%H'>\n", uri);
hprint(hout, " <img border='0' alt='%s' src='/nav/up-arrow.gif' />\n", alt);
hprint(hout, " </a>\n");
free(uri);
hprint(hout, " </td>\n");
hprint(hout, " <td align='right' width='34'>\n");
hprint(hout, " </tr>\n");
hprint(hout, "</table>\n");
hprint(hout, "<br>\n");
free(parent);
free(title);
/* page body */
hprint(hout, "<table border='0' bgcolor='%s' width='100%%' >\n", Bodycolor);
hprint(hout, " <tr>\n");
hprint(hout, " <td align='center' width='30%%'>\n");
if(type == Tphoto)
uri = mkuri("/magic/webphoto?image=%s/thumbnail.jpg", path);
else
uri = mkuri("/magic/webphoto?image=%s", path);
hprint(hout, " <img border='0' width='%d' src='%H' />\n", Twid, uri);
hprint(hout, " </td>\n");
hprint(hout, " <td align='center' >\n");
hprint(hout, " <table border='0' bgcolor='%s' ' >\n", Bodycolor);
hprint(hout, " <font face='ARIAL, HELVETICA, GENEVA' size='3'>\n");
hprint(hout, " <tr>\n");
hprint(hout, " <td >\n");
hprint(hout, " \n");
hprint(hout, " </td>\n");
hprint(hout, " </tr>\n");
lines = 0;
meta = smprint("%s/metadata", path);
if((bp = Bopen(meta, OREAD)) != nil){
while((p = Brdline(bp, '\n')) != nil){
lines++;
p[Blinelen(bp) -1] = 0;
if((q = strchr(p, ':')) != nil)
*q++ = 0;
hprint(hout, " <tr>\n");
hprint(hout, " <td align='left' width='60%%'>\n");
hprint(hout, " %s\n", p);
hprint(hout, " </td>\n");
if(q){
while(*q && isspace(*q))
q++;
hprint(hout, " <td align='left'>\n");
hprint(hout, " %s\n", q);
hprint(hout, " </td>\n");
}
hprint(hout, " </tr>\n");
}
Bterm(bp);
}
free(meta);
if(lines == 0){
hprint(hout, " <tr>\n");
hprint(hout, " <td >\n");
hprint(hout, " No EXIF metadata\n");
hprint(hout, " </td>\n");
hprint(hout, " </tr>\n");
}
hprint(hout, " </font>\n");
hprint(hout, " </table>\n");
hprint(hout, " </td>\n");
hprint(hout, " </tr>\n");
hprint(hout, "</table>\n");
prologue();
hflush(hout);
}
void
photo(char *str)
{
if (strncmp(str, "frame=", 6) == 0){
str = hurlunesc(connect, str+6);
frame(str);
return;
}
if (strncmp(str, "dir=", 4) == 0){
str = hurlunesc(connect, str+4);
dir(str);
return;
}
if (strncmp(str, "image=", 6) == 0){
str = hurlunesc(connect, str+6);
image(str);
return;
}
if (strncmp(str, "thumb=", 6) == 0){
str = hurlunesc(connect, str+6);
image(str);
return;
}
if (strncmp(str, "metadata=", 9) == 0){
str = hurlunesc(connect, str+9);
metadata(str);
return;
}
hfail(connect, HBadReq);
}
void
main(int argc, char *argv[])
{
fmtinstall('H', httpfmt);
fmtinstall('U', hurlfmt);
fmtinstall('M', dirmodefmt);
fmtinstall('[', encodefmt);
close(2);
connect = init(argc, argv);
hout = &connect->hout;
vermaj = connect->req.vermaj;
if(hparseheaders(connect, HSTIMEOUT) < 0)
exits("failed");
if(connect->head.expectother || connect->head.expectcont){
hfail(connect, HExpectFail, nil);
exits("failed");
}
contentinit();
bind("/usr/photos", "/", MREPL);
if(connect->req.search != nil)
photo(connect->req.search);
else
hfail(connect, HSyntax);
hflush(hout);
writelog(connect, "200 webphoto %ld %ld\n", hout->seek, hout->seek);
exits(nil);
}
|