1*7dd7cddfSDavid du Colombier /* 2*7dd7cddfSDavid du Colombier * for GET or POST to /magic/save/foo. 3*7dd7cddfSDavid du Colombier * add incoming data to foo.data. 4*7dd7cddfSDavid du Colombier * send foo.html as reply. 5*7dd7cddfSDavid du Colombier * 6*7dd7cddfSDavid du Colombier * supports foo.data with "exclusive use" mode to prevent interleaved saves. 7*7dd7cddfSDavid du Colombier * thus http://cm.bell-labs.com/magic/save/t?args should access: 8*7dd7cddfSDavid du Colombier * -lrw-rw--w- M 21470 ehg web 1533 May 21 18:19 /usr/web/save/t.data 9*7dd7cddfSDavid du Colombier * --rw-rw-r-- M 21470 ehg web 73 May 21 18:17 /usr/web/save/t.html 10*7dd7cddfSDavid du Colombier */ 11*7dd7cddfSDavid du Colombier #include <u.h> 12*7dd7cddfSDavid du Colombier #include <libc.h> 13*7dd7cddfSDavid du Colombier #include <bio.h> 14*7dd7cddfSDavid du Colombier #include "httpd.h" 15*7dd7cddfSDavid du Colombier 16*7dd7cddfSDavid du Colombier enum 17*7dd7cddfSDavid du Colombier { 18*7dd7cddfSDavid du Colombier MaxLog = 24*1024, /* limit on length of any one log request */ 19*7dd7cddfSDavid du Colombier LockSecs = MaxLog/500, /* seconds to wait before giving up on opening the data file */ 20*7dd7cddfSDavid du Colombier }; 21*7dd7cddfSDavid du Colombier 22*7dd7cddfSDavid du Colombier static int 23*7dd7cddfSDavid du Colombier dangerous(char *s) 24*7dd7cddfSDavid du Colombier { 25*7dd7cddfSDavid du Colombier if(s == nil) 26*7dd7cddfSDavid du Colombier return 1; 27*7dd7cddfSDavid du Colombier 28*7dd7cddfSDavid du Colombier /* 29*7dd7cddfSDavid du Colombier * This check shouldn't be needed; 30*7dd7cddfSDavid du Colombier * filename folding is already supposed to have happened. 31*7dd7cddfSDavid du Colombier * But I'm paranoid. 32*7dd7cddfSDavid du Colombier */ 33*7dd7cddfSDavid du Colombier while(s = strchr(s,'/')){ 34*7dd7cddfSDavid du Colombier if(s[1]=='.' && s[2]=='.') 35*7dd7cddfSDavid du Colombier return 1; 36*7dd7cddfSDavid du Colombier s++; 37*7dd7cddfSDavid du Colombier } 38*7dd7cddfSDavid du Colombier return 0; 39*7dd7cddfSDavid du Colombier } 40*7dd7cddfSDavid du Colombier 41*7dd7cddfSDavid du Colombier /* 42*7dd7cddfSDavid du Colombier * open a file which might be locked. 43*7dd7cddfSDavid du Colombier * if it is, spin until available 44*7dd7cddfSDavid du Colombier */ 45*7dd7cddfSDavid du Colombier int 46*7dd7cddfSDavid du Colombier openLocked(char *file, int mode) 47*7dd7cddfSDavid du Colombier { 48*7dd7cddfSDavid du Colombier char buf[ERRLEN]; 49*7dd7cddfSDavid du Colombier int tries, fd; 50*7dd7cddfSDavid du Colombier 51*7dd7cddfSDavid du Colombier for(tries = 0; tries < LockSecs*2; tries++){ 52*7dd7cddfSDavid du Colombier fd = open(file, mode); 53*7dd7cddfSDavid du Colombier if(fd >= 0) 54*7dd7cddfSDavid du Colombier return fd; 55*7dd7cddfSDavid du Colombier errstr(buf); 56*7dd7cddfSDavid du Colombier if(strstr(buf, "locked") == nil) 57*7dd7cddfSDavid du Colombier break; 58*7dd7cddfSDavid du Colombier sleep(500); 59*7dd7cddfSDavid du Colombier } 60*7dd7cddfSDavid du Colombier return -1; 61*7dd7cddfSDavid du Colombier } 62*7dd7cddfSDavid du Colombier 63*7dd7cddfSDavid du Colombier void 64*7dd7cddfSDavid du Colombier main(int argc, char **argv) 65*7dd7cddfSDavid du Colombier { 66*7dd7cddfSDavid du Colombier Connect *c; 67*7dd7cddfSDavid du Colombier Dir dir; 68*7dd7cddfSDavid du Colombier Hio *hin, *hout; 69*7dd7cddfSDavid du Colombier char *s, *t, *fn; 70*7dd7cddfSDavid du Colombier int n, nfn, datafd, htmlfd; 71*7dd7cddfSDavid du Colombier 72*7dd7cddfSDavid du Colombier c = init(argc, argv); 73*7dd7cddfSDavid du Colombier 74*7dd7cddfSDavid du Colombier if(dangerous(c->req.uri)) 75*7dd7cddfSDavid du Colombier fail(c, Syntax); 76*7dd7cddfSDavid du Colombier 77*7dd7cddfSDavid du Colombier httpheaders(c); 78*7dd7cddfSDavid du Colombier hout = &c->hout; 79*7dd7cddfSDavid du Colombier if(c->head.expectother) 80*7dd7cddfSDavid du Colombier fail(c, ExpectFail, nil); 81*7dd7cddfSDavid du Colombier if(c->head.expectcont){ 82*7dd7cddfSDavid du Colombier hprint(hout, "100 Continue\r\n"); 83*7dd7cddfSDavid du Colombier hprint(hout, "\r\n"); 84*7dd7cddfSDavid du Colombier hflush(hout); 85*7dd7cddfSDavid du Colombier } 86*7dd7cddfSDavid du Colombier 87*7dd7cddfSDavid du Colombier s = nil; 88*7dd7cddfSDavid du Colombier if(strcmp(c->req.meth, "POST") == 0){ 89*7dd7cddfSDavid du Colombier hin = hbodypush(&c->hin, c->head.contlen, c->head.transenc); 90*7dd7cddfSDavid du Colombier if(hin != nil){ 91*7dd7cddfSDavid du Colombier alarm(15*60*1000); 92*7dd7cddfSDavid du Colombier s = hreadbuf(hin, hin->pos); 93*7dd7cddfSDavid du Colombier alarm(0); 94*7dd7cddfSDavid du Colombier } 95*7dd7cddfSDavid du Colombier if(s == nil) 96*7dd7cddfSDavid du Colombier fail(c, BadReq, nil); 97*7dd7cddfSDavid du Colombier t = strchr(s, '\n'); 98*7dd7cddfSDavid du Colombier if(t != nil) 99*7dd7cddfSDavid du Colombier *t = '\0'; 100*7dd7cddfSDavid du Colombier }else if(strcmp(c->req.meth, "GET") != 0 && strcmp(c->req.meth, "HEAD") != 0) 101*7dd7cddfSDavid du Colombier unallowed(c, "GET, HEAD, PUT"); 102*7dd7cddfSDavid du Colombier else 103*7dd7cddfSDavid du Colombier s = c->req.search; 104*7dd7cddfSDavid du Colombier if(s == nil) 105*7dd7cddfSDavid du Colombier fail(c, NoData, "save"); 106*7dd7cddfSDavid du Colombier 107*7dd7cddfSDavid du Colombier if(strlen(s) > MaxLog) 108*7dd7cddfSDavid du Colombier s[MaxLog] = '\0'; 109*7dd7cddfSDavid du Colombier n = snprint(c->xferbuf, BufSize, "at %ld %s\n", time(0), s); 110*7dd7cddfSDavid du Colombier 111*7dd7cddfSDavid du Colombier 112*7dd7cddfSDavid du Colombier nfn = strlen(c->req.uri) + 4 * NAMELEN; 113*7dd7cddfSDavid du Colombier fn = halloc(nfn); 114*7dd7cddfSDavid du Colombier 115*7dd7cddfSDavid du Colombier /* 116*7dd7cddfSDavid du Colombier * open file descriptors & write log line 117*7dd7cddfSDavid du Colombier */ 118*7dd7cddfSDavid du Colombier snprint(fn, nfn, "/usr/web/save/%s.html", c->req.uri); 119*7dd7cddfSDavid du Colombier htmlfd = open(fn, OREAD); 120*7dd7cddfSDavid du Colombier if(htmlfd < 0 || dirfstat(htmlfd, &dir) < 0) 121*7dd7cddfSDavid du Colombier fail(c, NotFound, c->req.uri); 122*7dd7cddfSDavid du Colombier 123*7dd7cddfSDavid du Colombier snprint(fn, nfn, "/usr/web/save/%s.data", c->req.uri); 124*7dd7cddfSDavid du Colombier datafd = openLocked(fn, OWRITE); 125*7dd7cddfSDavid du Colombier if(datafd < 0){ 126*7dd7cddfSDavid du Colombier errstr(c->xferbuf); 127*7dd7cddfSDavid du Colombier if(strstr(c->xferbuf, "locked") != nil) 128*7dd7cddfSDavid du Colombier fail(c, TempFail, c->req.uri); 129*7dd7cddfSDavid du Colombier fail(c, NotFound, c->req.uri); 130*7dd7cddfSDavid du Colombier } 131*7dd7cddfSDavid du Colombier seek(datafd, 0, 2); 132*7dd7cddfSDavid du Colombier write(datafd, c->xferbuf, n); 133*7dd7cddfSDavid du Colombier close(datafd); 134*7dd7cddfSDavid du Colombier 135*7dd7cddfSDavid du Colombier /* 136*7dd7cddfSDavid du Colombier * send the reply 137*7dd7cddfSDavid du Colombier */ 138*7dd7cddfSDavid du Colombier if(c->req.vermaj){ 139*7dd7cddfSDavid du Colombier okheaders(c); 140*7dd7cddfSDavid du Colombier hprint(hout, "Content-type: text/html\r\n"); 141*7dd7cddfSDavid du Colombier hprint(hout, "Content-Length: %lld\r\n", dir.length); 142*7dd7cddfSDavid du Colombier hprint(hout, "\r\n"); 143*7dd7cddfSDavid du Colombier } 144*7dd7cddfSDavid du Colombier if(strcmp(c->req.meth, "HEAD") == 0) 145*7dd7cddfSDavid du Colombier exits(0); 146*7dd7cddfSDavid du Colombier 147*7dd7cddfSDavid du Colombier hflush(hout); 148*7dd7cddfSDavid du Colombier while((n = read(htmlfd, c->xferbuf, BufSize)) > 0) 149*7dd7cddfSDavid du Colombier if(write(1, c->xferbuf, n) != n) 150*7dd7cddfSDavid du Colombier break; 151*7dd7cddfSDavid du Colombier 152*7dd7cddfSDavid du Colombier exits(nil); 153*7dd7cddfSDavid du Colombier } 154