ref: 3a91d0da6accefe72f46e3c7d149ef3d5cfd759e
parent: 54f4cf61dada165e94b3cd61f72a7003092e9867
author: Sigrid Haflínudóttir <ftrvxmtrx@gmail.com>
date: Mon Aug 24 07:29:07 EDT 2020
fix queries, split request/response code
--- a/gemnine.h
+++ b/gemnine.h
@@ -1,7 +1,15 @@
+typedef struct Response Response;
typedef struct Url Url;
-struct Url
-{
+struct Response {
+ Url *url;
+ char *mime;
+ char *prompt;
+ int status;
+ int fd;
+};
+
+struct Url {
char *full;
char *scheme;
char *user;
@@ -13,8 +21,21 @@
char *fragment;
};
+typedef struct {
+ char *s1;
+ char *s2;
+}Str2;
+
#pragma varargck type "U" Url*
+#pragma varargck type "E" Str2
+#pragma varargck type "N" char*
+#pragma varargck type "]" char*
+/* req.c */
+Response *request(Url *url);
+void freeresponse(Response *r);
+
+/* url.c */
int Efmt(Fmt*);
int Nfmt(Fmt*);
int Mfmt(Fmt*);
@@ -24,5 +45,6 @@
void freeurl(Url *u);
char *Upath(Url *u);
+/* util.c */
void *emalloc(int n);
char *estrdup(char *s);
--- a/main.c
+++ b/main.c
@@ -1,132 +1,10 @@
#include <u.h>
#include <libc.h>
-#include <libsec.h>
#include <bio.h>
-#include <ctype.h>
#include <plumb.h>
+#include <ctype.h>
#include "gemnine.h"
-typedef struct Response Response;
-
-struct Response {
- Url *url;
- char *mime;
- char *prompt;
- int status;
- int fd;
-};
-
-#pragma varargck type "E" char*
-
-void
-freeresponse(Response *r)
-{
- if(r != nil){
- close(r->fd);
- freeurl(r->url);
- free(r->mime);
- free(r->prompt);
- free(r);
- }
-}
-
-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);
- 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->status = 10*(int)(s[0]-'0') + s[1] - '0';
- s += 2;
- while(isspace(*s))
- s++;
-
- if(r->status >= 10 && r->status < 20){ /* input */
- r->prompt = estrdup(s);
- }else if(r->status >= 20 && r->status < 30){ /* success */
- r->mime = estrdup(s[0] ? s : "text/gemini");
- }else if(r->status >= 30 && r->status < 40){ /* redirect */
- if((u = urlparse(r->url, s)) == nil){
- werrstr("invalid redirect url");
- goto err;
- }
- freeresponse(r);
- if((r = request(u)) == nil)
- freeurl(u);
- }else if(r->status >= 40 && r->status < 50){
- werrstr("temporary failure: %s", s);
- goto err;
- }else if(r->status >= 50 && r->status < 60){
- werrstr("permanent failure: %s", s);
- goto err;
- }else if(r->status >= 60 && r->status < 70){
- werrstr("client cert required: %s", s);
- goto err;
- }
-
- return r;
-
-err:
- if(r != nil && r->url != nil)
- werrstr("%U: %r", r->url);
- freeresponse(r);
- return nil;
-}
-
char *
readall(int fd)
{
@@ -249,7 +127,7 @@
print("%s\n", r->prompt);
s = readall(0);
free(url);
- t = smprint("%s?%E", r->url->full, s);
+ t = smprint("%s?%E", r->url->full, (Str2){s, "/:@ \n"});
free(s);
url = urlparse(nil, t);
free(t);
--- a/mkfile
+++ b/mkfile
@@ -9,6 +9,7 @@
OFILES=\
main.$O\
+ req.$O\
url.$O\
util.$O\
--- /dev/null
+++ b/req.c
@@ -1,0 +1,114 @@
+#include <u.h>
+#include <libc.h>
+#include <libsec.h>
+#include <ctype.h>
+#include "gemnine.h"
+
+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);
+ 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->status = 10*(int)(s[0]-'0') + s[1] - '0';
+ s += 2;
+ while(isspace(*s))
+ s++;
+
+ if(r->status >= 10 && r->status < 20){ /* input */
+ r->prompt = estrdup(s);
+ }else if(r->status >= 20 && r->status < 30){ /* success */
+ r->mime = estrdup(s[0] ? s : "text/gemini");
+ }else if(r->status >= 30 && r->status < 40){ /* redirect */
+ if((u = urlparse(r->url, s)) == nil){
+ werrstr("invalid redirect url");
+ goto err;
+ }
+ freeresponse(r);
+ if((r = request(u)) == nil)
+ freeurl(u);
+ }else if(r->status >= 40 && r->status < 50){
+ werrstr("temporary failure: %s", s);
+ goto err;
+ }else if(r->status >= 50 && r->status < 60){
+ werrstr("permanent failure: %s", s);
+ goto err;
+ }else if(r->status >= 60 && r->status < 70){
+ werrstr("client cert required: %s", s);
+ goto err;
+ }
+
+ return r;
+
+err:
+ if(r != nil && r->url != nil)
+ werrstr("%U: %r", r->url);
+ freeresponse(r);
+ return nil;
+}
+
+void
+freeresponse(Response *r)
+{
+ if(r != nil){
+ close(r->fd);
+ freeurl(r->url);
+ free(r->mime);
+ free(r->prompt);
+ free(r);
+ }
+}
--- a/url.c
+++ b/url.c
@@ -8,15 +8,6 @@
Domlen = 256,
};
-typedef struct {
- char *s1;
- char *s2;
-}Str2;
-
-#pragma varargck type "E" Str2
-#pragma varargck type "N" char*
-#pragma varargck type "]" char*
-
static char reserved[] = "%:/?#[]@!$&'()*+,;=";
static int