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
location(HttpState * hs,char * value)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
contenttype(HttpState * hs,char * value)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
setcookie(HttpState * hs,char * value)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*
unquote(char * s,char ** ps)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*
servername(char * addr)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
wwwauthenticate(HttpState * hs,char * line)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
httprcode(HttpState * hs)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
getheader(HttpState * hs,char * buf,int n)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
httpheaders(HttpState * hs)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
httpopen(Client * c,Url * url)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;
271360053c8SDavid 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;
278360053c8SDavid du Colombier
279360053c8SDavid du Colombier if(url->port)
280360053c8SDavid du Colombier service = url->port;
281360053c8SDavid du Colombier else
282360053c8SDavid du Colombier service = url->scheme;
283360053c8SDavid du Colombier hs->netaddr = estrdup(netmkaddr(url->host, 0, service));
2849a747e4fSDavid du Colombier c->aux = hs;
285360053c8SDavid du Colombier if(httpdebug){
2869a747e4fSDavid du Colombier fprint(2, "dial %s\n", hs->netaddr);
287360053c8SDavid du Colombier fprint(2, "dial port: %s\n", url->port);
288360053c8SDavid 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. */
3172c23bbf7SDavid du Colombier cookies = httpcookies(url->host, url->http.page_spec,
3182c23bbf7SDavid du Colombier url->ischeme == UShttps);
3199a747e4fSDavid du Colombier if(cookies && cookies[0])
3203ff48bf5SDavid du Colombier ioprint(io, fd, "%s", cookies);
3219a747e4fSDavid du Colombier if(httpdebug)
3229a747e4fSDavid du Colombier fprint(2, "<- %s", cookies);
3239a747e4fSDavid du Colombier free(cookies);
3249a747e4fSDavid du Colombier }
3259a747e4fSDavid du Colombier if(c->havepostbody){
3263ff48bf5SDavid du Colombier ioprint(io, fd, "Content-type: %s\r\n", PostContentType);
3273ff48bf5SDavid du Colombier ioprint(io, fd, "Content-length: %ud\r\n", c->npostbody);
3289a747e4fSDavid du Colombier if(httpdebug){
3299a747e4fSDavid du Colombier fprint(2, "<- Content-type: %s\n", PostContentType);
3309a747e4fSDavid du Colombier fprint(2, "<- Content-length: %ud\n", c->npostbody);
3319a747e4fSDavid du Colombier }
3329a747e4fSDavid du Colombier }
3339dfc0cb2SDavid du Colombier if(c->authenticate){
3349dfc0cb2SDavid du Colombier ioprint(io, fd, "Authorization: %s\r\n", c->authenticate);
3359dfc0cb2SDavid du Colombier if(httpdebug)
3369dfc0cb2SDavid du Colombier fprint(2, "<- Authorization: %s\n", c->authenticate);
3379dfc0cb2SDavid du Colombier }
3383ff48bf5SDavid du Colombier ioprint(io, fd, "\r\n");
3399a747e4fSDavid du Colombier if(c->havepostbody)
3403ff48bf5SDavid du Colombier if(iowrite(io, fd, c->postbody, c->npostbody) != c->npostbody)
3419a747e4fSDavid du Colombier goto Error;
3429a747e4fSDavid du Colombier
3439a747e4fSDavid du Colombier redirect = 0;
3449dfc0cb2SDavid du Colombier authenticate = 0;
3459a747e4fSDavid du Colombier initibuf(&hs->b, io, fd);
3469a747e4fSDavid du Colombier code = httprcode(hs);
3479a747e4fSDavid du Colombier
3489a747e4fSDavid du Colombier switch(code){
3499a747e4fSDavid du Colombier case -1: /* connection timed out */
3509a747e4fSDavid du Colombier goto Error;
3519a747e4fSDavid du Colombier
3529a747e4fSDavid du Colombier /*
3539a747e4fSDavid du Colombier case Eof:
3549a747e4fSDavid du Colombier werrstr("EOF from HTTP server");
3559a747e4fSDavid du Colombier goto Error;
3569a747e4fSDavid du Colombier */
3579a747e4fSDavid du Colombier
3589a747e4fSDavid du Colombier case 200: /* OK */
3599a747e4fSDavid du Colombier case 201: /* Created */
3609a747e4fSDavid du Colombier case 202: /* Accepted */
3619a747e4fSDavid du Colombier case 204: /* No Content */
362de8abbc9SDavid du Colombier case 205: /* Reset Content */
3639a747e4fSDavid du Colombier #ifdef NOT_DEFINED
3649a747e4fSDavid du Colombier if(ofile == nil && r->start != 0)
3659a747e4fSDavid du Colombier sysfatal("page changed underfoot");
3669a747e4fSDavid du Colombier #endif
3679a747e4fSDavid du Colombier break;
3689a747e4fSDavid du Colombier
3699a747e4fSDavid du Colombier case 206: /* Partial Content */
3709a747e4fSDavid du Colombier werrstr("Partial Content (206)");
3719a747e4fSDavid du Colombier goto Error;
3729a747e4fSDavid du Colombier
3739a747e4fSDavid du Colombier case 301: /* Moved Permanently */
3749a747e4fSDavid du Colombier case 302: /* Moved Temporarily */
3757c70c028SDavid du Colombier case 303: /* See Other */
376de8abbc9SDavid du Colombier case 307: /* Temporary Redirect */
3779a747e4fSDavid du Colombier redirect = 1;
3789a747e4fSDavid du Colombier break;
3799a747e4fSDavid du Colombier
3809a747e4fSDavid du Colombier case 304: /* Not Modified */
3819a747e4fSDavid du Colombier break;
3829a747e4fSDavid du Colombier
3839a747e4fSDavid du Colombier case 400: /* Bad Request */
3849a747e4fSDavid du Colombier werrstr("Bad Request (400)");
3859a747e4fSDavid du Colombier goto Error;
3869a747e4fSDavid du Colombier
3879a747e4fSDavid du Colombier case 401: /* Unauthorized */
3889dfc0cb2SDavid du Colombier if(c->authenticate){
3899dfc0cb2SDavid du Colombier werrstr("Authentication failed (401)");
3909dfc0cb2SDavid du Colombier goto Error;
3919dfc0cb2SDavid du Colombier }
3929dfc0cb2SDavid du Colombier authenticate = 1;
3939dfc0cb2SDavid du Colombier break;
394de8abbc9SDavid du Colombier case 402: /* Payment Required */
395de8abbc9SDavid du Colombier werrstr("Payment Required (402)");
3969a747e4fSDavid du Colombier goto Error;
3979a747e4fSDavid du Colombier
3989a747e4fSDavid du Colombier case 403: /* Forbidden */
3999a747e4fSDavid du Colombier werrstr("Forbidden by server (403)");
4009a747e4fSDavid du Colombier goto Error;
4019a747e4fSDavid du Colombier
4029a747e4fSDavid du Colombier case 404: /* Not Found */
4039a747e4fSDavid du Colombier werrstr("Not found on server (404)");
4049a747e4fSDavid du Colombier goto Error;
4059a747e4fSDavid du Colombier
40635393782SDavid du Colombier case 405: /* Method Not Allowed */
40735393782SDavid du Colombier werrstr("Method not allowed (405)");
40835393782SDavid du Colombier goto Error;
40935393782SDavid du Colombier
410de8abbc9SDavid du Colombier case 406: /* Not Acceptable */
411de8abbc9SDavid du Colombier werrstr("Not Acceptable (406)");
412de8abbc9SDavid du Colombier goto Error;
413de8abbc9SDavid du Colombier
4149dfc0cb2SDavid du Colombier case 407: /* Proxy auth */
4159dfc0cb2SDavid du Colombier werrstr("Proxy authentication required (407)");
4169dfc0cb2SDavid du Colombier goto Error;
4179dfc0cb2SDavid du Colombier
418de8abbc9SDavid du Colombier case 408: /* Request Timeout */
419de8abbc9SDavid du Colombier werrstr("Request Timeout (408)");
420de8abbc9SDavid du Colombier goto Error;
421de8abbc9SDavid du Colombier
422de8abbc9SDavid du Colombier case 409: /* Conflict */
423de8abbc9SDavid du Colombier werrstr("Conflict (409)");
424de8abbc9SDavid du Colombier goto Error;
425de8abbc9SDavid du Colombier
426de8abbc9SDavid du Colombier case 410: /* Gone */
427de8abbc9SDavid du Colombier werrstr("Gone (410)");
428de8abbc9SDavid du Colombier goto Error;
429de8abbc9SDavid du Colombier
430de8abbc9SDavid du Colombier case 411: /* Length Required */
431de8abbc9SDavid du Colombier werrstr("Length Required (411)");
432de8abbc9SDavid du Colombier goto Error;
433de8abbc9SDavid du Colombier
434de8abbc9SDavid du Colombier case 412: /* Precondition Failed */
435de8abbc9SDavid du Colombier werrstr("Precondition Failed (412)");
436de8abbc9SDavid du Colombier goto Error;
437de8abbc9SDavid du Colombier
438de8abbc9SDavid du Colombier case 413: /* Request Entity Too Large */
439de8abbc9SDavid du Colombier werrstr("Request Entity Too Large (413)");
440de8abbc9SDavid du Colombier goto Error;
441de8abbc9SDavid du Colombier
442de8abbc9SDavid du Colombier case 414: /* Request-URI Too Long */
443de8abbc9SDavid du Colombier werrstr("Request-URI Too Long (414)");
444de8abbc9SDavid du Colombier goto Error;
445de8abbc9SDavid du Colombier
446de8abbc9SDavid du Colombier case 415: /* Unsupported Media Type */
447de8abbc9SDavid du Colombier werrstr("Unsupported Media Type (415)");
448de8abbc9SDavid du Colombier goto Error;
449de8abbc9SDavid du Colombier
450de8abbc9SDavid du Colombier case 416: /* Requested Range Not Satisfiable */
451de8abbc9SDavid du Colombier werrstr("Requested Range Not Satisfiable (416)");
452de8abbc9SDavid du Colombier goto Error;
453de8abbc9SDavid du Colombier
454de8abbc9SDavid du Colombier case 417: /* Expectation Failed */
455de8abbc9SDavid du Colombier werrstr("Expectation Failed (417)");
456de8abbc9SDavid du Colombier goto Error;
457de8abbc9SDavid du Colombier
4589a747e4fSDavid du Colombier case 500: /* Internal server error */
4599a747e4fSDavid du Colombier werrstr("Server choked (500)");
4609a747e4fSDavid du Colombier goto Error;
4619a747e4fSDavid du Colombier
4629a747e4fSDavid du Colombier case 501: /* Not implemented */
4639a747e4fSDavid du Colombier werrstr("Server can't do it (501)");
4649a747e4fSDavid du Colombier goto Error;
4659a747e4fSDavid du Colombier
4669a747e4fSDavid du Colombier case 502: /* Bad gateway */
4679a747e4fSDavid du Colombier werrstr("Bad gateway (502)");
4689a747e4fSDavid du Colombier goto Error;
4699a747e4fSDavid du Colombier
4709a747e4fSDavid du Colombier case 503: /* Service unavailable */
4719a747e4fSDavid du Colombier werrstr("Service unavailable (503)");
4729a747e4fSDavid du Colombier goto Error;
4739a747e4fSDavid du Colombier
4749a747e4fSDavid du Colombier default:
4759a747e4fSDavid du Colombier /* Bogus: we should treat unknown code XYZ as code X00 */
4769a747e4fSDavid du Colombier werrstr("Unknown response code %d", code);
4779a747e4fSDavid du Colombier goto Error;
4789a747e4fSDavid du Colombier }
4799a747e4fSDavid du Colombier
4809a747e4fSDavid du Colombier if(httpheaders(hs) < 0)
4819a747e4fSDavid du Colombier goto Error;
4829a747e4fSDavid du Colombier if(c->ctl.acceptcookies && hs->setcookie)
4839a747e4fSDavid du Colombier httpsetcookie(hs->setcookie, url->host, url->path);
4849dfc0cb2SDavid du Colombier if(authenticate){
4859dfc0cb2SDavid du Colombier if(!hs->credentials){
4869dfc0cb2SDavid du Colombier if(hs->autherror[0])
4879dfc0cb2SDavid du Colombier werrstr("%s", hs->autherror);
4889dfc0cb2SDavid du Colombier else
4899dfc0cb2SDavid du Colombier werrstr("unauthorized; no www-authenticate: header");
490ac84fd08SDavid du Colombier goto Error;
4919dfc0cb2SDavid du Colombier }
4929dfc0cb2SDavid du Colombier c->authenticate = hs->credentials;
4939dfc0cb2SDavid du Colombier hs->credentials = nil;
494*b39189fdSDavid du Colombier }else if(c->authenticate)
495*b39189fdSDavid du Colombier c->authenticate = 0;
4969a747e4fSDavid du Colombier if(redirect){
4979a747e4fSDavid du Colombier if(!hs->location){
4989a747e4fSDavid du Colombier werrstr("redirection without Location: header");
499ac84fd08SDavid du Colombier goto Error;
5009a747e4fSDavid du Colombier }
5019a747e4fSDavid du Colombier c->redirect = hs->location;
5029a747e4fSDavid du Colombier hs->location = nil;
5039a747e4fSDavid du Colombier }
5049a747e4fSDavid du Colombier return 0;
5059a747e4fSDavid du Colombier }
5069a747e4fSDavid du Colombier
5079a747e4fSDavid du Colombier int
httpread(Client * c,Req * r)5089a747e4fSDavid du Colombier httpread(Client *c, Req *r)
5099a747e4fSDavid du Colombier {
5109a747e4fSDavid du Colombier HttpState *hs;
5111066d6deSDavid du Colombier long n;
5129a747e4fSDavid du Colombier
5139a747e4fSDavid du Colombier hs = c->aux;
5141066d6deSDavid du Colombier n = readibuf(&hs->b, r->ofcall.data, r->ifcall.count);
5151066d6deSDavid du Colombier if(n < 0)
5169a747e4fSDavid du Colombier return -1;
5171066d6deSDavid du Colombier
5181066d6deSDavid du Colombier r->ofcall.count = n;
5199a747e4fSDavid du Colombier return 0;
5209a747e4fSDavid du Colombier }
5219a747e4fSDavid du Colombier
5229a747e4fSDavid du Colombier void
httpclose(Client * c)5239a747e4fSDavid du Colombier httpclose(Client *c)
5249a747e4fSDavid du Colombier {
5259a747e4fSDavid du Colombier HttpState *hs;
5269a747e4fSDavid du Colombier
5279a747e4fSDavid du Colombier hs = c->aux;
5286b6b9ac8SDavid du Colombier if(hs == nil)
5296b6b9ac8SDavid du Colombier return;
530ac84fd08SDavid du Colombier if(hs->fd >= 0)
5313ff48bf5SDavid du Colombier ioclose(c->io, hs->fd);
5329a747e4fSDavid du Colombier hs->fd = -1;
5339a747e4fSDavid du Colombier free(hs->location);
5349a747e4fSDavid du Colombier free(hs->setcookie);
5359a747e4fSDavid du Colombier free(hs->netaddr);
5369dfc0cb2SDavid du Colombier free(hs->credentials);
5379a747e4fSDavid du Colombier free(hs);
5389a747e4fSDavid du Colombier c->aux = nil;
5399a747e4fSDavid du Colombier }
540