ref: 578fad97c2a3599aec2ac4085fed2430e3c2bbc8
dir: /req.c/
#include <u.h> #include <libc.h> #include <libsec.h> #include <ctype.h> #include "gemnine.h" static char *statuses[] = { [Cinput] = "input", [Cinputnoecho] = "sensitive input", [Csuccess] = "success", [Credirtmp] = "redirect - temporary", [Credirperm] = "redirect - permanent", [Cfailtmp] = "temporary failure", [Cunavail] = "server unavailable", [Ccgierr] = "cgi error", [Cproxyerr] = "proxy error", [Cslowdown] = "slow down", [Cfailperm] = "permanent failure", [Cnotfound] = "not found", [Cgone] = "gone", [Cnoproxy] = "proxy request refused", [Cbadrequest] = "bad request", [Ccertrequired] = "client certificate required", [Ccertnotauth] = "certificate not authorized", [Ccertinvalid] = "certificate not valid", }; Response * request(Url *url) { Thumbprint *th; Response *r; char *s, buf[1024], *port; TLSconn conn; int i, ok, len, oldfd; Url *u; r = calloc(1, sizeof(*r)); r->fd = -1; r->url = url; if((port = url->port) == nil) port = "1965"; if((r->fd = dial(netmkaddr(url->host, "tcp", port), nil, nil, nil)) < 0){ werrstr("dial: %r"); goto err; } th = initThumbprints("/sys/lib/ssl/gemini", nil, "x509"); memset(&conn, 0, sizeof(conn)); conn.serverName = r->url->host; oldfd = r->fd; r->fd = tlsClient(oldfd, &conn); close(oldfd); if(r->fd < 0){ werrstr("tls: %r"); goto err; } /* FIXME find a way to trust on the first run */ if(th != nil){ ok = okCertificate(conn.cert, conn.certlen, th); freeThumbprints(th); free(conn.cert); if(!ok){ //fprint(2, "echo 'x509 %r server=%s' >>/sys/lib/ssl/gemini\n", r->url->server); //werrstr("untrusted cert"); //goto err; } } fprint(r->fd, "%s\r\n", r->url->full); for(len = 0; len < sizeof(buf)-1; len++){ if((i = read(r->fd, buf+len, 1)) < 0){ werrstr("read: %r"); goto err; } if(i == 0 || buf[len] == '\n') break; } s = buf; s[len] = 0; for(len--; len >= 0 && (s[len] == '\r' || s[len] == '\n'); len--) s[len] = 0; if(s[0] < '0' || s[0] > '9' || s[1] < '0' || s[1] > '9'){ werrstr("invalid status"); goto err; } r->code = 10*(int)(s[0]-'0') + s[1] - '0'; s += 2; while(isspace(*s)) s++; if(r->code < nelem(statuses)) r->status = statuses[r->code]; if(r->status == nil) r->status = "???"; if(r->code >= 10 && r->code < 20){ /* input */ r->prompt = estrdup(s); }else if(r->code >= 20 && r->code < 30){ /* success */ r->mime = estrdup(s[0] ? s : "text/gemini"); }else if(r->code >= 30 && r->code < 40){ /* redirect */ if((u = urlparse(r->url, s)) == nil){ werrstr("invalid redirect"); goto err; } freeresponse(r); if((r = request(u)) == nil) freeurl(u); }else{ r->meta = estrdup(s); werrstr(r->status); goto err; } return r; err: freeresponse(r); return nil; } void freeresponse(Response *r) { if(r == nil) return; close(r->fd); freeurl(r->url); free(r->mime); free(r->prompt); free(r->meta); free(r); }