def __init__(self, _arg=None, **kwd): if _arg is None: config = dict() elif type(_arg) is dict or type(_arg) is Configuration: config = dict(_arg) elif type(_arg) is file: config = json.loads(_arg.read()) unicode2str(config) elif type(_arg) is str: with open(_arg) as source: config = json.loads(source.read()) unicode2str(config) config.update(kwd) for key, value in config.iteritems(): self[key] = parse_config(value)
def __init__(self, _arg = None, **kwd): if _arg is None: config = dict() elif type(_arg) is dict or type(_arg) is Configuration: config = dict(_arg) elif type(_arg) is file: config = json.loads(_arg.read()) unicode2str(config) elif type(_arg) is str: with open(_arg) as source: config = json.loads(source.read()) unicode2str(config) config.update(kwd) for key, value in config.iteritems(): self[key] = parse_config(value)
def _request_one(self, request, timeout): """ Use urllib2 opener mechanism to make on HTTP(S) request. """ if self.auth_handler: opener = urllib2.build_opener( self.auth_handler(self.auth_handler_conf)) else: opener = urllib2.build_opener() if 'Accept' not in self.headers: opener.addheaders.append(('Accept', self.accept)) opener.addheaders.extend(self.headers) if timeout > 0: watcher = RequestWatcher('Webservice (%s)' % request.get_full_url()) watcher.start(timeout) response = opener.open(request) if timeout > 0: watcher.stop() # clean up - break reference cycle so python can free the memory up for handler in opener.handlers: handler.parent = None del opener content = response.read() del response if self.accept == 'application/json': result = json.loads(content) unicode2str(result) elif self.accept == 'application/xml': # TODO implement xml -> dict result = content del content return result
def __init__(self, config=dict()): if type(config) is file: config = json.loads(config.read()) unicode2str(config) elif type(config) is str: with open(config) as source: config = json.loads(source.read()) unicode2str(config) for key, value in config.iteritems(): if type(value) is str: matches = re.findall('\$\(([^\)]+)\)', value) for match in matches: value = value.replace('$(%s)' % match, os.environ[match]) if type(value) is dict or type(value) is Configuration: self[key] = Configuration(value) else: self[key] = value
def _request_one(self, request, timeout): """ Use urllib2 opener mechanism to make on HTTP(S) request. """ if self.auth_handler: opener = urllib2.build_opener(self.auth_handler(self.auth_handler_conf)) else: opener = urllib2.build_opener() if 'Accept' not in self.headers: opener.addheaders.append(('Accept', self.accept)) opener.addheaders.extend(self.headers) if timeout > 0: watcher = RequestWatcher('Webservice (%s)' % request.get_full_url()) watcher.start(timeout) response = opener.open(request) if timeout > 0: watcher.stop() # clean up - break reference cycle so python can free the memory up for handler in opener.handlers: handler.parent = None del opener content = response.read() del response if self.accept == 'application/json': result = json.loads(content) unicode2str(result) elif self.accept == 'application/xml': # TODO implement xml -> dict result = content del content return result
def _main(self, environ): """ Body of the WSGI callable. Steps: 1. Determine protocol. If HTTPS, identify the user. 2. If js or css is requested, respond. 3. Find the module class and instantiate it. 4. Parse the query string into a dictionary. 5. Call the run() function of the module class. 6. Respond. """ authorizer = None ## Step 1 if environ['REQUEST_SCHEME'] == 'http': # No auth user, dn, user_id = None, None, 0 authlist = [] elif environ['REQUEST_SCHEME'] == 'https': authorizer = self.dynamo_server.manager.master.create_authorizer() # Client DN must match a known user try: dn = WebServer.format_dn(environ['SSL_CLIENT_S_DN']) userinfo = authorizer.identify_user(dn=dn, check_trunc=True) if userinfo is None: raise exceptions.AuthorizationError() user, user_id, dn = userinfo except exceptions.AuthorizationError: self.code = 403 self.message = 'Unknown user. Client name: %s' % environ[ 'SSL_CLIENT_S_DN'] return except: return self._internal_server_error() authlist = authorizer.list_user_auth(user) else: self.code = 400 self.message = 'Only HTTP or HTTPS requests are allowed.' return ## Step 2 mode = environ['SCRIPT_NAME'].strip('/') if mode == 'js' or mode == 'css': try: source = open(HTMLMixin.contents_path + '/' + mode + environ['PATH_INFO']) except IOError: self.code = 404 self.content_type = 'text/plain' return 'Invalid request %s%s.\n' % (mode, environ['PATH_INFO']) else: if mode == 'js': self.content_type = 'text/javascript' else: self.content_type = 'text/css' content = source.read() + '\n' source.close() return content ## Step 3 if mode != 'data' and mode != 'web' and mode != 'registry' and mode != 'phedexdata': # registry and phedexdata for backward compatibility self.code = 404 self.message = 'Invalid request %s.' % mode return if mode == 'phedexdata': mode = 'data' self.phedex_request = environ['PATH_INFO'][1:] module, _, command = environ['PATH_INFO'][1:].partition('/') try: cls = modules[mode][module][command] except KeyError: # Was a new module added perhaps? load_modules() try: # again cls = modules[mode][module][command] except KeyError: self.code = 404 self.message = 'Invalid request %s/%s.' % (module, command) return try: provider = cls(self.modules_config) except: return self._internal_server_error() if provider.must_authenticate and user is None: self.code = 400 self.message = 'Resource only available with HTTPS.' return if provider.write_enabled: self.dynamo_server.manager.master.lock() try: if self.dynamo_server.manager.master.inhibit_write(): # We need to give up here instead of waiting, because the web server processes will be flushed out as soon as # inventory is updated after the current writing process is done self.code = 503 self.message = 'Server cannot execute %s/%s at the moment because the inventory is being updated.' % ( module, command) return else: self.dynamo_server.manager.master.start_write_web( socket.gethostname(), os.getpid()) # stop is called from the DynamoServer upon successful inventory update except: self.dynamo_server.manager.master.stop_write_web() raise finally: self.dynamo_server.manager.master.unlock() if provider.require_authorizer: if authorizer is None: authorizer = self.dynamo_server.manager.master.create_authorizer( ) provider.authorizer = authorizer if provider.require_appmanager: provider.appmanager = self.dynamo_server.manager.master.create_appmanager( ) try: ## Step 4 post_request = None if environ['REQUEST_METHOD'] == 'POST': try: content_type = environ['CONTENT_TYPE'] except KeyError: content_type = 'application/x-www-form-urlencoded' # In principle we should grab CONTENT_LENGTH from environ and only read as many bytes as given, but wsgi.input seems to know where the EOF is try: content_length = environ['CONTENT_LENGTH'] except KeyError: # length -1: rely on wsgi.input having an EOF at the end content_length = -1 post_data = environ['wsgi.input'].read(content_length) # Even though our default content type is URL form, we check if this is a JSON try: json_data = json.loads(post_data) except: if content_type == 'application/json': self.code = 400 self.message = 'Could not parse input.' return else: content_type = 'application/json' provider.input_data = json_data unicode2str(provider.input_data) if content_type == 'application/x-www-form-urlencoded': try: post_request = parse_qs(post_data) except: self.code = 400 self.message = 'Could not parse input.' elif content_type != 'application/json': self.code = 400 self.message = 'Unknown Content-Type %s.' % content_type get_request = parse_qs(environ['QUERY_STRING']) if post_request is not None: for key, value in post_request.iteritems(): if key in get_request: # return dict of parse_qs is {key: list} get_request[key].extend(post_request[key]) else: get_request[key] = post_request[key] unicode2str(get_request) request = {} for key, value in get_request.iteritems(): if key.endswith('[]'): key = key[:-2] request[key] = map(escape, value) else: if len(value) == 1: request[key] = escape(value[0]) else: request[key] = map(escape, value) ## Step 5 caller = WebServer.User(user, dn, user_id, authlist) if self.dynamo_server.inventory.loaded: inventory = self.dynamo_server.inventory.create_proxy() if provider.write_enabled: inventory._update_commands = [] else: inventory = DummyInventory() content = provider.run(caller, request, inventory) if provider.write_enabled: self.dynamo_server._send_updates(inventory) except (exceptions.AuthorizationError, exceptions.ResponseDenied, exceptions.MissingParameter, exceptions.ExtraParameter, exceptions.IllFormedRequest, exceptions.InvalidRequest) as ex: self.code = 400 self.message = str(ex) return except exceptions.TryAgain as ex: self.code = 503 self.message = str(ex) return except: return self._internal_server_error() ## Step 6 self.message = provider.message self.content_type = provider.content_type self.headers = provider.additional_headers if 'callback' in request: self.callback = request['callback'] return content
def _main(self, environ): """ Body of the WSGI callable. Steps: 1. Determine protocol. If HTTPS, identify the user. 2. If js or css is requested, respond. 3. Find the module class and instantiate it. 4. Parse the query string into a dictionary. 5. Call the run() function of the module class. 6. Respond. """ authorizer = None ## Step 1 if environ['REQUEST_SCHEME'] == 'http': # No auth user, dn, user_id = None, None, 0 authlist = [] elif environ['REQUEST_SCHEME'] == 'https': authorizer = self.dynamo_server.manager.master.create_authorizer() # Client DN must match a known user try: dn = WebServer.format_dn(environ['SSL_CLIENT_S_DN']) userinfo = authorizer.identify_user(dn = dn, check_trunc = True) if userinfo is None: raise exceptions.AuthorizationError() user, user_id, dn = userinfo except exceptions.AuthorizationError: self.code = 403 self.message = 'Unknown user. Client name: %s' % environ['SSL_CLIENT_S_DN'] return except: return self._internal_server_error() authlist = authorizer.list_user_auth(user) else: self.code = 400 self.message = 'Only HTTP or HTTPS requests are allowed.' return ## Step 2 mode = environ['SCRIPT_NAME'].strip('/') if mode == 'js' or mode == 'css': try: source = open(HTMLMixin.contents_path + '/' + mode + environ['PATH_INFO']) except IOError: self.code = 404 self.content_type = 'text/plain' return 'Invalid request %s%s.\n' % (mode, environ['PATH_INFO']) else: if mode == 'js': self.content_type = 'text/javascript' else: self.content_type = 'text/css' content = source.read() + '\n' source.close() return content ## Step 3 if mode != 'data' and mode != 'web' and mode != 'registry' and mode != 'phedexdata': # registry and phedexdata for backward compatibility self.code = 404 self.message = 'Invalid request %s.' % mode return if mode == 'phedexdata': mode = 'data' self.phedex_request = environ['PATH_INFO'][1:] module, _, command = environ['PATH_INFO'][1:].partition('/') try: cls = modules[mode][module][command] except KeyError: # Was a new module added perhaps? load_modules() try: # again cls = modules[mode][module][command] except KeyError: self.code = 404 self.message = 'Invalid request %s/%s.' % (module, command) return try: provider = cls(self.modules_config) except: return self._internal_server_error() if provider.must_authenticate and user is None: self.code = 400 self.message = 'Resource only available with HTTPS.' return if provider.write_enabled: self.dynamo_server.manager.master.lock() try: if self.dynamo_server.manager.master.inhibit_write(): # We need to give up here instead of waiting, because the web server processes will be flushed out as soon as # inventory is updated after the current writing process is done self.code = 503 self.message = 'Server cannot execute %s/%s at the moment because the inventory is being updated.' % (module, command) return else: self.dynamo_server.manager.master.start_write_web(socket.gethostname(), os.getpid()) # stop is called from the DynamoServer upon successful inventory update except: self.dynamo_server.manager.master.stop_write_web() raise finally: self.dynamo_server.manager.master.unlock() if provider.require_authorizer: if authorizer is None: authorizer = self.dynamo_server.manager.master.create_authorizer() provider.authorizer = authorizer if provider.require_appmanager: provider.appmanager = self.dynamo_server.manager.master.create_appmanager() try: ## Step 4 post_request = None if environ['REQUEST_METHOD'] == 'POST': try: content_type = environ['CONTENT_TYPE'] except KeyError: content_type = 'application/x-www-form-urlencoded' # In principle we should grab CONTENT_LENGTH from environ and only read as many bytes as given, but wsgi.input seems to know where the EOF is try: content_length = environ['CONTENT_LENGTH'] except KeyError: # length -1: rely on wsgi.input having an EOF at the end content_length = -1 post_data = environ['wsgi.input'].read(content_length) # Even though our default content type is URL form, we check if this is a JSON try: json_data = json.loads(post_data) except: if content_type == 'application/json': self.code = 400 self.message = 'Could not parse input.' return else: content_type = 'application/json' provider.input_data = json_data unicode2str(provider.input_data) if content_type == 'application/x-www-form-urlencoded': try: post_request = parse_qs(post_data) except: self.code = 400 self.message = 'Could not parse input.' elif content_type != 'application/json': self.code = 400 self.message = 'Unknown Content-Type %s.' % content_type get_request = parse_qs(environ['QUERY_STRING']) if post_request is not None: for key, value in post_request.iteritems(): if key in get_request: # return dict of parse_qs is {key: list} get_request[key].extend(post_request[key]) else: get_request[key] = post_request[key] unicode2str(get_request) request = {} for key, value in get_request.iteritems(): if key.endswith('[]'): key = key[:-2] request[key] = map(escape, value) else: if len(value) == 1: request[key] = escape(value[0]) else: request[key] = map(escape, value) ## Step 5 caller = WebServer.User(user, dn, user_id, authlist) if self.dynamo_server.inventory.loaded: inventory = self.dynamo_server.inventory.create_proxy() if provider.write_enabled: inventory._update_commands = [] else: inventory = DummyInventory() content = provider.run(caller, request, inventory) if provider.write_enabled: self.dynamo_server._send_updates(inventory) except (exceptions.AuthorizationError, exceptions.ResponseDenied, exceptions.MissingParameter, exceptions.ExtraParameter, exceptions.IllFormedRequest, exceptions.InvalidRequest) as ex: self.code = 400 self.message = str(ex) return except exceptions.TryAgain as ex: self.code = 503 self.message = str(ex) return except: return self._internal_server_error() ## Step 6 self.message = provider.message self.content_type = provider.content_type self.headers = provider.additional_headers if 'callback' in request: self.callback = request['callback'] return content