diff options
author | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2021-06-23 16:21:12 +0000 |
---|---|---|
committer | Peter Mikkelsen <petermikkelsen10@gmail.com> | 2021-06-23 16:21:12 +0000 |
commit | 2d5ebf3532e32ff63224cd7c4568832afaab3e84 (patch) | |
tree | 798c83180af851ee35b42ef55d4a4ce382df4119 /sites/pmikkelsen.com/_files | |
parent | 9b3a308c7248fd2fa94162e4401726327cc66aa3 (diff) |
Add websocket webfs patch and notes
Diffstat (limited to 'sites/pmikkelsen.com/_files')
-rw-r--r-- | sites/pmikkelsen.com/_files/websocket-webfs.patch | 565 |
1 files changed, 565 insertions, 0 deletions
diff --git a/sites/pmikkelsen.com/_files/websocket-webfs.patch b/sites/pmikkelsen.com/_files/websocket-webfs.patch new file mode 100644 index 0000000..77c44b0 --- /dev/null +++ b/sites/pmikkelsen.com/_files/websocket-webfs.patch @@ -0,0 +1,565 @@ +From 424bcc25db6c3de73678fe43d44e4b408cd0434d +From: Peter Mikkelsen <petermikkelsen10@gmail.com> +Date: Wed, 23 Jun 2021 15:44:24 +0000 +Subject: [PATCH] Initial buggy version of adding websocket support to webfs + + +It can create connections but doesn't handle errors very well yet. +--- +diff ce73821f3575921e24f839b21c7be60520a9dc42 424bcc25db6c3de73678fe43d44e4b408cd0434d +--- a/sys/src/cmd/webfs/fns.h Mon Jun 21 17:38:11 2021 ++++ b/sys/src/cmd/webfs/fns.h Wed Jun 23 17:44:24 2021 +@@ -41,3 +41,6 @@ + int authenticate(Url *u, Url *ru, char *method, char *s); + void flushauth(Url *u, char *t); + void http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost); ++ ++/* websocket */ ++void websocket(int fd, Buq *qbody, Buq *qpost); +--- a/sys/src/cmd/webfs/fs.c Mon Jun 21 17:38:11 2021 ++++ b/sys/src/cmd/webfs/fs.c Wed Jun 23 17:44:24 2021 +@@ -4,6 +4,7 @@ + #include <fcall.h> + #include <thread.h> + #include <9p.h> ++#include <libsec.h> + + #include "dat.h" + #include "fns.h" +@@ -19,10 +20,12 @@ + Url *baseurl; + Url *url; + Key *hdr; ++ int wantwebsocket; + + int obody; /* body opend */ + int cbody; /* body closed */ + Buq *qbody; ++ Buq *websocketin; /* websocket input */ + }; + + struct Webfid +@@ -121,6 +124,8 @@ + + buclose(cl->qbody, 0); + bufree(cl->qbody); ++ buclose(cl->websocketin, 0); ++ bufree(cl->websocketin); + + while(k = cl->hdr){ + cl->hdr = k->next; +@@ -384,6 +389,25 @@ + if(cl->qbody == nil){ + char *m; + ++ if(f->level == Qbody && (!strcmp(cl->url->scheme, "ws") || !strcmp(cl->url->scheme, "wss"))){ ++ cl->wantwebsocket = 1; ++ cl->websocketin = bualloc(64*1024); ++ if(!lookkey(cl->hdr, "Upgrade")) ++ cl->hdr = addkey(cl->hdr, "Upgrade", "websocket"); ++ if(!lookkey(cl->hdr, "Connection")) ++ cl->hdr = addkey(cl->hdr, "Connection", "upgrade"); ++ if(!lookkey(cl->hdr, "Sec-WebSocket-Version")) ++ cl->hdr = addkey(cl->hdr, "Sec-WebSocket-Version", "13"); ++ if(!lookkey(cl->hdr, "Sec-WebSocket-Key")){ ++ uchar nonce[16]; ++ char *b64nonce; ++ genrandom(nonce, 16); ++ b64nonce = smprint("%.*[", 16, nonce); ++ cl->hdr = addkey(cl->hdr, "Sec-WebSocket-Key", b64nonce); ++ free(b64nonce); ++ } ++ } ++ + if(cl->url == nil){ + respond(r, "no url set"); + return; +@@ -413,7 +437,7 @@ + if(agent && !lookkey(cl->hdr, "User-Agent")) + cl->hdr = addkey(cl->hdr, "User-Agent", agent); + +- http(m, cl->url, cl->hdr, cl->qbody, f->buq); ++ http(m, cl->url, cl->hdr, cl->qbody, cl->wantwebsocket ? cl->websocketin : f->buq); + cl->request[0] = 0; + cl->url = nil; + cl->hdr = nil; +@@ -683,6 +707,11 @@ + case Qpost: + bureq(f->buq, r); + return; ++ case Qbody: ++ if(f->client->wantwebsocket){ ++ bureq(f->client->websocketin, r); ++ return; ++ } + } + respond(r, "not implemented"); + } +--- a/sys/src/cmd/webfs/http.c Mon Jun 21 17:38:11 2021 ++++ b/sys/src/cmd/webfs/http.c Wed Jun 23 17:44:24 2021 +@@ -131,7 +131,7 @@ + if(strcmp(proxy->scheme, "https") == 0) + fd = tlswrap(fd, proxy->host); + } else { +- if(strcmp(u->scheme, "https") == 0) ++ if(strcmp(u->scheme, "https") == 0 || strcmp(u->scheme, "wss") == 0) + fd = tlswrap(fd, u->host); + } + if(fd < 0){ +@@ -520,7 +520,7 @@ + void + http(char *m, Url *u, Key *shdr, Buq *qbody, Buq *qpost) + { +- int i, l, n, try, pid, fd, cfd, needlength, chunked, retry, nobody, badauth; ++ int i, l, n, try, pid, fd, cfd, needlength, chunked, retry, nobody, badauth, wantwebsocket; + char *s, *x, buf[8192+2], status[256], method[16], *host; + vlong length, offset; + Url ru, tu, *nu; +@@ -549,8 +549,13 @@ + break; + } + ++ if(!strcmp(u->scheme, "ws") || !strcmp(u->scheme, "wss")) ++ wantwebsocket = 1; ++ else ++ wantwebsocket = 0; ++ + notify(catch); +- if(qpost){ ++ if(qpost && !wantwebsocket){ + /* file for spooling the postbody if we need to restart the request */ + snprint(buf, sizeof(buf), "/tmp/http.%d.%d.post", getppid(), getpid()); + fd = create(buf, OEXCL|ORDWR|ORCLOSE, 0600); +@@ -565,7 +570,7 @@ + badauth = 0; + for(try = 0; try < 12; try++){ + strcpy(status, "0 No status"); +- if(u == nil || (strcmp(u->scheme, "http") && strcmp(u->scheme, "https"))){ ++ if(u == nil || (strcmp(u->scheme, "http") && strcmp(u->scheme, "https") && strcmp(u->scheme, "ws") && strcmp(u->scheme, "wss"))){ + werrstr("bad url scheme"); + break; + } +@@ -591,7 +596,7 @@ + + length = 0; + chunked = 0; +- if(qpost){ ++ if(qpost && !wantwebsocket){ + /* have to read it to temp file to figure out the length */ + if(fd >= 0 && needlength && lookkey(shdr, "Content-Length") == nil){ + seek(fd, 0, 2); +@@ -700,7 +705,7 @@ + goto Retry; + } + +- if(qpost && !h->tunnel){ ++ if(qpost && !h->tunnel && !wantwebsocket){ + h->cancel = 0; + if((pid = rfork(RFMEM|RFPROC)) <= 0){ + int ifd; +@@ -802,8 +807,42 @@ + goto Status; + } + goto Error; +- case 100: /* Continue */ + case 101: /* Switching Protocols */ ++ if(wantwebsocket){ ++ int ok = 1; ++ char *wskey = lookkey(shdr, "Sec-WebSocket-Key"); ++ ++ k = getkey(rhdr, "Upgrade"); ++ if(k == nil || cistrcmp(k->val, "websocket") != 0) ++ ok = 0; ++ ++ k = getkey(rhdr, "Connection"); ++ if(k == nil && cistrcmp(k->val, "upgrade") != 0) ++ ok = 0; ++ ++ k = getkey(rhdr, "Sec-WebSocket-Accept"); ++ if(k == nil || wskey == nil) ++ ok = 0; ++ else{ ++ uchar digest[SHA1dlen]; ++ char *str = smprint("%s258EAFA5-E914-47DA-95CA-C5AB0DC85B11", wskey); ++ ++ sha1((uchar*)str, strlen(str), digest, nil); ++ char *val = smprint("%.*[", SHA1dlen, digest); ++ if(strcmp(val, k->val) != 0) ++ ok = 0; ++ free(str); ++ free(val); ++ } ++ ++ if(ok){ ++ qbody->url = u; u = nil; ++ qbody->hdr = rhdr; rhdr = nil; ++ websocket(h->fd, qbody, qpost); ++ } ++ goto Error; ++ } ++ case 100: /* Continue */ + case 102: /* Processing */ + case 103: /* Early Hints */ + while(k = rhdr){ +--- a/sys/src/cmd/webfs/mkfile Mon Jun 21 17:38:11 2021 ++++ b/sys/src/cmd/webfs/mkfile Wed Jun 23 17:44:24 2021 +@@ -3,6 +3,6 @@ + TARG=webfs + + HFILES=fns.h dat.h +-OFILES=sub.$O url.$O buq.$O http.$O fs.$O ++OFILES=sub.$O url.$O buq.$O http.$O websocket.$O fs.$O + + </sys/src/cmd/mkone +--- /dev/null Mon Jun 21 23:24:08 2021 ++++ b/sys/src/cmd/webfs/websocket.c Wed Jun 23 17:44:24 2021 +@@ -0,0 +1,349 @@ ++#include <u.h> ++#include <libc.h> ++#include <fcall.h> ++#include <thread.h> ++#include <9p.h> ++#include <libsec.h> ++ ++#include "dat.h" ++#include "fns.h" ++ ++typedef struct Frame Frame; ++typedef struct Message Message; ++ ++struct Frame ++{ ++ int final; ++ int opcode; ++ int masked; ++ uchar maskkey[4]; ++ uvlong length; ++ uchar *data; ++ ++ Frame *next; /* Chain frames in a message together */ ++}; ++ ++struct Message ++{ ++ int type; ++ uvlong length; ++ uchar *data; ++}; ++ ++enum { ++ ContinueFrame = 0x0, ++ TextFrame = 0x1, ++ BinaryFrame = 0x2, ++ CloseFrame = 0x8, ++ PingFrame = 0x9, ++ PongFrame = 0xA, ++}; ++ ++void writemessage(int, Message *); ++ ++void ++maskframe(Frame *f) ++{ ++ uvlong i; ++ for(i = 0; i < f->length; i++) ++ f->data[i] = f->data[i] ^ f->maskkey[i%4]; ++} ++ ++Frame * ++readframe(int fd) ++{ ++ Frame *f = malloc(sizeof(Frame)); ++ long n; ++ int offset; ++ uchar len; ++ ++ uchar buf[4096]; ++ ++Again: ++ offset = 0; ++ n = read(fd, buf, 2); ++ if(n != 2) ++ goto Error; ++ ++ f->final = (buf[offset] >> 7) & 0x1; ++ /* ignore rsv1, rsv2, rsv3 */ ++ f->opcode = buf[offset] & 0x0F; ++ offset++; ++ ++ f->masked = (buf[offset] >> 7) & 0x1; ++ len = buf[offset] & 0x7F; ++ offset++; ++ ++ if(len <= 125) ++ f->length = len; ++ else if(len == 126){ ++ n = read(fd, buf+offset, 2); ++ if(n != 2) ++ goto Error; ++ ++ f->length = buf[offset++] << 8; ++ f->length |= buf[offset++]; ++ }else if(len == 127){ ++ n = read(fd, buf+offset, 8); ++ if(n != 8) ++ goto Error; ++ f->length = (uvlong)buf[offset++] << 56; ++ f->length |= (uvlong)buf[offset++] << 48; ++ f->length |= (uvlong)buf[offset++] << 40; ++ f->length |= (uvlong)buf[offset++] << 32; ++ f->length |= buf[offset++] << 24; ++ f->length |= buf[offset++] << 16; ++ f->length |= buf[offset++] << 8; ++ f->length |= buf[offset++]; ++ } ++ ++ if(f->masked){ ++ n = read(fd, buf+offset, 4); ++ if(n != 4) ++ goto Error; ++ ++ f->maskkey[0] = buf[offset++]; ++ f->maskkey[1] = buf[offset++]; ++ f->maskkey[2] = buf[offset++]; ++ f->maskkey[3] = buf[offset]; ++ } ++ ++ f->data = malloc(f->length); ++ readn(fd, f->data, f->length); ++ if(f->masked) ++ maskframe(f); ++ ++ if(f->opcode == PingFrame){ ++ Message *m = malloc(sizeof(Message)); ++ m->type = PongFrame; ++ m->length = f->length; ++ m->data = f->data; ++ writemessage(fd, m); /* SHOULD LOCK */ ++ free(m); ++ free(f->data); ++ goto Again; ++ } ++ ++ return f; ++Error: ++ exits("Readframe failed"); ++ return nil; ++} ++ ++Message * ++framestomessage(Frame *frames) ++{ ++ Message *m = malloc(sizeof(Message)); ++ uvlong length = 0; ++ uvlong offset = 0; ++ ++ Frame *f; ++ for(f = frames; f != nil; f = f->next) ++ length += f->length; ++ ++ m->type = frames->opcode; ++ m->length = length; ++ m->data = malloc(length); ++ for(f = frames; f != nil; f = f->next){ ++ memcpy(m->data + offset, f->data, f->length); ++ offset += f->length; ++ } ++ ++ return m; ++} ++ ++Message * ++readmsg(int fd) ++{ ++ Frame *frames = readframe(fd); ++ Frame *last = frames; ++ Message *m; ++ ++ while(!last->final){ ++ last->next = readframe(fd); ++ last = last->next; ++ } ++ last->next = nil; ++ ++ m = framestomessage(frames); ++ while(frames){ ++ Frame *f = frames->next; ++ free(frames->data); ++ free(frames); ++ frames = f; ++ } ++ return m; ++} ++ ++void ++writeframe(int fd, Frame *f) ++{ ++ uchar *buf; ++ uvlong totsize = 0; ++ uvlong offset = 0; ++ int lenbytes = 0; ++ ++ totsize += 2; /* Always there */ ++ if(f->length == 126) ++ lenbytes = 2; ++ else if(f->length == 127) ++ lenbytes = 8; ++ totsize += lenbytes; ++ ++ if(f->masked) ++ totsize += 4; ++ ++ totsize += f->length; ++ ++ buf = malloc(totsize); ++ ++ buf[offset] = f->final << 7; ++ buf[offset++] |= f->opcode; ++ buf[offset] = f->masked << 7; ++ ++ if(lenbytes == 0) ++ buf[offset++] |= f->length; ++ else if(lenbytes == 2) ++ buf[offset++] |= 126; ++ else if(lenbytes == 8) ++ buf[offset++] |= 127; ++ ++ if(lenbytes == 2){ ++ buf[offset++] = 0xFF & (f->length >> 8); ++ buf[offset++] = 0xFF & f->length; ++ }else if(lenbytes == 8){ ++ buf[offset++] = 0xFF & (f->length >> 56); ++ buf[offset++] = 0xFF & (f->length >> 48); ++ buf[offset++] = 0xFF & (f->length >> 40); ++ buf[offset++] = 0xFF & (f->length >> 32); ++ buf[offset++] = 0xFF & (f->length >> 24); ++ buf[offset++] = 0xFF & (f->length >> 16); ++ buf[offset++] = 0xFF & (f->length >> 8); ++ buf[offset++] = 0xFF & f->length; ++ } ++ ++ if(f->masked){ ++ buf[offset++] = f->maskkey[0]; ++ buf[offset++] = f->maskkey[1]; ++ buf[offset++] = f->maskkey[2]; ++ buf[offset++] = f->maskkey[3]; ++ } ++ ++ memcpy(buf + offset, f->data, f->length); ++ write(fd, buf, totsize); ++} ++ ++void ++writemessage(int fd, Message *m) ++{ ++ /* Could split up the message into frames but not right now. */ ++ ++ Frame *f = malloc(sizeof(Frame)); ++ f->final = 1; ++ f->opcode = m->type; ++ f->masked = 1; ++ genrandom(f->maskkey, 4); ++ f->length = m->length; ++ f->data = malloc(f->length); ++ memcpy(f->data, m->data, f->length); ++ maskframe(f); ++ f->next = nil; ++ ++ writeframe(fd, f); ++ free(f->data); ++ free(f); ++} ++ ++void ++websocketrecv(int fd, Buq *qbody) ++{ ++ /* ++ * Plan: Read frames and when we have a whole message do: ++ * 1) If control, act on it ++ * 2) If data, format as text and buwrite it ++ */ ++ while(1){ ++ Message *m = readmsg(fd); ++ //print("Received message type=%d length=%ulld\n", m->type, m->length); ++ ++ if(m->type == TextFrame || m->type == BinaryFrame){ ++ char *header; ++ if(m->type == TextFrame) ++ header = smprint("t %0.20ulld", m->length); ++ else ++ header = smprint("b %0.20ulld", m->length); ++ buwrite(qbody, header, 22); ++ buwrite(qbody, m->data, m->length); ++ } ++ free(m->data); ++ free(m); ++ } ++} ++ ++void ++websocketsend(int fd, Buq *qpost) ++{ ++ /* buread messages and pack them up in frames and send them */ ++ char buf[64]; ++ long n; ++ Message *m; ++ while(1){ ++ n = buread(qpost, buf, 22); ++ if(n != 22){ ++ buclose(qpost, "Header short"); ++ return; ++ } ++ buf[n] = 0; ++ ++ m = malloc(sizeof(Message)); ++ if(buf[0] == 't') ++ m->type = TextFrame; ++ else if(buf[0] == 'b') ++ m->type = BinaryFrame; ++ ++ char *ret; ++ m->length = strtoull(buf+2, &ret, 10); ++ if(ret != buf+22){ ++ buclose(qpost, "Header format wrong"); ++ return; ++ } ++ ++ m->data = malloc(m->length); ++ n = 0; ++ while(n < m->length){ ++ uvlong missing = m->length - n; ++ n += buread(qpost, m->data + n, (missing < 8192) ? missing : 8192); ++ } ++ ++ writemessage(fd, m); ++ free(m->data); ++ free(m); ++ } ++} ++ ++void ++websocket(int fd, Buq *qbody, Buq *qpost) ++{ ++ buwrite(qbody, "websocket ready\n", 16); ++ switch(rfork(RFPROC|RFMEM)){ ++ default: ++ websocketrecv(fd, qbody); ++ break; ++ case 0: ++ websocketsend(fd, qpost); ++ goto End; ++ case -1: ++ buclose(qbody, "can't fork"); ++ bufree(qbody); ++ buclose(qpost, "can't fork"); ++ bufree(qpost); ++ break; ++ } ++End: ++ close(fd); ++ buclose(qbody, nil); ++ bufree(qbody); ++ buclose(qpost, nil); ++ bufree(qpost); ++ exits(nil); ++} |