Premiere version : mise en route du suivi.
[auf_roundup.git] / roundup / scripts / .svn / text-base / roundup_xmlrpc_server.py.svn-base
1 #! /usr/bin/env python
2 #
3 # Copyright (C) 2007 Stefan Seefeld
4 # All rights reserved.
5 # For license terms see the file COPYING.txt.
6 #
7
8 import base64, getopt, os, sys, socket, urllib
9 from roundup.xmlrpc import translate
10 from roundup.xmlrpc import RoundupInstance
11 import roundup.instance
12 from roundup.instance import TrackerError
13 from roundup.cgi.exceptions import Unauthorised
14 from SimpleXMLRPCServer import SimpleXMLRPCServer
15 from SimpleXMLRPCServer import SimpleXMLRPCRequestHandler
16
17
18 class RequestHandler(SimpleXMLRPCRequestHandler):
19     """A SimpleXMLRPCRequestHandler with support for basic
20     HTTP Authentication."""
21
22     TRACKER_HOMES = {}
23     TRACKERS = {}
24
25     def is_rpc_path_valid(self):
26         path = self.path.split('/')
27         name = urllib.unquote(path[1]).lower()
28         return name in self.TRACKER_HOMES
29
30     def get_tracker(self, name):
31         """Return a tracker instance for given tracker name."""
32
33         if name in self.TRACKERS:
34             return self.TRACKERS[name]
35
36         if name not in self.TRACKER_HOMES:
37             raise Exception('No such tracker "%s"'%name)
38         tracker_home = self.TRACKER_HOMES[name]
39         tracker = roundup.instance.open(tracker_home)
40         self.TRACKERS[name] = tracker
41         return tracker
42
43
44     def authenticate(self, tracker):
45
46         
47         # Try to extract username and password from HTTP Authentication.
48         username, password = None, None
49         authorization = self.headers.get('authorization', ' ')
50         scheme, challenge = authorization.split(' ', 1)
51
52         if scheme.lower() == 'basic':
53             decoded = base64.decodestring(challenge)
54             if ':' in decoded:
55                 username, password = decoded.split(':')
56             else:
57                 username = decoded
58         if not username:
59             username = 'anonymous'
60         db = tracker.open('admin')
61         try:
62             userid = db.user.lookup(username)
63         except KeyError: # No such user
64             db.close()
65             raise Unauthorised, 'Invalid user'
66         stored = db.user.get(userid, 'password')
67         if stored != password:
68             # Wrong password
69             db.close()
70             raise Unauthorised, 'Invalid user'
71         db.setCurrentUser(username)
72         return db
73
74
75     def do_POST(self):
76         """Extract username and password from authorization header."""
77
78         db = None
79         try:
80             path = self.path.split('/')
81             tracker_name = urllib.unquote(path[1]).lower()
82             tracker = self.get_tracker(tracker_name)
83             db = self.authenticate(tracker)
84
85             instance = RoundupInstance(db, tracker.actions, None)
86             self.server.register_instance(instance)
87             SimpleXMLRPCRequestHandler.do_POST(self)
88         except Unauthorised, message:
89             self.send_error(403, '%s (%s)'%(self.path, message))
90         except:
91             if db:
92                 db.close()
93             exc, val, tb = sys.exc_info()
94             print exc, val, tb
95             raise
96         if db:
97             db.close()
98
99
100 class Server(SimpleXMLRPCServer):
101
102     def _dispatch(self, method, params):
103
104         retn = SimpleXMLRPCServer._dispatch(self, method, params)
105         retn = translate(retn)
106         return retn
107
108
109 def usage():
110     print """Usage: %s: [options] [name=tracker home]+
111
112 Options:
113  -e, --encoding    -- specify the encoding to use
114  -V                -- be verbose when importing
115  -p, --port <port> -- port to listen on
116
117 """%sys.argv[0]
118
119 def run():
120
121     try:
122         opts, args = getopt.getopt(sys.argv[1:],
123                                    'e:i:p:V', ['encoding=', 'port='])
124     except getopt.GetoptError, e:
125         usage()
126         return 1
127
128     verbose = False
129     port = 8000
130     encoding = None
131
132     for opt, arg in opts:
133         if opt == '-V':
134             verbose = True
135         elif opt in ['-p', '--port']:
136             port = int(arg)
137         elif opt in ['-e', '--encoding']:
138             encoding = encoding
139
140     tracker_homes = {}
141     for arg in args:
142         try:
143             name, home = arg.split('=', 1)
144             # Validate the argument
145             tracker = roundup.instance.open(home)
146         except ValueError:
147             print 'Instances must be name=home'
148             sys.exit(-1)
149         except TrackerError:
150             print 'Tracker home does not exist.'
151             sys.exit(-1)
152
153         tracker_homes[name] = home
154
155     RequestHandler.TRACKER_HOMES=tracker_homes
156
157     if sys.version_info[0:2] < (2,5):
158         if encoding:
159             print 'encodings not supported with python < 2.5'
160             sys.exit(-1)
161         server = Server(('', port), RequestHandler)
162     else:
163         server = Server(('', port), RequestHandler,
164                         allow_none=True, encoding=encoding)
165
166     # Go into the main listener loop
167     print 'Roundup XMLRPC server started on %s:%d' \
168           % (socket.gethostname(), port)
169     try:
170         server.serve_forever()
171     except KeyboardInterrupt:
172         print 'Keyboard Interrupt: exiting'
173
174 if __name__ == '__main__':
175     run()