Class: Tina4::WSDL::Service

Inherits:
Object
  • Object
show all
Defined in:
lib/tina4/wsdl.rb

Overview

── Legacy wrapper ───────────────────────────────────────────────────Keeps backward compatibility with the old Tina4::WSDL::Service API used in demos and existing code.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name:, namespace: "http://tina4.com/wsdl") ⇒ Service

Returns a new instance of Service.



416
417
418
419
420
# File 'lib/tina4/wsdl.rb', line 416

def initialize(name:, namespace: "http://tina4.com/wsdl")
  @name       = name
  @namespace  = namespace
  @operations = {}
end

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



414
415
416
# File 'lib/tina4/wsdl.rb', line 414

def name
  @name
end

#namespaceObject (readonly)

Returns the value of attribute namespace.



414
415
416
# File 'lib/tina4/wsdl.rb', line 414

def namespace
  @namespace
end

#operationsObject (readonly)

Returns the value of attribute operations.



414
415
416
# File 'lib/tina4/wsdl.rb', line 414

def operations
  @operations
end

Instance Method Details

#add_operation(name, input_params: {}, output_params: {}, &handler) ⇒ Object



422
423
424
425
426
427
428
# File 'lib/tina4/wsdl.rb', line 422

def add_operation(name, input_params: {}, output_params: {}, &handler)
  @operations[name.to_s] = {
    input: input_params,
    output: output_params,
    handler: handler
  }
end

#generate_wsdl(endpoint_url) ⇒ Object



430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/tina4/wsdl.rb', line 430

def generate_wsdl(endpoint_url)
  xml = '<?xml version="1.0" encoding="UTF-8"?>'
  xml += "\n<definitions xmlns=\"http://schemas.xmlsoap.org/wsdl/\""
  xml += " xmlns:soap=\"http://schemas.xmlsoap.org/wsdl/soap/\""
  xml += " xmlns:tns=\"#{@namespace}\""
  xml += " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\""
  xml += " name=\"#{@name}\" targetNamespace=\"#{@namespace}\">\n"

  # Types
  xml += "  <types>\n    <xsd:schema targetNamespace=\"#{@namespace}\">\n"
  @operations.each do |op_name, op|
    xml += _generate_elements(op_name, op[:input], "Request")
    xml += _generate_elements(op_name, op[:output], "Response")
  end
  xml += "    </xsd:schema>\n  </types>\n"

  # Messages
  @operations.each_key do |op_name|
    xml += "  <message name=\"#{op_name}Request\">\n"
    xml += "    <part name=\"parameters\" element=\"tns:#{op_name}Request\"/>\n"
    xml += "  </message>\n"
    xml += "  <message name=\"#{op_name}Response\">\n"
    xml += "    <part name=\"parameters\" element=\"tns:#{op_name}Response\"/>\n"
    xml += "  </message>\n"
  end

  # PortType
  xml += "  <portType name=\"#{@name}PortType\">\n"
  @operations.each_key do |op_name|
    xml += "    <operation name=\"#{op_name}\">\n"
    xml += "      <input message=\"tns:#{op_name}Request\"/>\n"
    xml += "      <output message=\"tns:#{op_name}Response\"/>\n"
    xml += "    </operation>\n"
  end
  xml += "  </portType>\n"

  # Binding
  xml += "  <binding name=\"#{@name}Binding\" type=\"tns:#{@name}PortType\">\n"
  xml += "    <soap:binding style=\"document\" transport=\"http://schemas.xmlsoap.org/soap/http\"/>\n"
  @operations.each_key do |op_name|
    xml += "    <operation name=\"#{op_name}\">\n"
    xml += "      <soap:operation soapAction=\"#{@namespace}/#{op_name}\"/>\n"
    xml += "      <input><soap:body use=\"literal\"/></input>\n"
    xml += "      <output><soap:body use=\"literal\"/></output>\n"
    xml += "    </operation>\n"
  end
  xml += "  </binding>\n"

  # Service
  xml += "  <service name=\"#{@name}\">\n"
  xml += "    <port name=\"#{@name}Port\" binding=\"tns:#{@name}Binding\">\n"
  xml += "      <soap:address location=\"#{endpoint_url}\"/>\n"
  xml += "    </port>\n"
  xml += "  </service>\n"
  xml += "</definitions>"
  xml
end

#handle_soap_request(xml_body) ⇒ Object



488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
# File 'lib/tina4/wsdl.rb', line 488

def handle_soap_request(xml_body)
  # SOAP 1.1 (§3) forbids a DOCTYPE/DTD. Reject before parsing — this
  # closes the REXML internal-entity expansion (billion-laughs) and XXE
  # surface. Mirrors the class-based process_soap path.
  return _soap_fault("DOCTYPE declarations are not allowed in SOAP messages") if xml_body =~ /<!DOCTYPE/i

  doc = REXML::Document.new(xml_body)

  # Find Body element (namespace-agnostic)
  body_el = _find_child(doc.root, "Body")
  return _soap_fault("Unknown operation") unless body_el

  op_el = body_el.elements.first
  return _soap_fault("Unknown operation") unless op_el

  op_name = op_el.name
  return _soap_fault("Unknown operation") unless @operations.key?(op_name)

  operation = @operations[op_name]

  # Extract parameters
  params = {}
  operation[:input].each_key do |param_name|
    child = _find_child(op_el, param_name.to_s)
    params[param_name.to_s] = child.text if child
  end

  # Execute handler
  result = operation[:handler].call(params)

  # Build SOAP response
  _build_soap_response(op_name, result)
rescue StandardError => e
  # Mask the real cause in production (parity with process_soap) — a
  # handler exception can carry internal state that must not reach a
  # SOAP client. Detail is logged; only surfaced under TINA4_DEBUG.
  Tina4::Log.error("WSDL operation '#{op_name}' failed: #{e.message}")
  detail = Tina4::Env.is_truthy(ENV["TINA4_DEBUG"]) ? e.message : "Internal server error"
  _soap_fault(detail)
end