AmendHub

Download:

jcs

/

detritus

/

amendments

/

8

browser: Switch to TextView for main output, fix a few TLS bugs

When the remote server disconnects, we may still have data in the TLS
engine to read and parse.

jcs made amendment 8 about 1 year ago
--- browser.c Tue Oct 1 20:15:34 2024 +++ browser.c Tue Oct 22 17:37:20 2024 @@ -42,8 +42,6 @@ void browser_mouse_down(struct focusable *focusable, E bool browser_handle_menu(struct focusable *focusable, short menu, short item); void browser_atexit(struct focusable *focusable); -bool browser_avoid_te_overflow(struct browser *browser, TEHandle te, - short line_height); void browser_cleanup(struct browser *browser); void browser_connect(struct browser *browser); @@ -66,12 +64,14 @@ browser_idle(struct focusable *focusable, EventRecord struct browser *browser = (struct browser *)focusable->cookie; size_t len; - TEIdle(browser->active_te); + TEIdle(browser->uri_te); if (!browser->req) return; switch (browser->req->state) { + case REQ_STATE_DISCONNECTED: + break; case REQ_STATE_IDLE: break; case REQ_STATE_CONNECTED: @@ -87,10 +87,8 @@ browser_init(void) char title[64]; struct browser *browser; struct focusable *focusable; - Rect bounds = { 0 }, te_bounds = { 0 }; + Rect bounds, te_bounds, padding; Rect data_bounds = { 0, 0, 0, 1 }; /* tlbr */ - Point cell_size = { 0, 0 }; - Cell cell = { 0 }; short n, width, height; browser = xmalloczero(sizeof(struct browser)); @@ -138,40 +136,35 @@ browser_init(void) panic("Out of memory allocating TE"); TEAutoView(false, browser->uri_te); TEActivate(browser->uri_te); - browser->active_te = browser->uri_te; bounds.left = bounds.right + PADDING; bounds.right = browser->win->portRect.right - PADDING; browser->go_button = NewControl(browser->win, &bounds, "\pGo", true, 1, 1, 1, pushButProc, 0L); - /* output TE */ + /* output TV */ bounds.left = PADDING; bounds.right = browser->win->portRect.right - SCROLLBAR_WIDTH - PADDING; bounds.top = bounds.bottom + PADDING; bounds.bottom = browser->win->portRect.bottom - PADDING; - te_bounds = bounds; - InsetRect(&te_bounds, 2, 2); - browser->output_te = TEStylNew(&te_bounds, &bounds); - if (browser->output_te == NULL) - panic("Out of memory allocating TE"); - TEAutoView(false, browser->output_te); - (*(browser->output_te))->caretHook = NullCaretHook; + SetRect(&padding, 2, 2, 2, 2); + browser->output_tv = TVNew(&bounds, &padding); + if (browser->output_tv == NULL) + panic("Out of memory allocating TV"); /* scrollbar for output text */ bounds.right = browser->win->portRect.right - PADDING; bounds.left = bounds.right - SCROLLBAR_WIDTH; bounds.bottom++; bounds.top--; - browser->output_te_scroller = NewControl(browser->win, &bounds, "\p", + browser->output_tv_scroller = NewControl(browser->win, &bounds, "\p", true, 1, 1, 1, scrollBarProc, 0L); browser_update_menu(browser); - UpdateScrollbarForTE(browser->win, browser->output_te_scroller, - browser->output_te, true); + TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); - TESetText("geminiprotocol.net", strlen("geminiprotocol.net"), - browser->uri_te); + TESetText("gemini://geminiprotocol.net/", + strlen("gemini://geminiprotocol.net/"), browser->uri_te); focusable = xmalloczero(sizeof(struct focusable)); if (focusable == NULL) @@ -196,7 +189,7 @@ browser_close(struct focusable *focusable) struct browser *browser = (struct browser *)focusable->cookie; TEDispose(browser->uri_te); - TEDispose(browser->output_te); + TVDispose(browser->output_tv); DisposeWindow(browser->win); browser_cleanup(browser); @@ -302,18 +295,16 @@ browser_update(struct focusable *focusable, EventRecor InsetRect(&r, -1, -1); FrameRect(&r); - HLock(browser->output_te); - r = (*(browser->output_te))->viewRect; - HUnlock(browser->output_te); - FillRect(&r, white); - TEUpdate(&r, browser->output_te); + HLock(browser->output_tv); + r = (*(browser->output_tv))->view; + HUnlock(browser->output_tv); + TVUpdate(browser->output_tv); InsetRect(&r, -1, -1); FrameRect(&r); UpdtControl(browser->win, browser->win->visRgn); browser_reveal_shadow(browser); - browser_update_menu(browser); break; @@ -361,25 +352,20 @@ browser_mouse_down(struct focusable *focusable, EventR r = (*(browser->uri_te))->viewRect; HUnlock(browser->uri_te); if (PtInRect(p, &r)) { - if (browser->active_te != browser->uri_te) { - TEDeactivate(browser->active_te); - browser->active_te = browser->uri_te; - TEActivate(browser->uri_te); - } TEClick(p, ((event->modifiers & shiftKey) != 0), browser->uri_te); browser_update_menu(browser); return; } - HLock(browser->output_te); - r = (*(browser->output_te))->viewRect; - HUnlock(browser->output_te); + HLock(browser->output_tv); + r = (*(browser->output_tv))->view; + HUnlock(browser->output_tv); if (PtInRect(p, &r)) { - TEClick(p, ((event->modifiers & shiftKey) != 0), - browser->output_te); + TVClick(browser->output_tv, p, + ((event->modifiers & shiftKey) != 0)); if (browser->req && browser->req->links) { - off = TEGetOffset(p, browser->output_te); + off = TVGetOffset(browser->output_tv, p); for (n = 0; n < browser->req->links_count; n++) { link = &browser->req->links[n]; if ((link->pos <= off) && (off < link->pos + link->len)) { @@ -406,10 +392,10 @@ browser_mouse_down(struct focusable *focusable, EventR case inDownButton: case inPageUp: case inPageDown: - if (control != browser->output_te_scroller) + if (control != browser->output_tv_scroller) break; - SetTrackControlTE(browser->output_te); - TrackControl(control, p, TrackMouseDownInControl); + TVSetTrackScrollControl(browser->output_tv); + TrackControl(control, p, TVTrackScrollControl); break; case inThumb: val = GetCtlValue(control); @@ -418,10 +404,8 @@ browser_mouse_down(struct focusable *focusable, EventR adj = val - GetCtlValue(control); if (adj != 0) { val -= adj; - if (control == browser->output_te_scroller) { - TEScroll(0, adj * TEGetHeight(0, 0, - browser->output_te), browser->output_te); - } + if (control == browser->output_tv_scroller) + TVScroll(browser->output_tv, 0, adj); SetCtlValue(control, val); } break; @@ -454,10 +438,10 @@ browser_handle_menu(struct focusable *focusable, short case EDIT_MENU_ID: switch (item) { case EDIT_MENU_COPY_ID: - TECopy(browser->active_te); + TECopy(browser->uri_te); return true; case EDIT_MENU_SELECT_ALL_ID: - TESetSelect(0, 1024 * 32, browser->active_te); + TESetSelect(0, 1024 * 32, browser->uri_te); return true; } break; @@ -502,6 +486,7 @@ browser_connect(struct browser *browser) /* TODO: support URIs with port? */ browser->req->port = DEFAULT_GEMINI_PORT; + browser->req->uri_len = strlen(browser->req->uri); if (count = 0, sscanf(browser->req->uri, "gemini://%255[^/]/%*s%n", &browser->req->hostname, &count) == 1 && count > 10) { @@ -537,20 +522,18 @@ browser_connect(struct browser *browser) return; } - TESetText(browser->req->uri, browser->req->uri_len, browser->uri_te); HLock(browser->uri_te); r = (*(browser->uri_te))->viewRect; HUnlock(browser->uri_te); + TESetText(browser->req->uri, browser->req->uri_len, browser->uri_te); TESetSelect(SHRT_MAX, SHRT_MAX, browser->uri_te); TEUpdate(&r, browser->uri_te); - TEDeactivate(browser->uri_te); - browser->active_te = browser->output_te; browser->req->uri_len = strlen(browser->req->uri); memcpy(browser->req->message, browser->req->uri, browser->req->uri_len); browser->req->message[browser->req->uri_len] = '\r'; - browser->req->message[browser->req->uri_len] = '\n'; + browser->req->message[browser->req->uri_len + 1] = '\n'; browser->req->message_len = browser->req->uri_len + 2; if (browser->req->host_ip == 0) { @@ -628,9 +611,11 @@ browser_shuffle_data(struct browser *browser) short err, status; short cipherspace, plainspace, error; - if (browser->req->tcp_iopb.ioResult > 0) { + if (browser->req->tcp_iopb.ioResult > 0 || CommandPeriodPressed()) { progress(NULL); browser->req->state = REQ_STATE_DISCONNECTED; + browser_debugf(browser, "[TCP IO Result %d, disconnecting]\r", + browser->req->tcp_iopb.ioResult); return; } @@ -641,8 +626,9 @@ browser_shuffle_data(struct browser *browser) if (status & 0x1) { /* closed */ progress(NULL); - browser_printf(browser, "[TLS handshake failed: %d, 0x%x]\r", - error, status); + if (error != 0) + browser_printf(browser, "[TLS handshake failed: %d, 0x%x]\r", + error, status); browser->req->state = REQ_STATE_DISCONNECTED; break; } @@ -696,6 +682,9 @@ shuffle_read_tls_ciphertext(struct browser *browser) browser_debugf(browser, "[Read %lu bytes of ciphertext from TLS, " "forwarding to TCP]\r", len); + if (browser->req->tcp_done_reading) + return; + memset(&browser->req->tcp_wds, 0, sizeof(browser->req->tcp_wds)); browser->req->tcp_wds[0].ptr = (Ptr)browser->scsi_buf; browser->req->tcp_wds[0].length = len; @@ -718,7 +707,8 @@ shuffle_read_tcp_ciphertext(struct browser *browser, s unsigned short slen; /* read ciphertext from TCP and send it to TLS */ - if (browser->req->tcp_input_len < sizeof(browser->req->tcp_input)) { + if (browser->req->tcp_input_len < sizeof(browser->req->tcp_input) && + !browser->req->tcp_done_reading) { err = _TCPStatus(&browser->req->tcp_iopb, browser->req->tcp_stream, &browser->req->tcp_status_pb, NULL, NULL, false); if (browser->req->tcp_status_pb.amtUnreadData > 0) { @@ -743,11 +733,15 @@ shuffle_read_tcp_ciphertext(struct browser *browser, s "tcp_input]\r"); } } + if (err) { - progress(NULL); - browser_printf(browser, "[Failed TCPStatus: %d]\r", err); - browser->req->state = REQ_STATE_DISCONNECTED; - return; + browser->req->tcp_done_reading = true; + browser_printf(browser, "[Bad TCPStatus: %d]\r", err); + } else if (browser->req->tcp_status_pb.connectionState != + ConnectionStateEstablished) { + browser_debugf(browser, "[TCP connection closed (state %d)]\r", + browser->req->tcp_status_pb.connectionState); + browser->req->tcp_done_reading = true; } } @@ -765,12 +759,9 @@ shuffle_read_tcp_ciphertext(struct browser *browser, s else { size_t n; - /* TODO: why does memmove fail? */ - //memmove(browser->req->readbuf, browser->req->readbuf + len, - // browser->req->readbuflen - len); - for (n = 0; n < browser->req->tcp_input_len - len; n++) - browser->req->tcp_input[n] = - browser->req->tcp_input[len + n]; + memmove(browser->req->tcp_input, + browser->req->tcp_input + len, + browser->req->tcp_input_len - len); browser->req->tcp_input_len -= len; browser_debugf(browser, "[Wrote %ld bytes of " @@ -893,64 +884,31 @@ browser_debugf(struct browser *browser, const char *fo size_t browser_print(struct browser *browser, const char *str, size_t len) { - StScrpRec *scrp_rec; - ScrpSTElement *scrp_ele; + struct TVStyle style; struct browser_link *link; - short line_height; size_t n; - unsigned long style = STYLE_NONE; - if (browser->req && browser->req->style) - style = browser->req->style; - - line_height = BROWSER_FONT_SIZE + 3; - - browser_avoid_te_overflow(browser, browser->output_te, line_height); + style.font = BROWSER_FONT; + style.size = BROWSER_FONT_SIZE; + style.style = 0; - if (browser->scrp_rec_h == NULL) { - browser->scrp_rec_h = xNewHandle(sizeof(short) + - (sizeof(ScrpSTElement) * BROWSER_SCRAP_ELEMENTS)); - HLock(browser->scrp_rec_h); - memset(*(browser->scrp_rec_h), 0, - GetHandleSize(browser->scrp_rec_h)); - } else { - HLock(browser->scrp_rec_h); - } - - scrp_rec = (StScrpRec *)(*(browser->scrp_rec_h)); - scrp_rec->scrpNStyles = 1; - scrp_ele = &scrp_rec->scrpStyleTab[0]; - scrp_ele->scrpHeight = line_height; - scrp_ele->scrpAscent = BROWSER_FONT_SIZE; - scrp_ele->scrpFont = BROWSER_FONT; - scrp_ele->scrpSize = BROWSER_FONT_SIZE; - scrp_ele->scrpFace = 0; - - if (style & STYLE_BOLD) - scrp_ele->scrpFace |= bold | condense; - if (style & (STYLE_H1 | STYLE_H2 | STYLE_H3)) - scrp_ele->scrpFace |= bold; - if (style & STYLE_ITALIC) - scrp_ele->scrpFace |= italic; - if (style & STYLE_LINK) - scrp_ele->scrpFace |= underline; - if (style & STYLE_H1) { - scrp_ele->scrpSize += 8; - scrp_ele->scrpHeight += 10; - scrp_ele->scrpAscent += 8; - } else if (style & STYLE_H2) { - scrp_ele->scrpSize += 4; - scrp_ele->scrpHeight += 6; - scrp_ele->scrpAscent += 4; - } else if (style & STYLE_H3) { - scrp_ele->scrpSize += 2; - scrp_ele->scrpHeight += 4; - scrp_ele->scrpAscent += 2; - } - - TESetSelect(SHRT_MAX, SHRT_MAX, browser->output_te); + if (browser->req->style & STYLE_BOLD) + style.style |= bold | condense; + if (browser->req->style & (STYLE_H1 | STYLE_H2 | STYLE_H3)) + style.style |= bold; + if (browser->req->style & STYLE_ITALIC) + style.style |= italic; + if (browser->req->style & STYLE_LINK) + style.style |= underline; - if (style & STYLE_LINK) { + if (browser->req->style & STYLE_H1) + style.size += 8; + else if (browser->req->style & STYLE_H2) + style.size += 4; + else if (browser->req->style & STYLE_H3) + style.size += 2; + + if (browser->req->style & STYLE_LINK) { if (browser->req->links_count == browser->req->links_size) { browser->req->links_size += BROWSER_LINKS_CHUNK_SIZE; browser->req->links = xreallocarray(browser->req->links, @@ -962,13 +920,13 @@ browser_print(struct browser *browser, const char *str memset(&browser->req->links[browser->req->links_count], 0, sizeof(struct browser_link) * BROWSER_LINKS_CHUNK_SIZE); } - + link = &browser->req->links[browser->req->links_count++]; + + HLock(browser->output_tv); + link->pos = (*(browser->output_tv))->text_length; + HUnlock(browser->output_tv); - HLock(browser->output_te); - link->pos = (*(browser->output_te))->teLength; - HUnlock(browser->output_te); - /* [<whitespace>]<URL>[<whitespace><title>] */ /* eat leading whitespace */ @@ -1018,94 +976,32 @@ browser_print(struct browser *browser, const char *str link->title[len - 1] = '\0'; link->len = len - 1; - TEStylInsert(link->title, len - 1, browser->scrp_rec_h, - browser->output_te); + TVAppend(browser->output_tv, &style, link->title, len - 1); str += len - 1; len = 1; } else - TEStylInsert(link->link, len, browser->scrp_rec_h, - browser->output_te); + TVAppend(browser->output_tv, &style, (char *)str, len); - style &= ~(STYLE_LINK); + browser->req->style &= ~(STYLE_LINK); } if (str[len - 1] == '\r' && - (style & (STYLE_H1 | STYLE_H2 | STYLE_H3))) { + (browser->req->style & (STYLE_H1 | STYLE_H2 | STYLE_H3))) { /* print newlines in a small size */ - TEStylInsert(str, len - 1, browser->scrp_rec_h, browser->output_te); - scrp_ele->scrpHeight = line_height; - scrp_ele->scrpAscent = BROWSER_FONT_SIZE; - scrp_ele->scrpFont = BROWSER_FONT; - scrp_ele->scrpSize = BROWSER_FONT_SIZE; - TEStylInsert("\r", 1, browser->scrp_rec_h, browser->output_te); + TVAppend(browser->output_tv, &style, (char *)str, len - 1); + style.font = BROWSER_FONT; + style.size = BROWSER_FONT_SIZE; + style.style = 0; + TVAppend(browser->output_tv, &style, "\r", 1); } else - TEStylInsert(str, len, browser->scrp_rec_h, browser->output_te); + TVAppend(browser->output_tv, &style, (char *)str, len); + + TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); - HUnlock(browser->scrp_rec_h); - -// if (was_len == 0) { -// SetCtlValue(browser->output_te_scroller, -// GetCtlMin(browser->output_te_scroller)); -// } - UpdateScrollbarForTE(browser->win, browser->output_te_scroller, - browser->output_te, false); - - HUnlock(browser->output_te); - return len; } -bool -browser_avoid_te_overflow(struct browser *browser, TEHandle te, - short line_height) -{ - RgnHandle savergn; - Rect zerorect = { 0, 0, 0, 0 }; - - HLock(te); - - /* too many lines */ - if ((*te)->nLines >= (nitems((*te)->lineStarts) - 10)) - goto te_overflow; - - /* too many characters */ - if ((*te)->teLength >= (SHRT_MAX - 500)) - goto te_overflow; - - /* rect of all lines is too tall */ - if ((*te)->nLines * line_height >= (SHRT_MAX - 100)) - goto te_overflow; - - HUnlock(te); - - return false; - -te_overflow: - savergn = NewRgn(); - GetClip(savergn); - /* create an empty clip region so all TE updates are hidden */ - ClipRect(&zerorect); - - /* select some lines at the start, delete them */ - TESetSelect(0, (*te)->lineStarts[5], te); - TEDelete(te); - - /* scroll up, causing a repaint */ - TEPinScroll(0, INT_MAX, te); - - /* then scroll back down to what it looked like before we did anything */ - TEPinScroll(0, -INT_MAX, te); - - /* resume normal drawing */ - SetClip(savergn); - DisposeRgn(savergn); - - HUnlock(te); - - return true; -} - void browser_clear(struct browser *browser) { @@ -1114,12 +1010,9 @@ browser_clear(struct browser *browser) GetPort(&win); SetPort(browser->win); - EraseRect(&(*(browser->output_te))->viewRect); - TESetText("", 0, browser->output_te); + TVClear(browser->output_tv); + TVUpdateScrollbar(browser->output_tv, browser->output_tv_scroller); - UpdateScrollbarForTE(browser->win, browser->output_te_scroller, - browser->output_te, true); - SetPort(win); } @@ -1144,6 +1037,8 @@ handle_state: browser->req->response[n - 1] = '\0'; if (!browser_parse_header(browser, browser->req->response)) { + browser_debugf(browser, "[Header parsing failed, " + "disconnecting]\r"); browser->req->state = REQ_STATE_DISCONNECTED; return; } @@ -1176,13 +1071,14 @@ restart_parse: */ break; } - + if (!(n == browser->req->response_len || browser->req->response[n] == '\n')) continue; len = n + 1; trail = 0; + skip = 0; if (n < browser->req->response_len && browser->req->response[n] == '\n') { @@ -1191,8 +1087,21 @@ restart_parse: len--; trail = 1; } + } else if (browser->req->response_len < + sizeof(browser->req->response) && + !browser->req->tcp_done_reading) { + /* + * No newline found at the end of the buffer, but the + * buffer isn't full so wait for more data. + */ + break; } + /* + * If we didn't find a newline but we're at the end of the + * buffer, shift it down first to see if we can fit the whole + * line in the buffer at once */ + if (browser->req->response[0] == '=' && browser->req->response[1] == '>') { /* link */ @@ -1315,12 +1224,15 @@ restart_parse: void browser_consume_response(struct browser *browser, size_t len) { - if (len == browser->req->response_len) + if (len == browser->req->response_len) { browser->req->response_len = 0; - else { + memset(browser->req->response, 0, sizeof(browser->req->response)); + } else { memmove(browser->req->response, browser->req->response + len, sizeof(browser->req->response) - len); browser->req->response_len -= len; + memset(browser->req->response + browser->req->response_len, 0, + sizeof(browser->req->response) - browser->req->response_len); } } @@ -1329,7 +1241,7 @@ browser_parse_header(struct browser *browser, char *st { short status; - browser_debugf(browser, "[Received header: %d]\r", str); + browser_debugf(browser, "[Received header: %s]\r", str); if (!(str[0] >= '0' && str[0] <= '9' && str[1] >= '0' && str[1] <= '9' && str[2] == ' ')) { browser_printf(browser, "[Malformed response %s]\r", str); @@ -1408,12 +1320,12 @@ browser_click_link(struct browser *browser, struct bro } TESetText(new_uri, len, browser->uri_te); + TESetSelect(SHRT_MAX, SHRT_MAX, browser->uri_te); HLock(browser->uri_te); r = (*(browser->uri_te))->viewRect; HUnlock(browser->uri_te); - TESetSelect(SHRT_MAX, SHRT_MAX, browser->uri_te); TEUpdate(&r, browser->uri_te); - //browser_connect(browser); + browser_connect(browser); } \ No newline at end of file --- browser.h Tue Oct 1 20:08:53 2024 +++ browser.h Tue Oct 22 15:29:10 2024 @@ -18,6 +18,7 @@ #define __BROWSER_H__ #include <stdlib.h> +#include "textview.h" #include "tcp.h" #include "util.h" @@ -69,6 +70,7 @@ struct tcp_request { StreamPtr tcp_stream; wdsEntry tcp_wds[2]; TCPStatusPB tcp_status_pb; + bool tcp_done_reading; char uri[1024 + 1]; size_t uri_len; @@ -94,11 +96,8 @@ struct browser { BitMap shadow; TEHandle uri_te; ControlHandle go_button; - TEHandle output_te; - ControlHandle output_te_scroller; - Handle scrp_rec_h; -#define BROWSER_SCRAP_ELEMENTS 20 - TEHandle active_te; + TVHandle output_tv; + ControlHandle output_tv_scroller; struct tcp_request *req; unsigned char scsi_buf[2048];