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

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

switched from using spider, added BasicHTTP authenticaion

  • Property svn:eol-style set to native
File size: 6.8 KB
Line 
1import os
2import socket
3import sys
4from time import time
5from paste.script.appinstall import Installer as BaseInstaller
6from paste.fileapp import FileApp
7from paste import urlparser
8from paste import request
9from paste.httpexceptions import HTTPNotFound
10import urllib2
11
12
13class PackageProxyApp(object):
14
15    def __init__(self, index_url=None, pack_dir=None, username=None,password=None,realm=None):
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()
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)
33        self.index_url = index_url
34        self.pack_dir = pack_dir
35
36    def __call__(self, environ, start_response):
37        """ serve the static files """
38        path = environ.get('PATH_INFO', '').strip()
39        path_parts = path.split('/')
40        if len(path_parts) > 1 and path_parts[1] == "favicon.ico":
41            return HTTPNotFound()(environ, start_response)
42        filename = self.checkCache(path[1:])
43        if filename is None:
44            return HTTPNotFound()(environ, start_response)
45        return FileApp(filename)(environ, start_response)
46
47    def checkCache(self, path):
48        """check if we already have the file and download it if not"""   
49        pth = self.pack_dir + path
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
57        else:
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()           
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)
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)
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):
106                start_response('200 OK', [('Content-Type', 'text/html')])
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
135        names = [i for i in os.listdir(path) if not i.startswith('.')]
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
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)
171"""
Note: See TracBrowser for help on using the repository browser.