siffer 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/LICENSE +20 -0
- data/README.rdoc +65 -0
- data/Rakefile +64 -0
- data/bin/siffer +71 -0
- data/doc/SIF ImplementationSpecification.pdf +0 -0
- data/doc/rdoc/classes/Siffer.html +374 -0
- data/doc/rdoc/classes/Siffer/Agent.html +296 -0
- data/doc/rdoc/classes/Siffer/Container.html +286 -0
- data/doc/rdoc/classes/Siffer/Messages.html +141 -0
- data/doc/rdoc/classes/Siffer/Messages/Ack.html +216 -0
- data/doc/rdoc/classes/Siffer/Messages/Acl.html +160 -0
- data/doc/rdoc/classes/Siffer/Messages/Error.html +248 -0
- data/doc/rdoc/classes/Siffer/Messages/Message.html +359 -0
- data/doc/rdoc/classes/Siffer/Messages/Message/Header.html +181 -0
- data/doc/rdoc/classes/Siffer/Messages/Register.html +257 -0
- data/doc/rdoc/classes/Siffer/Messages/RequestBody.html +300 -0
- data/doc/rdoc/classes/Siffer/Messages/Status.html +269 -0
- data/doc/rdoc/classes/Siffer/Messaging.html +331 -0
- data/doc/rdoc/classes/Siffer/Protocol.html +388 -0
- data/doc/rdoc/classes/Siffer/Protocol/NonPostRequest.html +111 -0
- data/doc/rdoc/classes/Siffer/Protocol/UnknownPath.html +111 -0
- data/doc/rdoc/classes/Siffer/Registration.html +391 -0
- data/doc/rdoc/classes/Siffer/Request.html +209 -0
- data/doc/rdoc/classes/Siffer/RequestLogger.html +211 -0
- data/doc/rdoc/classes/Siffer/Response.html +182 -0
- data/doc/rdoc/classes/Siffer/Server.html +242 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/LICENSE.html +129 -0
- data/doc/rdoc/files/README_rdoc.html +184 -0
- data/doc/rdoc/files/lib/agent_rb.html +101 -0
- data/doc/rdoc/files/lib/container_rb.html +108 -0
- data/doc/rdoc/files/lib/messages/ack_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/acl_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/error_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/message_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/register_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/request_body_rb.html +101 -0
- data/doc/rdoc/files/lib/messages/status_rb.html +101 -0
- data/doc/rdoc/files/lib/messages_rb.html +114 -0
- data/doc/rdoc/files/lib/messaging_rb.html +101 -0
- data/doc/rdoc/files/lib/protocol_rb.html +101 -0
- data/doc/rdoc/files/lib/registration_rb.html +101 -0
- data/doc/rdoc/files/lib/request_logger_rb.html +101 -0
- data/doc/rdoc/files/lib/request_rb.html +101 -0
- data/doc/rdoc/files/lib/response_rb.html +101 -0
- data/doc/rdoc/files/lib/server_rb.html +101 -0
- data/doc/rdoc/files/lib/siffer_rb.html +115 -0
- data/doc/rdoc/fr_class_index.html +47 -0
- data/doc/rdoc/fr_file_index.html +46 -0
- data/doc/rdoc/fr_method_index.html +96 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/lib/agent.rb +43 -0
- data/lib/container.rb +96 -0
- data/lib/messages.rb +7 -0
- data/lib/messages/ack.rb +43 -0
- data/lib/messages/acl.rb +25 -0
- data/lib/messages/error.rb +174 -0
- data/lib/messages/message.rb +71 -0
- data/lib/messages/register.rb +60 -0
- data/lib/messages/request_body.rb +66 -0
- data/lib/messages/status.rb +55 -0
- data/lib/messaging.rb +96 -0
- data/lib/protocol.rb +159 -0
- data/lib/registration.rb +87 -0
- data/lib/request.rb +25 -0
- data/lib/request_logger.rb +31 -0
- data/lib/response.rb +26 -0
- data/lib/server.rb +40 -0
- data/lib/siffer.rb +44 -0
- data/spec/agent_spec.rb +53 -0
- data/spec/cli_spec.rb +40 -0
- data/spec/container_spec.rb +103 -0
- data/spec/default_agent +6 -0
- data/spec/default_server +5 -0
- data/spec/message_specs/ack_spec.rb +28 -0
- data/spec/message_specs/error_spec.rb +24 -0
- data/spec/message_specs/header_spec.rb +25 -0
- data/spec/message_specs/message_spec.rb +57 -0
- data/spec/message_specs/register_spec.rb +86 -0
- data/spec/message_specs/request_body_spec.rb +58 -0
- data/spec/message_specs/status_spec.rb +25 -0
- data/spec/messaging_spec.rb +88 -0
- data/spec/protocol_spec.rb +49 -0
- data/spec/registration_spec.rb +33 -0
- data/spec/request_logger_spec.rb +15 -0
- data/spec/request_spec.rb +10 -0
- data/spec/response_spec.rb +24 -0
- data/spec/server_spec.rb +35 -0
- data/spec/spec_helper.rb +26 -0
- metadata +191 -0
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
module Messages
|
|
3
|
+
class Error
|
|
4
|
+
|
|
5
|
+
attr_reader :category, :code, :description
|
|
6
|
+
|
|
7
|
+
def initialize(category, code, desc = nil)
|
|
8
|
+
@category = CATEGORY[category]
|
|
9
|
+
@category_index = category
|
|
10
|
+
@code = CODE[@category][code]
|
|
11
|
+
@code_index = code
|
|
12
|
+
@description = desc
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def read
|
|
16
|
+
xml = Builder::XmlMarkup.new
|
|
17
|
+
xml.SIF_Error { |error|
|
|
18
|
+
error.SIF_Category(@category_index)
|
|
19
|
+
error.SIF_Code(@code_index)
|
|
20
|
+
error.SIF_Desc(@code)
|
|
21
|
+
error.SIF_ExtendedDesc(@description) unless @description.nil?
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
alias :to_str :read
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
# Categories of Errors specified by SIF
|
|
28
|
+
CATEGORY = [
|
|
29
|
+
"Unknown (This should NEVER be used if possible)",
|
|
30
|
+
"XML Validation",
|
|
31
|
+
"Encryption",
|
|
32
|
+
"Authentication",
|
|
33
|
+
"Access and Permissions",
|
|
34
|
+
"Registration",
|
|
35
|
+
"Provision",
|
|
36
|
+
"Subscription",
|
|
37
|
+
"Request and Response",
|
|
38
|
+
"Event Reporting and Processing",
|
|
39
|
+
"Transport",
|
|
40
|
+
"System (OS, Database, Vendor localized, etc.)",
|
|
41
|
+
"Generic Message Handling",
|
|
42
|
+
"SMB Handling"
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
# Codes related to CATEGORY
|
|
46
|
+
# Some codes are blank to match the SIF Spec
|
|
47
|
+
CODE = {
|
|
48
|
+
CATEGORY[1] => [ # Xml Validation
|
|
49
|
+
"",
|
|
50
|
+
"Generic error",
|
|
51
|
+
"Message is not well-formed",
|
|
52
|
+
"Generic validation error",
|
|
53
|
+
"Invalid value for element/attribute",
|
|
54
|
+
"",
|
|
55
|
+
"Missing mandatory element/attribute"
|
|
56
|
+
],
|
|
57
|
+
CATEGORY[2] => [ # Encryption
|
|
58
|
+
"",
|
|
59
|
+
"Generic error"
|
|
60
|
+
],
|
|
61
|
+
CATEGORY[3] => [ # Authentication
|
|
62
|
+
"",
|
|
63
|
+
"Generic error",
|
|
64
|
+
"Generic authentication error (with signature)",
|
|
65
|
+
"Missing sender's certificate",
|
|
66
|
+
"Invalid certificate",
|
|
67
|
+
"Sender's certificate is not trusted",
|
|
68
|
+
"Expired certificate",
|
|
69
|
+
"Invalid signature",
|
|
70
|
+
"Invalid encryption algorithm (only accepts MD4)",
|
|
71
|
+
"Missing public key of the receiver (when decrypting message)",
|
|
72
|
+
"Missing receiver's private key (when decrypting message)"
|
|
73
|
+
],
|
|
74
|
+
CATEGORY[4] => [ # Access and Permissions
|
|
75
|
+
"",
|
|
76
|
+
"Generic error",
|
|
77
|
+
"No permission to register",
|
|
78
|
+
"No permission to provide this object",
|
|
79
|
+
"No permission to subscribe to this SIF_Event",
|
|
80
|
+
"No permission to request this object",
|
|
81
|
+
"No permission to respond to this object request",
|
|
82
|
+
"No permission to publish SIF_Event",
|
|
83
|
+
"No permission to administer policies",
|
|
84
|
+
"SIF_SourceId is not registered",
|
|
85
|
+
"No permission to publish SIF_Event Add",
|
|
86
|
+
"No permission to publish SIF_Event Change",
|
|
87
|
+
"No permission to publish SIF_Event Delete"
|
|
88
|
+
],
|
|
89
|
+
CATEGORY[5] => [ # Registration
|
|
90
|
+
"",
|
|
91
|
+
"Generic error",
|
|
92
|
+
"The SIF_SourceId is invalid",
|
|
93
|
+
"Requested transport protocol is unsupported",
|
|
94
|
+
"Requested SIF_Version(s) not supported",
|
|
95
|
+
"",
|
|
96
|
+
"Requested SIF_MaxBufferSize is too small",
|
|
97
|
+
"ZIS requires a secure transport",
|
|
98
|
+
"",
|
|
99
|
+
"Agent is registered for push mode (returned when a push-mode agent sends a SIF_GetMessage)",
|
|
100
|
+
"ZIS does not support the requested Accept-Encoding value"
|
|
101
|
+
],
|
|
102
|
+
CATEGORY[6] => [ # Provision
|
|
103
|
+
"",
|
|
104
|
+
"Generic error",
|
|
105
|
+
"",
|
|
106
|
+
"Invalid object",
|
|
107
|
+
"Object already has a provider (SIF_Provide message)"
|
|
108
|
+
],
|
|
109
|
+
CATEGORY[7] => [ # Subscription
|
|
110
|
+
"",
|
|
111
|
+
"Generic error",
|
|
112
|
+
"",
|
|
113
|
+
"Invalid object"
|
|
114
|
+
],
|
|
115
|
+
CATEGORY[8] => [ # Request and Response
|
|
116
|
+
"",
|
|
117
|
+
"Generic error",
|
|
118
|
+
"",
|
|
119
|
+
"Invalid object",
|
|
120
|
+
"No provider",
|
|
121
|
+
"",
|
|
122
|
+
"",
|
|
123
|
+
"Responder does not support requested SIF_Version",
|
|
124
|
+
"Responder does not support requested SIF_MaxBufferSize",
|
|
125
|
+
"Unsupported query in request",
|
|
126
|
+
"Invalid SIF_RequestMsgId specified in SIF_Response",
|
|
127
|
+
"SIF_Response is larger than requested SIF_MaxBufferSize",
|
|
128
|
+
"SIF_PacketNumber is invalid in SIF_Response",
|
|
129
|
+
"SIF_Response does not match any SIF_Version from SIF_Request",
|
|
130
|
+
"SIF_DestinationId does not match SIF_SourceId from SIF_Request",
|
|
131
|
+
"No support for SIF_ExtendedQuery",
|
|
132
|
+
"SIF_RequestMsgId deleted from cache due to timeout",
|
|
133
|
+
"SIF_RequestMsgId deleted from cache by administrator",
|
|
134
|
+
"SIF_Request cancelled by requesting agent"
|
|
135
|
+
],
|
|
136
|
+
CATEGORY[9] => [ # Event Reporting and Processing
|
|
137
|
+
"",
|
|
138
|
+
"Generic error",
|
|
139
|
+
"",
|
|
140
|
+
"Invalid event"
|
|
141
|
+
],
|
|
142
|
+
CATEGORY[10] => [ # Transport
|
|
143
|
+
"",
|
|
144
|
+
"Generic error",
|
|
145
|
+
"Requested protocol is not supported",
|
|
146
|
+
"Secure channel requested and no secure path exists",
|
|
147
|
+
"Unable to establish connection"
|
|
148
|
+
],
|
|
149
|
+
CATEGORY[11] => [ # System
|
|
150
|
+
"",
|
|
151
|
+
"Generic Error"
|
|
152
|
+
],
|
|
153
|
+
CATEGORY[12] => [ # Generic Message Handling
|
|
154
|
+
"",
|
|
155
|
+
"Generic error",
|
|
156
|
+
"Message not supported",
|
|
157
|
+
"Version not supported",
|
|
158
|
+
"Context not supported",
|
|
159
|
+
"Protocol error",
|
|
160
|
+
"No such message (as identified by SIF_OriginalMsgId)",
|
|
161
|
+
"Multiple contexts not supported"
|
|
162
|
+
],
|
|
163
|
+
CATEGORY[13] => [ # SMB Handling
|
|
164
|
+
"",
|
|
165
|
+
"Generic error",
|
|
166
|
+
"SMB can only be invoked during a SIF_Event acknowledgement",
|
|
167
|
+
"Final SIF_Ack expected from Push-Mode Agent",
|
|
168
|
+
"Incorrect SIF_MsgId in final SIF_Ack"
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
module Messages
|
|
3
|
+
|
|
4
|
+
# Base class for all Messages in the framework. Embeds the XMLNS as
|
|
5
|
+
# well as the version of SIF implemented.
|
|
6
|
+
class Message
|
|
7
|
+
|
|
8
|
+
attr_reader :xmlns, :version, :header
|
|
9
|
+
|
|
10
|
+
# source parameter is required (string describing the original sender)
|
|
11
|
+
def initialize(source, options = {})
|
|
12
|
+
raise ArgumentError, "Source not provided." if source.nil?
|
|
13
|
+
@xmlns = options[:xmlns] || Siffer.sif_xmlns
|
|
14
|
+
@version = options[:version] || Siffer.sif_version
|
|
15
|
+
@header = Header.new(source)
|
|
16
|
+
@body = Builder::XmlMarkup.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Builds the xml for this message. Accepts a block if nested
|
|
20
|
+
# elements are required.
|
|
21
|
+
def content
|
|
22
|
+
@xml ||= @body.SIF_Message(:version => @version, :xmlns => @xmlns) { |xml|
|
|
23
|
+
yield xml if block_given?
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Alias method to the Header SourceId
|
|
28
|
+
def source_id() header.source_id; end
|
|
29
|
+
# Alias method to the Header MsgId
|
|
30
|
+
def msg_id() header.msg_id; end
|
|
31
|
+
|
|
32
|
+
# used to remove the stack too deep issue when overridden
|
|
33
|
+
# there has to be a better way .... TODO: Fix the alias crap
|
|
34
|
+
alias :body :content
|
|
35
|
+
|
|
36
|
+
def put_header_into(xml)
|
|
37
|
+
xml.SIF_Header { |head|
|
|
38
|
+
head.SIF_MsgId(@header.msg_id)
|
|
39
|
+
head.SIF_Timestamp(@header.timestamp)
|
|
40
|
+
head.SIF_SourceId(@header.source_id)
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Returns the content of the message
|
|
45
|
+
def read
|
|
46
|
+
# this construct prevents the xml from being built
|
|
47
|
+
# over and over again for every read made to this
|
|
48
|
+
# message.
|
|
49
|
+
@xml ||= content
|
|
50
|
+
end
|
|
51
|
+
alias :to_str :read
|
|
52
|
+
|
|
53
|
+
# Each Message requires a Header to identify the source.
|
|
54
|
+
# You shouldn't need to initialize this by itself, it is
|
|
55
|
+
# used by Message.
|
|
56
|
+
class Header
|
|
57
|
+
|
|
58
|
+
attr_reader :timestamp, :msg_id, :source_id
|
|
59
|
+
|
|
60
|
+
def initialize(source)
|
|
61
|
+
raise ArgumentError, "Source not provided." if source.nil?
|
|
62
|
+
@timestamp = Time.now
|
|
63
|
+
@msg_id = UUID.generate(:compact).upcase
|
|
64
|
+
@source_id = source
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
module Messages
|
|
3
|
+
|
|
4
|
+
# Message used by Agents to register themselves with the ZIS.
|
|
5
|
+
class Register < Message
|
|
6
|
+
|
|
7
|
+
attr_reader :name, :version, :vendor, :max_buffer, :mode
|
|
8
|
+
|
|
9
|
+
def initialize(source, name, options = {})
|
|
10
|
+
super(source, options)
|
|
11
|
+
raise ArgumentError, "Agent name required" unless name
|
|
12
|
+
@name = name
|
|
13
|
+
@version = options[:version] || Siffer.sif_version
|
|
14
|
+
@max_buffer = options[:max_buffer] || 1024
|
|
15
|
+
@mode = options[:mode] || 'Pull'
|
|
16
|
+
@vendor = options[:vendor] || Siffer.vendor
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def content
|
|
20
|
+
body do |reg|
|
|
21
|
+
reg.SIF_Register() { |xml|
|
|
22
|
+
put_header_into xml
|
|
23
|
+
reg.SIF_Name(@name)
|
|
24
|
+
reg.SIF_Version(@version)
|
|
25
|
+
reg.SIF_MaxBufferSize(@max_buffer)
|
|
26
|
+
reg.SIF_Mode(@mode)
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Parses the body passed as a Register message and returns a
|
|
32
|
+
# RequestBody that provides access to Register properties.
|
|
33
|
+
def self.parse(body)
|
|
34
|
+
RegisterBody.parse(body)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
class RegisterBody < RequestBody #:nodoc:
|
|
38
|
+
|
|
39
|
+
def name
|
|
40
|
+
(@doc/:SIF_Name).text
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def version
|
|
44
|
+
(@doc/:SIF_Version).text
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def max_buffer
|
|
48
|
+
(@doc/:SIF_MaxBufferSize).text.to_i
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def mode
|
|
52
|
+
(@doc/:SIF_Mode).text
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
end
|
|
60
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
|
|
3
|
+
module Messages
|
|
4
|
+
|
|
5
|
+
# This class is used to parse the SIF Message information
|
|
6
|
+
# out of the Request Body. It parses enough information to redirect
|
|
7
|
+
# to other processes. It does not parse details of the Message such as
|
|
8
|
+
# Protocol if a Register message, or Error if an Ack message. Each
|
|
9
|
+
# message type will inherit this class in order to provide a #parse
|
|
10
|
+
# method that will allow access to those specific attributes.
|
|
11
|
+
# It provides access to:
|
|
12
|
+
# * source_id
|
|
13
|
+
# * msg_id
|
|
14
|
+
# * type
|
|
15
|
+
class RequestBody
|
|
16
|
+
|
|
17
|
+
def initialize(xml_string)
|
|
18
|
+
@xml = xml_string
|
|
19
|
+
@doc = Hpricot(@xml, :xml => true)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Will return the name of the element found just inside the root
|
|
23
|
+
# or just inside SIF_SystemControl if present.
|
|
24
|
+
def type
|
|
25
|
+
begin
|
|
26
|
+
msg_type = (@doc/:SIF_Message).first.children[0].name
|
|
27
|
+
if msg_type == "SIF_SystemControl"
|
|
28
|
+
msg_type = (@doc/:SIF_Message/:SIF_SystemControl).first.children[0].name
|
|
29
|
+
end
|
|
30
|
+
drop_sif msg_type
|
|
31
|
+
rescue
|
|
32
|
+
raise "Failed to parse #{@xml} for SIF Type"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The SIF_SourceId from the SIF_Header
|
|
37
|
+
def source_id
|
|
38
|
+
(@doc/"//SIF_Header/SIF_SourceId/").text
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# The SIF_MsgId from the SIF_Header
|
|
42
|
+
def msg_id
|
|
43
|
+
(@doc/"//SIF_Header/SIF_MsgId/").text
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Parses the xml provided and returns a RequestBody.
|
|
47
|
+
# Xml must respond to read or be a String.
|
|
48
|
+
def self.parse(xml)
|
|
49
|
+
unless xml.respond_to?("read") or xml.is_a?(String)
|
|
50
|
+
raise ArgumentError, "Unable to read Xml"
|
|
51
|
+
end
|
|
52
|
+
xml = xml.read if xml.respond_to?("read")
|
|
53
|
+
self.new(xml) # use self because we are going to inherit this class
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
private
|
|
57
|
+
# Drops the SIF_ from the front of the string provided
|
|
58
|
+
def drop_sif(string)
|
|
59
|
+
string.gsub!("SIF_","")
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
end
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
module Messages
|
|
3
|
+
|
|
4
|
+
class Status
|
|
5
|
+
|
|
6
|
+
attr_reader :code, :description, :data
|
|
7
|
+
|
|
8
|
+
def initialize(code,data)
|
|
9
|
+
@code = code
|
|
10
|
+
@description = CODES[code]
|
|
11
|
+
@data = data
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def read
|
|
15
|
+
xml = Builder::XmlMarkup.new
|
|
16
|
+
xml.SIF_Status { |status|
|
|
17
|
+
status.SIF_Code(code)
|
|
18
|
+
status.SIF_Description(description)
|
|
19
|
+
if data.nil?
|
|
20
|
+
status.SIF_Data
|
|
21
|
+
else
|
|
22
|
+
status.SIF_Data{ |data_node| data_node << data.read }
|
|
23
|
+
end
|
|
24
|
+
}
|
|
25
|
+
end
|
|
26
|
+
alias :to_str :read
|
|
27
|
+
|
|
28
|
+
def self.method_missing(sym,*args)
|
|
29
|
+
data = args.first
|
|
30
|
+
status = nil
|
|
31
|
+
CODES.each do |key, val|
|
|
32
|
+
if val.downcase.to_sym == sym
|
|
33
|
+
status = Status.new(key,data)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
if status
|
|
37
|
+
return status
|
|
38
|
+
else
|
|
39
|
+
super(sym,*args)
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
CODES = {
|
|
44
|
+
0 => "Success",
|
|
45
|
+
1 => "Immediate",
|
|
46
|
+
2 => "Intermediate",
|
|
47
|
+
3 => "Final",
|
|
48
|
+
7 => "Duplicate",
|
|
49
|
+
8 => "Sleeping",
|
|
50
|
+
9 => "No Messages"
|
|
51
|
+
}
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
end
|
data/lib/messaging.rb
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
module Siffer
|
|
2
|
+
# The Messaging module takes care of all of the Message handling for
|
|
3
|
+
# Siffer. It will check messages against content-type constraints as
|
|
4
|
+
# well as validate the message XML against constraints outlined in the
|
|
5
|
+
# SIF Implementation Specification.
|
|
6
|
+
module Messaging
|
|
7
|
+
|
|
8
|
+
include Siffer::Messages
|
|
9
|
+
|
|
10
|
+
class BadContentType < Exception #:nodoc:
|
|
11
|
+
end
|
|
12
|
+
class MalformedXml < Exception #:nodoc:
|
|
13
|
+
end
|
|
14
|
+
class MalformedSIFMessage < Exception #:nodoc:
|
|
15
|
+
end
|
|
16
|
+
class XmlNsMismatch < Exception #:nodoc:
|
|
17
|
+
end
|
|
18
|
+
class VersionMismatch < Exception #:nodoc:
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Checks the request against the messaging constraints:
|
|
22
|
+
# * check_content_type
|
|
23
|
+
# * validate_message
|
|
24
|
+
# Raises exceptions accordingly.
|
|
25
|
+
def request_failed_messaging?
|
|
26
|
+
begin
|
|
27
|
+
check_content_type
|
|
28
|
+
validate_message
|
|
29
|
+
rescue BadContentType
|
|
30
|
+
# Make a better Not Acceptable response
|
|
31
|
+
@response = Response.new(Siffer::Protocol::HTTP_STATUS_CODES[406],
|
|
32
|
+
406,
|
|
33
|
+
{"Content-Type" => MIME_TYPES["htm"]})
|
|
34
|
+
rescue MalformedXml; error_response(1,2);
|
|
35
|
+
rescue MalformedSIFMessage; error_response(12,2);
|
|
36
|
+
rescue VersionMismatch; error_response(12,3);
|
|
37
|
+
rescue XmlNsMismatch; error_response(1,4,"XMLNS not compatible with SIF")
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Provides a context for the original message.
|
|
42
|
+
def using_message_from(request, &block)
|
|
43
|
+
yield if block_given?
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
# Reads request content type and validates it's either text/xml
|
|
47
|
+
# or application/xml;charset=utf-8. If it isn't it will raise a
|
|
48
|
+
# BadContentType exception.
|
|
49
|
+
def check_content_type
|
|
50
|
+
content_type = @request.content_type
|
|
51
|
+
unless [MIME_TYPES["xml"], MIME_TYPES["appxml"]].include? content_type
|
|
52
|
+
raise BadContentType
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Validates the Request Body against the constraints of SIF Messaging.
|
|
57
|
+
# The word "validate" is used loosely as there is no XML validation
|
|
58
|
+
# currently.
|
|
59
|
+
#
|
|
60
|
+
# Currently validates:
|
|
61
|
+
# * <tt>well-formed XML</tt> - XML must be well formed.
|
|
62
|
+
# * <tt>message root</tt> - XML must be a SIF message.
|
|
63
|
+
# * <tt>version</tt> - Must match SIF version implemented.
|
|
64
|
+
# * <tt>xmlns</tt> - Must match xmlns implemented.
|
|
65
|
+
#
|
|
66
|
+
# Does not validate:
|
|
67
|
+
# * valid XML
|
|
68
|
+
# * different versions of SIF
|
|
69
|
+
def validate_message
|
|
70
|
+
begin
|
|
71
|
+
body = (@request.body.respond_to? :read) ? @request.body.read : @request.body
|
|
72
|
+
xml = REXML::Document.new(body)
|
|
73
|
+
# validate Message Root
|
|
74
|
+
raise MalformedXml if xml.root.nil?
|
|
75
|
+
# validate Message Root is a SIF_Message
|
|
76
|
+
raise MalformedSIFMessage if xml.root.name != "SIF_Message"
|
|
77
|
+
# validate SIF version
|
|
78
|
+
raise VersionMismatch if xml.root.attributes["version"] != Siffer.sif_version
|
|
79
|
+
# validate SIF xmlns
|
|
80
|
+
raise XmlNsMismatch if xml.root.attributes["xmlns"] != Siffer.sif_xmlns
|
|
81
|
+
# any others?
|
|
82
|
+
rescue REXML::ParseException
|
|
83
|
+
raise MalformedXml
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# MIME Types used in Siffer
|
|
88
|
+
MIME_TYPES = {
|
|
89
|
+
"appxml" => "application/xml;charset=utf-8",
|
|
90
|
+
"htm" => "text/html",
|
|
91
|
+
"html" => "text/html",
|
|
92
|
+
"xml" => "text/xml"
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
end
|
|
96
|
+
end
|