diff options
author | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-30 08:20:38 +0300 |
---|---|---|
committer | Jaakko Keränen <jaakko.keranen@iki.fi> | 2021-06-30 08:20:38 +0300 |
commit | 73a721fc93c3be7b13361dea41d4431ad14a3fdd (patch) | |
tree | e6de1687d1932509789e21ed4232fe2c6def32ad | |
parent | 42d461f32eb77a83c0f9d7b4fb202de72c64a97f (diff) |
Canonical URIs
Internally, all URIs should be converted to a canonical form so that they can be compared against each other.
The canonical form is an IRI with spaces and reserved characters percent-encoded.
-rw-r--r-- | src/app.c | 2 | ||||
-rw-r--r-- | src/bookmarks.c | 6 | ||||
-rw-r--r-- | src/feeds.c | 4 | ||||
-rw-r--r-- | src/gempub.c | 4 | ||||
-rw-r--r-- | src/gmdocument.c | 3 | ||||
-rw-r--r-- | src/gmutil.c | 26 | ||||
-rw-r--r-- | src/gmutil.h | 1 | ||||
-rw-r--r-- | src/ui/documentwidget.c | 14 | ||||
-rw-r--r-- | src/ui/inputwidget.c | 2 | ||||
-rw-r--r-- | src/ui/root.c | 2 | ||||
-rw-r--r-- | src/ui/sidebarwidget.c | 6 | ||||
-rw-r--r-- | src/visited.c | 2 |
12 files changed, 51 insertions, 21 deletions
@@ -2815,7 +2815,7 @@ iStringSet *listOpenURLs_App(void) { | |||
2815 | iStringSet *set = new_StringSet(); | 2815 | iStringSet *set = new_StringSet(); |
2816 | iObjectList *docs = listDocuments_App(NULL); | 2816 | iObjectList *docs = listDocuments_App(NULL); |
2817 | iConstForEach(ObjectList, i, docs) { | 2817 | iConstForEach(ObjectList, i, docs) { |
2818 | insert_StringSet(set, withSpacesEncoded_String(url_DocumentWidget(i.object))); | 2818 | insert_StringSet(set, canonicalUrl_String(url_DocumentWidget(i.object))); |
2819 | } | 2819 | } |
2820 | iRelease(docs); | 2820 | iRelease(docs); |
2821 | return set; | 2821 | return set; |
diff --git a/src/bookmarks.c b/src/bookmarks.c index 1f887c98..65cc7982 100644 --- a/src/bookmarks.c +++ b/src/bookmarks.c | |||
@@ -158,6 +158,7 @@ void load_Bookmarks(iBookmarks *d, const char *dirPath) { | |||
158 | appendChar_String(&bm->url, '/'); | 158 | appendChar_String(&bm->url, '/'); |
159 | } | 159 | } |
160 | stripDefaultUrlPort_String(&bm->url); | 160 | stripDefaultUrlPort_String(&bm->url); |
161 | set_String(&bm->url, canonicalUrl_String(&bm->url)); | ||
161 | } | 162 | } |
162 | nextSplit_Rangecc(src, "\n", &line); | 163 | nextSplit_Rangecc(src, "\n", &line); |
163 | setRange_String(&bm->title, line); | 164 | setRange_String(&bm->title, line); |
@@ -201,7 +202,7 @@ uint32_t add_Bookmarks(iBookmarks *d, const iString *url, const iString *title, | |||
201 | iChar icon) { | 202 | iChar icon) { |
202 | lock_Mutex(d->mtx); | 203 | lock_Mutex(d->mtx); |
203 | iBookmark *bm = new_Bookmark(); | 204 | iBookmark *bm = new_Bookmark(); |
204 | set_String(&bm->url, url); | 205 | set_String(&bm->url, canonicalUrl_String(url)); |
205 | set_String(&bm->title, title); | 206 | set_String(&bm->title, title); |
206 | if (tags) { | 207 | if (tags) { |
207 | set_String(&bm->tags, tags); | 208 | set_String(&bm->tags, tags); |
@@ -298,6 +299,7 @@ static iBool matchUrl_(void *url, const iBookmark *bm) { | |||
298 | 299 | ||
299 | uint32_t findUrl_Bookmarks(const iBookmarks *d, const iString *url) { | 300 | uint32_t findUrl_Bookmarks(const iBookmarks *d, const iString *url) { |
300 | /* TODO: O(n), boo */ | 301 | /* TODO: O(n), boo */ |
302 | url = canonicalUrl_String(url); | ||
301 | const iPtrArray *found = list_Bookmarks(d, NULL, matchUrl_, (void *) url); | 303 | const iPtrArray *found = list_Bookmarks(d, NULL, matchUrl_, (void *) url); |
302 | if (isEmpty_PtrArray(found)) return 0; | 304 | if (isEmpty_PtrArray(found)) return 0; |
303 | return id_Bookmark(constFront_PtrArray(found)); | 305 | return id_Bookmark(constFront_PtrArray(found)); |
@@ -448,7 +450,7 @@ void requestFinished_Bookmarks(iBookmarks *d, iGmRequest *req) { | |||
448 | const iRangecc url = capturedRange_RegExpMatch(&m, 1); | 450 | const iRangecc url = capturedRange_RegExpMatch(&m, 1); |
449 | const iRangecc title = capturedRange_RegExpMatch(&m, 3); | 451 | const iRangecc title = capturedRange_RegExpMatch(&m, 3); |
450 | iString * urlStr = newRange_String(url); | 452 | iString * urlStr = newRange_String(url); |
451 | const iString *absUrl = absoluteUrl_String(url_GmRequest(req), urlStr); | 453 | const iString *absUrl = canonicalUrl_String(absoluteUrl_String(url_GmRequest(req), urlStr)); |
452 | if (!findUrl_Bookmarks(d, absUrl)) { | 454 | if (!findUrl_Bookmarks(d, absUrl)) { |
453 | iString *titleStr = newRange_String(title); | 455 | iString *titleStr = newRange_String(title); |
454 | if (isEmpty_String(titleStr)) { | 456 | if (isEmpty_String(titleStr)) { |
diff --git a/src/feeds.c b/src/feeds.c index 6b102fef..a68fd726 100644 --- a/src/feeds.c +++ b/src/feeds.c | |||
@@ -215,7 +215,7 @@ static void parseResult_FeedJob_(iFeedJob *d) { | |||
215 | entry->discovered = now; | 215 | entry->discovered = now; |
216 | entry->bookmarkId = d->bookmarkId; | 216 | entry->bookmarkId = d->bookmarkId; |
217 | setRange_String(&entry->url, url); | 217 | setRange_String(&entry->url, url); |
218 | set_String(&entry->url, absoluteUrl_String(url_GmRequest(d->request), &entry->url)); | 218 | set_String(&entry->url, canonicalUrl_String(absoluteUrl_String(url_GmRequest(d->request), &entry->url))); |
219 | setRange_String(&entry->title, title); | 219 | setRange_String(&entry->title, title); |
220 | trimTitle_(&entry->title); | 220 | trimTitle_(&entry->title); |
221 | int year, month, day; | 221 | int year, month, day; |
@@ -241,7 +241,7 @@ static void parseResult_FeedJob_(iFeedJob *d) { | |||
241 | entry->bookmarkId = d->bookmarkId; | 241 | entry->bookmarkId = d->bookmarkId; |
242 | iString *title = newRange_String(line); | 242 | iString *title = newRange_String(line); |
243 | set_String(&entry->title, title); | 243 | set_String(&entry->title, title); |
244 | set_String(&entry->url, &d->url); | 244 | set_String(&entry->url, canonicalUrl_String(&d->url)); |
245 | appendChar_String(&entry->url, '#'); | 245 | appendChar_String(&entry->url, '#'); |
246 | append_String(&entry->url, collect_String(urlEncode_String(title))); | 246 | append_String(&entry->url, collect_String(urlEncode_String(title))); |
247 | delete_String(title); | 247 | delete_String(title); |
diff --git a/src/gempub.c b/src/gempub.c index 1f5d58ce..23846414 100644 --- a/src/gempub.c +++ b/src/gempub.c | |||
@@ -246,10 +246,10 @@ size_t navSize_Gempub(const iGempub *d) { | |||
246 | 246 | ||
247 | size_t navIndex_Gempub(const iGempub *d, const iString *url) { | 247 | size_t navIndex_Gempub(const iGempub *d, const iString *url) { |
248 | parseNavigationLinks_Gempub_(d); | 248 | parseNavigationLinks_Gempub_(d); |
249 | const iString *normUrl = withSpacesEncoded_String(url); | 249 | const iString *canonUrl = withSpacesEncoded_String(url); |
250 | iConstForEach(Array, i, d->navLinks) { | 250 | iConstForEach(Array, i, d->navLinks) { |
251 | const iGempubNavLink *nav = i.value; | 251 | const iGempubNavLink *nav = i.value; |
252 | if (equalCase_String(&nav->url, normUrl)) { | 252 | if (equalCase_String(&nav->url, canonUrl)) { |
253 | return index_ArrayConstIterator(&i); | 253 | return index_ArrayConstIterator(&i); |
254 | } | 254 | } |
255 | } | 255 | } |
diff --git a/src/gmdocument.c b/src/gmdocument.c index f15d9d1d..8832271a 100644 --- a/src/gmdocument.c +++ b/src/gmdocument.c | |||
@@ -1554,13 +1554,14 @@ static void normalize_GmDocument(iGmDocument *d) { | |||
1554 | printf("wasNormalized: %d\n", wasNormalized); | 1554 | printf("wasNormalized: %d\n", wasNormalized); |
1555 | fflush(stdout); | 1555 | fflush(stdout); |
1556 | set_String(&d->source, collect_String(normalized)); | 1556 | set_String(&d->source, collect_String(normalized)); |
1557 | normalize_String(&d->source); /* NFC */ | 1557 | //normalize_String(&d->source); /* NFC */ |
1558 | printf("orig:%zu norm:%zu\n", size_String(&d->unormSource), size_String(&d->source)); | 1558 | printf("orig:%zu norm:%zu\n", size_String(&d->unormSource), size_String(&d->source)); |
1559 | /* normalized source has an extra newline at the end */ | 1559 | /* normalized source has an extra newline at the end */ |
1560 | // iAssert(wasNormalized || equal_String(&d->unormSource, &d->source)); | 1560 | // iAssert(wasNormalized || equal_String(&d->unormSource, &d->source)); |
1561 | } | 1561 | } |
1562 | 1562 | ||
1563 | void setUrl_GmDocument(iGmDocument *d, const iString *url) { | 1563 | void setUrl_GmDocument(iGmDocument *d, const iString *url) { |
1564 | url = canonicalUrl_String(url); | ||
1564 | set_String(&d->url, url); | 1565 | set_String(&d->url, url); |
1565 | iUrl parts; | 1566 | iUrl parts; |
1566 | init_Url(&parts, url); | 1567 | init_Url(&parts, url); |
diff --git a/src/gmutil.c b/src/gmutil.c index 7a1ae938..846405c3 100644 --- a/src/gmutil.c +++ b/src/gmutil.c | |||
@@ -537,9 +537,29 @@ const iString *withSpacesEncoded_String(const iString *d) { | |||
537 | if (isDataUrl_String(d)) { | 537 | if (isDataUrl_String(d)) { |
538 | return d; | 538 | return d; |
539 | } | 539 | } |
540 | iString *enc = copy_String(d); | 540 | /* Only make a copy if we need to modify the URL. */ |
541 | urlEncodeSpaces_String(enc); | 541 | if (indexOfCStr_String(d, " ") != iInvalidPos) { |
542 | return collect_String(enc); | 542 | iString *enc = copy_String(d); |
543 | urlEncodeSpaces_String(enc); | ||
544 | return collect_String(enc); | ||
545 | } | ||
546 | return d; | ||
547 | } | ||
548 | |||
549 | const iString *canonicalUrl_String(const iString *d) { | ||
550 | /* The "canonical" form, used for internal storage and comparisons, is: | ||
551 | - all non-reserved characters decoded (i.e., it's an IRI) | ||
552 | - expect for spaces, which are always `%20` | ||
553 | This means a canonical URL can be used on a gemtext link line without modifications. */ | ||
554 | iString *canon = maybeUrlDecodeExclude_String(d, "/?:;#&= "); | ||
555 | /* `canon` may now be NULL if nothing was decoded. */ | ||
556 | if (indexOfCStr_String(canon ? canon : d, " ") != iInvalidPos) { | ||
557 | if (!canon) { | ||
558 | canon = copy_String(d); | ||
559 | } | ||
560 | urlEncodeSpaces_String(canon); | ||
561 | } | ||
562 | return canon ? collect_String(canon) : d; | ||
543 | } | 563 | } |
544 | 564 | ||
545 | iRangecc mediaTypeWithoutParameters_Rangecc(iRangecc mime) { | 565 | iRangecc mediaTypeWithoutParameters_Rangecc(iRangecc mime) { |
diff --git a/src/gmutil.h b/src/gmutil.h index e7ff7cc5..be6b471e 100644 --- a/src/gmutil.h +++ b/src/gmutil.h | |||
@@ -123,6 +123,7 @@ const char * makeFileUrl_CStr (const char *localFilePath); | |||
123 | iString * localFilePathFromUrl_String(const iString *); | 123 | iString * localFilePathFromUrl_String(const iString *); |
124 | void urlEncodeSpaces_String (iString *); | 124 | void urlEncodeSpaces_String (iString *); |
125 | const iString * withSpacesEncoded_String(const iString *); | 125 | const iString * withSpacesEncoded_String(const iString *); |
126 | const iString * canonicalUrl_String (const iString *); | ||
126 | 127 | ||
127 | const char * mediaType_Path (const iString *path); | 128 | const char * mediaType_Path (const iString *path); |
128 | iRangecc mediaTypeWithoutParameters_Rangecc (iRangecc mime); | 129 | iRangecc mediaTypeWithoutParameters_Rangecc (iRangecc mime); |
diff --git a/src/ui/documentwidget.c b/src/ui/documentwidget.c index cb1fde28..509933af 100644 --- a/src/ui/documentwidget.c +++ b/src/ui/documentwidget.c | |||
@@ -1470,7 +1470,7 @@ static void updateDocument_DocumentWidget_(iDocumentWidget *d, | |||
1470 | baseName_Path(collect_String(newRange_String(parts.path))).start; | 1470 | baseName_Path(collect_String(newRange_String(parts.path))).start; |
1471 | } | 1471 | } |
1472 | format_String(&str, "=> %s %s\n", | 1472 | format_String(&str, "=> %s %s\n", |
1473 | cstr_String(withSpacesEncoded_String(d->mod.url)), | 1473 | cstr_String(canonicalUrl_String(d->mod.url)), |
1474 | linkTitle); | 1474 | linkTitle); |
1475 | setData_Media(media_GmDocument(d->doc), | 1475 | setData_Media(media_GmDocument(d->doc), |
1476 | imgLinkId, | 1476 | imgLinkId, |
@@ -1638,7 +1638,7 @@ static void updateFromCachedResponse_DocumentWidget_(iDocumentWidget *d, float n | |||
1638 | } | 1638 | } |
1639 | 1639 | ||
1640 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { | 1640 | static iBool updateFromHistory_DocumentWidget_(iDocumentWidget *d) { |
1641 | const iRecentUrl *recent = findUrl_History(d->mod.history, withSpacesEncoded_String(d->mod.url)); | 1641 | const iRecentUrl *recent = findUrl_History(d->mod.history, canonicalUrl_String(d->mod.url)); |
1642 | if (recent && recent->cachedResponse) { | 1642 | if (recent && recent->cachedResponse) { |
1643 | iChangeFlags(d->flags, | 1643 | iChangeFlags(d->flags, |
1644 | openedFromSidebar_DocumentWidgetFlag, | 1644 | openedFromSidebar_DocumentWidgetFlag, |
@@ -1845,8 +1845,11 @@ static void checkResponse_DocumentWidget_(iDocumentWidget *d) { | |||
1845 | d->sourceStatus = statusCode; | 1845 | d->sourceStatus = statusCode; |
1846 | switch (category_GmStatusCode(statusCode)) { | 1846 | switch (category_GmStatusCode(statusCode)) { |
1847 | case categoryInput_GmStatusCode: { | 1847 | case categoryInput_GmStatusCode: { |
1848 | /* Let the navigation history know that we have been to this URL even though | ||
1849 | it is only displayed as an input dialog. */ | ||
1850 | visitUrl_Visited(visited_App(), d->mod.url, transient_VisitedUrlFlag); | ||
1848 | iUrl parts; | 1851 | iUrl parts; |
1849 | init_Url(&parts, d->mod.url); | 1852 | init_Url(&parts, d->mod.url); |
1850 | iWidget *dlg = makeValueInput_Widget( | 1853 | iWidget *dlg = makeValueInput_Widget( |
1851 | as_Widget(d), | 1854 | as_Widget(d), |
1852 | NULL, | 1855 | NULL, |
@@ -2646,11 +2649,11 @@ static iBool handleCommand_DocumentWidget_(iDocumentWidget *d, const char *cmd) | |||
2646 | } | 2649 | } |
2647 | else if (equal_Command(cmd, "document.copylink") && document_App() == d) { | 2650 | else if (equal_Command(cmd, "document.copylink") && document_App() == d) { |
2648 | if (d->contextLink) { | 2651 | if (d->contextLink) { |
2649 | SDL_SetClipboardText(cstr_String(withSpacesEncoded_String(absoluteUrl_String( | 2652 | SDL_SetClipboardText(cstr_String(canonicalUrl_String(absoluteUrl_String( |
2650 | d->mod.url, linkUrl_GmDocument(d->doc, d->contextLink->linkId))))); | 2653 | d->mod.url, linkUrl_GmDocument(d->doc, d->contextLink->linkId))))); |
2651 | } | 2654 | } |
2652 | else { | 2655 | else { |
2653 | SDL_SetClipboardText(cstr_String(withSpacesEncoded_String(d->mod.url))); | 2656 | SDL_SetClipboardText(cstr_String(canonicalUrl_String(d->mod.url))); |
2654 | } | 2657 | } |
2655 | return iTrue; | 2658 | return iTrue; |
2656 | } | 2659 | } |
@@ -4870,6 +4873,7 @@ void deserializeState_DocumentWidget(iDocumentWidget *d, iStream *ins) { | |||
4870 | } | 4873 | } |
4871 | 4874 | ||
4872 | static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) { | 4875 | static void setUrl_DocumentWidget_(iDocumentWidget *d, const iString *url) { |
4876 | url = canonicalUrl_String(url); | ||
4873 | if (!equal_String(d->mod.url, url)) { | 4877 | if (!equal_String(d->mod.url, url)) { |
4874 | d->flags |= urlChanged_DocumentWidgetFlag; | 4878 | d->flags |= urlChanged_DocumentWidgetFlag; |
4875 | set_String(d->mod.url, url); | 4879 | set_String(d->mod.url, url); |
diff --git a/src/ui/inputwidget.c b/src/ui/inputwidget.c index b108ee17..8ea21cff 100644 --- a/src/ui/inputwidget.c +++ b/src/ui/inputwidget.c | |||
@@ -903,7 +903,7 @@ static iBool copy_InputWidget_(iInputWidget *d, iBool doCut) { | |||
903 | iString *str = collect_String(newUnicodeN_String(constAt_Array(&d->text, m.start), | 903 | iString *str = collect_String(newUnicodeN_String(constAt_Array(&d->text, m.start), |
904 | size_Range(&m))); | 904 | size_Range(&m))); |
905 | SDL_SetClipboardText( | 905 | SDL_SetClipboardText( |
906 | cstr_String(d->inFlags & isUrl_InputWidgetFlag ? withSpacesEncoded_String(str) : str)); | 906 | cstr_String(d->inFlags & isUrl_InputWidgetFlag ? canonicalUrl_String(str) : str)); |
907 | if (doCut) { | 907 | if (doCut) { |
908 | pushUndo_InputWidget_(d); | 908 | pushUndo_InputWidget_(d); |
909 | deleteMarked_InputWidget_(d); | 909 | deleteMarked_InputWidget_(d); |
diff --git a/src/ui/root.c b/src/ui/root.c index 5266978b..c78c9632 100644 --- a/src/ui/root.c +++ b/src/ui/root.c | |||
@@ -725,7 +725,7 @@ static iBool handleNavBarCommands_(iWidget *navBar, const char *cmd) { | |||
725 | const iString *urlStr = collect_String(suffix_Command(cmd, "url")); | 725 | const iString *urlStr = collect_String(suffix_Command(cmd, "url")); |
726 | trimCache_App(); | 726 | trimCache_App(); |
727 | trimMemory_App(); | 727 | trimMemory_App(); |
728 | visitUrl_Visited(visited_App(), withSpacesEncoded_String(urlStr), 0); /* TODO: internal URI normalization */ | 728 | visitUrl_Visited(visited_App(), urlStr, 0); /* TODO: internal URI normalization */ |
729 | postCommand_App("visited.changed"); /* sidebar will update */ | 729 | postCommand_App("visited.changed"); /* sidebar will update */ |
730 | setText_InputWidget(url, urlStr); | 730 | setText_InputWidget(url, urlStr); |
731 | checkLoadAnimation_Root_(get_Root()); | 731 | checkLoadAnimation_Root_(get_Root()); |
diff --git a/src/ui/sidebarwidget.c b/src/ui/sidebarwidget.c index c0a22e99..4c2a9d64 100644 --- a/src/ui/sidebarwidget.c +++ b/src/ui/sidebarwidget.c | |||
@@ -217,7 +217,7 @@ static void updateItems_SidebarWidget_(iSidebarWidget *d) { | |||
217 | iBool isEmpty = iFalse; /* show blank? */ | 217 | iBool isEmpty = iFalse; /* show blank? */ |
218 | switch (d->mode) { | 218 | switch (d->mode) { |
219 | case feeds_SidebarMode: { | 219 | case feeds_SidebarMode: { |
220 | const iString *docUrl = withSpacesEncoded_String(url_DocumentWidget(document_App())); | 220 | const iString *docUrl = canonicalUrl_String(url_DocumentWidget(document_App())); |
221 | /* TODO: internal URI normalization */ | 221 | /* TODO: internal URI normalization */ |
222 | iTime now; | 222 | iTime now; |
223 | iDate on; | 223 | iDate on; |
@@ -1111,7 +1111,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1111 | else if (isCommand_Widget(w, ev, "bookmark.copy")) { | 1111 | else if (isCommand_Widget(w, ev, "bookmark.copy")) { |
1112 | const iSidebarItem *item = d->contextItem; | 1112 | const iSidebarItem *item = d->contextItem; |
1113 | if (d->mode == bookmarks_SidebarMode && item) { | 1113 | if (d->mode == bookmarks_SidebarMode && item) { |
1114 | SDL_SetClipboardText(cstr_String(withSpacesEncoded_String(&item->url))); | 1114 | SDL_SetClipboardText(cstr_String(canonicalUrl_String(&item->url))); |
1115 | } | 1115 | } |
1116 | return iTrue; | 1116 | return iTrue; |
1117 | } | 1117 | } |
@@ -1374,7 +1374,7 @@ static iBool processEvent_SidebarWidget_(iSidebarWidget *d, const SDL_Event *ev) | |||
1374 | else if (isCommand_Widget(w, ev, "history.copy")) { | 1374 | else if (isCommand_Widget(w, ev, "history.copy")) { |
1375 | const iSidebarItem *item = d->contextItem; | 1375 | const iSidebarItem *item = d->contextItem; |
1376 | if (item && !isEmpty_String(&item->url)) { | 1376 | if (item && !isEmpty_String(&item->url)) { |
1377 | SDL_SetClipboardText(cstr_String(withSpacesEncoded_String(&item->url))); | 1377 | SDL_SetClipboardText(cstr_String(canonicalUrl_String(&item->url))); |
1378 | } | 1378 | } |
1379 | return iTrue; | 1379 | return iTrue; |
1380 | } | 1380 | } |
diff --git a/src/visited.c b/src/visited.c index f4769e97..94cff492 100644 --- a/src/visited.c +++ b/src/visited.c | |||
@@ -144,6 +144,7 @@ static size_t find_Visited_(const iVisited *d, const iString *url) { | |||
144 | 144 | ||
145 | void visitUrl_Visited(iVisited *d, const iString *url, uint16_t visitFlags) { | 145 | void visitUrl_Visited(iVisited *d, const iString *url, uint16_t visitFlags) { |
146 | if (isEmpty_String(url)) return; | 146 | if (isEmpty_String(url)) return; |
147 | url = canonicalUrl_String(url); | ||
147 | iVisitedUrl visit; | 148 | iVisitedUrl visit; |
148 | init_VisitedUrl(&visit); | 149 | init_VisitedUrl(&visit); |
149 | visit.flags = visitFlags; | 150 | visit.flags = visitFlags; |
@@ -165,6 +166,7 @@ void visitUrl_Visited(iVisited *d, const iString *url, uint16_t visitFlags) { | |||
165 | } | 166 | } |
166 | 167 | ||
167 | void removeUrl_Visited(iVisited *d, const iString *url) { | 168 | void removeUrl_Visited(iVisited *d, const iString *url) { |
169 | url = canonicalUrl_String(url); | ||
168 | iGuardMutex(d->mtx, { | 170 | iGuardMutex(d->mtx, { |
169 | size_t pos = find_Visited_(d, url); | 171 | size_t pos = find_Visited_(d, url); |
170 | if (pos < size_SortedArray(&d->visited)) { | 172 | if (pos < size_SortedArray(&d->visited)) { |