Class: Nondisposable::TldListUpdater

Inherits:
Object
  • Object
show all
Defined in:
lib/nondisposable/tld_list_updater.rb

Overview

Refreshes the vendored IANA TLD snapshot from the root zone database.

⚠️ This is a MAINTENANCE task, not a runtime one — the deliberate opposite of DomainListUpdater. That one runs in your app, on a schedule, because disposable domains change every few days and live in your database. This one rewrites a file inside the gem, which is read-only once the gem is installed. Run it in a checkout of the gem before cutting a release:

rake nondisposable:tlds:update

If you need a TLD that is newer than your installed gem, do NOT reach for this. Add it to config.additional_tlds and you are unblocked immediately, with no release and no writable-gem-directory problem:

config.additional_tlds = %w[newtld]

New TLDs are delegated in batches a few times a year, so a snapshot ages slowly. ICANN's next application round is the first real test of that.

Constant Summary collapse

LIST_URL =
'https://data.iana.org/TLD/tlds-alpha-by-domain.txt'
OPEN_TIMEOUT =
10
READ_TIMEOUT =
10
MINIMUM_PLAUSIBLE_TLD_COUNT =

A root zone that suddenly contains a handful of entries means the fetch went wrong (a captive portal, an error page, a truncated body), not that ICANN deleted the internet. Refuse to overwrite a good list with junk.

1_000

Class Method Summary collapse

Class Method Details

.update(path: Nondisposable::Tld::LIST_PATH) ⇒ Object

Returns the number of TLDs written, or nil if nothing was written.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/nondisposable/tld_list_updater.rb', line 38

def update(path: Nondisposable::Tld::LIST_PATH)
  log :info, "Fetching the IANA root zone TLD list from #{LIST_URL}..."

  response = fetch
  unless response.is_a?(Net::HTTPSuccess)
    log :error, "Failed to download the TLD list. HTTP status: #{response.code}. Keeping the existing snapshot."
    return nil
  end

  body = response.body.to_s
  count = body.lines.count { |line| meaningful?(line) }

  if count < MINIMUM_PLAUSIBLE_TLD_COUNT
    log :error, "Refusing to write a TLD list with only #{count} entries (expected at least #{MINIMUM_PLAUSIBLE_TLD_COUNT}). Keeping the existing snapshot."
    return nil
  end

  # Written whole, then moved into place, so an interrupted run can never
  # leave a half-written root zone behind.
  tmp = "#{path}.tmp"
  File.write(tmp, body)
  File.rename(tmp, path)
  Nondisposable::Tld.reload!

  log :info, "Wrote #{count} TLDs to #{path} (#{Nondisposable::Tld.version})."
  count
rescue StandardError => e
  log :error, "Could not update the TLD list: #{e.class}: #{e.message}. Keeping the existing snapshot."
  nil
ensure
  File.delete(tmp) if tmp && File.exist?(tmp)
end