19a747e4fSDavid du Colombier #include <u.h> 29a747e4fSDavid du Colombier #include <libc.h> 39a747e4fSDavid du Colombier #include <bio.h> 49a747e4fSDavid du Colombier #include <ip.h> 59a747e4fSDavid du Colombier #include <plumb.h> 69a747e4fSDavid du Colombier #include <thread.h> 79a747e4fSDavid du Colombier #include <fcall.h> 89a747e4fSDavid du Colombier #include <9p.h> 99dfc0cb2SDavid du Colombier #include <libsec.h> 109dfc0cb2SDavid du Colombier #include <auth.h> 119a747e4fSDavid du Colombier #include "dat.h" 129a747e4fSDavid du Colombier #include "fns.h" 139a747e4fSDavid du Colombier 14*1066d6deSDavid du Colombier char PostContentType[] = "application/x-www-form-urlencoded"; 159a747e4fSDavid du Colombier int httpdebug; 169a747e4fSDavid du Colombier 179a747e4fSDavid du Colombier typedef struct HttpState HttpState; 189a747e4fSDavid du Colombier struct HttpState 199a747e4fSDavid du Colombier { 209a747e4fSDavid du Colombier int fd; 219a747e4fSDavid du Colombier Client *c; 229a747e4fSDavid du Colombier char *location; 239a747e4fSDavid du Colombier char *setcookie; 249a747e4fSDavid du Colombier char *netaddr; 259dfc0cb2SDavid du Colombier char *credentials; 269dfc0cb2SDavid du Colombier char autherror[ERRMAX]; 279a747e4fSDavid du Colombier Ibuf b; 289a747e4fSDavid du Colombier }; 299a747e4fSDavid du Colombier 309a747e4fSDavid du Colombier static void 319a747e4fSDavid du Colombier location(HttpState *hs, char *value) 329a747e4fSDavid du Colombier { 339a747e4fSDavid du Colombier if(hs->location == nil) 349a747e4fSDavid du Colombier hs->location = estrdup(value); 359a747e4fSDavid du Colombier } 369a747e4fSDavid du Colombier 379a747e4fSDavid du Colombier static void 389a747e4fSDavid du Colombier contenttype(HttpState *hs, char *value) 399a747e4fSDavid du Colombier { 403b56890dSDavid du Colombier if(hs->c->contenttype != nil) 413b56890dSDavid du Colombier free(hs->c->contenttype); 429a747e4fSDavid du Colombier hs->c->contenttype = estrdup(value); 439a747e4fSDavid du Colombier } 449a747e4fSDavid du Colombier 459a747e4fSDavid du Colombier static void 469a747e4fSDavid du Colombier setcookie(HttpState *hs, char *value) 479a747e4fSDavid du Colombier { 489a747e4fSDavid du Colombier char *s, *t; 499a747e4fSDavid du Colombier Fmt f; 509a747e4fSDavid du Colombier 519a747e4fSDavid du Colombier s = hs->setcookie; 529a747e4fSDavid du Colombier fmtstrinit(&f); 539a747e4fSDavid du Colombier if(s) 549a747e4fSDavid du Colombier fmtprint(&f, "%s", s); 559a747e4fSDavid du Colombier fmtprint(&f, "set-cookie: "); 569a747e4fSDavid du Colombier fmtprint(&f, "%s", value); 579a747e4fSDavid du Colombier fmtprint(&f, "\n"); 589a747e4fSDavid du Colombier t = fmtstrflush(&f); 599a747e4fSDavid du Colombier if(t){ 609a747e4fSDavid du Colombier free(s); 619a747e4fSDavid du Colombier hs->setcookie = t; 629a747e4fSDavid du Colombier } 639a747e4fSDavid du Colombier } 649a747e4fSDavid du Colombier 659dfc0cb2SDavid du Colombier static char* 669dfc0cb2SDavid du Colombier unquote(char *s, char **ps) 679dfc0cb2SDavid du Colombier { 689dfc0cb2SDavid du Colombier char *p; 699dfc0cb2SDavid du Colombier 709dfc0cb2SDavid du Colombier if(*s != '"'){ 719dfc0cb2SDavid du Colombier p = strpbrk(s, " \t\r\n"); 729dfc0cb2SDavid du Colombier *p++ = 0; 739dfc0cb2SDavid du Colombier *ps = p; 749dfc0cb2SDavid du Colombier return s; 759dfc0cb2SDavid du Colombier } 769dfc0cb2SDavid du Colombier for(p=s+1; *p; p++){ 779dfc0cb2SDavid du Colombier if(*p == '\"'){ 789dfc0cb2SDavid du Colombier *p++ = 0; 799dfc0cb2SDavid du Colombier break; 809dfc0cb2SDavid du Colombier } 819dfc0cb2SDavid du Colombier if(*p == '\\' && *(p+1)){ 829dfc0cb2SDavid du Colombier p++; 839dfc0cb2SDavid du Colombier continue; 849dfc0cb2SDavid du Colombier } 859dfc0cb2SDavid du Colombier } 869dfc0cb2SDavid du Colombier memmove(s, s+1, p-(s+1)); 879dfc0cb2SDavid du Colombier s[p-(s+1)] = 0; 889dfc0cb2SDavid du Colombier *ps = p; 899dfc0cb2SDavid du Colombier return s; 909dfc0cb2SDavid du Colombier } 919dfc0cb2SDavid du Colombier 929dfc0cb2SDavid du Colombier static char* 939dfc0cb2SDavid du Colombier servername(char *addr) 949dfc0cb2SDavid du Colombier { 959dfc0cb2SDavid du Colombier char *p; 969dfc0cb2SDavid du Colombier 979dfc0cb2SDavid du Colombier if(strncmp(addr, "tcp!", 4) == 0 989dfc0cb2SDavid du Colombier || strncmp(addr, "net!", 4) == 0) 999dfc0cb2SDavid du Colombier addr += 4; 1009dfc0cb2SDavid du Colombier addr = estrdup(addr); 1019dfc0cb2SDavid du Colombier p = addr+strlen(addr); 1029dfc0cb2SDavid du Colombier if(p>addr && *(p-1) == 's') 1039dfc0cb2SDavid du Colombier p--; 1049dfc0cb2SDavid du Colombier if(p>addr+5 && strcmp(p-5, "!http") == 0) 1059dfc0cb2SDavid du Colombier p[-5] = 0; 1069dfc0cb2SDavid du Colombier return addr; 1079dfc0cb2SDavid du Colombier } 1089dfc0cb2SDavid du Colombier 1099dfc0cb2SDavid du Colombier void 1109dfc0cb2SDavid du Colombier wwwauthenticate(HttpState *hs, char *line) 1119dfc0cb2SDavid du Colombier { 1129dfc0cb2SDavid du Colombier char cred[64], *user, *pass, *realm, *s, *spec, *name; 1139dfc0cb2SDavid du Colombier Fmt fmt; 1149dfc0cb2SDavid du Colombier UserPasswd *up; 1159dfc0cb2SDavid du Colombier 1169dfc0cb2SDavid du Colombier spec = nil; 1179dfc0cb2SDavid du Colombier up = nil; 1189dfc0cb2SDavid du Colombier cred[0] = 0; 1199dfc0cb2SDavid du Colombier hs->autherror[0] = 0; 1209dfc0cb2SDavid du Colombier if(cistrncmp(line, "basic ", 6) != 0){ 1219dfc0cb2SDavid du Colombier werrstr("unknown auth: %s", line); 1229dfc0cb2SDavid du Colombier goto error; 1239dfc0cb2SDavid du Colombier } 1249dfc0cb2SDavid du Colombier line += 6; 1259dfc0cb2SDavid du Colombier if(cistrncmp(line, "realm=", 6) != 0){ 1269dfc0cb2SDavid du Colombier werrstr("missing realm: %s", line); 1279dfc0cb2SDavid du Colombier goto error; 1289dfc0cb2SDavid du Colombier } 1299dfc0cb2SDavid du Colombier line += 6; 1309dfc0cb2SDavid du Colombier user = hs->c->url->user; 1319dfc0cb2SDavid du Colombier pass = hs->c->url->passwd; 1329dfc0cb2SDavid du Colombier if(user==nil || pass==nil){ 1339dfc0cb2SDavid du Colombier realm = unquote(line, &line); 1349dfc0cb2SDavid du Colombier fmtstrinit(&fmt); 1359dfc0cb2SDavid du Colombier name = servername(hs->netaddr); 1369dfc0cb2SDavid du Colombier fmtprint(&fmt, "proto=pass service=http server=%q realm=%q", name, realm); 1379dfc0cb2SDavid du Colombier free(name); 1389dfc0cb2SDavid du Colombier if(hs->c->url->user) 1399dfc0cb2SDavid du Colombier fmtprint(&fmt, " user=%q", hs->c->url->user); 1409dfc0cb2SDavid du Colombier spec = fmtstrflush(&fmt); 1419dfc0cb2SDavid du Colombier if(spec == nil) 1429dfc0cb2SDavid du Colombier goto error; 1439dfc0cb2SDavid du Colombier if((up = auth_getuserpasswd(nil, "%s", spec)) == nil) 1449dfc0cb2SDavid du Colombier goto error; 1459dfc0cb2SDavid du Colombier user = up->user; 1469dfc0cb2SDavid du Colombier pass = up->passwd; 1479dfc0cb2SDavid du Colombier } 1489dfc0cb2SDavid du Colombier if((s = smprint("%s:%s", user, pass)) == nil) 1499dfc0cb2SDavid du Colombier goto error; 1509dfc0cb2SDavid du Colombier free(up); 1519dfc0cb2SDavid du Colombier enc64(cred, sizeof(cred), (uchar*)s, strlen(s)); 1529dfc0cb2SDavid du Colombier memset(s, 0, strlen(s)); 1539dfc0cb2SDavid du Colombier free(s); 1549dfc0cb2SDavid du Colombier hs->credentials = smprint("Basic %s", cred); 1559dfc0cb2SDavid du Colombier if(hs->credentials == nil) 1569dfc0cb2SDavid du Colombier goto error; 1579dfc0cb2SDavid du Colombier return; 1589dfc0cb2SDavid du Colombier 1599dfc0cb2SDavid du Colombier error: 1609dfc0cb2SDavid du Colombier free(up); 1619dfc0cb2SDavid du Colombier free(spec); 1629dfc0cb2SDavid du Colombier snprint(hs->autherror, sizeof hs->autherror, "%r"); 1639dfc0cb2SDavid du Colombier } 1649dfc0cb2SDavid du Colombier 1659a747e4fSDavid du Colombier struct { 1669a747e4fSDavid du Colombier char *name; /* Case-insensitive */ 1679a747e4fSDavid du Colombier void (*fn)(HttpState *hs, char *value); 1689a747e4fSDavid du Colombier } hdrtab[] = { 1699a747e4fSDavid du Colombier { "location:", location }, 1709a747e4fSDavid du Colombier { "content-type:", contenttype }, 1719a747e4fSDavid du Colombier { "set-cookie:", setcookie }, 1729dfc0cb2SDavid du Colombier { "www-authenticate:", wwwauthenticate }, 1739a747e4fSDavid du Colombier }; 1749a747e4fSDavid du Colombier 1759a747e4fSDavid du Colombier static int 1769a747e4fSDavid du Colombier httprcode(HttpState *hs) 1779a747e4fSDavid du Colombier { 1789a747e4fSDavid du Colombier int n; 1799a747e4fSDavid du Colombier char *p; 1809a747e4fSDavid du Colombier char buf[256]; 1819a747e4fSDavid du Colombier 1829a747e4fSDavid du Colombier n = readline(&hs->b, buf, sizeof(buf)-1); 1839a747e4fSDavid du Colombier if(n <= 0) 1849a747e4fSDavid du Colombier return n; 1859a747e4fSDavid du Colombier if(httpdebug) 1869a747e4fSDavid du Colombier fprint(2, "-> %s\n", buf); 1879a747e4fSDavid du Colombier p = strchr(buf, ' '); 1889a747e4fSDavid du Colombier if(memcmp(buf, "HTTP/", 5) != 0 || p == nil){ 1899a747e4fSDavid du Colombier werrstr("bad response from server"); 1909a747e4fSDavid du Colombier return -1; 1919a747e4fSDavid du Colombier } 1929a747e4fSDavid du Colombier buf[n] = 0; 1939a747e4fSDavid du Colombier return atoi(p+1); 1949a747e4fSDavid du Colombier } 1959a747e4fSDavid du Colombier 1969a747e4fSDavid du Colombier /* 1979a747e4fSDavid du Colombier * read a single mime header, collect continuations. 1989a747e4fSDavid du Colombier * 1999a747e4fSDavid du Colombier * this routine assumes that there is a blank line twixt 2009a747e4fSDavid du Colombier * the header and the message body, otherwise bytes will 2019a747e4fSDavid du Colombier * be lost. 2029a747e4fSDavid du Colombier */ 2039a747e4fSDavid du Colombier static int 2049a747e4fSDavid du Colombier getheader(HttpState *hs, char *buf, int n) 2059a747e4fSDavid du Colombier { 2069a747e4fSDavid du Colombier char *p, *e; 2079a747e4fSDavid du Colombier int i; 2089a747e4fSDavid du Colombier 2099a747e4fSDavid du Colombier n--; 2109a747e4fSDavid du Colombier p = buf; 2119a747e4fSDavid du Colombier for(e = p + n; ; p += i){ 2129a747e4fSDavid du Colombier i = readline(&hs->b, p, e-p); 2139a747e4fSDavid du Colombier if(i < 0) 2149a747e4fSDavid du Colombier return i; 2159a747e4fSDavid du Colombier 2169a747e4fSDavid du Colombier if(p == buf){ 2179a747e4fSDavid du Colombier /* first line */ 2189a747e4fSDavid du Colombier if(strchr(buf, ':') == nil) 2199a747e4fSDavid du Colombier break; /* end of headers */ 2209a747e4fSDavid du Colombier } else { 2219a747e4fSDavid du Colombier /* continuation line */ 2229a747e4fSDavid du Colombier if(*p != ' ' && *p != '\t'){ 2239a747e4fSDavid du Colombier unreadline(&hs->b, p); 2249a747e4fSDavid du Colombier *p = 0; 2259a747e4fSDavid du Colombier break; /* end of this header */ 2269a747e4fSDavid du Colombier } 2279a747e4fSDavid du Colombier } 2289a747e4fSDavid du Colombier } 2299a747e4fSDavid du Colombier 2309a747e4fSDavid du Colombier if(httpdebug) 2319a747e4fSDavid du Colombier fprint(2, "-> %s\n", buf); 2329a747e4fSDavid du Colombier return p-buf; 2339a747e4fSDavid du Colombier } 2349a747e4fSDavid du Colombier 2359a747e4fSDavid du Colombier static int 2369a747e4fSDavid du Colombier httpheaders(HttpState *hs) 2379a747e4fSDavid du Colombier { 2389a747e4fSDavid du Colombier char buf[2048]; 2399a747e4fSDavid du Colombier char *p; 2409a747e4fSDavid du Colombier int i, n; 2419a747e4fSDavid du Colombier 2429a747e4fSDavid du Colombier for(;;){ 2439a747e4fSDavid du Colombier n = getheader(hs, buf, sizeof(buf)); 2449a747e4fSDavid du Colombier if(n < 0) 2459a747e4fSDavid du Colombier return -1; 2469a747e4fSDavid du Colombier if(n == 0) 2479a747e4fSDavid du Colombier return 0; 2489a747e4fSDavid du Colombier // print("http header: '%.*s'\n", n, buf); 2499a747e4fSDavid du Colombier for(i = 0; i < nelem(hdrtab); i++){ 2509a747e4fSDavid du Colombier n = strlen(hdrtab[i].name); 2519a747e4fSDavid du Colombier if(cistrncmp(buf, hdrtab[i].name, n) == 0){ 2529a747e4fSDavid du Colombier /* skip field name and leading white */ 2539a747e4fSDavid du Colombier p = buf + n; 2549a747e4fSDavid du Colombier while(*p == ' ' || *p == '\t') 2559a747e4fSDavid du Colombier p++; 2569a747e4fSDavid du Colombier (*hdrtab[i].fn)(hs, p); 2579a747e4fSDavid du Colombier break; 2589a747e4fSDavid du Colombier } 2599a747e4fSDavid du Colombier } 2609a747e4fSDavid du Colombier } 2619a747e4fSDavid du Colombier } 2629a747e4fSDavid du Colombier 2639a747e4fSDavid du Colombier int 2649a747e4fSDavid du Colombier httpopen(Client *c, Url *url) 2659a747e4fSDavid du Colombier { 2669dfc0cb2SDavid du Colombier int fd, code, redirect, authenticate; 2679a747e4fSDavid du Colombier char *cookies; 2689a747e4fSDavid du Colombier Ioproc *io; 2699a747e4fSDavid du Colombier HttpState *hs; 2709a747e4fSDavid du Colombier 2719a747e4fSDavid du Colombier if(httpdebug) 2729a747e4fSDavid du Colombier fprint(2, "httpopen\n"); 2739a747e4fSDavid du Colombier io = c->io; 2749a747e4fSDavid du Colombier hs = emalloc(sizeof(*hs)); 2759a747e4fSDavid du Colombier hs->c = c; 2769a747e4fSDavid du Colombier hs->netaddr = estrdup(netmkaddr(url->host, 0, url->scheme)); 2779a747e4fSDavid du Colombier c->aux = hs; 2789a747e4fSDavid du Colombier if(httpdebug) 2799a747e4fSDavid du Colombier fprint(2, "dial %s\n", hs->netaddr); 2803ff48bf5SDavid du Colombier fd = iotlsdial(io, hs->netaddr, 0, 0, 0, url->ischeme==UShttps); 2819a747e4fSDavid du Colombier if(fd < 0){ 2829a747e4fSDavid du Colombier Error: 2839a747e4fSDavid du Colombier if(httpdebug) 2843ff48bf5SDavid du Colombier fprint(2, "iodial: %r\n"); 2859a747e4fSDavid du Colombier free(hs->netaddr); 2869a747e4fSDavid du Colombier close(hs->fd); 2879a747e4fSDavid du Colombier hs->fd = -1; 288e288d156SDavid du Colombier free(hs); 2899a747e4fSDavid du Colombier c->aux = nil; 2909a747e4fSDavid du Colombier return -1; 2919a747e4fSDavid du Colombier } 2929a747e4fSDavid du Colombier hs->fd = fd; 2939a747e4fSDavid du Colombier if(httpdebug) 2949a747e4fSDavid du Colombier fprint(2, "<- %s %s HTTP/1.0\n<- Host: %s\n", 2959a747e4fSDavid du Colombier c->havepostbody? "POST": " GET", url->http.page_spec, url->host); 2963ff48bf5SDavid du Colombier ioprint(io, fd, "%s %s HTTP/1.0\r\nHost: %s\r\n", 2979a747e4fSDavid du Colombier c->havepostbody? "POST" : "GET", url->http.page_spec, url->host); 2989a747e4fSDavid du Colombier if(httpdebug) 2999a747e4fSDavid du Colombier fprint(2, "<- User-Agent: %s\n", c->ctl.useragent); 3009a747e4fSDavid du Colombier if(c->ctl.useragent) 3013ff48bf5SDavid du Colombier ioprint(io, fd, "User-Agent: %s\r\n", c->ctl.useragent); 3029a747e4fSDavid du Colombier if(c->ctl.sendcookies){ 3039a747e4fSDavid du Colombier /* should we use url->page here? sometimes it is nil. */ 3049a747e4fSDavid du Colombier cookies = httpcookies(url->host, url->http.page_spec, 0); 3059a747e4fSDavid du Colombier if(cookies && cookies[0]) 3063ff48bf5SDavid du Colombier ioprint(io, fd, "%s", cookies); 3079a747e4fSDavid du Colombier if(httpdebug) 3089a747e4fSDavid du Colombier fprint(2, "<- %s", cookies); 3099a747e4fSDavid du Colombier free(cookies); 3109a747e4fSDavid du Colombier } 3119a747e4fSDavid du Colombier if(c->havepostbody){ 3123ff48bf5SDavid du Colombier ioprint(io, fd, "Content-type: %s\r\n", PostContentType); 3133ff48bf5SDavid du Colombier ioprint(io, fd, "Content-length: %ud\r\n", c->npostbody); 3149a747e4fSDavid du Colombier if(httpdebug){ 3159a747e4fSDavid du Colombier fprint(2, "<- Content-type: %s\n", PostContentType); 3169a747e4fSDavid du Colombier fprint(2, "<- Content-length: %ud\n", c->npostbody); 3179a747e4fSDavid du Colombier } 3189a747e4fSDavid du Colombier } 3199dfc0cb2SDavid du Colombier if(c->authenticate){ 3209dfc0cb2SDavid du Colombier ioprint(io, fd, "Authorization: %s\r\n", c->authenticate); 3219dfc0cb2SDavid du Colombier if(httpdebug) 3229dfc0cb2SDavid du Colombier fprint(2, "<- Authorization: %s\n", c->authenticate); 3239dfc0cb2SDavid du Colombier } 3243ff48bf5SDavid du Colombier ioprint(io, fd, "\r\n"); 3259a747e4fSDavid du Colombier if(c->havepostbody) 3263ff48bf5SDavid du Colombier if(iowrite(io, fd, c->postbody, c->npostbody) != c->npostbody) 3279a747e4fSDavid du Colombier goto Error; 3289a747e4fSDavid du Colombier 3299a747e4fSDavid du Colombier c->havepostbody = 0; 3309a747e4fSDavid du Colombier redirect = 0; 3319dfc0cb2SDavid du Colombier authenticate = 0; 3329a747e4fSDavid du Colombier initibuf(&hs->b, io, fd); 3339a747e4fSDavid du Colombier code = httprcode(hs); 3349a747e4fSDavid du Colombier 3359a747e4fSDavid du Colombier switch(code){ 3369a747e4fSDavid du Colombier case -1: /* connection timed out */ 3379a747e4fSDavid du Colombier goto Error; 3389a747e4fSDavid du Colombier 3399a747e4fSDavid du Colombier /* 3409a747e4fSDavid du Colombier case Eof: 3419a747e4fSDavid du Colombier werrstr("EOF from HTTP server"); 3429a747e4fSDavid du Colombier goto Error; 3439a747e4fSDavid du Colombier */ 3449a747e4fSDavid du Colombier 3459a747e4fSDavid du Colombier case 200: /* OK */ 3469a747e4fSDavid du Colombier case 201: /* Created */ 3479a747e4fSDavid du Colombier case 202: /* Accepted */ 3489a747e4fSDavid du Colombier case 204: /* No Content */ 3499a747e4fSDavid du Colombier #ifdef NOT_DEFINED 3509a747e4fSDavid du Colombier if(ofile == nil && r->start != 0) 3519a747e4fSDavid du Colombier sysfatal("page changed underfoot"); 3529a747e4fSDavid du Colombier #endif 3539a747e4fSDavid du Colombier break; 3549a747e4fSDavid du Colombier 3559a747e4fSDavid du Colombier case 206: /* Partial Content */ 3569a747e4fSDavid du Colombier werrstr("Partial Content (206)"); 3579a747e4fSDavid du Colombier goto Error; 3589a747e4fSDavid du Colombier 3599a747e4fSDavid du Colombier case 301: /* Moved Permanently */ 3609a747e4fSDavid du Colombier case 302: /* Moved Temporarily */ 3619a747e4fSDavid du Colombier redirect = 1; 3629a747e4fSDavid du Colombier break; 3639a747e4fSDavid du Colombier 3649a747e4fSDavid du Colombier case 304: /* Not Modified */ 3659a747e4fSDavid du Colombier break; 3669a747e4fSDavid du Colombier 3679a747e4fSDavid du Colombier case 400: /* Bad Request */ 3689a747e4fSDavid du Colombier werrstr("Bad Request (400)"); 3699a747e4fSDavid du Colombier goto Error; 3709a747e4fSDavid du Colombier 3719a747e4fSDavid du Colombier case 401: /* Unauthorized */ 3729dfc0cb2SDavid du Colombier if(c->authenticate){ 3739dfc0cb2SDavid du Colombier werrstr("Authentication failed (401)"); 3749dfc0cb2SDavid du Colombier goto Error; 3759dfc0cb2SDavid du Colombier } 3769dfc0cb2SDavid du Colombier authenticate = 1; 3779dfc0cb2SDavid du Colombier break; 3789a747e4fSDavid du Colombier case 402: /* ??? */ 3799dfc0cb2SDavid du Colombier werrstr("Unauthorized (402)"); 3809a747e4fSDavid du Colombier goto Error; 3819a747e4fSDavid du Colombier 3829a747e4fSDavid du Colombier case 403: /* Forbidden */ 3839a747e4fSDavid du Colombier werrstr("Forbidden by server (403)"); 3849a747e4fSDavid du Colombier goto Error; 3859a747e4fSDavid du Colombier 3869a747e4fSDavid du Colombier case 404: /* Not Found */ 3879a747e4fSDavid du Colombier werrstr("Not found on server (404)"); 3889a747e4fSDavid du Colombier goto Error; 3899a747e4fSDavid du Colombier 39035393782SDavid du Colombier case 405: /* Method Not Allowed */ 39135393782SDavid du Colombier werrstr("Method not allowed (405)"); 39235393782SDavid du Colombier goto Error; 39335393782SDavid du Colombier 3949dfc0cb2SDavid du Colombier case 407: /* Proxy auth */ 3959dfc0cb2SDavid du Colombier werrstr("Proxy authentication required (407)"); 3969dfc0cb2SDavid du Colombier goto Error; 3979dfc0cb2SDavid du Colombier 3989a747e4fSDavid du Colombier case 500: /* Internal server error */ 3999a747e4fSDavid du Colombier werrstr("Server choked (500)"); 4009a747e4fSDavid du Colombier goto Error; 4019a747e4fSDavid du Colombier 4029a747e4fSDavid du Colombier case 501: /* Not implemented */ 4039a747e4fSDavid du Colombier werrstr("Server can't do it (501)"); 4049a747e4fSDavid du Colombier goto Error; 4059a747e4fSDavid du Colombier 4069a747e4fSDavid du Colombier case 502: /* Bad gateway */ 4079a747e4fSDavid du Colombier werrstr("Bad gateway (502)"); 4089a747e4fSDavid du Colombier goto Error; 4099a747e4fSDavid du Colombier 4109a747e4fSDavid du Colombier case 503: /* Service unavailable */ 4119a747e4fSDavid du Colombier werrstr("Service unavailable (503)"); 4129a747e4fSDavid du Colombier goto Error; 4139a747e4fSDavid du Colombier 4149a747e4fSDavid du Colombier default: 4159a747e4fSDavid du Colombier /* Bogus: we should treat unknown code XYZ as code X00 */ 4169a747e4fSDavid du Colombier werrstr("Unknown response code %d", code); 4179a747e4fSDavid du Colombier goto Error; 4189a747e4fSDavid du Colombier } 4199a747e4fSDavid du Colombier 4209a747e4fSDavid du Colombier if(httpheaders(hs) < 0) 4219a747e4fSDavid du Colombier goto Error; 4229a747e4fSDavid du Colombier if(c->ctl.acceptcookies && hs->setcookie) 4239a747e4fSDavid du Colombier httpsetcookie(hs->setcookie, url->host, url->path); 4249dfc0cb2SDavid du Colombier if(authenticate){ 4259dfc0cb2SDavid du Colombier if(!hs->credentials){ 4269dfc0cb2SDavid du Colombier if(hs->autherror[0]) 4279dfc0cb2SDavid du Colombier werrstr("%s", hs->autherror); 4289dfc0cb2SDavid du Colombier else 4299dfc0cb2SDavid du Colombier werrstr("unauthorized; no www-authenticate: header"); 4309dfc0cb2SDavid du Colombier return -1; 4319dfc0cb2SDavid du Colombier } 4329dfc0cb2SDavid du Colombier c->authenticate = hs->credentials; 4339dfc0cb2SDavid du Colombier hs->credentials = nil; 4349dfc0cb2SDavid du Colombier } 4359a747e4fSDavid du Colombier if(redirect){ 4369a747e4fSDavid du Colombier if(!hs->location){ 4379a747e4fSDavid du Colombier werrstr("redirection without Location: header"); 4389a747e4fSDavid du Colombier return -1; 4399a747e4fSDavid du Colombier } 4409a747e4fSDavid du Colombier c->redirect = hs->location; 4419a747e4fSDavid du Colombier hs->location = nil; 4429a747e4fSDavid du Colombier } 4439a747e4fSDavid du Colombier return 0; 4449a747e4fSDavid du Colombier } 4459a747e4fSDavid du Colombier 4469a747e4fSDavid du Colombier int 4479a747e4fSDavid du Colombier httpread(Client *c, Req *r) 4489a747e4fSDavid du Colombier { 4499a747e4fSDavid du Colombier HttpState *hs; 450*1066d6deSDavid du Colombier long n; 4519a747e4fSDavid du Colombier 4529a747e4fSDavid du Colombier hs = c->aux; 453*1066d6deSDavid du Colombier n = readibuf(&hs->b, r->ofcall.data, r->ifcall.count); 454*1066d6deSDavid du Colombier if(n < 0) 4559a747e4fSDavid du Colombier return -1; 456*1066d6deSDavid du Colombier 457*1066d6deSDavid du Colombier r->ofcall.count = n; 4589a747e4fSDavid du Colombier return 0; 4599a747e4fSDavid du Colombier } 4609a747e4fSDavid du Colombier 4619a747e4fSDavid du Colombier void 4629a747e4fSDavid du Colombier httpclose(Client *c) 4639a747e4fSDavid du Colombier { 4649a747e4fSDavid du Colombier HttpState *hs; 4659a747e4fSDavid du Colombier 4669a747e4fSDavid du Colombier hs = c->aux; 4676b6b9ac8SDavid du Colombier if(hs == nil) 4686b6b9ac8SDavid du Colombier return; 4693ff48bf5SDavid du Colombier ioclose(c->io, hs->fd); 4709a747e4fSDavid du Colombier hs->fd = -1; 4719a747e4fSDavid du Colombier free(hs->location); 4729a747e4fSDavid du Colombier free(hs->setcookie); 4739a747e4fSDavid du Colombier free(hs->netaddr); 4749dfc0cb2SDavid du Colombier free(hs->credentials); 4759a747e4fSDavid du Colombier free(hs); 4769a747e4fSDavid du Colombier c->aux = nil; 4779a747e4fSDavid du Colombier } 4789a747e4fSDavid du Colombier 479