summaryrefslogtreecommitdiff
path: root/src/gmutil.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/gmutil.c')
-rw-r--r--src/gmutil.c138
1 files changed, 95 insertions, 43 deletions
diff --git a/src/gmutil.c b/src/gmutil.c
index af090574..2008ea36 100644
--- a/src/gmutil.c
+++ b/src/gmutil.c
@@ -6,30 +6,36 @@
6 6
7void init_Url(iUrl *d, const iString *text) { 7void init_Url(iUrl *d, const iString *text) {
8 iRegExp *absPat = 8 iRegExp *absPat =
9 new_RegExp("(.+)://([^/:?]*)(:[0-9]+)?([^?]*)(\\?.*)?", caseInsensitive_RegExpOption); 9 new_RegExp("([a-z]+:)?(//[^/:?]*)(:[0-9]+)?([^?]*)(\\?.*)?", caseInsensitive_RegExpOption);
10 iRegExpMatch m; 10 iRegExpMatch m;
11 if (matchString_RegExp(absPat, text, &m)) { 11 if (matchString_RegExp(absPat, text, &m)) {
12 d->protocol = capturedRange_RegExpMatch(&m, 1); 12 d->protocol = capturedRange_RegExpMatch(&m, 1);
13 d->host = capturedRange_RegExpMatch(&m, 2); 13 d->host = capturedRange_RegExpMatch(&m, 2);
14 d->port = capturedRange_RegExpMatch(&m, 3); 14 if (!isEmpty_Range(&d->host)) {
15 d->host.start += 2; /* skip the double slash */
16 }
17 d->port = capturedRange_RegExpMatch(&m, 3);
15 if (!isEmpty_Range(&d->port)) { 18 if (!isEmpty_Range(&d->port)) {
16 /* Don't include the colon. */ 19 d->port.start++; /* omit the colon */
17 d->port.start++;
18 } 20 }
19 d->path = capturedRange_RegExpMatch(&m, 4); 21 d->path = capturedRange_RegExpMatch(&m, 4);
20 d->query = capturedRange_RegExpMatch(&m, 5); 22 d->query = capturedRange_RegExpMatch(&m, 5);
21 } 23 }
22 else { 24 else {
23 /* Must be a relative path. */ 25 /* Must be a relative path. */
24 iZap(*d); 26 iZap(*d);
25 iRegExp *relPat = new_RegExp("([^?]*)(\\?.*)?", 0); 27 iRegExp *relPat = new_RegExp("([a-z]+:)?([^?]*)(\\?.*)?", 0);
26 if (matchString_RegExp(relPat, text, &m)) { 28 if (matchString_RegExp(relPat, text, &m)) {
27 d->path = capturedRange_RegExpMatch(&m, 1); 29 d->protocol = capturedRange_RegExpMatch(&m, 1);
28 d->query = capturedRange_RegExpMatch(&m, 2); 30 d->path = capturedRange_RegExpMatch(&m, 2);
31 d->query = capturedRange_RegExpMatch(&m, 3);
29 } 32 }
30 iRelease(relPat); 33 iRelease(relPat);
31 } 34 }
32 iRelease(absPat); 35 iRelease(absPat);
36 if (!isEmpty_Range(&d->protocol)) {
37 d->protocol.end--; /* omit the colon */
38 }
33} 39}
34 40
35static iRangecc dirPath_(iRangecc path) { 41static iRangecc dirPath_(iRangecc path) {
@@ -38,51 +44,97 @@ static iRangecc dirPath_(iRangecc path) {
38 return (iRangecc){ path.start, path.start + pos }; 44 return (iRangecc){ path.start, path.start + pos };
39} 45}
40 46
47iLocalDef iBool isDef_(iRangecc cc) {
48 return !isEmpty_Range(&cc);
49}
50
51static iRangecc prevPathSeg_(const char *end, const char *start) {
52 iRangecc seg = { end, end };
53 do {
54 seg.start--;
55 } while (*seg.start != '/' && seg.start != start);
56 return seg;
57}
58
59void cleanUrlPath_String(iString *d) {
60 iString clean;
61 init_String(&clean);
62 iUrl parts;
63 init_Url(&parts, d);
64 iRangecc seg = iNullRange;
65 while (nextSplit_Rangecc(&parts.path, "/", &seg)) {
66 if (equal_Rangecc(&seg, "..")) {
67 /* Back up one segment. */
68 iRangecc last = prevPathSeg_(constEnd_String(&clean), constBegin_String(&clean));
69 truncate_Block(&clean.chars, last.start - constBegin_String(&clean));
70 }
71 else if (equal_Rangecc(&seg, ".")) {
72 /* Skip it. */
73 }
74 else {
75 appendCStr_String(&clean, "/");
76 appendRange_String(&clean, seg);
77 }
78 }
79 if (endsWith_Rangecc(&parts.path, "/")) {
80 appendCStr_String(&clean, "/");
81 }
82 /* Replace with the new path. */
83 if (cmpCStrNSc_Rangecc(&parts.path, cstr_String(&clean), size_String(&clean), &iCaseSensitive)) {
84 const size_t pos = parts.path.start - constBegin_String(d);
85 remove_Block(&d->chars, pos, size_Range(&parts.path));
86 insertData_Block(&d->chars, pos, cstr_String(&clean), size_String(&clean));
87 }
88 deinit_String(&clean);
89}
90
41const iString *absoluteUrl_String(const iString *d, const iString *urlMaybeRelative) { 91const iString *absoluteUrl_String(const iString *d, const iString *urlMaybeRelative) {
42 if (indexOfCStr_String(urlMaybeRelative, "://") != iInvalidPos) { 92 iUrl orig;
43 /* Already absolute. */ 93 iUrl rel;
94 init_Url(&orig, d);
95 init_Url(&rel, urlMaybeRelative);
96 if (equalCase_Rangecc(&rel.protocol, "data")) {
97 /* Special case, the contents should be left unparsed. */
44 return urlMaybeRelative; 98 return urlMaybeRelative;
45 } 99 }
46 iUrl parts; 100 const iBool isRelative = !isDef_(rel.host);
47 init_Url(&parts, d); 101 iRangecc protocol = range_CStr("gemini");
48 iString *absolute = new_String(); 102 if (isDef_(rel.protocol)) {
49 appendRange_String(absolute, parts.protocol); 103 protocol = rel.protocol;
50 appendCStr_String(absolute, "://"); 104 }
51 appendRange_String(absolute, parts.host); 105 else if (isRelative && isDef_(orig.protocol)) {
52 if (!isEmpty_Range(&parts.port)) { 106 protocol = orig.protocol;
53 appendCStr_String(absolute, ":");
54 appendRange_String(absolute, parts.port);
55 } 107 }
56 if (startsWith_String(urlMaybeRelative, "/")) { 108 iString *absolute = collectNew_String();
57 append_String(absolute, urlMaybeRelative); 109 appendRange_String(absolute, protocol);
110 appendCStr_String(absolute, "://"); {
111 const iUrl *selHost = isDef_(rel.host) ? &rel : &orig;
112 appendRange_String(absolute, selHost->host);
113 if (!isEmpty_Range(&selHost->port)) {
114 appendCStr_String(absolute, ":");
115 appendRange_String(absolute, selHost->port);
116 }
117 }
118 if (isDef_(rel.protocol) || isDef_(rel.host) || startsWith_Rangecc(&rel.path, "/")) {
119 appendRange_String(absolute, rel.path); /* absolute path */
58 } 120 }
59 else { 121 else {
60 iRangecc relPath = range_String(urlMaybeRelative); 122 if (!endsWith_Rangecc(&orig.path, "/")) {
61 iRangecc dir = dirPath_(parts.path); 123 /* Referencing a file. */
62 for (;;) { 124 appendRange_String(absolute, dirPath_(orig.path));
63 if (equal_Rangecc(&relPath, ".")) { 125 }
64 relPath.start++; 126 else {
65 } 127 /* Referencing a directory. */
66 else if (startsWith_Rangecc(&relPath, "./")) { 128 appendRange_String(absolute, orig.path);
67 relPath.start += 2;
68 }
69 else if (equal_Rangecc(&relPath, "..")) {
70 relPath.start += 2;
71 dir = dirPath_(dir);
72 }
73 else if (startsWith_Rangecc(&relPath, "../")) {
74 relPath.start += 3;
75 dir = dirPath_(dir);
76 }
77 else break;
78 } 129 }
79 appendRange_String(absolute, dir);
80 if (!endsWith_String(absolute, "/")) { 130 if (!endsWith_String(absolute, "/")) {
81 appendCStr_String(absolute, "/"); 131 appendCStr_String(absolute, "/");
82 } 132 }
83 appendRange_String(absolute, relPath); 133 appendRange_String(absolute, rel.path);
84 } 134 }
85 return collect_String(absolute); 135 appendRange_String(absolute, rel.query);
136 cleanUrlPath_String(absolute);
137 return absolute;
86} 138}
87 139
88void urlEncodeSpaces_String(iString *d) { 140void urlEncodeSpaces_String(iString *d) {