def mklisting(self, listing, start_response): container_info = self._get_container_info().get('meta', {}) # Load the template template_name = container_info.get('web-listings-template') if template_name and template_name != '-': if template_name.startswith("../"): template_path = "/v1/%s/%s" % (self.account, template_name[3:]) else: template_path = "/v1/%s/%s/%s" % ( self.account, self.container, template_name) # TODO: ponder whether this should be preauthenticated status, headers, answer = self.do_internal_get(template_path) if status[0] == '2': template = answer else: # Forward any errors. start_response(status, headers) return answer else: template = default_template # Try to find a local handler. local_path = os.path.join( self.conf.get('template_path', __file__), "index.html") try: with open(local_path, 'r') as f: template = f.read() except IOError: pass for subdir in listing['subdirs']: if 'bytes' in subdir: subdir['size'] = human_readable(subdir['bytes']) subdir['size_num'], subdir[ 'size_unit'] = human_readable_size(subdir['bytes']) subdir.setdefault('subdir', subdir.get('name')) for fil in listing['files']: fil['size'] = human_readable(fil['bytes']) fil['size_num'], fil[ 'size_unit'] = human_readable_size(fil['bytes']) fil['date'] = fil['last_modified'] fil['type_classes'] = " ".join( ('type-%s' % t.replace(".", '-')) for t in fil['content_type'].split('/')) if '.' in fil['name']: fil['type_classes'] += " ext-" + fil['name'].rsplit('.', 1)[-1] headers = {'Content-Type': 'text/html; charset=UTF-8'} template_engine = jinja2.Template(template) listing.setdefault('at_root', listing['path'].count('/') <= 1) listing.setdefault('account', self.account) listing.setdefault('container', self.container) listing.setdefault('object', self.obj) listing.setdefault('powered', self.conf.get("powered", '')) listing.setdefault('authenticated', any( (header in self.env) for header in ['HTTP_AUTHORIZATION', 'HTTP_X_AUTH_TOKEN']) ) try: html = template_engine.render(listing) except Exception, e: html = "Could not generate listing<br> %s" % str(e)
def test_human_readable(self): self.assertEquals(utils.human_readable(0), '0') self.assertEquals(utils.human_readable(1), '1') self.assertEquals(utils.human_readable(10), '10') self.assertEquals(utils.human_readable(100), '100') self.assertEquals(utils.human_readable(999), '999') self.assertEquals(utils.human_readable(1024), '1Ki') self.assertEquals(utils.human_readable(1535), '1Ki') self.assertEquals(utils.human_readable(1536), '2Ki') self.assertEquals(utils.human_readable(1047552), '1023Ki') self.assertEquals(utils.human_readable(1048063), '1023Ki') self.assertEquals(utils.human_readable(1048064), '1Mi') self.assertEquals(utils.human_readable(1048576), '1Mi') self.assertEquals(utils.human_readable(1073741824), '1Gi') self.assertEquals(utils.human_readable(1099511627776), '1Ti') self.assertEquals(utils.human_readable(1125899906842624), '1Pi') self.assertEquals(utils.human_readable(1152921504606846976), '1Ei') self.assertEquals(utils.human_readable(1180591620717411303424), '1Zi') self.assertEquals(utils.human_readable(1208925819614629174706176), '1Yi') self.assertEquals(utils.human_readable(1237940039285380274899124224), '1024Yi')
def _listing(self, env, start_response, prefix=None): """ Sends an HTML object listing to the remote client. :param env: The original WSGI environment dict. :param start_response: The original WSGI start_response hook. :param prefix: Any prefix desired for the container listing. """ if not config_true_value(self._listings): body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \ '<html>\n' \ '<head>\n' \ '<title>Listing of %s</title>\n' % cgi.escape(env['PATH_INFO']) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' \ 'href="%s" />\n' % self._build_css_path(prefix or '') else: body += ' <style type="text/css">\n' \ ' h1 {font-size: 1em; font-weight: bold;}\n' \ ' p {font-size: 2}\n' \ ' </style>\n' body += '</head>\n<body>' \ ' <h1>Web Listing Disabled</h1>' \ ' <p>The owner of this web site has disabled web listing.' \ ' <p>If you are the owner of this web site, you can enable' \ ' web listing by setting X-Container-Meta-Web-Listings.</p>' if self._index: body += '<h1>Index File Not Found</h1>' \ ' <p>The owner of this web site has set ' \ ' <b>X-Container-Meta-Web-Index: %s</b>. ' \ ' However, this file is not found.</p>' % self._index body += ' </body>\n</html>\n' resp = HTTPNotFound(body=body)(env, self._start_response) return self._error_response(resp, env, start_response) tmp_env = make_env(env, 'GET', '/%s/%s/%s' % (self.version, self.account, self.container), self.agent, swift_source='SW') tmp_env['QUERY_STRING'] = 'delimiter=/&format=json' if prefix: tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix) else: prefix = '' resp = self._app_call(tmp_env) if not is_success(self._get_status_int()): return self._error_response(resp, env, start_response) listing = None body = ''.join(resp) if body: listing = json.loads(body) if not listing: resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) headers = {'Content-Type': 'text/html; charset=UTF-8'} body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \ '<html>\n' \ ' <head>\n' \ ' <title>Listing of %s</title>\n' % \ cgi.escape(env['PATH_INFO']) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' \ 'href="%s" />\n' % (self._build_css_path(prefix)) else: body += ' <style type="text/css">\n' \ ' h1 {font-size: 1em; font-weight: bold;}\n' \ ' th {text-align: left; padding: 0px 1em 0px 1em;}\n' \ ' td {padding: 0px 1em 0px 1em;}\n' \ ' a {text-decoration: none;}\n' \ ' </style>\n' body += ' </head>\n' \ ' <body>\n' \ ' <h1 id="title">Listing of %s</h1>\n' \ ' <table id="listing">\n' \ ' <tr id="heading">\n' \ ' <th class="colname">Name</th>\n' \ ' <th class="colsize">Size</th>\n' \ ' <th class="coldate">Date</th>\n' \ ' </tr>\n' % \ cgi.escape(env['PATH_INFO']) if prefix: body += ' <tr id="parent" class="item">\n' \ ' <td class="colname"><a href="../">../</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' for item in listing: if 'subdir' in item: subdir = item['subdir'].encode("utf-8") if prefix: subdir = subdir[len(prefix):] body += ' <tr class="item subdir">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' % \ (quote(subdir), cgi.escape(subdir)) for item in listing: if 'name' in item: name = item['name'].encode("utf-8") if prefix: name = name[len(prefix):] content_type = item['content_type'].encode("utf-8") bytes = human_readable(item['bytes']) last_modified = (cgi.escape(item['last_modified'].encode( "utf-8")).split('.')[0].replace('T', ' ')) body += ' <tr class="item %s">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize">%s</td>\n' \ ' <td class="coldate">%s</td>\n' \ ' </tr>\n' % \ (' '.join('type-' + cgi.escape(t.lower(), quote=True) for t in content_type.split('/')), quote(name), cgi.escape(name), bytes, last_modified) body += ' </table>\n' \ ' </body>\n' \ '</html>\n' resp = Response(headers=headers, body=body) return resp(env, start_response)
def _listing(self, env, start_response, prefix=None): """ Sends an HTML object listing to the remote client. :param env: The original WSGI environment dict. :param start_response: The original WSGI start_response hook. :param prefix: Any prefix desired for the container listing. """ if not config_true_value(self._listings): resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) tmp_env = make_pre_authed_env( env, 'GET', '/%s/%s/%s' % ( self.version, self.account, self.container), self.agent, swift_source='SW') tmp_env['QUERY_STRING'] = 'delimiter=/&format=json' if prefix: tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix) else: prefix = '' resp = self._app_call(tmp_env) if not is_success(self._get_status_int()): return self._error_response(resp, env, start_response) listing = None body = ''.join(resp) if body: listing = json.loads(body) if not listing: resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) headers = {'Content-Type': 'text/html; charset=UTF-8'} body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \ '<html>\n' \ ' <head>\n' \ ' <title>Listing of %s</title>\n' % \ cgi.escape(env['PATH_INFO']) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' \ 'href="%s" />\n' % (self._build_css_path(prefix)) else: body += ' <style type="text/css">\n' \ ' h1 {font-size: 1em; font-weight: bold;}\n' \ ' th {text-align: left; padding: 0px 1em 0px 1em;}\n' \ ' td {padding: 0px 1em 0px 1em;}\n' \ ' a {text-decoration: none;}\n' \ ' </style>\n' body += ' </head>\n' \ ' <body>\n' \ ' <h1 id="title">Listing of %s</h1>\n' \ ' <table id="listing">\n' \ ' <tr id="heading">\n' \ ' <th class="colname">Name</th>\n' \ ' <th class="colsize">Size</th>\n' \ ' <th class="coldate">Date</th>\n' \ ' </tr>\n' % \ cgi.escape(env['PATH_INFO']) if prefix: body += ' <tr id="parent" class="item">\n' \ ' <td class="colname"><a href="../">../</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' for item in listing: if 'subdir' in item: if isinstance(item['subdir'], unicode): subdir = item['subdir'].encode('utf-8') else: subdir = item['subdir'] if prefix: subdir = subdir[len(prefix):] body += ' <tr class="item subdir">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' % \ (quote(subdir), cgi.escape(subdir)) for item in listing: if 'name' in item: if isinstance(item['name'], unicode): name = item['name'].encode('utf-8') else: name = item['name'] if prefix: name = name[len(prefix):] body += ' <tr class="item %s">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize">%s</td>\n' \ ' <td class="coldate">%s</td>\n' \ ' </tr>\n' % \ (' '.join('type-' + cgi.escape(t.lower(), quote=True) for t in item['content_type'].split('/')), quote(name), cgi.escape(name), human_readable(item['bytes']), cgi.escape(item['last_modified']).split('.')[0]. replace('T', ' ')) body += ' </table>\n' \ ' </body>\n' \ '</html>\n' resp = Response(headers=headers, body=body) return resp(env, start_response)
def _listing(self, env, start_response, prefix=None): """ Sends an HTML object listing to the remote client. :param env: The original WSGI environment dict. :param start_response: The original WSGI start_response hook. :param prefix: Any prefix desired for the container listing. """ if self._listings not in TRUE_VALUES: resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) tmp_env = self._get_escalated_env(env) tmp_env['REQUEST_METHOD'] = 'GET' tmp_env['PATH_INFO'] = \ '/%s/%s/%s' % (self.version, self.account, self.container) tmp_env['QUERY_STRING'] = 'delimiter=/&format=json' if prefix: tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix) else: prefix = '' resp = self.app(tmp_env, self._start_response) if self._get_status_int() // 100 != 2: return self._error_response(resp, env, start_response) listing = json.loads(''.join(resp)) if not listing: resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) headers = {'Content-Type': 'text/html'} body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \ '<html>\n' \ ' <head>\n' \ ' <title>Listing of %s</title>\n' % \ cgi.escape(env['PATH_INFO']) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' \ 'href="%s%s" />\n' % \ ('../' * prefix.count('/'), quote(self._listings_css)) else: body += ' <style type="text/css">\n' \ ' h1 {font-size: 1em; font-weight: bold;}\n' \ ' th {text-align: left; padding: 0px 1em 0px 1em;}\n' \ ' td {padding: 0px 1em 0px 1em;}\n' \ ' a {text-decoration: none;}\n' \ ' </style>\n' body += ' </head>\n' \ ' <body>\n' \ ' <h1 id="title">Listing of %s</h1>\n' \ ' <table id="listing">\n' \ ' <tr id="heading">\n' \ ' <th class="colname">Name</th>\n' \ ' <th class="colsize">Size</th>\n' \ ' <th class="coldate">Date</th>\n' \ ' </tr>\n' % \ cgi.escape(env['PATH_INFO']) if prefix: body += ' <tr id="parent" class="item">\n' \ ' <td class="colname"><a href="../">../</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' for item in listing: if 'subdir' in item: subdir = item['subdir'] if prefix: subdir = subdir[len(prefix):] body += ' <tr class="item subdir">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' % \ (quote(subdir), cgi.escape(subdir)) for item in listing: if 'name' in item: name = item['name'] if prefix: name = name[len(prefix):] body += ' <tr class="item %s">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize">%s</td>\n' \ ' <td class="coldate">%s</td>\n' \ ' </tr>\n' % \ (' '.join('type-' + cgi.escape(t.lower(), quote=True) for t in item['content_type'].split('/')), quote(name), cgi.escape(name), human_readable(item['bytes']), cgi.escape(item['last_modified']).split('.')[0]. replace('T', ' ')) body += ' </table>\n' \ ' </body>\n' \ '</html>\n' resp = Response(headers=headers, body=body) self._log_response(env, resp.status_int) return resp(env, start_response)
def _listing(self, env, start_response, prefix=None): """ Sends an HTML object listing to the remote client. :param env: The original WSGI environment dict. :param start_response: The original WSGI start_response hook. :param prefix: Any prefix desired for the container listing. """ label = env['PATH_INFO'] if self._listings_label: groups = env['PATH_INFO'].split('/') label = '{0}/{1}'.format(self._listings_label, '/'.join(groups[4:])) if not config_true_value(self._listings): body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \ '<html>\n' \ '<head>\n' \ '<title>Listing of %s</title>\n' % cgi.escape(label) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' \ 'href="%s" />\n' % self._build_css_path(prefix or '') else: body += ' <style type="text/css">\n' \ ' h1 {font-size: 1em; font-weight: bold;}\n' \ ' p {font-size: 2}\n' \ ' </style>\n' body += '</head>\n<body>' \ ' <h1>Web Listing Disabled</h1>' \ ' <p>The owner of this web site has disabled web listing.' \ ' <p>If you are the owner of this web site, you can enable' \ ' web listing by setting X-Container-Meta-Web-Listings.</p>' if self._index: body += '<h1>Index File Not Found</h1>' \ ' <p>The owner of this web site has set ' \ ' <b>X-Container-Meta-Web-Index: %s</b>. ' \ ' However, this file is not found.</p>' % self._index body += ' </body>\n</html>\n' resp = HTTPNotFound(body=body)(env, self._start_response) return self._error_response(resp, env, start_response) tmp_env = make_env( env, 'GET', '/%s/%s/%s' % ( self.version, self.account, self.container), self.agent, swift_source='SW') tmp_env['QUERY_STRING'] = 'delimiter=/&format=json' if prefix: tmp_env['QUERY_STRING'] += '&prefix=%s' % quote(prefix) else: prefix = '' resp = self._app_call(tmp_env) if not is_success(self._get_status_int()): return self._error_response(resp, env, start_response) listing = None body = ''.join(resp) if body: listing = json.loads(body) if not listing: resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) headers = {'Content-Type': 'text/html; charset=UTF-8'} body = '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' \ 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' \ '<html>\n' \ ' <head>\n' \ ' <title>Listing of %s</title>\n' % cgi.escape(label) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' \ 'href="%s" />\n' % (self._build_css_path(prefix)) else: body += ' <style type="text/css">\n' \ ' h1 {font-size: 1em; font-weight: bold;}\n' \ ' th {text-align: left; padding: 0px 1em 0px 1em;}\n' \ ' td {padding: 0px 1em 0px 1em;}\n' \ ' a {text-decoration: none;}\n' \ ' </style>\n' body += ' </head>\n' \ ' <body>\n' \ ' <h1 id="title">Listing of %s</h1>\n' \ ' <table id="listing">\n' \ ' <tr id="heading">\n' \ ' <th class="colname">Name</th>\n' \ ' <th class="colsize">Size</th>\n' \ ' <th class="coldate">Date</th>\n' \ ' </tr>\n' % cgi.escape(label) if prefix: body += ' <tr id="parent" class="item">\n' \ ' <td class="colname"><a href="../">../</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' for item in listing: if 'subdir' in item: subdir = item['subdir'].encode("utf-8") if prefix: subdir = subdir[len(prefix):] body += ' <tr class="item subdir">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize"> </td>\n' \ ' <td class="coldate"> </td>\n' \ ' </tr>\n' % \ (quote(subdir), cgi.escape(subdir)) for item in listing: if 'name' in item: name = item['name'].encode("utf-8") if prefix: name = name[len(prefix):] content_type = item['content_type'].encode("utf-8") bytes = human_readable(item['bytes']) last_modified = ( cgi.escape(item['last_modified'].encode("utf-8")). split('.')[0].replace('T', ' ')) body += ' <tr class="item %s">\n' \ ' <td class="colname"><a href="%s">%s</a></td>\n' \ ' <td class="colsize">%s</td>\n' \ ' <td class="coldate">%s</td>\n' \ ' </tr>\n' % \ (' '.join('type-' + cgi.escape(t.lower(), quote=True) for t in content_type.split('/')), quote(name), cgi.escape(name), bytes, last_modified) body += ' </table>\n' \ ' </body>\n' \ '</html>\n' resp = Response(headers=headers, body=body) return resp(env, start_response)
def test_human_readable(self): self.assertEquals(utils.human_readable(0), "0") self.assertEquals(utils.human_readable(1), "1") self.assertEquals(utils.human_readable(10), "10") self.assertEquals(utils.human_readable(100), "100") self.assertEquals(utils.human_readable(999), "999") self.assertEquals(utils.human_readable(1024), "1Ki") self.assertEquals(utils.human_readable(1535), "1Ki") self.assertEquals(utils.human_readable(1536), "2Ki") self.assertEquals(utils.human_readable(1047552), "1023Ki") self.assertEquals(utils.human_readable(1048063), "1023Ki") self.assertEquals(utils.human_readable(1048064), "1Mi") self.assertEquals(utils.human_readable(1048576), "1Mi") self.assertEquals(utils.human_readable(1073741824), "1Gi") self.assertEquals(utils.human_readable(1099511627776), "1Ti") self.assertEquals(utils.human_readable(1125899906842624), "1Pi") self.assertEquals(utils.human_readable(1152921504606846976), "1Ei") self.assertEquals(utils.human_readable(1180591620717411303424), "1Zi") self.assertEquals(utils.human_readable(1208925819614629174706176), "1Yi") self.assertEquals(utils.human_readable(1237940039285380274899124224), "1024Yi")
def _listing(self, env, start_response, prefix=None): """ Sends an HTML object listing to the remote client. :param env: The original WSGI environment dict. :param start_response: The original WSGI start_response hook. :param prefix: Any prefix desired for the container listing. """ if not config_true_value(self._listings): resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) tmp_env = make_pre_authed_env( env, "GET", "/%s/%s/%s" % (self.version, self.account, self.container), self.agent, swift_source="SW" ) tmp_env["QUERY_STRING"] = "delimiter=/&format=json" if prefix: tmp_env["QUERY_STRING"] += "&prefix=%s" % quote(prefix) else: prefix = "" resp = self._app_call(tmp_env) if not is_success(self._get_status_int()): return self._error_response(resp, env, start_response) listing = None body = "".join(resp) if body: listing = json.loads(body) if not listing: resp = HTTPNotFound()(env, self._start_response) return self._error_response(resp, env, start_response) headers = {"Content-Type": "text/html; charset=UTF-8"} body = ( '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 ' 'Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n' "<html>\n" " <head>\n" " <title>Listing of %s</title>\n" % cgi.escape(env["PATH_INFO"]) ) if self._listings_css: body += ' <link rel="stylesheet" type="text/css" ' 'href="%s" />\n' % (self._build_css_path(prefix)) else: body += ( ' <style type="text/css">\n' " h1 {font-size: 1em; font-weight: bold;}\n" " th {text-align: left; padding: 0px 1em 0px 1em;}\n" " td {padding: 0px 1em 0px 1em;}\n" " a {text-decoration: none;}\n" " </style>\n" ) body += ( " </head>\n" " <body>\n" ' <h1 id="title">Listing of %s</h1>\n' ' <table id="listing">\n' ' <tr id="heading">\n' ' <th class="colname">Name</th>\n' ' <th class="colsize">Size</th>\n' ' <th class="coldate">Date</th>\n' " </tr>\n" % cgi.escape(env["PATH_INFO"]) ) if prefix: body += ( ' <tr id="parent" class="item">\n' ' <td class="colname"><a href="../">../</a></td>\n' ' <td class="colsize"> </td>\n' ' <td class="coldate"> </td>\n' " </tr>\n" ) for item in listing: if "subdir" in item: if isinstance(item["subdir"], unicode): subdir = item["subdir"].encode("utf-8") else: subdir = item["subdir"] if prefix: subdir = subdir[len(prefix) :] body += ( ' <tr class="item subdir">\n' ' <td class="colname"><a href="%s">%s</a></td>\n' ' <td class="colsize"> </td>\n' ' <td class="coldate"> </td>\n' " </tr>\n" % (quote(subdir), cgi.escape(subdir)) ) for item in listing: if "name" in item: if isinstance(item["name"], unicode): name = item["name"].encode("utf-8") else: name = item["name"] if prefix: name = name[len(prefix) :] body += ( ' <tr class="item %s">\n' ' <td class="colname"><a href="%s">%s</a></td>\n' ' <td class="colsize">%s</td>\n' ' <td class="coldate">%s</td>\n' " </tr>\n" % ( " ".join("type-" + cgi.escape(t.lower(), quote=True) for t in item["content_type"].split("/")), quote(name), cgi.escape(name), human_readable(item["bytes"]), cgi.escape(item["last_modified"]).split(".")[0].replace("T", " "), ) ) body += " </table>\n" " </body>\n" "</html>\n" resp = Response(headers=headers, body=body) return resp(env, start_response)