Class: A2A::Server::Middleware::CorsMiddleware

Inherits:
Object
  • Object
show all
Defined in:
lib/a2a/server/middleware/cors_middleware.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(origins: "*", methods: %w[POST OPTIONS],, headers: %w[Content-Type Authorization],, credentials: false, max_age: 86_400, expose_headers: []) ⇒ CorsMiddleware

Initialize CORS middleware

Parameters:

  • (defaults to: "*")

    Allowed origins (* for all)

  • (defaults to: %w[POST OPTIONS],)

    Allowed HTTP methods

  • (defaults to: %w[Content-Type Authorization],)

    Allowed headers

  • (defaults to: false)

    Whether to allow credentials

  • (defaults to: 86_400)

    Preflight cache duration in seconds

  • (defaults to: [])

    Headers to expose to client



31
32
33
34
35
36
37
38
39
40
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 31

def initialize(origins: "*", methods: %w[POST OPTIONS],
               headers: %w[Content-Type Authorization],
               credentials: false, max_age: 86_400, expose_headers: [])
  @origins = normalize_origins(origins)
  @methods = Array(methods).map(&:upcase)
  @headers = Array(headers)
  @credentials = credentials
  @max_age = max_age
  @expose_headers = Array(expose_headers)
end

Instance Attribute Details

#credentialsObject (readonly)

Returns the value of attribute credentials.



20
21
22
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 20

def credentials
  @credentials
end

#headersObject (readonly)

Returns the value of attribute headers.



20
21
22
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 20

def headers
  @headers
end

#max_ageObject (readonly)

Returns the value of attribute max_age.



20
21
22
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 20

def max_age
  @max_age
end

#methodsObject (readonly)

Returns the value of attribute methods.



20
21
22
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 20

def methods
  @methods
end

#originsObject (readonly)

Returns the value of attribute origins.



20
21
22
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 20

def origins
  @origins
end

Instance Method Details

#add_cors_headers(origin, context) ⇒ Object (private)

Add CORS headers to response context

Parameters:

  • The request origin

  • The request context



163
164
165
166
167
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 163

def add_cors_headers(origin, context)
  cors_headers(origin).each do |key, value|
    context.("response_header_#{key.downcase}", value)
  end
end

#call(_request, context) { ... } ⇒ Object

Process CORS for a request

Parameters:

  • The JSON-RPC request

  • The request context

Yields:

  • Block to continue the middleware chain

Returns:

  • The result from the next middleware or handler



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 49

def call(_request, context)
  # Extract HTTP method and origin from context
  http_method = context.(:http_method) || "POST"
  origin = context.(:origin) || context.("Origin")

  # Handle preflight requests
  return handle_preflight(origin, context) if http_method.casecmp("OPTIONS").zero?

  # Add CORS headers to the response
  add_cors_headers(origin, context)

  # Continue to next middleware
  yield
end

#cors_headers(origin) ⇒ Hash

Get CORS headers for an origin

Parameters:

  • The request origin

Returns:

  • CORS headers



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 89

def cors_headers(origin)
  headers = {}

  if origin_allowed?(origin)
    headers["Access-Control-Allow-Origin"] = @origins == "*" ? "*" : origin

    headers["Access-Control-Allow-Credentials"] = "true" if @credentials

    headers["Access-Control-Expose-Headers"] = @expose_headers.join(", ") unless @expose_headers.empty?
  end

  headers
end

#handle_preflight(origin, context) ⇒ Hash (private)

Handle preflight OPTIONS request

Parameters:

  • The request origin

  • The request context

Returns:

  • Preflight response



144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 144

def handle_preflight(origin, context)
  # Add preflight headers to context for response
  preflight_headers(origin).each do |key, value|
    context.("response_header_#{key.downcase}", value)
  end

  # Return empty response for preflight
  {
    status: 200,
    headers: preflight_headers(origin),
    body: ""
  }
end

#normalize_origins(origins) ⇒ Array<String>, String (private)

Normalize origins configuration

Parameters:

  • Origins configuration

Returns:

  • Normalized origins



127
128
129
130
131
132
133
134
135
136
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 127

def normalize_origins(origins)
  case origins
  when String
    origins == "*" ? "*" : [origins]
  when Array
    origins.include?("*") ? "*" : origins
  else
    ["*"]
  end
end

#origin_allowed?(origin) ⇒ Boolean

Check if an origin is allowed

Parameters:

  • The origin to check

Returns:

  • True if origin is allowed



69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 69

def origin_allowed?(origin)
  return true if @origins == "*"
  return false if origin.nil?

  @origins.any? do |allowed_origin|
    if allowed_origin.include?("*")
      # Handle wildcard patterns
      pattern = Regexp.escape(allowed_origin).gsub('\*', ".*")
      origin.match?(/\A#{pattern}\z/)
    else
      origin == allowed_origin
    end
  end
end

#preflight_headers(origin) ⇒ Hash

Get preflight CORS headers

Parameters:

  • The request origin

Returns:

  • Preflight CORS headers



108
109
110
111
112
113
114
115
116
117
118
# File 'lib/a2a/server/middleware/cors_middleware.rb', line 108

def preflight_headers(origin)
  headers = cors_headers(origin)

  if origin_allowed?(origin)
    headers["Access-Control-Allow-Methods"] = @methods.join(", ")
    headers["Access-Control-Allow-Headers"] = @headers.join(", ")
    headers["Access-Control-Max-Age"] = @max_age.to_s
  end

  headers
end