|
- <?xml version="1.0"?>
- <!-- RouterComponent.wsc -->
- <component>
-
- <!-- COM registration -->
- <registration
- description = "Classic ASP Router Component"
- progid = "App.Router"
- version = "1.0"
- classid = "{A1FC6EA8-519E-4E34-AC08-77788E3E5E44}" />
-
- <!-- Public interface -->
- <public>
- <method name="AddRoute"/>
- <method name="Resolve"/>
- </public>
- <!-- Give the component ASP intrinsic objects (Request, Response, Server …) -->
- <implements type="ASP"/>
- <!-- Implementation -->
- <script language="VBScript">
- <![CDATA[
- Option Explicit
-
- '------------------------------------------------------------
- ' Private state
- '------------------------------------------------------------
- Dim routes : Set routes = CreateObject("Scripting.Dictionary")
-
- '------------------------------------------------------------
- ' METHOD AddRoute(method, path, controller, action)
- '------------------------------------------------------------
- Public Sub AddRoute(method, path, controller, action)
- ' Input validation
- If IsEmpty(method) Or Len(Trim(method)) = 0 Then
- Err.Raise 5, "Router.AddRoute", "HTTP method parameter is required and cannot be empty"
- End If
-
- If IsEmpty(path) Then
- Err.Raise 5, "Router.AddRoute", "Path parameter is required"
- End If
-
- If IsEmpty(controller) Or Len(Trim(controller)) = 0 Then
- Err.Raise 5, "Router.AddRoute", "Controller parameter is required and cannot be empty"
- End If
-
- If IsEmpty(action) Or Len(Trim(action)) = 0 Then
- Err.Raise 5, "Router.AddRoute", "Action parameter is required and cannot be empty"
- End If
-
- ' Validate HTTP method (allow common methods)
- Dim validMethods, methodUpper, i, isValidMethod
- validMethods = Array("GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS")
- methodUpper = UCase(Trim(method))
- isValidMethod = False
-
- For i = 0 To UBound(validMethods)
- If validMethods(i) = methodUpper Then
- isValidMethod = True
- Exit For
- End If
- Next
-
- If Not isValidMethod Then
- Err.Raise 5, "Router.AddRoute", "Invalid HTTP method: " & method & ". Allowed: GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS"
- End If
-
- Dim routeKey
- routeKey = methodUpper & ":" & LCase(Trim(path))
-
- If Not routes.Exists(routeKey) Then
- routes.Add routeKey, Array(Trim(controller), Trim(action))
- End If
- End Sub
-
- '------------------------------------------------------------
- ' METHOD Resolve(method, path) -> Array(controller, action, params())
- '------------------------------------------------------------
- Public Function Resolve(method, path)
- Dim routeKey, routeValue, values
- routeKey = UCase(method) & ":" & LCase(path)
-
- ' Always return a params array (empty by default)
- Dim emptyParams() : ReDim emptyParams(-1)
-
- ' Exact match first
- If routes.Exists(routeKey) Then
- routeValue = routes(routeKey)
- Resolve = Array(routeValue(0), routeValue(1), emptyParams)
- Exit Function
- End If
-
- ' Dynamic routes (e.g. /users/:id)
- Dim r, routeMethod, routePattern
- For Each r In routes.Keys
- routeMethod = Split(r, ":")(0)
- routePattern = Mid(r, Len(routeMethod) + 2) ' strip "METHOD:"
- If UCase(routeMethod) = UCase(method) Then
- If IsMatch(path, routePattern, values) Then
- routeValue = routes(r)
- Resolve = Array(routeValue(0), routeValue(1), values)
- Exit Function
- End If
- End If
- Next
-
- ' 404 fallback
- Resolve = Array("ErrorController", "NotFound", emptyParams)
- End Function
-
- '------------------------------------------------------------
- ' INTERNAL IsMatch(requestPath, routePattern, values())
- ' Returns True/False and fills values() with parameters
- '------------------------------------------------------------
- Private Function IsMatch(requestPath, routePattern, values)
- Dim reqParts, routeParts, i, paramCount
- reqParts = Split(requestPath, "/")
- routeParts = Split(routePattern, "/")
-
- If UBound(reqParts) <> UBound(routeParts) Then
- IsMatch = False : Exit Function
- End If
-
- paramCount = 0 : ReDim values(-1)
-
- For i = 0 To UBound(reqParts)
- If Left(routeParts(i), 1) = ":" Then
- ReDim Preserve values(paramCount)
- values(paramCount) = reqParts(i)
- paramCount = paramCount + 1
- ElseIf LCase(routeParts(i)) <> LCase(reqParts(i)) Then
- IsMatch = False : Exit Function
- End If
- Next
-
- If paramCount = 0 Then ReDim values(-1)
- IsMatch = True
- End Function
-
- '------------------------------------------------------------
- ' Optional lifecycle hooks
- '------------------------------------------------------------
- Private Sub Class_Terminate()
- Set routes = Nothing
- End Sub
- ]]>
- </script>
- </component>
|