thirdparty/google_appengine/google/appengine/tools/dev_appserver.py
changeset 2273 e4cb9c53db3e
parent 2172 ac7bd3b467ff
child 2309 be1b94099f2d
equal deleted inserted replaced
2272:26491ee91e33 2273:e4cb9c53db3e
    37 import BaseHTTPServer
    37 import BaseHTTPServer
    38 import Cookie
    38 import Cookie
    39 import cStringIO
    39 import cStringIO
    40 import cgi
    40 import cgi
    41 import cgitb
    41 import cgitb
       
    42 
       
    43 try:
       
    44   import distutils.util
       
    45 except ImportError:
       
    46   pass
       
    47 
    42 import dummy_thread
    48 import dummy_thread
    43 import email.Utils
    49 import email.Utils
    44 import errno
    50 import errno
    45 import httplib
    51 import httplib
    46 import imp
    52 import imp
   256         URL; False if anyone can access this URL.
   262         URL; False if anyone can access this URL.
   257       admin_only: True if the user must be a logged-in administrator to
   263       admin_only: True if the user must be a logged-in administrator to
   258         access the URL; False if anyone can access the URL.
   264         access the URL; False if anyone can access the URL.
   259     """
   265     """
   260     if not isinstance(dispatcher, URLDispatcher):
   266     if not isinstance(dispatcher, URLDispatcher):
   261       raise TypeError, 'dispatcher must be a URLDispatcher sub-class'
   267       raise TypeError('dispatcher must be a URLDispatcher sub-class')
   262 
   268 
   263     if regex.startswith('^') or regex.endswith('$'):
   269     if regex.startswith('^') or regex.endswith('$'):
   264       raise InvalidAppConfigError, 'regex starts with "^" or ends with "$"'
   270       raise InvalidAppConfigError('regex starts with "^" or ends with "$"')
   265 
   271 
   266     adjusted_regex = '^%s$' % regex
   272     adjusted_regex = '^%s$' % regex
   267 
   273 
   268     try:
   274     try:
   269       url_re = re.compile(adjusted_regex)
   275       url_re = re.compile(adjusted_regex)
   270     except re.error, e:
   276     except re.error, e:
   271       raise InvalidAppConfigError, 'regex invalid: %s' % e
   277       raise InvalidAppConfigError('regex invalid: %s' % e)
   272 
   278 
   273     match_tuple = (url_re, dispatcher, path, requires_login, admin_only)
   279     match_tuple = (url_re, dispatcher, path, requires_login, admin_only)
   274     self._url_patterns.append(match_tuple)
   280     self._url_patterns.append(match_tuple)
   275 
   281 
   276   def Match(self,
   282   def Match(self,
   346     Matchers are checked in the order they were supplied to the constructor.
   352     Matchers are checked in the order they were supplied to the constructor.
   347     If no matcher matches, a 404 error will be written to the outfile. The
   353     If no matcher matches, a 404 error will be written to the outfile. The
   348     path variable supplied to this method is ignored.
   354     path variable supplied to this method is ignored.
   349     """
   355     """
   350     cookies = ', '.join(headers.getheaders('cookie'))
   356     cookies = ', '.join(headers.getheaders('cookie'))
   351     email, admin = self._get_user_info(cookies)
   357     email, admin, user_id = self._get_user_info(cookies)
   352 
   358 
   353     for matcher in self._url_matchers:
   359     for matcher in self._url_matchers:
   354       dispatcher, matched_path, requires_login, admin_only = matcher.Match(relative_url)
   360       dispatcher, matched_path, requires_login, admin_only = matcher.Match(relative_url)
   355       if dispatcher is None:
   361       if dispatcher is None:
   356         continue
   362         continue
   538   env['CONTENT_TYPE'] = headers.getheader('content-type',
   544   env['CONTENT_TYPE'] = headers.getheader('content-type',
   539                                           'application/x-www-form-urlencoded')
   545                                           'application/x-www-form-urlencoded')
   540   env['CONTENT_LENGTH'] = headers.getheader('content-length', '')
   546   env['CONTENT_LENGTH'] = headers.getheader('content-length', '')
   541 
   547 
   542   cookies = ', '.join(headers.getheaders('cookie'))
   548   cookies = ', '.join(headers.getheaders('cookie'))
   543   email, admin = get_user_info(cookies)
   549   email, admin, user_id = get_user_info(cookies)
   544   env['USER_EMAIL'] = email
   550   env['USER_EMAIL'] = email
       
   551   env['USER_ID'] = user_id
   545   if admin:
   552   if admin:
   546     env['USER_IS_ADMIN'] = '1'
   553     env['USER_IS_ADMIN'] = '1'
   547 
   554 
   548   for key in headers:
   555   for key in headers:
   549     if key in _IGNORE_REQUEST_HEADERS:
   556     if key in _IGNORE_REQUEST_HEADERS:
   613 
   620 
   614 
   621 
   615 def FakeUnlink(path):
   622 def FakeUnlink(path):
   616   """Fake version of os.unlink."""
   623   """Fake version of os.unlink."""
   617   if os.path.isdir(path):
   624   if os.path.isdir(path):
   618     raise OSError(2, "Is a directory", path)
   625     raise OSError(errno.ENOENT, "Is a directory", path)
   619   else:
   626   else:
   620     raise OSError(1, "Operation not permitted", path)
   627     raise OSError(errno.EPERM, "Operation not permitted", path)
   621 
   628 
   622 
   629 
   623 def FakeReadlink(path):
   630 def FakeReadlink(path):
   624   """Fake version of os.readlink."""
   631   """Fake version of os.readlink."""
   625   raise OSError(22, "Invalid argument", path)
   632   raise OSError(errno.EINVAL, "Invalid argument", path)
   626 
   633 
   627 
   634 
   628 def FakeAccess(path, mode):
   635 def FakeAccess(path, mode):
   629   """Fake version of os.access where only reads are supported."""
   636   """Fake version of os.access where only reads are supported."""
   630   if not os.path.exists(path) or mode != os.R_OK:
   637   if not os.path.exists(path) or mode != os.R_OK:
   634 
   641 
   635 
   642 
   636 def FakeSetLocale(category, value=None, original_setlocale=locale.setlocale):
   643 def FakeSetLocale(category, value=None, original_setlocale=locale.setlocale):
   637   """Fake version of locale.setlocale that only supports the default."""
   644   """Fake version of locale.setlocale that only supports the default."""
   638   if value not in (None, '', 'C', 'POSIX'):
   645   if value not in (None, '', 'C', 'POSIX'):
   639     raise locale.Error, 'locale emulation only supports "C" locale'
   646     raise locale.Error('locale emulation only supports "C" locale')
   640   return original_setlocale(category, 'C')
   647   return original_setlocale(category, 'C')
       
   648 
       
   649 
       
   650 def FakeOpen(file, flags, mode=0777):
       
   651   """Fake version of os.open."""
       
   652   raise OSError(errno.EPERM, "Operation not permitted", file)
       
   653 
       
   654 
       
   655 def FakeRename(src, dst):
       
   656   """Fake version of os.rename."""
       
   657   raise OSError(errno.EPERM, "Operation not permitted", src)
       
   658 
       
   659 
       
   660 def FakeUTime(path, times):
       
   661   """Fake version of os.utime."""
       
   662   raise OSError(errno.EPERM, "Operation not permitted", path)
       
   663 
       
   664 
       
   665 def FakeGetPlatform():
       
   666   """Fake distutils.util.get_platform on OS/X.  Pass-through otherwise."""
       
   667   if sys.platform == 'darwin':
       
   668     return 'macosx-'
       
   669   else:
       
   670     return distutils.util.get_platform()
   641 
   671 
   642 
   672 
   643 def IsPathInSubdirectories(filename,
   673 def IsPathInSubdirectories(filename,
   644                            subdirectories,
   674                            subdirectories,
   645                            normcase=os.path.normcase):
   675                            normcase=os.path.normcase):
   737       output_dict[module_name] = module
   767       output_dict[module_name] = module
   738 
   768 
   739   return output_dict
   769   return output_dict
   740 
   770 
   741 
   771 
       
   772 def GeneratePythonPaths(*p):
       
   773   """Generate all valid filenames for the given file
       
   774 
       
   775   Args:
       
   776     p: Positional args are the folders to the file and finally the file
       
   777        without a suffix.
       
   778 
       
   779   Returns:
       
   780     A list of strings representing the given path to a file with each valid
       
   781       suffix for this python build.
       
   782   """
       
   783   suffixes = imp.get_suffixes()
       
   784   return [os.path.join(*p) + s for s, m, t in suffixes]
       
   785 
       
   786 
   742 class FakeFile(file):
   787 class FakeFile(file):
   743   """File sub-class that enforces the security restrictions of the production
   788   """File sub-class that enforces the security restrictions of the production
   744   environment.
   789   environment.
   745   """
   790   """
   746 
   791 
   768     os.path.normcase(os.path.abspath(os.path.join(
   813     os.path.normcase(os.path.abspath(os.path.join(
   769       os.path.dirname(os.__file__), 'site-packages', path)))
   814       os.path.dirname(os.__file__), 'site-packages', path)))
   770     for path in [
   815     for path in [
   771 
   816 
   772   ])
   817   ])
       
   818 
       
   819   ALLOWED_SITE_PACKAGE_FILES = set(
       
   820     os.path.normcase(os.path.abspath(os.path.join(
       
   821       os.path.dirname(os.__file__), 'site-packages', path)))
       
   822     for path in itertools.chain(*[
       
   823 
       
   824       [os.path.join('Crypto')],
       
   825       GeneratePythonPaths('Crypto', '__init__'),
       
   826       [os.path.join('Crypto', 'Cipher')],
       
   827       GeneratePythonPaths('Crypto', 'Cipher', '__init__'),
       
   828       GeneratePythonPaths('Crypto', 'Cipher', 'AES'),
       
   829       GeneratePythonPaths('Crypto', 'Cipher', 'ARC2'),
       
   830       GeneratePythonPaths('Crypto', 'Cipher', 'ARC4'),
       
   831       GeneratePythonPaths('Crypto', 'Cipher', 'Blowfish'),
       
   832       GeneratePythonPaths('Crypto', 'Cipher', 'CAST'),
       
   833       GeneratePythonPaths('Crypto', 'Cipher', 'DES'),
       
   834       GeneratePythonPaths('Crypto', 'Cipher', 'DES3'),
       
   835       GeneratePythonPaths('Crypto', 'Cipher', 'XOR'),
       
   836       [os.path.join('Crypto', 'Hash')],
       
   837       GeneratePythonPaths('Crypto', 'Hash', '__init__'),
       
   838       GeneratePythonPaths('Crypto', 'Hash', 'HMAC'),
       
   839       os.path.join('Crypto', 'Hash', 'MD2'),
       
   840       os.path.join('Crypto', 'Hash', 'MD4'),
       
   841       GeneratePythonPaths('Crypto', 'Hash', 'MD5'),
       
   842       GeneratePythonPaths('Crypto', 'Hash', 'SHA'),
       
   843       os.path.join('Crypto', 'Hash', 'SHA256'),
       
   844       os.path.join('Crypto', 'Hash', 'RIPEMD'),
       
   845       [os.path.join('Crypto', 'Protocol')],
       
   846       GeneratePythonPaths('Crypto', 'Protocol', '__init__'),
       
   847       GeneratePythonPaths('Crypto', 'Protocol', 'AllOrNothing'),
       
   848       GeneratePythonPaths('Crypto', 'Protocol', 'Chaffing'),
       
   849       [os.path.join('Crypto', 'PublicKey')],
       
   850       GeneratePythonPaths('Crypto', 'PublicKey', '__init__'),
       
   851       GeneratePythonPaths('Crypto', 'PublicKey', 'DSA'),
       
   852       GeneratePythonPaths('Crypto', 'PublicKey', 'ElGamal'),
       
   853       GeneratePythonPaths('Crypto', 'PublicKey', 'RSA'),
       
   854       GeneratePythonPaths('Crypto', 'PublicKey', 'pubkey'),
       
   855       GeneratePythonPaths('Crypto', 'PublicKey', 'qNEW'),
       
   856       [os.path.join('Crypto', 'Util')],
       
   857       GeneratePythonPaths('Crypto', 'Util', '__init__'),
       
   858       GeneratePythonPaths('Crypto', 'Util', 'RFC1751'),
       
   859       GeneratePythonPaths('Crypto', 'Util', 'number'),
       
   860       GeneratePythonPaths('Crypto', 'Util', 'randpool'),
       
   861   ]))
   773 
   862 
   774   _original_file = file
   863   _original_file = file
   775 
   864 
   776   _root_path = None
   865   _root_path = None
   777   _application_paths = None
   866   _application_paths = None
   860 
   949 
   861     Returns:
   950     Returns:
   862       True if the file is accessible, False otherwise.
   951       True if the file is accessible, False otherwise.
   863     """
   952     """
   864     logical_filename = normcase(os.path.abspath(filename))
   953     logical_filename = normcase(os.path.abspath(filename))
   865 
       
   866     if os.path.isdir(logical_filename):
       
   867       logical_filename = os.path.join(logical_filename, 'foo')
       
   868 
   954 
   869     result = FakeFile._availability_cache.get(logical_filename)
   955     result = FakeFile._availability_cache.get(logical_filename)
   870     if result is None:
   956     if result is None:
   871       result = FakeFile._IsFileAccessibleNoCache(logical_filename,
   957       result = FakeFile._IsFileAccessibleNoCache(logical_filename,
   872                                                  normcase=normcase)
   958                                                  normcase=normcase)
   884       normcase: Used for dependency injection.
   970       normcase: Used for dependency injection.
   885 
   971 
   886     Returns:
   972     Returns:
   887       True if the file is accessible, False otherwise.
   973       True if the file is accessible, False otherwise.
   888     """
   974     """
   889     if IsPathInSubdirectories(logical_filename, [FakeFile._root_path],
   975     logical_dirfakefile = logical_filename
       
   976     if os.path.isdir(logical_filename):
       
   977       logical_dirfakefile = os.path.join(logical_filename, 'foo')
       
   978 
       
   979     if IsPathInSubdirectories(logical_dirfakefile, [FakeFile._root_path],
   890                               normcase=normcase):
   980                               normcase=normcase):
   891       relative_filename = logical_filename[len(FakeFile._root_path):]
   981       relative_filename = logical_dirfakefile[len(FakeFile._root_path):]
   892 
   982 
   893       if (not FakeFile._allow_skipped_files and
   983       if (not FakeFile._allow_skipped_files and
   894           FakeFile._skip_files.match(relative_filename)):
   984           FakeFile._skip_files.match(relative_filename)):
   895         logging.warning('Blocking access to skipped file "%s"',
   985         logging.warning('Blocking access to skipped file "%s"',
   896                         logical_filename)
   986                         logical_filename)
   902         return False
   992         return False
   903 
   993 
   904     if logical_filename in FakeFile.ALLOWED_FILES:
   994     if logical_filename in FakeFile.ALLOWED_FILES:
   905       return True
   995       return True
   906 
   996 
   907     if IsPathInSubdirectories(logical_filename,
   997     if logical_filename in FakeFile.ALLOWED_SITE_PACKAGE_FILES:
       
   998       return True
       
   999 
       
  1000     if IsPathInSubdirectories(logical_dirfakefile,
   908                               FakeFile.ALLOWED_SITE_PACKAGE_DIRS,
  1001                               FakeFile.ALLOWED_SITE_PACKAGE_DIRS,
   909                               normcase=normcase):
  1002                               normcase=normcase):
   910       return True
  1003       return True
   911 
  1004 
   912     allowed_dirs = FakeFile._application_paths | FakeFile.ALLOWED_DIRS
  1005     allowed_dirs = FakeFile._application_paths | FakeFile.ALLOWED_DIRS
   913     if (IsPathInSubdirectories(logical_filename,
  1006     if (IsPathInSubdirectories(logical_dirfakefile,
   914                                allowed_dirs,
  1007                                allowed_dirs,
   915                                normcase=normcase) and
  1008                                normcase=normcase) and
   916         not IsPathInSubdirectories(logical_filename,
  1009         not IsPathInSubdirectories(logical_dirfakefile,
   917                                    FakeFile.NOT_ALLOWED_DIRS,
  1010                                    FakeFile.NOT_ALLOWED_DIRS,
   918                                    normcase=normcase)):
  1011                                    normcase=normcase)):
   919       return True
  1012       return True
   920 
  1013 
   921     return False
  1014     return False
   924     """Initializer. See file built-in documentation."""
  1017     """Initializer. See file built-in documentation."""
   925     if mode not in FakeFile.ALLOWED_MODES:
  1018     if mode not in FakeFile.ALLOWED_MODES:
   926       raise IOError('invalid mode: %s' % mode)
  1019       raise IOError('invalid mode: %s' % mode)
   927 
  1020 
   928     if not FakeFile.IsFileAccessible(filename):
  1021     if not FakeFile.IsFileAccessible(filename):
   929       raise IOError(errno.EACCES, 'file not accessible')
  1022       raise IOError(errno.EACCES, 'file not accessible', filename)
   930 
  1023 
   931     super(FakeFile, self).__init__(filename, mode, bufsize, **kwargs)
  1024     super(FakeFile, self).__init__(filename, mode, bufsize, **kwargs)
   932 
  1025 
   933 
  1026 
   934 class RestrictedPathFunction(object):
  1027 class RestrictedPathFunction(object):
   948 
  1041 
   949   def __call__(self, path, *args, **kwargs):
  1042   def __call__(self, path, *args, **kwargs):
   950     """Enforces access permissions for the function passed to the constructor.
  1043     """Enforces access permissions for the function passed to the constructor.
   951     """
  1044     """
   952     if not FakeFile.IsFileAccessible(path):
  1045     if not FakeFile.IsFileAccessible(path):
   953       raise OSError(errno.EACCES, 'path not accessible')
  1046       raise OSError(errno.EACCES, 'path not accessible', path)
   954 
  1047 
   955     return self._original_func(path, *args, **kwargs)
  1048     return self._original_func(path, *args, **kwargs)
   956 
  1049 
   957 
  1050 
   958 def GetSubmoduleName(fullname):
  1051 def GetSubmoduleName(fullname):
  1033     if HardenedModulesHook.ENABLE_LOGGING:
  1126     if HardenedModulesHook.ENABLE_LOGGING:
  1034       indent = self._indent_level * '  '
  1127       indent = self._indent_level * '  '
  1035       print >>sys.stderr, indent + (message % args)
  1128       print >>sys.stderr, indent + (message % args)
  1036 
  1129 
  1037   _WHITE_LIST_C_MODULES = [
  1130   _WHITE_LIST_C_MODULES = [
       
  1131     'AES',
       
  1132     'ARC2',
       
  1133     'ARC4',
       
  1134     'Blowfish',
       
  1135     'CAST',
       
  1136     'DES',
       
  1137     'DES3',
       
  1138     'MD2',
       
  1139     'MD4',
       
  1140     'RIPEMD',
       
  1141     'SHA256',
       
  1142     'XOR',
       
  1143 
       
  1144     '_Crypto_Cipher__AES',
       
  1145     '_Crypto_Cipher__ARC2',
       
  1146     '_Crypto_Cipher__ARC4',
       
  1147     '_Crypto_Cipher__Blowfish',
       
  1148     '_Crypto_Cipher__CAST',
       
  1149     '_Crypto_Cipher__DES',
       
  1150     '_Crypto_Cipher__DES3',
       
  1151     '_Crypto_Cipher__XOR',
       
  1152     '_Crypto_Hash__MD2',
       
  1153     '_Crypto_Hash__MD4',
       
  1154     '_Crypto_Hash__RIPEMD',
       
  1155     '_Crypto_Hash__SHA256',
  1038     'array',
  1156     'array',
  1039     'binascii',
  1157     'binascii',
  1040     'bz2',
  1158     'bz2',
  1041     'cmath',
  1159     'cmath',
  1042     'collections',
  1160     'collections',
  1087     '_types',
  1205     '_types',
  1088     '_weakref',
  1206     '_weakref',
  1089     '__main__',
  1207     '__main__',
  1090   ]
  1208   ]
  1091 
  1209 
       
  1210   __CRYPTO_CIPHER_ALLOWED_MODULES = [
       
  1211     'MODE_CBC',
       
  1212     'MODE_CFB',
       
  1213     'MODE_CTR',
       
  1214     'MODE_ECB',
       
  1215     'MODE_OFB',
       
  1216     'block_size',
       
  1217     'key_size',
       
  1218     'new',
       
  1219   ]
  1092   _WHITE_LIST_PARTIAL_MODULES = {
  1220   _WHITE_LIST_PARTIAL_MODULES = {
       
  1221     'Crypto.Cipher.AES': __CRYPTO_CIPHER_ALLOWED_MODULES,
       
  1222     'Crypto.Cipher.ARC2': __CRYPTO_CIPHER_ALLOWED_MODULES,
       
  1223     'Crypto.Cipher.Blowfish': __CRYPTO_CIPHER_ALLOWED_MODULES,
       
  1224     'Crypto.Cipher.CAST': __CRYPTO_CIPHER_ALLOWED_MODULES,
       
  1225     'Crypto.Cipher.DES': __CRYPTO_CIPHER_ALLOWED_MODULES,
       
  1226     'Crypto.Cipher.DES3': __CRYPTO_CIPHER_ALLOWED_MODULES,
       
  1227 
  1093     'gc': [
  1228     'gc': [
  1094       'enable',
  1229       'enable',
  1095       'disable',
  1230       'disable',
  1096       'isenabled',
  1231       'isenabled',
  1097       'collect',
  1232       'collect',
  1147       'O_RDWR',
  1282       'O_RDWR',
  1148       'O_RSYNC',
  1283       'O_RSYNC',
  1149       'O_SYNC',
  1284       'O_SYNC',
  1150       'O_TRUNC',
  1285       'O_TRUNC',
  1151       'O_WRONLY',
  1286       'O_WRONLY',
       
  1287       'open',
  1152       'pardir',
  1288       'pardir',
  1153       'path',
  1289       'path',
  1154       'pathsep',
  1290       'pathsep',
  1155       'R_OK',
  1291       'R_OK',
  1156       'readlink',
  1292       'readlink',
  1157       'remove',
  1293       'remove',
       
  1294       'rename',
  1158       'SEEK_CUR',
  1295       'SEEK_CUR',
  1159       'SEEK_END',
  1296       'SEEK_END',
  1160       'SEEK_SET',
  1297       'SEEK_SET',
  1161       'sep',
  1298       'sep',
  1162       'stat',
  1299       'stat',
  1164       'stat_result',
  1301       'stat_result',
  1165       'strerror',
  1302       'strerror',
  1166       'TMP_MAX',
  1303       'TMP_MAX',
  1167       'unlink',
  1304       'unlink',
  1168       'urandom',
  1305       'urandom',
       
  1306       'utime',
  1169       'walk',
  1307       'walk',
  1170       'WCOREDUMP',
  1308       'WCOREDUMP',
  1171       'WEXITSTATUS',
  1309       'WEXITSTATUS',
  1172       'WIFEXITED',
  1310       'WIFEXITED',
  1173       'WIFSIGNALED',
  1311       'WIFSIGNALED',
  1189     'os': {
  1327     'os': {
  1190       'access': FakeAccess,
  1328       'access': FakeAccess,
  1191       'listdir': RestrictedPathFunction(os.listdir),
  1329       'listdir': RestrictedPathFunction(os.listdir),
  1192 
  1330 
  1193       'lstat': RestrictedPathFunction(os.stat),
  1331       'lstat': RestrictedPathFunction(os.stat),
       
  1332       'open': FakeOpen,
  1194       'readlink': FakeReadlink,
  1333       'readlink': FakeReadlink,
  1195       'remove': FakeUnlink,
  1334       'remove': FakeUnlink,
       
  1335       'rename': FakeRename,
  1196       'stat': RestrictedPathFunction(os.stat),
  1336       'stat': RestrictedPathFunction(os.stat),
  1197       'uname': FakeUname,
  1337       'uname': FakeUname,
  1198       'unlink': FakeUnlink,
  1338       'unlink': FakeUnlink,
  1199       'urandom': FakeURandom,
  1339       'urandom': FakeURandom,
       
  1340       'utime': FakeUTime,
       
  1341     },
       
  1342 
       
  1343     'distutils.util': {
       
  1344       'get_platform': FakeGetPlatform,
  1200     },
  1345     },
  1201   }
  1346   }
  1202 
  1347 
  1203   _ENABLED_FILE_TYPES = (
  1348   _ENABLED_FILE_TYPES = (
  1204     imp.PKG_DIRECTORY,
  1349     imp.PKG_DIRECTORY,
  1481     elif submodule_fullname == 'cPickle':
  1626     elif submodule_fullname == 'cPickle':
  1482       module.__dict__.update(self._pickle.__dict__)
  1627       module.__dict__.update(self._pickle.__dict__)
  1483       module.__name__ = 'cPickle'
  1628       module.__name__ = 'cPickle'
  1484     elif submodule_fullname == 'os':
  1629     elif submodule_fullname == 'os':
  1485       module.__dict__.update(self._os.__dict__)
  1630       module.__dict__.update(self._os.__dict__)
  1486       self._module_dict['os.path'] = module.path
       
  1487     elif self.StubModuleExists(submodule_fullname):
  1631     elif self.StubModuleExists(submodule_fullname):
  1488       module = self.ImportStubModule(submodule_fullname)
  1632       module = self.ImportStubModule(submodule_fullname)
  1489     else:
  1633     else:
  1490       source_file, pathname, description = self.FindModuleRestricted(submodule, submodule_fullname, search_path)
  1634       source_file, pathname, description = self.FindModuleRestricted(submodule, submodule_fullname, search_path)
  1491       module = self.LoadModuleRestricted(submodule_fullname,
  1635       module = self.LoadModuleRestricted(submodule_fullname,
  1495 
  1639 
  1496     module.__loader__ = self
  1640     module.__loader__ = self
  1497     self.FixModule(module)
  1641     self.FixModule(module)
  1498     if submodule_fullname not in self._module_dict:
  1642     if submodule_fullname not in self._module_dict:
  1499       self._module_dict[submodule_fullname] = module
  1643       self._module_dict[submodule_fullname] = module
       
  1644 
       
  1645     if submodule_fullname == 'os':
       
  1646       os_path_name = module.path.__name__
       
  1647       os_path = self.FindAndLoadModule(os_path_name, os_path_name, search_path)
       
  1648       self._module_dict['os.path'] = os_path
       
  1649       module.__dict__['path'] = os_path
  1500 
  1650 
  1501     return module
  1651     return module
  1502 
  1652 
  1503   @Trace
  1653   @Trace
  1504   def GetParentPackage(self, fullname):
  1654   def GetParentPackage(self, fullname):
  3011     smtp_user: SMTP user.
  3161     smtp_user: SMTP user.
  3012     smtp_password: SMTP password.
  3162     smtp_password: SMTP password.
  3013     enable_sendmail: Whether to use sendmail as an alternative to SMTP.
  3163     enable_sendmail: Whether to use sendmail as an alternative to SMTP.
  3014     show_mail_body: Whether to log the body of emails.
  3164     show_mail_body: Whether to log the body of emails.
  3015     remove: Used for dependency injection.
  3165     remove: Used for dependency injection.
       
  3166     trusted: True if this app can access data belonging to other apps.  This
       
  3167       behavior is different from the real app server and should be left False
       
  3168       except for advanced uses of dev_appserver.
  3016   """
  3169   """
  3017   login_url = config['login_url']
  3170   login_url = config['login_url']
  3018   datastore_path = config['datastore_path']
  3171   datastore_path = config['datastore_path']
  3019   history_path = config['history_path']
  3172   history_path = config['history_path']
  3020   clear_datastore = config['clear_datastore']
  3173   clear_datastore = config['clear_datastore']
  3024   smtp_user = config.get('smtp_user', '')
  3177   smtp_user = config.get('smtp_user', '')
  3025   smtp_password = config.get('smtp_password', '')
  3178   smtp_password = config.get('smtp_password', '')
  3026   enable_sendmail = config.get('enable_sendmail', False)
  3179   enable_sendmail = config.get('enable_sendmail', False)
  3027   show_mail_body = config.get('show_mail_body', False)
  3180   show_mail_body = config.get('show_mail_body', False)
  3028   remove = config.get('remove', os.remove)
  3181   remove = config.get('remove', os.remove)
       
  3182   trusted = config.get('trusted', False)
  3029 
  3183 
  3030   os.environ['APPLICATION_ID'] = app_id
  3184   os.environ['APPLICATION_ID'] = app_id
  3031 
  3185 
  3032   if clear_datastore:
  3186   if clear_datastore:
  3033     for path in (datastore_path, history_path):
  3187     for path in (datastore_path, history_path):
  3039           logging.warning('Removing file failed: %s', e)
  3193           logging.warning('Removing file failed: %s', e)
  3040 
  3194 
  3041   apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
  3195   apiproxy_stub_map.apiproxy = apiproxy_stub_map.APIProxyStubMap()
  3042 
  3196 
  3043   datastore = datastore_file_stub.DatastoreFileStub(
  3197   datastore = datastore_file_stub.DatastoreFileStub(
  3044       app_id, datastore_path, history_path, require_indexes=require_indexes)
  3198       app_id, datastore_path, history_path, require_indexes=require_indexes,
       
  3199       trusted=trusted)
  3045   apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', datastore)
  3200   apiproxy_stub_map.apiproxy.RegisterStub('datastore_v3', datastore)
  3046 
  3201 
  3047   fixed_login_url = '%s?%s=%%s' % (login_url,
  3202   fixed_login_url = '%s?%s=%%s' % (login_url,
  3048                                    dev_appserver_login.CONTINUE_PARAM)
  3203                                    dev_appserver_login.CONTINUE_PARAM)
  3049   fixed_logout_url = '%s&%s' % (fixed_login_url,
  3204   fixed_logout_url = '%s&%s' % (fixed_login_url,