Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

280 lignes
8.4KB

  1. <?xml version="1.0"?>
  2. <?component error="true" debug="false"?>
  3. <component>
  4. <registration
  5. description="WscMvc Application bootstrap"
  6. progid="WscMvc.Application"
  7. version="1.00"
  8. classid="{851C7763-1638-42FE-A166-BF3DD3A96A88}">
  9. </registration>
  10. <public>
  11. <method name="Run">
  12. <parameter name="ctx"/>
  13. <parameter name="applicationName"/>
  14. <parameter name="statusLine"/>
  15. <parameter name="contentType"/>
  16. <parameter name="body"/>
  17. <parameter name="allowHeader"/>
  18. </method>
  19. </public>
  20. <script language="VBScript">
  21. <![CDATA[
  22. Option Explicit
  23. ' Central request boundary: one place decides expected (404) vs unexpected
  24. ' (COM/method failure -> 500) outcomes, and one place logs them. ctx is our
  25. ' own WscMvc.RequestContext object (not an ASP intrinsic), carrying only
  26. ' primitive request data. No ASP intrinsics are referenced here.
  27. Sub Run(ctx, applicationName, statusLine, contentType, body, allowHeader)
  28. Dim router, handlerKey
  29. statusLine = ""
  30. contentType = ""
  31. body = ""
  32. allowHeader = ""
  33. handlerKey = ""
  34. Set router = Nothing
  35. On Error Resume Next
  36. Set router = CreateObject("WscMvc.Router")
  37. If Err.Number <> 0 Then
  38. Err.Clear
  39. On Error Goto 0
  40. InternalServerError statusLine, contentType, body, allowHeader
  41. LogOutcome ctx, statusLine
  42. Exit Sub
  43. End If
  44. On Error Goto 0
  45. On Error Resume Next
  46. router.Match ctx, applicationName, statusLine, contentType, body, allowHeader, handlerKey
  47. If Err.Number <> 0 Then
  48. Err.Clear
  49. On Error Goto 0
  50. Set router = Nothing
  51. InternalServerError statusLine, contentType, body, allowHeader
  52. LogOutcome ctx, statusLine
  53. Exit Sub
  54. End If
  55. On Error Goto 0
  56. Set router = Nothing
  57. If Len(handlerKey) = 0 Then
  58. LogOutcome ctx, statusLine
  59. Exit Sub
  60. End If
  61. Select Case handlerKey
  62. Case "Home.Hello"
  63. RunHomeHello ctx, statusLine, contentType, body, allowHeader
  64. Case "SelfTest.RunSelfTest"
  65. RunSelfTest ctx, statusLine, contentType, body, allowHeader
  66. Case Else
  67. InternalServerError statusLine, contentType, body, allowHeader
  68. End Select
  69. LogOutcome ctx, statusLine
  70. End Sub
  71. Sub RunHomeHello(ctx, statusLine, contentType, body, allowHeader)
  72. Dim ctrl, helloBody
  73. Set ctrl = Nothing
  74. On Error Resume Next
  75. Set ctrl = CreateObject("WscMvc.HomeController")
  76. If Err.Number <> 0 Then
  77. Err.Clear
  78. On Error Goto 0
  79. InternalServerError statusLine, contentType, body, allowHeader
  80. Exit Sub
  81. End If
  82. On Error Goto 0
  83. helloBody = ""
  84. On Error Resume Next
  85. ctrl.Hello helloBody
  86. If Err.Number <> 0 Then
  87. Err.Clear
  88. On Error Goto 0
  89. Set ctrl = Nothing
  90. InternalServerError statusLine, contentType, body, allowHeader
  91. Exit Sub
  92. End If
  93. On Error Goto 0
  94. statusLine = "200 OK"
  95. contentType = "text/html; charset=utf-8"
  96. body = helloBody
  97. allowHeader = ""
  98. Set ctrl = Nothing
  99. End Sub
  100. Sub RunSelfTest(ctx, statusLine, contentType, body, allowHeader)
  101. Dim ctrl, selfTestBody
  102. Set ctrl = Nothing
  103. On Error Resume Next
  104. Set ctrl = CreateObject("WscMvc.SelfTestController")
  105. If Err.Number <> 0 Then
  106. Err.Clear
  107. On Error Goto 0
  108. InternalServerError statusLine, contentType, body, allowHeader
  109. Exit Sub
  110. End If
  111. On Error Goto 0
  112. selfTestBody = ""
  113. On Error Resume Next
  114. ctrl.RunSelfTest ctx.LogDir, selfTestBody
  115. If Err.Number <> 0 Then
  116. Err.Clear
  117. On Error Goto 0
  118. Set ctrl = Nothing
  119. InternalServerError statusLine, contentType, body, allowHeader
  120. Exit Sub
  121. End If
  122. On Error Goto 0
  123. ' Always 200: the self-test HTTP call itself succeeded. Whether the
  124. ' underlying checks passed is reported in the JSON body's "ok" field
  125. ' and per-check "pass" fields, not the HTTP status - this matches
  126. ' conventional health-check endpoint design (5xx is reserved for the
  127. ' diagnostics mechanism itself being broken, handled above).
  128. statusLine = "200 OK"
  129. contentType = "application/json; charset=utf-8"
  130. body = selfTestBody
  131. allowHeader = ""
  132. Set ctrl = Nothing
  133. End Sub
  134. Sub InternalServerError(statusLine, contentType, body, allowHeader)
  135. statusLine = "500 Internal Server Error"
  136. contentType = "text/plain; charset=utf-8"
  137. body = "Internal Server Error"
  138. allowHeader = ""
  139. End Sub
  140. ' Best-effort diagnostics only: a logging failure must never affect the
  141. ' response. Every filesystem step is individually guarded so one bad
  142. ' operation (e.g. concurrent-write contention) just skips this line rather
  143. ' than raising to the caller.
  144. Sub LogOutcome(ctx, statusLine)
  145. Dim fso, logFile, logPath, lockPath, line
  146. Set fso = Nothing
  147. On Error Resume Next
  148. Set fso = CreateObject("Scripting.FileSystemObject")
  149. If Err.Number <> 0 Then
  150. Err.Clear
  151. On Error Goto 0
  152. Exit Sub
  153. End If
  154. On Error Goto 0
  155. On Error Resume Next
  156. If Not fso.FolderExists(ctx.LogDir) Then
  157. fso.CreateFolder ctx.LogDir
  158. End If
  159. If Err.Number <> 0 Then
  160. Err.Clear
  161. On Error Goto 0
  162. Set fso = Nothing
  163. Exit Sub
  164. End If
  165. On Error Goto 0
  166. logPath = ctx.LogDir & "\app.log"
  167. lockPath = ctx.LogDir & "\app.log.lock"
  168. ' Concurrent requests race for this one shared file. Verified experimentally
  169. ' that FileSystemObject.OpenTextFile(ForAppending) mostly SUCCEEDS for every
  170. ' concurrent caller (it is not exclusive) but their writes overwrite each
  171. ' other - a lost-update race, not an open failure - so retrying the open
  172. ' alone did not help. No ASP intrinsic (Application.Lock/UnLock) is available
  173. ' here by contract, so a manual lock-file mutex is used instead:
  174. ' CreateTextFile(path, OverwriteExisting:=False) atomically fails with
  175. ' Err.Number=58 "File already exists" when another request holds the lock -
  176. ' confirmed correct/exclusive experimentally, not assumed.
  177. '
  178. ' The retry budget below is deliberately short. Measured under 8 genuinely
  179. ' concurrent requests: the mutex itself is correct, but making every request
  180. ' reliably win eventually needs a retry budget of 300+ attempts (~300-360ms
  181. ' of blocking) - too much added latency for a best-effort diagnostic write.
  182. ' With this short budget, heavy concurrent bursts will legitimately drop
  183. ' some log lines rather than delay the response; this is an accepted
  184. ' tradeoff for "best-effort diagnostics" (see docs/DECISIONS.md), not a
  185. ' correctness bug - the HTTP response itself is unaffected either way.
  186. ' Revisit with a real logging mechanism (e.g. per-request files aggregated
  187. ' out of band) in M6 if complete log coverage under load becomes a
  188. ' requirement.
  189. If Not AcquireLogLock(fso, lockPath) Then
  190. Set fso = Nothing
  191. Exit Sub
  192. End If
  193. Set logFile = Nothing
  194. On Error Resume Next
  195. Set logFile = fso.OpenTextFile(logPath, 8, True) ' 8 = ForAppending, create if missing
  196. If Err.Number <> 0 Then
  197. Err.Clear
  198. On Error Goto 0
  199. ReleaseLogLock fso, lockPath
  200. Set fso = Nothing
  201. Exit Sub
  202. End If
  203. On Error Goto 0
  204. line = Now & " | " & ctx.CorrelationId & " | " & ctx.HttpMethod & _
  205. " | " & ctx.Path & " | " & statusLine & " | " & ctx.ElapsedMs() & "ms"
  206. On Error Resume Next
  207. logFile.WriteLine line
  208. Err.Clear
  209. On Error Goto 0
  210. On Error Resume Next
  211. logFile.Close
  212. Err.Clear
  213. On Error Goto 0
  214. Set logFile = Nothing
  215. ReleaseLogLock fso, lockPath
  216. Set fso = Nothing
  217. End Sub
  218. Function AcquireLogLock(fso, lockPath)
  219. Dim attempt, maxAttempts, lockFile, busy, spinCount
  220. maxAttempts = 10
  221. spinCount = 8000
  222. AcquireLogLock = False
  223. For attempt = 1 To maxAttempts
  224. Set lockFile = Nothing
  225. On Error Resume Next
  226. Set lockFile = fso.CreateTextFile(lockPath, False) ' fails if lockPath already exists
  227. If Err.Number = 0 Then
  228. On Error Goto 0
  229. lockFile.Close
  230. Set lockFile = Nothing
  231. AcquireLogLock = True
  232. Exit For
  233. End If
  234. Err.Clear
  235. On Error Goto 0
  236. For busy = 1 To spinCount : Next
  237. Next
  238. End Function
  239. Sub ReleaseLogLock(fso, lockPath)
  240. On Error Resume Next
  241. fso.DeleteFile lockPath, True
  242. Err.Clear
  243. On Error Goto 0
  244. End Sub
  245. ]]>
  246. </script>
  247. </component>

Powered by TurnKey Linux.