commit - 5d0feb4b6d3aad62434dfb509ca754ab1739a19c
commit + 984245ce20826f010570cf6fe030c19a1b566311
blob - b32cdff12949df5c020c20d882438672582db9a4
blob + 924d67934989339cea0250fdf5099d6d7d67e9f5
--- ChangeLog
+++ ChangeLog
2021-06-23 Omar Polo <op@omarpolo.com>
+ * 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
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);
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,
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;
}
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)
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
#include "telescope.h"
+#include <phos/phos.h>
+
#include <assert.h>
#include <ctype.h>
#include <limits.h>
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 <str> TSTRING
%token <num> TNUMBER
}
| bind
| unbind
+ | proxy
;
set : TSET TSTRING '=' TSTRING { setvars($2, $4); }
unbind : TUNBIND TSTRING TSTRING { printf("TODO: unbind %s %s\n", $2, $3); }
;
+proxy : TPROXY TSTRING TVIA TSTRING { add_proxy($2, $4); free($4); }
+ ;
+
%%
void
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
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
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 .
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
struct event netev, fsev;
struct tabshead tabshead;
+struct proxylist proxies;
/* the first is also the fallback one */
static struct proto protos[] = {
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;
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! */
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);
{
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));
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) {
}
}
+ 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);
}
event_loopbreak();
return;
}
+
+ tab->proxy = NULL;
+
hist_push(&tab->hist, tab->hist_cur);
do_load_url(tab, url);
empty_vlist(&tab->buffer);
load_certs(&certs);
TAILQ_INIT(&tabshead);
+ TAILQ_INIT(&proxies);
event_init();
blob - 2f88e09f60ec774b7b5cfcf00b7bd34fc4f796b6
blob + 9c6425cb8c959dafe09935df78e7dea67a5192c4
--- telescope.h
+++ telescope.h
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,
char *cert;
enum trust_state trust;
+ struct proxy *proxy;
struct phos_uri uri;
struct histhead hist;
struct hist *hist_cur;
* 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);
/* 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*);