Lagrange [release]
GmRequest: Punycode for domain names
[1mdiff --git a/src/gmrequest.c b/src/gmrequest.c[m
[1mindex 884486b3..41b97620 100644[m
[1m--- a/src/gmrequest.c[m
[1m+++ b/src/gmrequest.c[m
[36m@@ -491,6 +491,9 @@[m [mvoid deinit_GmRequest(iGmRequest *d) {[m
[m
void setUrl_GmRequest(iGmRequest *d, const iString *url) {[m
set_String(&d->url, url);[m
[32m+[m[32m /* Encode hostname to Punycode here because we want to submit the Punycode domain name[m
[32m+[m[32m in the request. (TODO: Pending possible Gemini spec change.) */[m
[32m+[m[32m punyEncodeUrlHost_String(&d->url);[m
urlEncodeSpaces_String(&d->url);[m
}[m
[m
[36m@@ -646,7 +649,7 @@[m [mvoid submit_GmRequest(iGmRequest *d) {[m
if (port == 0) {[m
port = 1965; /* default Gemini port */[m
}[m
[31m- setUrl_TlsRequest(d->req, host, port);[m
[32m+[m[32m setHost_TlsRequest(d->req, host, port);[m
setContent_TlsRequest(d->req,[m
utf8_String(collectNewFormat_String("%s\r\n", cstr_String(&d->url))));[m
submit_TlsRequest(d->req);[m
[1mdiff --git a/src/gmutil.c b/src/gmutil.c[m
[1mindex 477d0f17..67b0d939 100644[m
[1m--- a/src/gmutil.c[m
[1m+++ b/src/gmutil.c[m
[36m@@ -185,10 +185,51 @@[m [mconst iString *absoluteUrl_String(const iString *d, const iString *urlMaybeRelat[m
appendRange_String(absolute, orig.path);[m
}[m
appendRange_String(absolute, rel.query);[m
[32m+[m[32m normalize_String(absolute);[m
cleanUrlPath_String(absolute);[m
return absolute;[m
}[m
[m
[32m+[m[32mstatic iBool equalPuny_(const iString *d, iRangecc orig) {[m
[32m+[m[32m if (!endsWith_String(d, "-")) {[m
[32m+[m[32m return iFalse; /* This is a sufficient condition? */[m
[32m+[m[32m }[m
[32m+[m[32m if (size_String(d) != size_Range(&orig) + 1) {[m
[32m+[m[32m return iFalse;[m
[32m+[m[32m }[m
[32m+[m[32m return iCmpStrN(cstr_String(d), orig.start, size_Range(&orig)) == 0;[m
[32m+[m[32m}[m
[32m+[m
[32m+[m[32mvoid punyEncodeUrlHost_String(iString *d) {[m
[32m+[m[32m /* `d` should be an absolute URL. */[m
[32m+[m[32m iUrl url;[m
[32m+[m[32m init_Url(&url, d);[m
[32m+[m[32m iString *encoded = new_String();[m
[32m+[m[32m setRange_String(encoded, (iRangecc){ url.scheme.start, url.host.start });[m
[32m+[m[32m /* The domain name needs to be split into segments. */ {[m
[32m+[m[32m iRangecc seg = iNullRange;[m
[32m+[m[32m iBool isFirst = iTrue;[m
[32m+[m[32m while (nextSplit_Rangecc(url.host, ".", &seg)) {[m
[32m+[m[32m if (!isFirst) {[m
[32m+[m[32m appendChar_String(encoded, '.');[m
[32m+[m[32m }[m
[32m+[m[32m isFirst = iFalse;[m
[32m+[m[32m iString *puny = punyEncode_Rangecc(seg);[m
[32m+[m[32m if (!isEmpty_String(puny) && !equalPuny_(puny, seg)) {[m
[32m+[m[32m appendCStr_String(encoded, "xn--");[m
[32m+[m[32m append_String(encoded, puny);[m
[32m+[m[32m }[m
[32m+[m[32m else {[m
[32m+[m[32m appendRange_String(encoded, seg);[m
[32m+[m[32m }[m
[32m+[m[32m delete_String(puny);[m
[32m+[m[32m }[m
[32m+[m[32m }[m
[32m+[m[32m appendRange_String(encoded, (iRangecc){ url.host.end, constEnd_String(d) });[m
[32m+[m[32m set_String(d, encoded);[m
[32m+[m[32m delete_String(encoded);[m
[32m+[m[32m}[m
[32m+[m
iString *makeFileUrl_String(const iString *localFilePath) {[m
iString *url = cleaned_Path(localFilePath);[m
replace_Block(&url->chars, '\\', '/'); /* in case it's a Windows path */[m
[1mdiff --git a/src/gmutil.h b/src/gmutil.h[m
[1mindex 926f5a10..bbadbafd 100644[m
[1m--- a/src/gmutil.h[m
[1m+++ b/src/gmutil.h[m
[36m@@ -103,6 +103,7 @@[m [mvoid init_Url (iUrl *, const iString *text);[m
iRangecc urlScheme_String (const iString *);[m
iRangecc urlHost_String (const iString *);[m
const iString * absoluteUrl_String (const iString *, const iString *urlMaybeRelative);[m
[32m+[m[32mvoid punyEncodeUrlHost_String(iString *);[m
iString * makeFileUrl_String (const iString *localFilePath);[m
const char * makeFileUrl_CStr (const char *localFilePath);[m
void urlEncodeSpaces_String (iString *);[m