@@ -150,6 +150,7 @@ containsBadUrlChar = \s ->
150 if s == "" then False {}
150 if s == "" then False {}
151 else if take 1 s == "/" || take 1 s == "?" || take 1 s == "#" || take 1 s == " " || take 1 s == "@" || take 1 s == "%" || take 1 s == "\\"
151 else if take 1 s == "/" || take 1 s == "?" || take 1 s == "#" || take 1 s == " " || take 1 s == "@" || take 1 s == "%" || take 1 s == "\\"
152 || take 1 (bytesToHex (textToBytes (take 1 s))) == "0" || take 1 (bytesToHex (textToBytes (take 1 s))) == "1" || bytesToHex (textToBytes (take 1 s)) == "7f"
152 || take 1 (bytesToHex (textToBytes (take 1 s))) == "0" || take 1 (bytesToHex (textToBytes (take 1 s))) == "1" || bytesToHex (textToBytes (take 1 s)) == "7f"
153+ || not (drop 2 (bytesToHex (textToBytes (take 1 s))) == "")
153 then True {}
154 then True {}
154 else containsBadUrlChar (drop 1 s)
155 else containsBadUrlChar (drop 1 s)
@@ -207,12 +208,6 @@ hasHexPrefixAfterDot = \s ->
207 else if take 1 s == "." && (take 2 (drop 1 s) == "0x" || take 2 (drop 1 s) == "0X") then True {}
208 else if take 1 s == "." && (take 2 (drop 1 s) == "0x" || take 2 (drop 1 s) == "0X") then True {}
208 else hasHexPrefixAfterDot (drop 1 s)
209 else hasHexPrefixAfterDot (drop 1 s)
210−isAllDigitsUntilColonOrEnd = \s ->
211− if s == "" then True {}
212− else if take 1 s == ":" then True {}
213− else if isDigitChar (take 1 s) then isAllDigitsUntilColonOrEnd (drop 1 s)
216isAllDigitsOrDotsUntilColonOrEnd = \s ->
211isAllDigitsOrDotsUntilColonOrEnd = \s ->
217 if s == "" then True {}
212 if s == "" then True {}
218 else if take 1 s == ":" then True {}
213 else if take 1 s == ":" then True {}
@@ -247,7 +242,8 @@ stripTrailingDot = \s ->
247 else take 1 s ++ stripTrailingDot (drop 1 s)
242 else take 1 s ++ stripTrailingDot (drop 1 s)
249isReservedHighRange = \s ->
244isReservedHighRange = \s ->
245+ isAllDigitsOrDotsUntilColonOrEnd s
250− (take 2 s == "22" && (take 1 (drop 2 s) == "4" || take 1 (drop 2 s) == "5" || take 1 (drop 2 s) == "6" || take 1 (drop 2 s) == "7" || take 1 (drop 2 s) == "8" || take 1 (drop 2 s) == "9") && take 1 (drop 3 s) == ".")
246+ && ((take 2 s == "22" && (take 1 (drop 2 s) == "4" || take 1 (drop 2 s) == "5" || take 1 (drop 2 s) == "6" || take 1 (drop 2 s) == "7" || take 1 (drop 2 s) == "8" || take 1 (drop 2 s) == "9") && take 1 (drop 3 s) == ".")
251 || (take 2 s == "23" && isDigitChar (take 1 (drop 2 s)) && take 1 (drop 3 s) == ".")
247 || (take 2 s == "23" && isDigitChar (take 1 (drop 2 s)) && take 1 (drop 3 s) == ".")
252 || (take 2 s == "24" && isDigitChar (take 1 (drop 2 s)) && take 1 (drop 3 s) == ".")
248 || (take 2 s == "24" && isDigitChar (take 1 (drop 2 s)) && take 1 (drop 3 s) == ".")
253 || (take 3 s == "250" && take 1 (drop 3 s) == ".")
249 || (take 3 s == "250" && take 1 (drop 3 s) == ".")
@@ -255,13 +251,20 @@ isReservedHighRange = \s ->
255 || (take 3 s == "252" && take 1 (drop 3 s) == ".")
251 || (take 3 s == "252" && take 1 (drop 3 s) == ".")
256 || (take 3 s == "253" && take 1 (drop 3 s) == ".")
252 || (take 3 s == "253" && take 1 (drop 3 s) == ".")
257 || (take 3 s == "254" && take 1 (drop 3 s) == ".")
253 || (take 3 s == "254" && take 1 (drop 3 s) == ".")
258− || (take 3 s == "255" && take 1 (drop 3 s) == ".")
254+ || (take 3 s == "255" && take 1 (drop 3 s) == "."))
256+containsLocalhostSuffix = \s ->
257+ if s == "" then False {}
258+ else if take 10 s == ".localhost" && (drop 10 s == "" || take 1 (drop 10 s) == ":") then True {}
259+ else containsLocalhostSuffix (drop 1 s)
260isBadServerName = \s ->
261isBadServerName = \s ->
261 let sn = toLower (stripTrailingDot s)
262 let sn = toLower (stripTrailingDot s)
263 || containsBadUrlChar sn
264 || containsBadUrlChar sn
264 || sn == "localhost" || take 10 sn == "localhost:"
265 || sn == "localhost" || take 10 sn == "localhost:"
266+ || sn == "localhost.localdomain" || take 22 sn == "localhost.localdomain:"
267+ || containsLocalhostSuffix sn
265 || take 4 sn == "127." || take 3 sn == "10."
268 || take 4 sn == "127." || take 3 sn == "10."
266 || take 8 sn == "192.168." || take 7 sn == "169.254."
269 || take 8 sn == "192.168." || take 7 sn == "169.254."
267 || take 2 sn == "0." || take 1 sn == "["
270 || take 2 sn == "0." || take 1 sn == "["
@@ -635,7 +638,7 @@ serve = \req -> case req of
635 else "queued"
638 else "queued"
636 forwards <- *forwards
639 forwards <- *forwards
637 let forwardsAtCapacity = count forwards >= maxForwardsEntries
640 let forwardsAtCapacity = count forwards >= maxForwardsEntries
638− set *forwards = if shouldInsert && not forwardsAtCapacity
641+ set *forwards = if shouldInsert && not forwardsAtCapacity && not localOnline
639 then union forwards (do s <- remoteServers; yield {messageId: msgId, toServer: s, createdAt: t})
642 then union forwards (do s <- remoteServers; yield {messageId: msgId, toServer: s, createdAt: t})
640 else forwards
643 else forwards
641 yield {status: status, remoteServers: remoteServers, fromKey: fromKey, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, forwardsAtCapacity: forwardsAtCapacity}
644 yield {status: status, remoteServers: remoteServers, fromKey: fromKey, expiredLocal: pr.expiredLocal, peerServers: pr.peerServers, forwardsAtCapacity: forwardsAtCapacity}