#!/usr/bin/env python ## ## Cherokee 0.5.x to 0.6.x configuration converter ## ## Copyright: Alvaro Lopez Ortega ## Licensed: GPL v2 ## import sys import string FAKED_DOCUMENT_ROOT = '/faked' class Syntax: srv_entries = {'port': 'int', 'porttls': 'int', 'ipv6': 'int', 'timeout': 'int', 'keepalive': 'int', 'maxkeepaliverequests': 'int', 'logflushinterval': 'int', 'maxfds': 'int', 'maxconnectionreuse': 'int', 'listenqueuesize': 'int', 'servertokens': 'str', 'listen': 'str', 'user': 'str', 'group': 'str', 'pollmethod': 'str', 'pidfile': 'path', 'mimefile': 'path', 'chroot': 'path', 'panicaction': 'path' } vsrv_entries = {'directoryindex': 'list', 'sslcertificatefile': 'path', 'sslcertificatekeyfile': 'path', 'sslcalistfile': 'path' } icons_entries = {'directory': 'str', 'parentdirectory': 'str', 'default': 'str'} similar_entries = {'maxkeepaliverequests': 'keepalive_max_requests', 'servertokens': 'server_tokens', 'pidfile': 'pid_file', 'mimefile': 'mime_file', 'documentroot': 'document_root', 'errorhandler': 'error_handler', 'accesslog': 'access_log', 'errorlog': 'error_log', 'name': 'realm', 'logflushinterval': 'log_flush_elapse', 'maxfds': 'max_fds', 'maxconnectionreuse': 'max_connection_reuse', 'panicaction': 'panic_action', 'pollmethod': 'poll_method', 'listenqueuesize': 'listen_queue_size', 'sslcertificatefile': 'ssl_certificate_file', 'sslcertificatekeyfile': 'ssl_certificate_key_file', 'sslcalistfile': 'ssl_cal_list_file', 'directoryindex': 'directory_index', 'scriptalias': 'script_alias' } def __init__ (self, lex): self._lex = lex def _process_entry_guts (self, prefix): kind, val = self._lex.get_token() if kind == 'handler': kind, val = self._lex.get_token() if kind == 'file': kind = 'str' val = 'file' if kind != 'str': raise "Expected a str" print '%s!handler = %s' % (prefix, val) kind, val = self._lex.get_token() if kind != '{': self._lex.rewind() return True regex_num = 1 while True: kind, val_prop = self._lex.get_token() # Special cases if kind == '}': break elif kind == 'server': kind, val_prop_val = self._lex.get_token() print '%s!handler!balancer = round_robin' % (prefix) print '%s!handler!balancer!type = interpreter' % (prefix) print '%s!handler!balancer!entry1!host = %s' % (prefix, val_prop_val) kind, val = self._lex.get_token() if kind != '{': self._lex.rewind() continue while True: kind, val = self._lex.get_token() if kind == '}': break elif kind == 'str': kind_prop, val_prop = self._lex.get_token() val = val.lower() if val == 'env': kind_prop_val, val_prop_val = self._lex.get_token() print "%s!handler!balancer!entry1!env!%s = %s" % (prefix, val_prop, val_prop_val) else: print "%s!handler!balancer!entry1!%s = %s" % (prefix, val, val_prop) continue elif kind == 'str': val_prop_low = val_prop.lower() if val_prop_low == 'justabout': print '%s!handler!just_about = 1' % (prefix) continue elif val_prop_low == 'env': kind, val_env_name = self._lex.get_token() if kind != 'str': raise "Expected a str" kind, val_env_val = self._lex.get_token() if kind != 'str': raise "Expected a str" print '%s!handler!env!%s = %s' % (prefix, val_env_name, val_env_val) continue elif val_prop_low == 'show' or \ val_prop_low == 'rewrite': kind, val_prop = self._lex.get_token() # dirlist if val_prop_low == 'show': if 'size' in val_prop or \ 'date' in val_prop or \ 'owner' in val_prop: print '%s!handler!size = %d' % (prefix, 'size' in val_prop) print '%s!handler!date = %d' % (prefix, 'date' in val_prop) print '%s!handler!user = %d' % (prefix, 'owner' in val_prop) continue # redir rewrite = (kind == 'str' and val_prop.lower() == 'rewrite') if not rewrite: self._lex.rewind() print '%s!handler!rewrite!%d!show = %d' % (prefix, regex_num, rewrite) kind, regex_val = self._lex.get_token() if kind != 'str': raise "Expected a str" kind, url_val = self._lex.get_token() if kind == '}': self._lex.rewind() print '%s!handler!rewrite!%d!substring = %s' % (prefix, regex_num, regex_val) regex_num = regex_num + 1 continue elif kind == 'str': print '%s!handler!rewrite!%d!regex = %s' % (prefix, regex_num, regex_val) print '%s!handler!rewrite!%d!substring = %s' % (prefix, regex_num, url_val) regex_num = regex_num + 1 continue else: raise "Expected a str or '}'" # Default case val_prop_low = val_prop.lower() if val_prop_low in self.similar_entries: val_prop = self.similar_entries[val_prop_low] else: val_prop = val_prop_low # Get property value kind, val_prop_val = self._lex.get_token() print '%s!handler!%s = %s' % (prefix, val_prop, val_prop_val) elif kind == 'documentroot': kind, val = self._lex.get_token() if kind != 'path': raise "Malformed DocumentRoot" print '%s!document_root = %s' % (prefix, val) elif kind == 'auth': return self._process_auth (prefix) elif kind == 'allow': kind, val = self._lex.get_token() if kind != 'str': raise "Malformed Allow" kind, val_ip = self._lex.get_token() if not kind in ['str', 'list']: raise "Malformed Allow from" print '%s!allow_from = %s' % (prefix, val_ip) else: self._lex.rewind() return False return True def _process_auth (self, prefix): kind, val_method = self._lex.get_token() if kind not in ['str', 'list']: raise "Malformed Auth" val_method = val_method.lower() print "%s!auth!methods = %s" % (prefix, val_method) kind, val = self._lex.get_token() if kind != '{': raise "Malformed Auth" while True: kind, val_prop_name = self._lex.get_token() if kind == 'user': kind = 'str' val_prop_name = 'user' if kind == '}': self._lex.rewind() break elif kind != 'str': raise "Malformed Auth" kind, val_prop = self._lex.get_token() if kind != 'str': raise "Malformed Auth" val_prop_name_low = val_prop_name.lower() if val_prop_name_low in self.similar_entries: val_prop_name = self.similar_entries[val_prop_name_low] else: val_prop_name = val_prop_name_low if val_prop_name == 'method': print "%s!auth = %s" % (prefix, val_prop) else: print "%s!auth!%s = %s" % (prefix, val_prop_name, val_prop) kind, val = self._lex.get_token() if kind == '{': while True: kind, val_prop = self._lex.get_token() if kind == '}': break else: val_prop = val_prop.lower() kind, val_val = self._lex.get_token() print "%s!auth!%s = %s" % (prefix, val_prop, val_val) else: self._lex.rewind() kind, val = self._lex.get_token() if kind != '}' : raise "Malformed Auth" return True def _process_entry (self, prefix): while True: more = self._process_entry_guts (prefix) if not more: break print "%s!priority = %d" % (prefix, self._vserver_last_priority * 10) self._vserver_last_priority += 1 def _process_encoder (self, prefix): while True: kind, val = self._lex.get_token() if kind not in ['allow', 'deny']: raise "Malformed encoder" kind_val, val_val = self._lex.get_token() if kind_val != 'list': raise "Malformed encoder" print "%s!%s = %s" % (prefix, kind, val_val) kind, val = self._lex.get_token() self._lex.rewind() if kind == '}': break def _process_log (self, prefix): while True: kind, val1 = self._lex.get_token() if kind == '}': self._lex.rewind() break if kind != 'str': raise "Malformed Log" val1 = val1.lower() if val1.startswith('access'): entry = 'access' elif val1.startswith('error'): entry = 'error' else: raise "Unknown Log entry " + val1 kind, val2 = self._lex.get_token() if kind != 'path': raise "Malformed Log" if val2[0] == '/' or val2[1:2] == ':\\': print "%s!%s!type = file" % (prefix, entry) print "%s!%s!filename = %s" % (prefix, entry, val2) elif val == 'syslog': print "%s!%s!type = syslog" % (prefix, entry) def _process_icons_content (self): kind, val = self._lex.get_token() if kind is None: return False if kind in self.icons_entries: val_kind, val_val = self._lex.get_token() expected_type = self.icons_entries[kind] if val_kind != expected_type: raise "Bad %s value: type=%s expected=%s" % \ (kind, val_kind, expected_type) if kind in self.similar_entries: kind = self.similar_entries[kind] print "icons!%s = %s" % (kind, str(val_val)) elif kind == 'file': kind, val = self._lex.get_token() if kind != '{': raise "Malformed Icon file entry" while True: kind, val_file = self._lex.get_token() if kind == '}': break elif kind != 'str': raise "Malformed Icon file entry" kind, val_pattern = self._lex.get_token() if kind != 'str': raise "Malformed Icon file entry" print "icons!file!%s = %s" % (val_file, val_pattern) elif kind == 'suffix': kind, val = self._lex.get_token() if kind != '{': raise "Malformed Icon suffix entry" while True: kind, val_file = self._lex.get_token() if kind == '}': break elif kind != 'str': raise "Malformed Icon suffix entry" kind, val_suffixes = self._lex.get_token() if kind not in ['str', 'list']: raise "Malformed Icon suffix entry" print "icons!suffix!%s = %s" % (val_file, val_suffixes) else: self._lex.rewind() return False return True def _process_virtual_server_content (self, vserver='default'): kind, val = self._lex.get_token() if kind is None: return False if kind in self.vsrv_entries: val_kind, val_val = self._lex.get_token() expected_type = self.vsrv_entries[kind] if val_kind != expected_type: raise "Bad %s value: type=%s expected=%s" % \ (kind, val_kind, expected_type) if kind in self.similar_entries: kind = self.similar_entries[kind] print "vserver!%s!%s = %s" % (vserver, kind, str(val_val)) elif kind == 'documentroot': kind, val = self._lex.get_token() if kind != 'path': raise "Malformed DocumentRoot" print "vserver!%s!document_root = %s" % (vserver, val) self._vserver_has_document_root = True elif kind == 'directory': kind, dir_val = self._lex.get_token() if kind == 'str': # If the token kind is a string, it means that # it's processing an icon. Return and let the # icon management method to take care for us. return False elif kind != 'path': raise "Malformed directory" kind, val = self._lex.get_token() if kind != '{': raise "Malformed directory" prefix = 'vserver!%s!directory!%s' % (vserver, dir_val) self._process_entry (prefix) kind, val = self._lex.get_token() if kind != '}': raise "Malformed directory", self._lex._txt elif kind == 'extension': kind, ext_val = self._lex.get_token() if not kind in ['list', 'str']: raise "Malformed extension" kind, val = self._lex.get_token() if kind != '{': raise "Malformed extension" prefix = 'vserver!%s!extensions!%s' % (vserver, ext_val) self._process_entry (prefix) kind, val = self._lex.get_token() if kind != '}': raise "Malformed extension" elif kind == 'request': kind, req_val = self._lex.get_token() if kind != 'str': raise "Malformed request" kind, val = self._lex.get_token() if kind != '{': raise "Malformed request" prefix = 'vserver!%s!request!%s' % (vserver, req_val) self._process_entry (prefix) kind, val = self._lex.get_token() if kind != '}': raise "Malformed request" elif kind == 'userdir': kind, pub_val = self._lex.get_token() if kind != 'str': raise "Malformed Userdir" kind, val = self._lex.get_token() if kind != '{': raise "Malformed Userdir" prefix = 'vserver!%s!user_dir!%s' % (vserver, pub_val) while True: more = self._process_virtual_server_content (prefix) if not more: break kind, val = self._lex.get_token() if kind != '}': raise "Malformed Userdir" elif kind == 'errorhandler': kind, handler_val = self._lex.get_token() if kind != 'str': raise "Malformed ErrorHandler" kind, val = self._lex.get_token() if kind != '{': raise "Malformed ErrorHandler" prefix = 'vserver!%s!error_handler' % (vserver) print "%s = %s" % (prefix, handler_val) while True: kind, error_val = self._lex.get_token() if kind == '}': self._lex.rewind() break elif kind != 'int': raise "Malformed ErrorHandler" kind, url_val = self._lex.get_token() if kind != 'str': raise "Malformed ErrorHandler" print "%s!%s = %s" % (prefix, error_val, url_val) kind, val = self._lex.get_token() if kind != '}': raise "Malformed ErrorHandler" elif kind == 'log': kind, log_val = self._lex.get_token() if kind != 'str': raise "Malformed Log" kind, val = self._lex.get_token() if kind != '{': self._lex.rewind() return True prefix = 'vserver!%s!logger' % (vserver) print "%s = %s" % (prefix, log_val) self._process_log (prefix) kind, val = self._lex.get_token() if kind != '}': raise "Malformed Log" else: self._lex.rewind() return False return True def _process_server_content (self): kind, val = self._lex.get_token() if kind is None: return False if kind in self.srv_entries: val_kind, val_val = self._lex.get_token() expected_type = self.srv_entries[kind] if val_kind != expected_type: raise "Bad %s value: type=%s expected=%s" % \ (kind, val_kind, expected_type) if kind in self.similar_entries: kind = self.similar_entries[kind] print "server!%s = %s" % (kind, str(val_val)) elif kind == 'icons': kind, icons_val = self._lex.get_token() if kind != 'path': raise "Malformed Icons" elif kind == 'include': kind, incl_val = self._lex.get_token() if kind != 'path': raise "Malformed Include" print "include = %s" % (incl_val) elif kind == 'encoder': kind, enc_val = self._lex.get_token() if kind != 'str': raise "Malformed encoder" kind, val = self._lex.get_token() if kind != '{': raise "Malformed encoder" prefix = 'server!encoder!%s' % (enc_val) self._process_encoder (prefix) kind, val = self._lex.get_token() if kind != '}': raise "Malformed encoder" elif kind == 'server': self._lex.rewind() self._process_server() elif kind == 'threadnumber': kind, val_num = self._lex.get_token() if kind != 'int': raise "Malformed threadnumber" print "server!thread_number = %s" % (val_num) kind, val = self._lex.get_token() if kind != '{': self._lex.rewind() return True kind, val_type = self._lex.get_token() if kind != 'policy': raise "Malformed threadnumber" kind, val_val = self._lex.get_token() if kind != 'str': raise "Malformed threadnumber" print "server!thread_policy = %s" % (val_val) kind, val = self._lex.get_token() if kind != '}': raise "Malformed threadnumber" elif kind == 'sendfile': kind, val = self._lex.get_token() if kind != '{': raise "Malformed Sendfile" while True: kind, val = self._lex.get_token() if kind == '}': break elif kind != 'str': raise "Malformed Sendfile" val = val.lower() if val == 'minsize': kind, val_num = self._lex.get_token() if kind != 'int': raise "Malformed Sendfile" print "server!sendfile_min = %s" % (val_num) elif val == 'maxsize': kind, val_num = self._lex.get_token() if kind != 'int': raise "Malformed Sendfile" print "server!sendfile_max = %s" % (val_num) else: raise "Malformed Sendfile" else: self._lex.rewind() return False return True def _process_server (self): self._vserver_last_priority = 1 kind, val = self._lex.get_token() if kind != 'server': raise "Expected server" kind, val = self._lex.get_token() if kind not in ['list', 'str']: raise "Malformed server" if kind == 'list': l = map(lambda x: x.strip(), val.split(',')) domains = l else: domains = [val] vserver = domains[0] kind, val = self._lex.get_token() if kind != '{': raise "Expected {" i = 0 for v in domains: i = i + 1 print "vserver!%s!domain!%d = %s" % (vserver, i, v) self._vserver_has_document_root = False while True: more = self._process_virtual_server_content (vserver) if not more: break kind, val = self._lex.get_token() if kind != '}': raise "Expected }, got %s=%s" % (kind,val) if not self._vserver_has_document_root: print "vserver!%s!document_root = %s" % (vserver, FAKED_DOCUMENT_ROOT) print def process_sentence (self): kind, val = self._lex.get_token() if kind == None: return False self._lex.rewind() # Global server stuff ok = self._process_server_content () if ok: return True # Default virtual server ok = self._process_virtual_server_content () if ok: return True # Icons ok = self._process_icons_content () if ok: return True # Unknown: report error kind, val = self._lex.get_token() raise "Unknown token: %s = %s" % (kind, str(val)) def convert (self): print '# Cherokee 0.6.x configuration file generated by 05to06.py\n' print '# Copyright (C) 2006 Alvaro Lopez Ortega \n' print '# This program is distributed in the hope that it will be useful,' print '# but WITHOUT ANY WARRANTY, to the extent permitted by law; without' print '# even the implied warranty of MERCHANTABILITY or FITNESS FOR A' print '# PARTICULAR PURPOSE.\n\n' while True: more = self.process_sentence() if not more: break class Lexer: special_strings = ['server_info'] reserved_words = ['{', '}', 'porttls', 'port', 'directoryindex', 'directory', 'extension', 'request', 'handler', 'ipv6', 'timeout', 'keepalive', 'logflushinterval', 'maxkeepaliverequests', 'servertokens', 'encoder', 'log', 'server', 'allow', 'deny', 'pidfile', 'icons', 'mimefile', 'errorhandler', 'auth', 'include', 'listenqueuesize', 'listen', 'userdir', 'user','group', 'chroot', 'maxfds', 'maxconnectionreuse', 'panicaction', 'pollmethod', 'documentroot', 'threadnumber', 'policy', 'sendfile', 'file', 'suffix', 'parentdirectory', 'default', 'sslcertificatefile', 'sslcertificatekeyfile', 'sslcalistfile'] def __init__ (self, txt): self._txt = txt self._last = None,None self._rewinded = False def _find_consume (self, s): found = (self._txt.lower().find (s.lower()) == 0) if not found: return False self._txt = self._txt[len(s):] return True def _get_word (self): if len(self._txt) == 0: return '' word = '' # Quoted string if self._txt[0] == '"': word += self._txt[0] self._txt = self._txt[1:] while True: word += self._txt[0] self._txt = self._txt[1:] if word[-2] != '\\': if word[-1] == '"' or len(self._txt) is 0: break return word # Common word while True: while self._txt[0] not in " \t\r\n": word += self._txt[0] self._txt = self._txt[1:] if len(self._txt) is 0: break if word[-1] != ',': break while self._txt[0] in " \t": self._txt = self._txt[1:] return word def rewind (self): self._rewinded = True def get_token (self): if self._rewinded: self._rewinded = False return self._last self._last = self._get_token_guts() return self._last def _get_token_guts (self): self._txt = self._txt.strip() # Special cases for word in self.special_strings: if self._find_consume(word): return 'str',word # Reserved words for word in self.reserved_words: if self._find_consume(word): return word,None # Int int_val = None word = self._get_word() if len(word) is 0: return None, None try: int_val = int(word) except: pass if int_val is not None: return 'int',int_val # Path if word[0] == '/' or word[1:3] in [':\\', ':/']: return 'path',word # Quoted string if word[0] == word[-1] == '"': return 'str',word[1:-1] # List if word.find(',') != -1: return 'list',word # Boolean if word.lower() == 'on': return 'int',1 if word.lower() == 'off': return 'int',0 # Name is_name = True for c in word: if not c in string.letters and \ not c in string.digits and \ not c in "._-&?=:\\/*": is_name = False if is_name: return 'str',word raise "Couldn't extract token " + word class Converter: def __init__ (self, fin, fout): self._in = fin self._out = fout def convert (self): tmp = filter (lambda x: len(x) > 0 and x[0] != '#', map (lambda x: x.strip(), self._in.readlines())) if not len(tmp): return incoming = reduce (lambda x,y: x+' '+y, tmp) self.lex = Lexer (incoming) self.syn = Syntax (self.lex) self.syn.convert() def main (): c = Converter (sys.stdin, sys.stdout) c.convert() if __name__ == "__main__": main()