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 141066d6deSDavid 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"); 163ac84fd08SDavid du Colombier fprint(2, "%s: Authentication failed: %r\n", argv0); 1649dfc0cb2SDavid du Colombier } 1659dfc0cb2SDavid du Colombier 1669a747e4fSDavid du Colombier struct { 1679a747e4fSDavid du Colombier char *name; /* Case-insensitive */ 1689a747e4fSDavid du Colombier void (*fn)(HttpState *hs, char *value); 1699a747e4fSDavid du Colombier } hdrtab[] = { 1709a747e4fSDavid du Colombier { "location:", location }, 1719a747e4fSDavid du Colombier { "content-type:", contenttype }, 1729a747e4fSDavid du Colombier { "set-cookie:", setcookie }, 1739dfc0cb2SDavid du Colombier { "www-authenticate:", wwwauthenticate }, 1749a747e4fSDavid du Colombier }; 1759a747e4fSDavid du Colombier 1769a747e4fSDavid du Colombier static int 1779a747e4fSDavid du Colombier httprcode(HttpState *hs) 1789a747e4fSDavid du Colombier { 1799a747e4fSDavid du Colombier int n; 1809a747e4fSDavid du Colombier char *p; 1819a747e4fSDavid du Colombier char buf[256]; 1829a747e4fSDavid du Colombier 1839a747e4fSDavid du Colombier n = readline(&hs->b, buf, sizeof(buf)-1); 1849a747e4fSDavid du Colombier if(n <= 0) 1859a747e4fSDavid du Colombier return n; 1869a747e4fSDavid du Colombier if(httpdebug) 1879a747e4fSDavid du Colombier fprint(2, "-> %s\n", buf); 1889a747e4fSDavid du Colombier p = strchr(buf, ' '); 1899a747e4fSDavid du Colombier if(memcmp(buf, "HTTP/", 5) != 0 || p == nil){ 1909a747e4fSDavid du Colombier werrstr("bad response from server"); 1919a747e4fSDavid du Colombier return -1; 1929a747e4fSDavid du Colombier } 1939a747e4fSDavid du Colombier buf[n] = 0; 1949a747e4fSDavid du Colombier return atoi(p+1); 1959a747e4fSDavid du Colombier } 1969a747e4fSDavid du Colombier 1979a747e4fSDavid du Colombier /* 1989a747e4fSDavid du Colombier * read a single mime header, collect continuations. 1999a747e4fSDavid du Colombier * 2009a747e4fSDavid du Colombier * this routine assumes that there is a blank line twixt 2019a747e4fSDavid du Colombier * the header and the message body, otherwise bytes will 2029a747e4fSDavid du Colombier * be lost. 2039a747e4fSDavid du Colombier */ 2049a747e4fSDavid du Colombier static int 2059a747e4fSDavid du Colombier getheader(HttpState *hs, char *buf, int n) 2069a747e4fSDavid du Colombier { 2079a747e4fSDavid du Colombier char *p, *e; 2089a747e4fSDavid du Colombier int i; 2099a747e4fSDavid du Colombier 2109a747e4fSDavid du Colombier n--; 2119a747e4fSDavid du Colombier p = buf; 2129a747e4fSDavid du Colombier for(e = p + n; ; p += i){ 2139a747e4fSDavid du Colombier i = readline(&hs->b, p, e-p); 2149a747e4fSDavid du Colombier if(i < 0) 2159a747e4fSDavid du Colombier return i; 2169a747e4fSDavid du Colombier 2179a747e4fSDavid du Colombier if(p == buf){ 2189a747e4fSDavid du Colombier /* first line */ 2199a747e4fSDavid du Colombier if(strchr(buf, ':') == nil) 2209a747e4fSDavid du Colombier break; /* end of headers */ 2219a747e4fSDavid du Colombier } else { 2229a747e4fSDavid du Colombier /* continuation line */ 2239a747e4fSDavid du Colombier if(*p != ' ' && *p != '\t'){ 2249a747e4fSDavid du Colombier unreadline(&hs->b, p); 2259a747e4fSDavid du Colombier *p = 0; 2269a747e4fSDavid du Colombier break; /* end of this header */ 2279a747e4fSDavid du Colombier } 2289a747e4fSDavid du Colombier } 2299a747e4fSDavid du Colombier } 2309a747e4fSDavid du Colombier 2319a747e4fSDavid du Colombier if(httpdebug) 2329a747e4fSDavid du Colombier fprint(2, "-> %s\n", buf); 2339a747e4fSDavid du Colombier return p-buf; 2349a747e4fSDavid du Colombier } 2359a747e4fSDavid du Colombier 2369a747e4fSDavid du Colombier static int 2379a747e4fSDavid du Colombier httpheaders(HttpState *hs) 2389a747e4fSDavid du Colombier { 2399a747e4fSDavid du Colombier char buf[2048]; 2409a747e4fSDavid du Colombier char *p; 2419a747e4fSDavid du Colombier int i, n; 2429a747e4fSDavid du Colombier 2439a747e4fSDavid du Colombier for(;;){ 2449a747e4fSDavid du Colombier n = getheader(hs, buf, sizeof(buf)); 2459a747e4fSDavid du Colombier if(n < 0) 2469a747e4fSDavid du Colombier return -1; 2479a747e4fSDavid du Colombier if(n == 0) 2489a747e4fSDavid du Colombier return 0; 2499a747e4fSDavid du Colombier // print("http header: '%.*s'\n", n, buf); 2509a747e4fSDavid du Colombier for(i = 0; i < nelem(hdrtab); i++){ 2519a747e4fSDavid du Colombier n = strlen(hdrtab[i].name); 2529a747e4fSDavid du Colombier if(cistrncmp(buf, hdrtab[i].name, n) == 0){ 2539a747e4fSDavid du Colombier /* skip field name and leading white */ 2549a747e4fSDavid du Colombier p = buf + n; 2559a747e4fSDavid du Colombier while(*p == ' ' || *p == '\t') 2569a747e4fSDavid du Colombier p++; 2579a747e4fSDavid du Colombier (*hdrtab[i].fn)(hs, p); 2589a747e4fSDavid du Colombier break; 2599a747e4fSDavid du Colombier } 2609a747e4fSDavid du Colombier } 2619a747e4fSDavid du Colombier } 2629a747e4fSDavid du Colombier } 2639a747e4fSDavid du Colombier 2649a747e4fSDavid du Colombier int 2659a747e4fSDavid du Colombier httpopen(Client *c, Url *url) 2669a747e4fSDavid du Colombier { 2679dfc0cb2SDavid du Colombier int fd, code, redirect, authenticate; 2689a747e4fSDavid du Colombier char *cookies; 2699a747e4fSDavid du Colombier Ioproc *io; 2709a747e4fSDavid du Colombier HttpState *hs; 271*360053c8SDavid du Colombier char *service; 2729a747e4fSDavid du Colombier 2739a747e4fSDavid du Colombier if(httpdebug) 2749a747e4fSDavid du Colombier fprint(2, "httpopen\n"); 2759a747e4fSDavid du Colombier io = c->io; 2769a747e4fSDavid du Colombier hs = emalloc(sizeof(*hs)); 2779a747e4fSDavid du Colombier hs->c = c; 278*360053c8SDavid du Colombier 279*360053c8SDavid du Colombier if(url->port) 280*360053c8SDavid du Colombier service = url->port; 281*360053c8SDavid du Colombier else 282*360053c8SDavid du Colombier service = url->scheme; 283*360053c8SDavid du Colombier hs->netaddr = estrdup(netmkaddr(url->host, 0, service)); 2849a747e4fSDavid du Colombier c->aux = hs; 285*360053c8SDavid du Colombier if(httpdebug){ 2869a747e4fSDavid du Colombier fprint(2, "dial %s\n", hs->netaddr); 287*360053c8SDavid du Colombier fprint(2, "dial port: %s\n", url->port); 288*360053c8SDavid du Colombier } 2893ff48bf5SDavid du Colombier fd = iotlsdial(io, hs->netaddr, 0, 0, 0, url->ischeme==UShttps); 2909a747e4fSDavid du Colombier if(fd < 0){ 2919a747e4fSDavid du Colombier Error: 2929a747e4fSDavid du Colombier if(httpdebug) 2933ff48bf5SDavid du Colombier fprint(2, "iodial: %r\n"); 294ac84fd08SDavid du Colombier free(hs->location); 295ac84fd08SDavid du Colombier free(hs->setcookie); 2969a747e4fSDavid du Colombier free(hs->netaddr); 297ac84fd08SDavid du Colombier free(hs->credentials); 298ac84fd08SDavid du Colombier if(fd >= 0) 299ac84fd08SDavid du Colombier ioclose(io, hs->fd); 3009a747e4fSDavid du Colombier hs->fd = -1; 301e288d156SDavid du Colombier free(hs); 3029a747e4fSDavid du Colombier c->aux = nil; 3039a747e4fSDavid du Colombier return -1; 3049a747e4fSDavid du Colombier } 3059a747e4fSDavid du Colombier hs->fd = fd; 3069a747e4fSDavid du Colombier if(httpdebug) 3079a747e4fSDavid du Colombier fprint(2, "<- %s %s HTTP/1.0\n<- Host: %s\n", 3089a747e4fSDavid du Colombier c->havepostbody? "POST": "GET", url->http.page_spec, url->host); 3093ff48bf5SDavid du Colombier ioprint(io, fd, "%s %s HTTP/1.0\r\nHost: %s\r\n", 3109a747e4fSDavid du Colombier c->havepostbody? "POST" : "GET", url->http.page_spec, url->host); 3119a747e4fSDavid du Colombier if(httpdebug) 3129a747e4fSDavid du Colombier fprint(2, "<- User-Agent: %s\n", c->ctl.useragent); 3139a747e4fSDavid du Colombier if(c->ctl.useragent) 3143ff48bf5SDavid du Colombier ioprint(io, fd, "User-Agent: %s\r\n", c->ctl.useragent); 3159a747e4fSDavid du Colombier if(c->ctl.sendcookies){ 3169a747e4fSDavid du Colombier /* should we use url->page here? sometimes it is nil. */ 3179a747e4fSDavid du Colombier cookies = httpcookies(url->host, url->http.page_spec, 0); 3189a747e4fSDavid du Colombier if(cookies && cookies[0]) 3193ff48bf5SDavid du Colombier ioprint(io, fd, "%s", cookies); 3209a747e4fSDavid du Colombier if(httpdebug) 3219a747e4fSDavid du Colombier fprint(2, "<- %s", cookies); 3229a747e4fSDavid du Colombier free(cookies); 3239a747e4fSDavid du Colombier } 3249a747e4fSDavid du Colombier if(c->havepostbody){ 3253ff48bf5SDavid du Colombier ioprint(io, fd, "Content-type: %s\r\n", PostContentType); 3263ff48bf5SDavid du Colombier ioprint(io, fd, "Content-length: %ud\r\n", c->npostbody); 3279a747e4fSDavid du Colombier if(httpdebug){ 3289a747e4fSDavid du Colombier fprint(2, "<- Content-type: %s\n", PostContentType); 3299a747e4fSDavid du Colombier fprint(2, "<- Content-length: %ud\n", c->npostbody); 3309a747e4fSDavid du Colombier } 3319a747e4fSDavid du Colombier } 3329dfc0cb2SDavid du Colombier if(c->authenticate){ 3339dfc0cb2SDavid du Colombier ioprint(io, fd, "Authorization: %s\r\n", c->authenticate); 3349dfc0cb2SDavid du Colombier if(httpdebug) 3359dfc0cb2SDavid du Colombier fprint(2, "<- Authorization: %s\n", c->authenticate); 3369dfc0cb2SDavid du Colombier } 3373ff48bf5SDavid du Colombier ioprint(io, fd, "\r\n"); 3389a747e4fSDavid du Colombier if(c->havepostbody) 3393ff48bf5SDavid du Colombier if(iowrite(io, fd, c->postbody, c->npostbody) != c->npostbody) 3409a747e4fSDavid du Colombier goto Error; 3419a747e4fSDavid du Colombier 3429a747e4fSDavid du Colombier redirect = 0; 3439dfc0cb2SDavid du Colombier authenticate = 0; 3449a747e4fSDavid du Colombier initibuf(&hs->b, io, fd); 3459a747e4fSDavid du Colombier code = httprcode(hs); 3469a747e4fSDavid du Colombier 3479a747e4fSDavid du Colombier switch(code){ 3489a747e4fSDavid du Colombier case -1: /* connection timed out */ 3499a747e4fSDavid du Colombier goto Error; 3509a747e4fSDavid du Colombier 3519a747e4fSDavid du Colombier /* 3529a747e4fSDavid du Colombier case Eof: 3539a747e4fSDavid du Colombier werrstr("EOF from HTTP server"); 3549a747e4fSDavid du Colombier goto Error; 3559a747e4fSDavid du Colombier */ 3569a747e4fSDavid du Colombier 3579a747e4fSDavid du Colombier case 200: /* OK */ 3589a747e4fSDavid du Colombier case 201: /* Created */ 3599a747e4fSDavid du Colombier case 202: /* Accepted */ 3609a747e4fSDavid du Colombier case 204: /* No Content */ 361de8abbc9SDavid du Colombier case 205: /* Reset Content */ 3629a747e4fSDavid du Colombier #ifdef NOT_DEFINED 3639a747e4fSDavid du Colombier if(ofile == nil && r->start != 0) 3649a747e4fSDavid du Colombier sysfatal("page changed underfoot"); 3659a747e4fSDavid du Colombier #endif 3669a747e4fSDavid du Colombier break; 3679a747e4fSDavid du Colombier 3689a747e4fSDavid du Colombier case 206: /* Partial Content */ 3699a747e4fSDavid du Colombier werrstr("Partial Content (206)"); 3709a747e4fSDavid du Colombier goto Error; 3719a747e4fSDavid du Colombier 3729a747e4fSDavid du Colombier case 301: /* Moved Permanently */ 3739a747e4fSDavid du Colombier case 302: /* Moved Temporarily */ 3747c70c028SDavid du Colombier case 303: /* See Other */ 375de8abbc9SDavid du Colombier case 307: /* Temporary Redirect */ 3769a747e4fSDavid du Colombier redirect = 1; 3779a747e4fSDavid du Colombier break; 3789a747e4fSDavid du Colombier 3799a747e4fSDavid du Colombier case 304: /* Not Modified */ 3809a747e4fSDavid du Colombier break; 3819a747e4fSDavid du Colombier 3829a747e4fSDavid du Colombier case 400: /* Bad Request */ 3839a747e4fSDavid du Colombier werrstr("Bad Request (400)"); 3849a747e4fSDavid du Colombier goto Error; 3859a747e4fSDavid du Colombier 3869a747e4fSDavid du Colombier case 401: /* Unauthorized */ 3879dfc0cb2SDavid du Colombier if(c->authenticate){ 3889dfc0cb2SDavid du Colombier werrstr("Authentication failed (401)"); 3899dfc0cb2SDavid du Colombier goto Error; 3909dfc0cb2SDavid du Colombier } 3919dfc0cb2SDavid du Colombier authenticate = 1; 3929dfc0cb2SDavid du Colombier break; 393de8abbc9SDavid du Colombier case 402: /* Payment Required */ 394de8abbc9SDavid du Colombier werrstr("Payment Required (402)"); 3959a747e4fSDavid du Colombier goto Error; 3969a747e4fSDavid du Colombier 3979a747e4fSDavid du Colombier case 403: /* Forbidden */ 3989a747e4fSDavid du Colombier werrstr("Forbidden by server (403)"); 3999a747e4fSDavid du Colombier goto Error; 4009a747e4fSDavid du Colombier 4019a747e4fSDavid du Colombier case 404: /* Not Found */ 4029a747e4fSDavid du Colombier werrstr("Not found on server (404)"); 4039a747e4fSDavid du Colombier goto Error; 4049a747e4fSDavid du Colombier 40535393782SDavid du Colombier case 405: /* Method Not Allowed */ 40635393782SDavid du Colombier werrstr("Method not allowed (405)"); 40735393782SDavid du Colombier goto Error; 40835393782SDavid du Colombier 409de8abbc9SDavid du Colombier case 406: /* Not Acceptable */ 410de8abbc9SDavid du Colombier werrstr("Not Acceptable (406)"); 411de8abbc9SDavid du Colombier goto Error; 412de8abbc9SDavid du Colombier 4139dfc0cb2SDavid du Colombier case 407: /* Proxy auth */ 4149dfc0cb2SDavid du Colombier werrstr("Proxy authentication required (407)"); 4159dfc0cb2SDavid du Colombier goto Error; 4169dfc0cb2SDavid du Colombier 417de8abbc9SDavid du Colombier case 408: /* Request Timeout */ 418de8abbc9SDavid du Colombier werrstr("Request Timeout (408)"); 419de8abbc9SDavid du Colombier goto Error; 420de8abbc9SDavid du Colombier 421de8abbc9SDavid du Colombier case 409: /* Conflict */ 422de8abbc9SDavid du Colombier werrstr("Conflict (409)"); 423de8abbc9SDavid du Colombier goto Error; 424de8abbc9SDavid du Colombier 425de8abbc9SDavid du Colombier case 410: /* Gone */ 426de8abbc9SDavid du Colombier werrstr("Gone (410)"); 427de8abbc9SDavid du Colombier goto Error; 428de8abbc9SDavid du Colombier 429de8abbc9SDavid du Colombier case 411: /* Length Required */ 430de8abbc9SDavid du Colombier werrstr("Length Required (411)"); 431de8abbc9SDavid du Colombier goto Error; 432de8abbc9SDavid du Colombier 433de8abbc9SDavid du Colombier case 412: /* Precondition Failed */ 434de8abbc9SDavid du Colombier werrstr("Precondition Failed (412)"); 435de8abbc9SDavid du Colombier goto Error; 436de8abbc9SDavid du Colombier 437de8abbc9SDavid du Colombier case 413: /* Request Entity Too Large */ 438de8abbc9SDavid du Colombier werrstr("Request Entity Too Large (413)"); 439de8abbc9SDavid du Colombier goto Error; 440de8abbc9SDavid du Colombier 441de8abbc9SDavid du Colombier case 414: /* Request-URI Too Long */ 442de8abbc9SDavid du Colombier werrstr("Request-URI Too Long (414)"); 443de8abbc9SDavid du Colombier goto Error; 444de8abbc9SDavid du Colombier 445de8abbc9SDavid du Colombier case 415: /* Unsupported Media Type */ 446de8abbc9SDavid du Colombier werrstr("Unsupported Media Type (415)"); 447de8abbc9SDavid du Colombier goto Error; 448de8abbc9SDavid du Colombier 449de8abbc9SDavid du Colombier case 416: /* Requested Range Not Satisfiable */ 450de8abbc9SDavid du Colombier werrstr("Requested Range Not Satisfiable (416)"); 451de8abbc9SDavid du Colombier goto Error; 452de8abbc9SDavid du Colombier 453de8abbc9SDavid du Colombier case 417: /* Expectation Failed */ 454de8abbc9SDavid du Colombier werrstr("Expectation Failed (417)"); 455de8abbc9SDavid du Colombier goto Error; 456de8abbc9SDavid du Colombier 4579a747e4fSDavid du Colombier case 500: /* Internal server error */ 4589a747e4fSDavid du Colombier werrstr("Server choked (500)"); 4599a747e4fSDavid du Colombier goto Error; 4609a747e4fSDavid du Colombier 4619a747e4fSDavid du Colombier case 501: /* Not implemented */ 4629a747e4fSDavid du Colombier werrstr("Server can't do it (501)"); 4639a747e4fSDavid du Colombier goto Error; 4649a747e4fSDavid du Colombier 4659a747e4fSDavid du Colombier case 502: /* Bad gateway */ 4669a747e4fSDavid du Colombier werrstr("Bad gateway (502)"); 4679a747e4fSDavid du Colombier goto Error; 4689a747e4fSDavid du Colombier 4699a747e4fSDavid du Colombier case 503: /* Service unavailable */ 4709a747e4fSDavid du Colombier werrstr("Service unavailable (503)"); 4719a747e4fSDavid du Colombier goto Error; 4729a747e4fSDavid du Colombier 4739a747e4fSDavid du Colombier default: 4749a747e4fSDavid du Colombier /* Bogus: we should treat unknown code XYZ as code X00 */ 4759a747e4fSDavid du Colombier werrstr("Unknown response code %d", code); 4769a747e4fSDavid du Colombier goto Error; 4779a747e4fSDavid du Colombier } 4789a747e4fSDavid du Colombier 4799a747e4fSDavid du Colombier if(httpheaders(hs) < 0) 4809a747e4fSDavid du Colombier goto Error; 4819a747e4fSDavid du Colombier if(c->ctl.acceptcookies && hs->setcookie) 4829a747e4fSDavid du Colombier httpsetcookie(hs->setcookie, url->host, url->path); 4839dfc0cb2SDavid du Colombier if(authenticate){ 4849dfc0cb2SDavid du Colombier if(!hs->credentials){ 4859dfc0cb2SDavid du Colombier if(hs->autherror[0]) 4869dfc0cb2SDavid du Colombier werrstr("%s", hs->autherror); 4879dfc0cb2SDavid du Colombier else 4889dfc0cb2SDavid du Colombier werrstr("unauthorized; no www-authenticate: header"); 489ac84fd08SDavid du Colombier goto Error; 4909dfc0cb2SDavid du Colombier } 4919dfc0cb2SDavid du Colombier c->authenticate = hs->credentials; 4929dfc0cb2SDavid du Colombier hs->credentials = nil; 4939dfc0cb2SDavid du Colombier } 4949a747e4fSDavid du Colombier if(redirect){ 4959a747e4fSDavid du Colombier if(!hs->location){ 4969a747e4fSDavid du Colombier werrstr("redirection without Location: header"); 497ac84fd08SDavid du Colombier goto Error; 4989a747e4fSDavid du Colombier } 4999a747e4fSDavid du Colombier c->redirect = hs->location; 5009a747e4fSDavid du Colombier hs->location = nil; 5019a747e4fSDavid du Colombier } 5029a747e4fSDavid du Colombier return 0; 5039a747e4fSDavid du Colombier } 5049a747e4fSDavid du Colombier 5059a747e4fSDavid du Colombier int 5069a747e4fSDavid du Colombier httpread(Client *c, Req *r) 5079a747e4fSDavid du Colombier { 5089a747e4fSDavid du Colombier HttpState *hs; 5091066d6deSDavid du Colombier long n; 5109a747e4fSDavid du Colombier 5119a747e4fSDavid du Colombier hs = c->aux; 5121066d6deSDavid du Colombier n = readibuf(&hs->b, r->ofcall.data, r->ifcall.count); 5131066d6deSDavid du Colombier if(n < 0) 5149a747e4fSDavid du Colombier return -1; 5151066d6deSDavid du Colombier 5161066d6deSDavid du Colombier r->ofcall.count = n; 5179a747e4fSDavid du Colombier return 0; 5189a747e4fSDavid du Colombier } 5199a747e4fSDavid du Colombier 5209a747e4fSDavid du Colombier void 5219a747e4fSDavid du Colombier httpclose(Client *c) 5229a747e4fSDavid du Colombier { 5239a747e4fSDavid du Colombier HttpState *hs; 5249a747e4fSDavid du Colombier 5259a747e4fSDavid du Colombier hs = c->aux; 5266b6b9ac8SDavid du Colombier if(hs == nil) 5276b6b9ac8SDavid du Colombier return; 528ac84fd08SDavid du Colombier if(hs->fd >= 0) 5293ff48bf5SDavid du Colombier ioclose(c->io, hs->fd); 5309a747e4fSDavid du Colombier hs->fd = -1; 5319a747e4fSDavid du Colombier free(hs->location); 5329a747e4fSDavid du Colombier free(hs->setcookie); 5339a747e4fSDavid du Colombier free(hs->netaddr); 5349dfc0cb2SDavid du Colombier free(hs->credentials); 5359a747e4fSDavid du Colombier free(hs); 5369a747e4fSDavid du Colombier c->aux = nil; 5379a747e4fSDavid du Colombier } 538