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> 9*9dfc0cb2SDavid du Colombier #include <libsec.h> 10*9dfc0cb2SDavid du Colombier #include <auth.h> 119a747e4fSDavid du Colombier #include "dat.h" 129a747e4fSDavid du Colombier #include "fns.h" 139a747e4fSDavid du Colombier 149a747e4fSDavid du Colombier char PostContentType[] = "application/octet-stream"; 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; 25*9dfc0cb2SDavid du Colombier char *credentials; 26*9dfc0cb2SDavid 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 { 409a747e4fSDavid du Colombier if(hs->c->contenttype == nil) 419a747e4fSDavid du Colombier hs->c->contenttype = estrdup(value); 429a747e4fSDavid du Colombier } 439a747e4fSDavid du Colombier 449a747e4fSDavid du Colombier static void 459a747e4fSDavid du Colombier setcookie(HttpState *hs, char *value) 469a747e4fSDavid du Colombier { 479a747e4fSDavid du Colombier char *s, *t; 489a747e4fSDavid du Colombier Fmt f; 499a747e4fSDavid du Colombier 509a747e4fSDavid du Colombier s = hs->setcookie; 519a747e4fSDavid du Colombier fmtstrinit(&f); 529a747e4fSDavid du Colombier if(s) 539a747e4fSDavid du Colombier fmtprint(&f, "%s", s); 549a747e4fSDavid du Colombier fmtprint(&f, "set-cookie: "); 559a747e4fSDavid du Colombier fmtprint(&f, "%s", value); 569a747e4fSDavid du Colombier fmtprint(&f, "\n"); 579a747e4fSDavid du Colombier t = fmtstrflush(&f); 589a747e4fSDavid du Colombier if(t){ 599a747e4fSDavid du Colombier free(s); 609a747e4fSDavid du Colombier hs->setcookie = t; 619a747e4fSDavid du Colombier } 629a747e4fSDavid du Colombier } 639a747e4fSDavid du Colombier 64*9dfc0cb2SDavid du Colombier static char* 65*9dfc0cb2SDavid du Colombier unquote(char *s, char **ps) 66*9dfc0cb2SDavid du Colombier { 67*9dfc0cb2SDavid du Colombier char *p; 68*9dfc0cb2SDavid du Colombier 69*9dfc0cb2SDavid du Colombier if(*s != '"'){ 70*9dfc0cb2SDavid du Colombier p = strpbrk(s, " \t\r\n"); 71*9dfc0cb2SDavid du Colombier *p++ = 0; 72*9dfc0cb2SDavid du Colombier *ps = p; 73*9dfc0cb2SDavid du Colombier return s; 74*9dfc0cb2SDavid du Colombier } 75*9dfc0cb2SDavid du Colombier for(p=s+1; *p; p++){ 76*9dfc0cb2SDavid du Colombier if(*p == '\"'){ 77*9dfc0cb2SDavid du Colombier *p++ = 0; 78*9dfc0cb2SDavid du Colombier break; 79*9dfc0cb2SDavid du Colombier } 80*9dfc0cb2SDavid du Colombier if(*p == '\\' && *(p+1)){ 81*9dfc0cb2SDavid du Colombier p++; 82*9dfc0cb2SDavid du Colombier continue; 83*9dfc0cb2SDavid du Colombier } 84*9dfc0cb2SDavid du Colombier } 85*9dfc0cb2SDavid du Colombier memmove(s, s+1, p-(s+1)); 86*9dfc0cb2SDavid du Colombier s[p-(s+1)] = 0; 87*9dfc0cb2SDavid du Colombier *ps = p; 88*9dfc0cb2SDavid du Colombier return s; 89*9dfc0cb2SDavid du Colombier } 90*9dfc0cb2SDavid du Colombier 91*9dfc0cb2SDavid du Colombier static char* 92*9dfc0cb2SDavid du Colombier servername(char *addr) 93*9dfc0cb2SDavid du Colombier { 94*9dfc0cb2SDavid du Colombier char *p; 95*9dfc0cb2SDavid du Colombier 96*9dfc0cb2SDavid du Colombier if(strncmp(addr, "tcp!", 4) == 0 97*9dfc0cb2SDavid du Colombier || strncmp(addr, "net!", 4) == 0) 98*9dfc0cb2SDavid du Colombier addr += 4; 99*9dfc0cb2SDavid du Colombier addr = estrdup(addr); 100*9dfc0cb2SDavid du Colombier p = addr+strlen(addr); 101*9dfc0cb2SDavid du Colombier if(p>addr && *(p-1) == 's') 102*9dfc0cb2SDavid du Colombier p--; 103*9dfc0cb2SDavid du Colombier if(p>addr+5 && strcmp(p-5, "!http") == 0) 104*9dfc0cb2SDavid du Colombier p[-5] = 0; 105*9dfc0cb2SDavid du Colombier return addr; 106*9dfc0cb2SDavid du Colombier } 107*9dfc0cb2SDavid du Colombier 108*9dfc0cb2SDavid du Colombier void 109*9dfc0cb2SDavid du Colombier wwwauthenticate(HttpState *hs, char *line) 110*9dfc0cb2SDavid du Colombier { 111*9dfc0cb2SDavid du Colombier char cred[64], *user, *pass, *realm, *s, *spec, *name; 112*9dfc0cb2SDavid du Colombier Fmt fmt; 113*9dfc0cb2SDavid du Colombier UserPasswd *up; 114*9dfc0cb2SDavid du Colombier 115*9dfc0cb2SDavid du Colombier spec = nil; 116*9dfc0cb2SDavid du Colombier up = nil; 117*9dfc0cb2SDavid du Colombier cred[0] = 0; 118*9dfc0cb2SDavid du Colombier hs->autherror[0] = 0; 119*9dfc0cb2SDavid du Colombier if(cistrncmp(line, "basic ", 6) != 0){ 120*9dfc0cb2SDavid du Colombier werrstr("unknown auth: %s", line); 121*9dfc0cb2SDavid du Colombier goto error; 122*9dfc0cb2SDavid du Colombier } 123*9dfc0cb2SDavid du Colombier line += 6; 124*9dfc0cb2SDavid du Colombier if(cistrncmp(line, "realm=", 6) != 0){ 125*9dfc0cb2SDavid du Colombier werrstr("missing realm: %s", line); 126*9dfc0cb2SDavid du Colombier goto error; 127*9dfc0cb2SDavid du Colombier } 128*9dfc0cb2SDavid du Colombier line += 6; 129*9dfc0cb2SDavid du Colombier user = hs->c->url->user; 130*9dfc0cb2SDavid du Colombier pass = hs->c->url->passwd; 131*9dfc0cb2SDavid du Colombier if(user==nil || pass==nil){ 132*9dfc0cb2SDavid du Colombier realm = unquote(line, &line); 133*9dfc0cb2SDavid du Colombier fmtstrinit(&fmt); 134*9dfc0cb2SDavid du Colombier name = servername(hs->netaddr); 135*9dfc0cb2SDavid du Colombier fmtprint(&fmt, "proto=pass service=http server=%q realm=%q", name, realm); 136*9dfc0cb2SDavid du Colombier free(name); 137*9dfc0cb2SDavid du Colombier if(hs->c->url->user) 138*9dfc0cb2SDavid du Colombier fmtprint(&fmt, " user=%q", hs->c->url->user); 139*9dfc0cb2SDavid du Colombier spec = fmtstrflush(&fmt); 140*9dfc0cb2SDavid du Colombier if(spec == nil) 141*9dfc0cb2SDavid du Colombier goto error; 142*9dfc0cb2SDavid du Colombier if((up = auth_getuserpasswd(nil, "%s", spec)) == nil) 143*9dfc0cb2SDavid du Colombier goto error; 144*9dfc0cb2SDavid du Colombier user = up->user; 145*9dfc0cb2SDavid du Colombier pass = up->passwd; 146*9dfc0cb2SDavid du Colombier } 147*9dfc0cb2SDavid du Colombier if((s = smprint("%s:%s", user, pass)) == nil) 148*9dfc0cb2SDavid du Colombier goto error; 149*9dfc0cb2SDavid du Colombier free(up); 150*9dfc0cb2SDavid du Colombier enc64(cred, sizeof(cred), (uchar*)s, strlen(s)); 151*9dfc0cb2SDavid du Colombier memset(s, 0, strlen(s)); 152*9dfc0cb2SDavid du Colombier free(s); 153*9dfc0cb2SDavid du Colombier hs->credentials = smprint("Basic %s", cred); 154*9dfc0cb2SDavid du Colombier if(hs->credentials == nil) 155*9dfc0cb2SDavid du Colombier goto error; 156*9dfc0cb2SDavid du Colombier return; 157*9dfc0cb2SDavid du Colombier 158*9dfc0cb2SDavid du Colombier error: 159*9dfc0cb2SDavid du Colombier free(up); 160*9dfc0cb2SDavid du Colombier free(spec); 161*9dfc0cb2SDavid du Colombier snprint(hs->autherror, sizeof hs->autherror, "%r"); 162*9dfc0cb2SDavid du Colombier } 163*9dfc0cb2SDavid du Colombier 1649a747e4fSDavid du Colombier struct { 1659a747e4fSDavid du Colombier char *name; /* Case-insensitive */ 1669a747e4fSDavid du Colombier void (*fn)(HttpState *hs, char *value); 1679a747e4fSDavid du Colombier } hdrtab[] = { 1689a747e4fSDavid du Colombier { "location:", location }, 1699a747e4fSDavid du Colombier { "content-type:", contenttype }, 1709a747e4fSDavid du Colombier { "set-cookie:", setcookie }, 171*9dfc0cb2SDavid du Colombier { "www-authenticate:", wwwauthenticate }, 1729a747e4fSDavid du Colombier }; 1739a747e4fSDavid du Colombier 1749a747e4fSDavid du Colombier static int 1759a747e4fSDavid du Colombier httprcode(HttpState *hs) 1769a747e4fSDavid du Colombier { 1779a747e4fSDavid du Colombier int n; 1789a747e4fSDavid du Colombier char *p; 1799a747e4fSDavid du Colombier char buf[256]; 1809a747e4fSDavid du Colombier 1819a747e4fSDavid du Colombier n = readline(&hs->b, buf, sizeof(buf)-1); 1829a747e4fSDavid du Colombier if(n <= 0) 1839a747e4fSDavid du Colombier return n; 1849a747e4fSDavid du Colombier if(httpdebug) 1859a747e4fSDavid du Colombier fprint(2, "-> %s\n", buf); 1869a747e4fSDavid du Colombier p = strchr(buf, ' '); 1879a747e4fSDavid du Colombier if(memcmp(buf, "HTTP/", 5) != 0 || p == nil){ 1889a747e4fSDavid du Colombier werrstr("bad response from server"); 1899a747e4fSDavid du Colombier return -1; 1909a747e4fSDavid du Colombier } 1919a747e4fSDavid du Colombier buf[n] = 0; 1929a747e4fSDavid du Colombier return atoi(p+1); 1939a747e4fSDavid du Colombier } 1949a747e4fSDavid du Colombier 1959a747e4fSDavid du Colombier /* 1969a747e4fSDavid du Colombier * read a single mime header, collect continuations. 1979a747e4fSDavid du Colombier * 1989a747e4fSDavid du Colombier * this routine assumes that there is a blank line twixt 1999a747e4fSDavid du Colombier * the header and the message body, otherwise bytes will 2009a747e4fSDavid du Colombier * be lost. 2019a747e4fSDavid du Colombier */ 2029a747e4fSDavid du Colombier static int 2039a747e4fSDavid du Colombier getheader(HttpState *hs, char *buf, int n) 2049a747e4fSDavid du Colombier { 2059a747e4fSDavid du Colombier char *p, *e; 2069a747e4fSDavid du Colombier int i; 2079a747e4fSDavid du Colombier 2089a747e4fSDavid du Colombier n--; 2099a747e4fSDavid du Colombier p = buf; 2109a747e4fSDavid du Colombier for(e = p + n; ; p += i){ 2119a747e4fSDavid du Colombier i = readline(&hs->b, p, e-p); 2129a747e4fSDavid du Colombier if(i < 0) 2139a747e4fSDavid du Colombier return i; 2149a747e4fSDavid du Colombier 2159a747e4fSDavid du Colombier if(p == buf){ 2169a747e4fSDavid du Colombier /* first line */ 2179a747e4fSDavid du Colombier if(strchr(buf, ':') == nil) 2189a747e4fSDavid du Colombier break; /* end of headers */ 2199a747e4fSDavid du Colombier } else { 2209a747e4fSDavid du Colombier /* continuation line */ 2219a747e4fSDavid du Colombier if(*p != ' ' && *p != '\t'){ 2229a747e4fSDavid du Colombier unreadline(&hs->b, p); 2239a747e4fSDavid du Colombier *p = 0; 2249a747e4fSDavid du Colombier break; /* end of this header */ 2259a747e4fSDavid du Colombier } 2269a747e4fSDavid du Colombier } 2279a747e4fSDavid du Colombier } 2289a747e4fSDavid du Colombier 2299a747e4fSDavid du Colombier if(httpdebug) 2309a747e4fSDavid du Colombier fprint(2, "-> %s\n", buf); 2319a747e4fSDavid du Colombier return p-buf; 2329a747e4fSDavid du Colombier } 2339a747e4fSDavid du Colombier 2349a747e4fSDavid du Colombier static int 2359a747e4fSDavid du Colombier httpheaders(HttpState *hs) 2369a747e4fSDavid du Colombier { 2379a747e4fSDavid du Colombier char buf[2048]; 2389a747e4fSDavid du Colombier char *p; 2399a747e4fSDavid du Colombier int i, n; 2409a747e4fSDavid du Colombier 2419a747e4fSDavid du Colombier for(;;){ 2429a747e4fSDavid du Colombier n = getheader(hs, buf, sizeof(buf)); 2439a747e4fSDavid du Colombier if(n < 0) 2449a747e4fSDavid du Colombier return -1; 2459a747e4fSDavid du Colombier if(n == 0) 2469a747e4fSDavid du Colombier return 0; 2479a747e4fSDavid du Colombier // print("http header: '%.*s'\n", n, buf); 2489a747e4fSDavid du Colombier for(i = 0; i < nelem(hdrtab); i++){ 2499a747e4fSDavid du Colombier n = strlen(hdrtab[i].name); 2509a747e4fSDavid du Colombier if(cistrncmp(buf, hdrtab[i].name, n) == 0){ 2519a747e4fSDavid du Colombier /* skip field name and leading white */ 2529a747e4fSDavid du Colombier p = buf + n; 2539a747e4fSDavid du Colombier while(*p == ' ' || *p == '\t') 2549a747e4fSDavid du Colombier p++; 2559a747e4fSDavid du Colombier (*hdrtab[i].fn)(hs, p); 2569a747e4fSDavid du Colombier break; 2579a747e4fSDavid du Colombier } 2589a747e4fSDavid du Colombier } 2599a747e4fSDavid du Colombier } 2609a747e4fSDavid du Colombier return 0; 2619a747e4fSDavid du Colombier } 2629a747e4fSDavid du Colombier 2639a747e4fSDavid du Colombier int 2649a747e4fSDavid du Colombier httpopen(Client *c, Url *url) 2659a747e4fSDavid du Colombier { 266*9dfc0cb2SDavid 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 } 319*9dfc0cb2SDavid du Colombier if(c->authenticate){ 320*9dfc0cb2SDavid du Colombier ioprint(io, fd, "Authorization: %s\r\n", c->authenticate); 321*9dfc0cb2SDavid du Colombier if(httpdebug) 322*9dfc0cb2SDavid du Colombier fprint(2, "<- Authorization: %s\n", c->authenticate); 323*9dfc0cb2SDavid 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; 331*9dfc0cb2SDavid 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 */ 372*9dfc0cb2SDavid du Colombier if(c->authenticate){ 373*9dfc0cb2SDavid du Colombier werrstr("Authentication failed (401)"); 374*9dfc0cb2SDavid du Colombier goto Error; 375*9dfc0cb2SDavid du Colombier } 376*9dfc0cb2SDavid du Colombier authenticate = 1; 377*9dfc0cb2SDavid du Colombier break; 3789a747e4fSDavid du Colombier case 402: /* ??? */ 379*9dfc0cb2SDavid 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 390*9dfc0cb2SDavid du Colombier case 407: /* Proxy auth */ 391*9dfc0cb2SDavid du Colombier werrstr("Proxy authentication required (407)"); 392*9dfc0cb2SDavid du Colombier goto Error; 393*9dfc0cb2SDavid du Colombier 3949a747e4fSDavid du Colombier case 500: /* Internal server error */ 3959a747e4fSDavid du Colombier werrstr("Server choked (500)"); 3969a747e4fSDavid du Colombier goto Error; 3979a747e4fSDavid du Colombier 3989a747e4fSDavid du Colombier case 501: /* Not implemented */ 3999a747e4fSDavid du Colombier werrstr("Server can't do it (501)"); 4009a747e4fSDavid du Colombier goto Error; 4019a747e4fSDavid du Colombier 4029a747e4fSDavid du Colombier case 502: /* Bad gateway */ 4039a747e4fSDavid du Colombier werrstr("Bad gateway (502)"); 4049a747e4fSDavid du Colombier goto Error; 4059a747e4fSDavid du Colombier 4069a747e4fSDavid du Colombier case 503: /* Service unavailable */ 4079a747e4fSDavid du Colombier werrstr("Service unavailable (503)"); 4089a747e4fSDavid du Colombier goto Error; 4099a747e4fSDavid du Colombier 4109a747e4fSDavid du Colombier default: 4119a747e4fSDavid du Colombier /* Bogus: we should treat unknown code XYZ as code X00 */ 4129a747e4fSDavid du Colombier werrstr("Unknown response code %d", code); 4139a747e4fSDavid du Colombier goto Error; 4149a747e4fSDavid du Colombier } 4159a747e4fSDavid du Colombier 4169a747e4fSDavid du Colombier if(httpheaders(hs) < 0) 4179a747e4fSDavid du Colombier goto Error; 4189a747e4fSDavid du Colombier if(c->ctl.acceptcookies && hs->setcookie) 4199a747e4fSDavid du Colombier httpsetcookie(hs->setcookie, url->host, url->path); 420*9dfc0cb2SDavid du Colombier if(authenticate){ 421*9dfc0cb2SDavid du Colombier if(!hs->credentials){ 422*9dfc0cb2SDavid du Colombier if(hs->autherror[0]) 423*9dfc0cb2SDavid du Colombier werrstr("%s", hs->autherror); 424*9dfc0cb2SDavid du Colombier else 425*9dfc0cb2SDavid du Colombier werrstr("unauthorized; no www-authenticate: header"); 426*9dfc0cb2SDavid du Colombier return -1; 427*9dfc0cb2SDavid du Colombier } 428*9dfc0cb2SDavid du Colombier c->authenticate = hs->credentials; 429*9dfc0cb2SDavid du Colombier hs->credentials = nil; 430*9dfc0cb2SDavid du Colombier } 4319a747e4fSDavid du Colombier if(redirect){ 4329a747e4fSDavid du Colombier if(!hs->location){ 4339a747e4fSDavid du Colombier werrstr("redirection without Location: header"); 4349a747e4fSDavid du Colombier return -1; 4359a747e4fSDavid du Colombier } 4369a747e4fSDavid du Colombier c->redirect = hs->location; 4379a747e4fSDavid du Colombier hs->location = nil; 4389a747e4fSDavid du Colombier } 4399a747e4fSDavid du Colombier return 0; 4409a747e4fSDavid du Colombier } 4419a747e4fSDavid du Colombier 4429a747e4fSDavid du Colombier int 4439a747e4fSDavid du Colombier httpread(Client *c, Req *r) 4449a747e4fSDavid du Colombier { 4459a747e4fSDavid du Colombier char *dst; 4469a747e4fSDavid du Colombier HttpState *hs; 4479a747e4fSDavid du Colombier int n; 4489a747e4fSDavid du Colombier long rlen, tot, len; 4499a747e4fSDavid du Colombier 4509a747e4fSDavid du Colombier hs = c->aux; 4519a747e4fSDavid du Colombier dst = r->ofcall.data; 4529a747e4fSDavid du Colombier len = r->ifcall.count; 4539a747e4fSDavid du Colombier tot = 0; 4549a747e4fSDavid du Colombier while (tot < len){ 4559a747e4fSDavid du Colombier rlen = len - tot; 4569a747e4fSDavid du Colombier n = readibuf(&hs->b, dst + tot, rlen); 4579a747e4fSDavid du Colombier if(n == 0) 4589a747e4fSDavid du Colombier break; 4599a747e4fSDavid du Colombier else if(n < 0){ 4609a747e4fSDavid du Colombier if(tot == 0) 4619a747e4fSDavid du Colombier return -1; 4629a747e4fSDavid du Colombier else 4639a747e4fSDavid du Colombier return tot; 4649a747e4fSDavid du Colombier } 4659a747e4fSDavid du Colombier tot += n; 4669a747e4fSDavid du Colombier } 4679a747e4fSDavid du Colombier r->ofcall.count = tot; 4689a747e4fSDavid du Colombier return 0; 4699a747e4fSDavid du Colombier } 4709a747e4fSDavid du Colombier 4719a747e4fSDavid du Colombier void 4729a747e4fSDavid du Colombier httpclose(Client *c) 4739a747e4fSDavid du Colombier { 4749a747e4fSDavid du Colombier HttpState *hs; 4759a747e4fSDavid du Colombier 4769a747e4fSDavid du Colombier hs = c->aux; 4776b6b9ac8SDavid du Colombier if(hs == nil) 4786b6b9ac8SDavid du Colombier return; 4793ff48bf5SDavid du Colombier ioclose(c->io, hs->fd); 4809a747e4fSDavid du Colombier hs->fd = -1; 4819a747e4fSDavid du Colombier free(hs->location); 4829a747e4fSDavid du Colombier free(hs->setcookie); 4839a747e4fSDavid du Colombier free(hs->netaddr); 484*9dfc0cb2SDavid du Colombier free(hs->credentials); 4859a747e4fSDavid du Colombier free(hs); 4869a747e4fSDavid du Colombier c->aux = nil; 4879a747e4fSDavid du Colombier } 4889a747e4fSDavid du Colombier 489