You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

107 lines
4.5KB

  1. <%
  2. '=======================================================================================================================
  3. ' Jurisdiction Number Validation
  4. '=======================================================================================================================
  5. ' Validates a submitted jurisdiction number against the JCode field of the jurisdictions
  6. ' list served by JurisdictionApiUrl (see public/web.config). That list is essentially static
  7. ' reference data (townships/municipalities), so it's cached in Application scope for
  8. ' JurisdictionCacheMinutes (default 60) instead of being fetched on every /request-order
  9. ' submission. If a refresh attempt fails, stale cached data is used rather than blocking
  10. ' order requests; only when there is no cached data at all (e.g. immediately after an app
  11. ' pool restart, with the API also unreachable) does validation fail open (allow) rather than
  12. ' block every order request site-wide.
  13. '
  14. ' The cache is stored as a single delimited STRING ("|code1|code2|...|"), not a
  15. ' Scripting.Dictionary or array of objects - Scripting.Dictionary is an apartment-threaded
  16. ' COM object, and IIS raises "ASP 0197: Disallowed object use" if you try to store one in
  17. ' the Application intrinsic (which is shared across all requests/threads). A plain string is
  18. ' just script data, so it's safe to cache this way.
  19. '=======================================================================================================================
  20. Function IsValidJurisdictionNumber(jurisdictionNumber)
  21. Dim codesText
  22. codesText = GetJurisdictionCodesText()
  23. jurisdictionNumber = Trim(jurisdictionNumber)
  24. If Len(codesText) = 0 Then
  25. ' No jurisdiction list available at all (first request after startup, API also
  26. ' down) - fail open rather than block every order request site-wide.
  27. IsValidJurisdictionNumber = True
  28. Else
  29. IsValidJurisdictionNumber = (InStr(codesText, "|" & jurisdictionNumber & "|") > 0)
  30. End If
  31. End Function
  32. ' Returns the cached "|code1|code2|...|" string, refreshing it from JurisdictionApiUrl when
  33. ' missing or older than JurisdictionCacheMinutes. Falls back to the existing (stale) cached
  34. ' string if a refresh attempt fails.
  35. Private Function GetJurisdictionCodesText()
  36. Dim cacheMinutes, cachedAt, isStale
  37. cacheMinutes = GetAppSetting("JurisdictionCacheMinutes")
  38. If Not IsNumeric(cacheMinutes) Then cacheMinutes = 60
  39. cachedAt = Application("JurisdictionCodesFetchedAt")
  40. isStale = IsEmpty(cachedAt)
  41. If Not isStale Then isStale = (DateDiff("n", cachedAt, Now()) >= CInt(cacheMinutes))
  42. If isStale Then
  43. Dim fresh
  44. fresh = FetchJurisdictionCodesText()
  45. If Len(fresh) > 0 Then
  46. Application.Lock
  47. Application("JurisdictionCodesText") = fresh
  48. Application("JurisdictionCodesFetchedAt") = Now()
  49. Application.Unlock
  50. End If
  51. End If
  52. GetJurisdictionCodesText = Application("JurisdictionCodesText")
  53. End Function
  54. ' Fetches the jurisdictions list and extracts every JCode value. Returns a
  55. ' "|code1|code2|...|" string, or "" on any failure (network, HTTP status, or no matches).
  56. '
  57. ' Uses a targeted regex over the raw response text rather than this codebase's generic
  58. ' aspJSON parser (core/lib.json.asp) - that parser walks the input character-by-character in
  59. ' plain VBScript, which measured at over 40 seconds for this API's ~450KB/1500-record
  60. ' response. RegExp.Execute is implemented natively and handles the same payload
  61. ' near-instantly; since JCode is the only field this validator needs, a full generic parse
  62. ' isn't necessary anyway.
  63. Private Function FetchJurisdictionCodesText()
  64. Dim apiUrl : apiUrl = GetAppSetting("JurisdictionApiUrl")
  65. Dim result : result = ""
  66. On Error Resume Next
  67. Dim http : Set http = Server.CreateObject("Msxml2.ServerXMLHTTP")
  68. http.setTimeouts 5000, 5000, 5000, 5000
  69. http.Open "GET", apiUrl, False
  70. http.Send ""
  71. If Err.Number = 0 And http.Status = 200 Then
  72. Dim re, matches, m, codes, code
  73. Set re = New RegExp
  74. re.Pattern = """JCode""\s*:\s*""([^""]*)"""
  75. re.Global = True
  76. re.IgnoreCase = True
  77. Set matches = re.Execute(http.responseText)
  78. If Err.Number = 0 And matches.Count > 0 Then
  79. codes = "|"
  80. For Each m In matches
  81. code = Trim(m.SubMatches(0))
  82. If Len(code) > 0 Then codes = codes & code & "|"
  83. Next
  84. If Len(codes) > 1 Then result = codes
  85. End If
  86. End If
  87. Err.Clear
  88. On Error GoTo 0
  89. FetchJurisdictionCodesText = result
  90. End Function
  91. %>

Powered by TurnKey Linux.