58a8d4cc587fb4021fbd1745c04053f0939bd714
[sfa.git] / sfatables / xmlrule.py
1 import libxml2
2 import libxslt
3 from sfatables.globals import *
4
5 class XMLRule:
6     
7     def apply_processor(self, type, doc, output_xpath_filter=None):
8         processor = self.processors[type]
9
10         # XXX TO CLEAN UP
11         filepath = os.path.join(sfatables_config, 'processors', processor)
12         # XXX
13
14         styledoc = libxml2.parseFile(filepath)
15         style = libxslt.parseStylesheetDoc(styledoc)
16         result = style.applyStylesheet(doc, None)
17         if (output_xpath_filter):
18             p = result.xpathNewContext()
19             xpath_result = p.xpathEval(output_xpath_filter)
20             if (xpath_result == []):
21                 raise Exception("Could not apply processor %s."%processor)
22
23             stylesheet_result = xpath_result
24             p.xpathFreeContext()
25         else:
26             stylesheet_result = result #style.saveResultToString(result)
27
28         style.freeStylesheet()
29         #doc.freeDoc()
30         #result.freeDoc()
31
32         return stylesheet_result
33
34     def wrap_up(self, doc):
35         filepath = os.path.join(sfatables_config, 'processors', self.final_processor)
36
37         if not os.path.exists(filepath):
38             # TODO: final_processor is not there yet
39             return doc#rspec
40
41         styledoc = libxml2.parseFile(filepath)
42         style = libxslt.parseStylesheetDoc(styledoc)
43         #doc = libxml2.parseDoc(rspec)
44         result = style.applyStylesheet(doc, None)
45         stylesheet_result = result #style.saveResultToString(result)
46         style.freeStylesheet()
47         #doc.freeDoc()
48         #result.freeDoc()
49
50         return stylesheet_result
51
52     def match(self, rspec):
53         match_result = self.apply_processor('match',rspec,"//result/@verdict") 
54         return (match_result[0].content=='True')
55
56     def target(self, rspec):
57         target_result = self.apply_processor('target',rspec,None)
58         return target_result
59
60     def apply_interpreted(self, rspec):
61         # Interpreted
62         #
63         # output =
64         #    if (match(match_args, rspec)
65         #       then target(target_args, rspec)
66         #       else rspec
67
68         if (self.match(rspec)):
69             return self.target(rspec)
70         else:
71             return rspec
72
73
74     def apply_compiled(rspec):
75         # Not supported yet
76         return None
77
78     def load_xml_extension (self, type, chain, rule_number):
79         filename = sfatables_config+"/"+chain+"/"+"sfatables-%d-%s"%(rule_number,type)
80
81         self.xmldoc = libxml2.parseFile(filename)
82         p = self.xmldoc.xpathNewContext()
83
84         context = p.xpathEval('//context/@select')
85         self.context[type] = context[0].content
86
87         processor = p.xpathEval('//processor/@filename')
88
89         context = p.xpathEval('//attributes/attribute[@terminal="yes"]')
90         if (context != []):
91             self.terminal = 1
92         
93         self.processors[type] = processor[0].content
94         self.arguments[type] = p.xpathEval('//rule')
95
96         p.xpathFreeContext()
97
98
99     def wrap_rspec (self, type, rspec):
100         argument = self.arguments[type]
101         p = rspec.xmldoc.xpathNewContext()
102         root_node = p.xpathEval('/RSpec')
103         if (not root_node or not root_node):
104             raise Exception('An evil aggregate manager sent me a malformed RSpec. Please see the stack trace to identify it.')
105
106         root_node.addChild(arguments[type])
107         return rspec
108
109     def __init__(self, chain=None, rule_number=None):
110         self.rule_number = None
111         self.chain = None
112         self.xmldoc = None
113         self.terminal = 0
114         self.final_processor = '__sfatables_wrap_up__.xsl'
115
116         self.arguments = {'match':None,'target':None}
117         self.processors = {'match':None,'target':None}
118         self.context = {'match':None,'target':None}
119
120         if (chain and rule_number):
121             self.load_xml_extension('match', chain, rule_number)
122             self.load_xml_extension('target',chain, rule_number)
123             self.rule_number = rule_number
124             self.chain = chain
125         return
126         
127     def free(self):
128         self.xmldoc.freeDoc()