commit 984245ce20826f010570cf6fe030c19a1b566311 from: Omar Polo date: Wed Jun 23 16:34:37 2021 UTC add support for custom protocol proxies commit - 5d0feb4b6d3aad62434dfb509ca754ab1739a19c commit + 984245ce20826f010570cf6fe030c19a1b566311 blob - b32cdff12949df5c020c20d882438672582db9a4 blob + 924d67934989339cea0250fdf5099d6d7d67e9f5 --- ChangeLog +++ ChangeLog @@ -1,5 +1,7 @@ 2021-06-23 Omar Polo + * parse.y (add_proxy): add proxy support (e.g. `proxy http via gemini://localhost:1965' for the duckling proxy) + * cmd.c (cmd_previous_button): stay on the line in next-button if there is no next link, and the same for previous-button * telescope.c (handle_imsg_buf): "humanize" byte progress (i.e. trasform XYZ bytes to something readable) blob - 3293bf279abb101b19418b65a4c9ab51ce428dd5 blob + f3fe5d8816cc4f553ec98a5bd13504932890f7cf --- gemini.c +++ gemini.c @@ -73,7 +73,7 @@ static void read_reply(int, short, void*); static void parse_reply(struct req*); static void copy_body(int, short, void*); -static void handle_get(struct imsg*, size_t); +static void handle_get_raw(struct imsg *, size_t); static void handle_cert_status(struct imsg*, size_t); static void handle_proceed(struct imsg*, size_t); static void handle_stop(struct imsg*, size_t); @@ -84,7 +84,7 @@ static void handle_dispatch_imsg(int, short, void*); struct timeval timeout_for_handshake = { 5, 0 }; static imsg_handlerfn *handlers[] = { - [IMSG_GET] = handle_get, + [IMSG_GET_RAW] = handle_get_raw, [IMSG_CERT_STATUS] = handle_cert_status, [IMSG_PROCEED] = handle_proceed, [IMSG_STOP] = handle_stop, @@ -373,16 +373,10 @@ write_request(int fd, short ev, void *d) struct req *req = d; ssize_t r; size_t len; - char buf[1027]; /* URL + \r\n\0 */ - - if (!phos_serialize_uri(&req->url, buf, sizeof(buf))) - die(); + + len = strlen(req->buf); - len = strlcat(buf, "\r\n", sizeof(buf)); - - assert(len <= sizeof(buf)); - - switch (r = tls_write(req->ctx, buf, len)) { + switch (r = tls_write(req->ctx, req->buf, len)) { case -1: close_with_errf(req, "tls_write: %s", tls_error(req->ctx)); break; @@ -507,14 +501,14 @@ copy_body(int fd, short ev, void *d) } static void -handle_get(struct imsg *imsg, size_t datalen) +handle_get_raw(struct imsg *imsg, size_t datalen) { struct req *req; - char *data; + struct get_req *r; - data = imsg->data; + r = imsg->data; - if (data[datalen-1] != '\0') + if (datalen != sizeof(*r)) die(); if ((req = calloc(1, sizeof(*req))) == NULL) @@ -523,10 +517,9 @@ handle_get(struct imsg *imsg, size_t datalen) req->id = imsg->hdr.peerid; TAILQ_INSERT_HEAD(&reqhead, req, reqs); - if (!phos_parse_absolute_uri(data, &req->url)) { - close_with_err(req, "Can't parse URI"); - return; - } + strlcpy(req->url.host, r->host, sizeof(req->url.host)); + strlcpy(req->url.port, r->port, sizeof(req->url.port)); + strlcpy(req->buf, r->req, sizeof(req->buf)); #if HAVE_ASR_RUN async_conn_towards(req); blob - 7765898b8e268892fecf2b6068d06d3990da70ef blob + c5cb9c10470e8b0c2b35adbc056382bc570e58ee --- parse.y +++ parse.y @@ -22,6 +22,8 @@ #include "telescope.h" +#include + #include #include #include @@ -59,12 +61,14 @@ static int colorname(const char *); static void setcolor(const char *, const char *, const char *); static int attrname(char *); static void setattr(char *, char *, char *); +static void add_proxy(char *, char *); %} %token TSET %token TSTYLE TPRFX TCONT TBG TFG TATTR %token TBIND TUNBIND +%token TPROXY TVIA %token TSTRING %token TNUMBER @@ -84,6 +88,7 @@ rule : set } | bind | unbind + | proxy ; set : TSET TSTRING '=' TSTRING { setvars($2, $4); } @@ -121,6 +126,9 @@ bind : TBIND TSTRING TSTRING TSTRING { printf("TODO: unbind : TUNBIND TSTRING TSTRING { printf("TODO: unbind %s %s\n", $2, $3); } ; +proxy : TPROXY TSTRING TVIA TSTRING { add_proxy($2, $4); free($4); } + ; + %% void @@ -140,15 +148,17 @@ static struct keyword { const char *word; int token; } keywords[] = { - { "set", TSET }, - { "style", TSTYLE }, - { "prefix", TPRFX }, - { "cont", TCONT }, - { "bg", TBG }, - { "fg", TFG }, { "attr", TATTR }, + { "bg", TBG }, { "bind", TBIND }, + { "cont", TCONT }, + { "fg", TFG }, + { "prefix", TPRFX }, + { "proxy", TPROXY }, + { "set", TSET }, + { "style", TSTYLE }, { "unbind", TUNBIND }, + { "via", TVIA }, }; int @@ -433,6 +443,41 @@ setattr(char *prfx, char *line, char *trail) yyerror("invalid style %s", current_style); } +static void +add_proxy(char *proto, char *proxy) +{ + struct proxy *p; + struct phos_uri uri; + + if (!phos_parse_absolute_uri(proxy, &uri)) { + yyerror("can't parse URL: %s", proxy); + return; + } + + if (*uri.path != '\0' || *uri.query != '\0' || *uri.fragment != '\0') { + yyerror("proxy url can't have path, query or fragments"); + return; + } + + if (strcmp(uri.scheme, "gemini")) { + yyerror("disallowed proxy protocol %s", uri.scheme); + return; + } + + if ((p = calloc(1, sizeof(*p))) == NULL) + err(1, "calloc"); + + p->match_proto = proto; + + if ((p->host = strdup(uri.host)) == NULL) + err(1, "strdup"); + + if ((p->port = strdup(uri.port)) == NULL) + err(1, "strdup"); + + TAILQ_INSERT_HEAD(&proxies, p, proxies); +} + void parseconfig(const char *filename, int fonf) { blob - 0e48481d190342f3a93f0b211012c997dd225863 blob + 281e57e54e838ad6ab4613166a9fe860cc696959 --- telescope.1 +++ telescope.1 @@ -499,6 +499,14 @@ Enable if non zero. By default is 0. .El +.It Ic proxy Ar proto Ic via Ar url +Use +.Ar url +as proxy for all URLs with +protocol +.Ar proto Ns . +.Ar url +must be a Gemini URI without path, query and fragment component. .It Ic style Ar name Ar option Change the styling of the element identified by .Ar name . @@ -611,6 +619,16 @@ style line.link { style line.quote { prefix " ┃ " } +.Ed +.Pp +It's possible to browse +.Dq the small web +.Pq i.e. simple websites +using programs like the duckling-proxy by defining a proxy in +.Pa ~/.telescope/config Ns : +.Bd -literal -offset indent +proxy http via "gemini://localhost:1965" +proxy https via "gemini://localhost:1965" .Ed .Sh AUTHORS .An -nosplit blob - 8fbb6fe92c489712e4e4f0a01e9542bcb16d995b blob + 8bc89bfa10d7876b108f85b77bf468c796837c69 --- telescope.c +++ telescope.c @@ -11,6 +11,7 @@ struct event netev, fsev; struct tabshead tabshead; +struct proxylist proxies; /* the first is also the fallback one */ static struct proto protos[] = { @@ -96,7 +97,7 @@ handle_imsg_err(struct imsg *imsg, size_t datalen) static void handle_imsg_check_cert(struct imsg *imsg, size_t datalen) { - const char *hash; + const char *hash, *host, *port; int tofu_res; struct tofu_entry *e; struct tab *tab; @@ -107,7 +108,15 @@ handle_imsg_check_cert(struct imsg *imsg, size_t datal tab = tab_by_id(imsg->hdr.peerid); - if ((e = tofu_lookup(&certs, tab->uri.host, tab->uri.port)) == NULL) { + if (tab->proxy != NULL) { + host = tab->proxy->host; + port = tab->proxy->port; + } else { + host = tab->uri.host; + port = tab->uri.port; + } + + if ((e = tofu_lookup(&certs, host, port)) == NULL) { /* TODO: an update in libressl/libretls changed * significantly. Find a better approach at storing * the certs! */ @@ -117,10 +126,10 @@ handle_imsg_check_cert(struct imsg *imsg, size_t datal tofu_res = 1; /* trust on first use */ if ((e = calloc(1, sizeof(*e))) == NULL) abort(); - strlcpy(e->domain, tab->uri.host, sizeof(e->domain)); - if (*tab->uri.port != '\0' && strcmp(tab->uri.port, "1965")) { + strlcpy(e->domain, host, sizeof(e->domain)); + if (*port != '\0' && strcmp(port, "1965")) { strlcat(e->domain, ":", sizeof(e->domain)); - strlcat(e->domain, tab->uri.port, sizeof(e->domain)); + strlcat(e->domain, port, sizeof(e->domain)); } strlcpy(e->hash, hash, sizeof(e->hash)); tofu_add(&certs, e); @@ -170,19 +179,28 @@ handle_maybe_save_new_cert(int accept, unsigned int ta { struct tab *tab; struct tofu_entry *e; + const char *host, *port; tab = tab_by_id(tabid); + if (tab->proxy != NULL) { + host = tab->proxy->host; + port = tab->proxy->port; + } else { + host = tab->uri.host; + port = tab->uri.port; + } + if (!accept) goto end; if ((e = calloc(1, sizeof(*e))) == NULL) die(); - strlcpy(e->domain, tab->uri.host, sizeof(e->domain)); - if (*tab->uri.port != '\0' && strcmp(tab->uri.port, "1965")) { + strlcpy(e->domain, host, sizeof(e->domain)); + if (*port != '\0' && strcmp(port, "1965")) { strlcat(e->domain, ":", sizeof(e->domain)); - strlcat(e->domain, tab->uri.port, sizeof(e->domain)); + strlcat(e->domain, port, sizeof(e->domain)); } strlcpy(e->hash, tab->cert, sizeof(e->hash)); imsg_compose(fsibuf, IMSG_UPDATE_CERT, 0, 0, -1, e, sizeof(*e)); @@ -473,23 +491,54 @@ load_about_url(struct tab *tab, const char *url) void load_gemini_url(struct tab *tab, const char *url) { - size_t len; + struct get_req req; stop_tab(tab); tab->id = tab_new_id(); - len = sizeof(tab->hist_cur->h); - imsg_compose(netibuf, IMSG_GET, tab->id, 0, -1, - tab->hist_cur->h, len); + memset(&req, 0, sizeof(req)); + strlcpy(req.host, tab->uri.host, sizeof(req.host)); + strlcpy(req.port, tab->uri.port, sizeof(req.host)); + + strlcpy(req.req, tab->hist_cur->h, sizeof(req.req)); + strlcat(req.req, "\r\n", sizeof(req.req)); + + req.proto = PROTO_GEMINI; + + imsg_compose(netibuf, IMSG_GET_RAW, tab->id, 0, -1, + &req, sizeof(req)); imsg_flush(netibuf); - return; } +void +load_via_proxy(struct tab *tab, const char *url, struct proxy *p) +{ + struct get_req req; + + stop_tab(tab); + tab->id = tab_new_id(); + tab->proxy = p; + + memset(&req, 0, sizeof(req)); + strlcpy(req.host, p->host, sizeof(req.host)); + strlcpy(req.port, p->port, sizeof(req.host)); + + strlcpy(req.req, tab->hist_cur->h, sizeof(req.req)); + strlcat(req.req, "\r\n", sizeof(req.req)); + + req.proto = p->proto; + + imsg_compose(netibuf, IMSG_GET_RAW, tab->id, 0, -1, + &req, sizeof(req)); + imsg_flush(netibuf); +} + static void do_load_url(struct tab *tab, const char *url) { struct phos_uri uri; struct proto *p; + struct proxy *proxy; char *t; if (tab->fd != -1) { @@ -522,6 +571,13 @@ do_load_url(struct tab *tab, const char *url) } } + TAILQ_FOREACH(proxy, &proxies, proxies) { + if (!strcmp(tab->uri.scheme, proxy->match_proto)) { + load_via_proxy(tab, url, proxy); + return; + } + } + protos[0].loadfn(tab, url); } @@ -535,6 +591,9 @@ load_url(struct tab *tab, const char *url) event_loopbreak(); return; } + + tab->proxy = NULL; + hist_push(&tab->hist, tab->hist_cur); do_load_url(tab, url); empty_vlist(&tab->buffer); @@ -661,6 +720,7 @@ main(int argc, char * const *argv) load_certs(&certs); TAILQ_INIT(&tabshead); + TAILQ_INIT(&proxies); event_init(); blob - 2f88e09f60ec774b7b5cfcf00b7bd34fc4f796b6 blob + 9c6425cb8c959dafe09935df78e7dea67a5192c4 --- telescope.h +++ telescope.h @@ -31,6 +31,7 @@ enum imsg_type { /* ui <-> client/fs */ IMSG_GET, /* data is URL, peerid the tab id */ + IMSG_GET_RAW, /* get but with an explicit req str */ IMSG_ERR, IMSG_CHECK_CERT, IMSG_CERT_STATUS, @@ -212,6 +213,7 @@ struct tab { char *cert; enum trust_state trust; + struct proxy *proxy; struct phos_uri uri; struct histhead hist; struct hist *hist_cur; @@ -242,8 +244,31 @@ struct proto { * human-friendly URL. */ void (*loadfn)(struct tab*, const char*); +}; + +extern TAILQ_HEAD(proxylist, proxy) proxies; +struct proxy { + char *match_proto; + + char *host; + char *port; + int proto; + + TAILQ_ENTRY(proxy) proxies; +}; + +enum { + PROTO_GEMINI, + /* ... */ }; +struct get_req { + int proto; + char host[254]; + char port[16]; + char req[1027]; +}; + struct kmap { TAILQ_HEAD(map, keymap) m; void (*unhandled_input)(void); @@ -319,6 +344,7 @@ void sandbox_fs_process(void); /* telescope.c */ void load_about_url(struct tab*, const char*); void load_gemini_url(struct tab*, const char*); +void load_via_proxy(struct tab *, const char *, struct proxy *); void load_url(struct tab*, const char*); int load_previous_page(struct tab*); int load_next_page(struct tab*);