source: products/quintagroup.distrpoxy/trunk/quintagroup/distproxy/wsgi.py @ 1603

Last change on this file since 1603 was 1603, checked in by chervol, 14 years ago

switched from using spider, added BasicHTTP authenticaion

  • Property svn:eol-style set to native
File size: 6.8 KB
RevLine 
[1066]1import os
2import socket
3import sys
[1587]4from time import time
[1066]5from paste.script.appinstall import Installer as BaseInstaller
6from paste.fileapp import FileApp
[1082]7from paste import urlparser
8from paste import request
[1066]9from paste.httpexceptions import HTTPNotFound
[1603]10import urllib2
[1066]11
[1603]12
[1066]13class PackageProxyApp(object):
14
[1603]15    def __init__(self, index_url=None, pack_dir=None, username=None,password=None,realm=None):
[1066]16        if not index_url: 
17            print "No repository index provided"
18            sys.exit()
19        if not pack_dir:
20            print "No packages cache directory provided"
21            sys.exit()
22        if not os.path.isdir(pack_dir):
23            print 'You must create the %r directory' % pack_dir
24            sys.exit()
[1603]25        if username and password:
26            # authenticate
27            password_mgr = urllib2.HTTPPasswordMgrWithDefaultRealm()
28            top_level_url = index_url
29            password_mgr.add_password(realm, top_level_url, username, password)
30            handler = urllib2.HTTPBasicAuthHandler(password_mgr)
31            opener = urllib2.build_opener(handler)
32            urllib2.install_opener(opener)
[1066]33        self.index_url = index_url
34        self.pack_dir = pack_dir
35
36    def __call__(self, environ, start_response):
[1603]37        """ serve the static files """
[1066]38        path = environ.get('PATH_INFO', '').strip()
[1083]39        path_parts = path.split('/')
40        if len(path_parts) > 1 and path_parts[1] == "favicon.ico":
[1082]41            return HTTPNotFound()(environ, start_response)
[1603]42        filename = self.checkCache(path[1:])
[1066]43        if filename is None:
44            return HTTPNotFound()(environ, start_response)
45        return FileApp(filename)(environ, start_response)
46
[1603]47    def checkCache(self, path):
48        """check if we already have the file and download it if not"""   
[1066]49        pth = self.pack_dir + path
[1603]50        index =0 
51        if not (path[-3:] in ['ico','txt','tgz','.gz','egg','zip','exe','cfg']): 
52            if not os.path.exists(pth):
53              os.makedirs(pth) #create dir if it is not there
54            # add index.html for supposedly folders
55            pth = pth + 'index.html'
56            index = 1
[1066]57        else:
[1603]58            pth1 = '/'.join(pth.split('/')[:-1])
59            if not os.path.exists(pth):
60              os.makedirs(pth1)#create parent dir if it is not there
61        url = self.index_url+path
62        #if we dont have download it
63        if not os.path.exists(pth):
64            f = urllib2.urlopen(url)
65            lf = open(pth,'wb')
66            lf.write(f.read())
67            lf.close()
68        #if we have the index.html file if it is older the 1 hour update
69        elif index and int(time()) - os.path.getmtime(pth) > 3600:
70            f = urllib2.urlopen(url)
71            lf = open(pth,'wb')
72            lf.write(f.read())
73            lf.close()           
[1066]74        return pth
75
76def app_factory(global_config, **local_conf):
77    # Grab config from wsgi .ini file. If not specified, config.py's values
78    # take over.
79    pack_dir = local_conf.get('pack_directory', None)
80    index_url = local_conf.get('index', None)
[1603]81    username = local_conf.get('username', None)
82    password = local_conf.get('password', None)
83    realm = local_conf.get('realm', None)
84    return PackageProxyApp(index_url, pack_dir, username, password, realm)
[1082]85
86class StaticURLParser(urlparser.StaticURLParser):
87
88    def __call__(self, environ, start_response):
89        path_info = environ.get('PATH_INFO', '')
90        if not path_info:
91            return self.add_slash(environ, start_response)
92        if path_info == '/':
93            # @@: This should obviously be configurable
94            filename = 'index.html'
95        else:
96            filename = request.path_info_pop(environ)
97        full = os.path.normcase(os.path.normpath(
98            os.path.join(self.directory, filename)))
99        if os.path.sep != '/':
100            full = full.replace('/', os.path.sep)
101        if self.root_directory is not None and not full.startswith(self.root_directory):
102            # Out of bounds
103            return self.not_found(environ, start_response)
104        if not os.path.exists(full):
105            if full.endswith('index.html') and not os.path.isfile(full):
[1083]106                start_response('200 OK', [('Content-Type', 'text/html')])
[1082]107                return [self.get_index_html()]
108            return self.not_found(environ, start_response)
109        if os.path.isdir(full):
110            # @@: Cache?
111            child_root = self.root_directory is not None and \
112                self.root_directory or self.directory
113            return self.__class__(full, root_directory=child_root,
114                                  cache_max_age=self.cache_max_age)(environ,
115                                                                   start_response)
116        if environ.get('PATH_INFO') and environ.get('PATH_INFO') != '/':
117            return self.error_extra_path(environ, start_response)
118        if_none_match = environ.get('HTTP_IF_NONE_MATCH')
119        if if_none_match:
120            mytime = os.stat(full).st_mtime
121            if str(mytime) == if_none_match:
122                headers = []
123                ETAG.update(headers, mytime)
124                start_response('304 Not Modified', headers)
125                return [''] # empty body
126
127        fa = self.make_app(full)
128        if self.cache_max_age:
129            fa.cache_control(max_age=self.cache_max_age)
130        return fa(environ, start_response)
131
132    def get_index_html(self):
133        path = self.directory
134        # create sorted lists of directories and files
[1083]135        names = [i for i in os.listdir(path) if not i.startswith('.')]
[1082]136        dirs = [i for i in names if os.path.isdir(os.path.join(path, i))]
137        dirs.sort()
138        files = [i for i in names if os.path.isfile(os.path.join(path, i))]
139        files.sort()
140        names = dirs + files
141        links = '\n'.join(['<li><a href="%s">%s</a></li>' %  (i, i) for i in names])
142        template = open(os.path.join(os.path.dirname(__file__), 'index.html')).read()
143        return template % {'path': path[len(self.root_directory):], 'links': links}
144
145def make_static(global_conf, document_root, cache_max_age=None):
146    """
147    Return a WSGI application that serves a directory (configured
148    with document_root)
149
150    cache_max_age - integer specifies CACHE_CONTROL max_age in seconds
151    """
152    if cache_max_age is not None:
153        cache_max_age = int(cache_max_age)
154    return StaticURLParser(
155        document_root, cache_max_age=cache_max_age)
156
157
[1066]158"""
159class Installer(BaseInstaller):
160    use_cheetah = False
161    config_file = 'deployment.ini_tmpl'
162
163    def config_content(self, command, vars):
164        import pkg_resources
165        module = 'collective.eggproxy'
166        if pkg_resources.resource_exists(module, self.config_file):
167            return self.template_renderer(
168                pkg_resources.resource_string(module, self.config_file),
169                vars,
170                filename=self.config_file)
[1260]171"""
Note: See TracBrowser for help on using the repository browser.