* lib/sapi.py
- Filled in ModPythonServer and AspServer header() methods to make use of the new http 'status' parameter. Also, changed CgiServer's header() method to ignore the status parameter under IIS to prevent the server from discarding the ViewCVS output and instead sending a static error page. - ModPythonFile and AspFile classes have been eliminated and replaced with a more generic File class. All server classes have new write() and flush() methods. - Common code from AspServer and ModPythonServer has been moved into a base class called ThreadedServer. AspProxy is renamed to ThreadedServerProxy. - All server classes now inherit from a new base class called Server which contains the small amount of code common to all of them. - added fix_iis_path_info() function, renamed IIS_FixURL() to fix_iis_url() - renamed getFile() methods to file() * lib/viewcvs.py - Eliminated global server variable. Changed some scattered server.escape() calls into cgi.escape() calls. Got around other uses of the variable by adding a server member to the Request class. - Deleted gstein's strongly worded comment about the quality of the sapi hack :) - Page-global 'g_name_printed' is now passed as a normal parameter called 'name_printed' to the augment_entry() function - Got rid of some confusing string manipulation in human_readable_diff() - added 'server' parameter to viewcvs.main() to avoid relying on the sapi.server global variable * cgi/viewcvs.cgi, windows/viewcvs.py, windows/viewcvs.asp - Added 'server' parameter to viewcvs.main() calls * standalone.py: - Changed StandaloneServer.header() method to accept http status code - Added 'server' parameter to viewcvs.main() call * lib/query.py - added 'server' parameter to query.main() to avoid relying on the sapi.server global variable - got rid of global 'server' variable and page-global 'viewcvs_link' variable, instead those values are passed as function parameters * cgi/query.cgi, windows/query.py, windows/query.asp - Added 'server' parameter to query.main() calls * lib/debug.py - Changed PrintStackTrace(), PrintException(), and DumpChildren() not to rely on global sapi.server variable and to use new server.write() method * lib/popen.py - changed server.getFile() calls to server.file() git-svn-id: http://viewvc.tigris.org/svn/viewvc/trunk@642 8cb11bc2-c004-0410-86c3-e597b4017df7remotes/tags/1.0.0-rc1
parent
c74fa8eb35
commit
459ed3fea3
|
@ -50,5 +50,4 @@ else:
|
|||
import sapi
|
||||
import query
|
||||
|
||||
sapi.CgiServer()
|
||||
query.main('viewcvs.cgi')
|
||||
query.main(sapi.CgiServer(), 'viewcvs.cgi')
|
||||
|
|
|
@ -55,5 +55,4 @@ else:
|
|||
import sapi
|
||||
import viewcvs
|
||||
|
||||
sapi.CgiServer()
|
||||
viewcvs.main()
|
||||
viewcvs.main(sapi.CgiServer())
|
||||
|
|
101
lib/debug.py
101
lib/debug.py
|
@ -70,25 +70,19 @@ class ViewCVSException:
|
|||
ViewcvsException = ViewCVSException
|
||||
|
||||
|
||||
def PrintStackTrace(text=''):
|
||||
import traceback, string, sapi
|
||||
def PrintStackTrace(server, text=''):
|
||||
import traceback, string
|
||||
|
||||
out = sys.stdout
|
||||
server = sapi.server.self()
|
||||
server.write("<hr><p><font color=red>%s</font></p>\n<p><pre>" % text)
|
||||
server.write(server.escape(string.join(traceback.format_stack(), '')))
|
||||
server.write("</pre></p>")
|
||||
server.flush()
|
||||
|
||||
out.write("<hr><p><font color=red>%s</font></p>\n<p><pre>" % text)
|
||||
out.write(server.escape(string.join(traceback.format_stack(), '')))
|
||||
out.write("</pre></p>")
|
||||
out.flush()
|
||||
|
||||
def PrintException():
|
||||
def PrintException(server):
|
||||
# capture the exception before doing anything else
|
||||
exc_type, exc, exc_tb = sys.exc_info()
|
||||
try:
|
||||
import traceback, string, sapi
|
||||
|
||||
out = sys.stdout
|
||||
server = sapi.server.self()
|
||||
import traceback, string
|
||||
|
||||
if issubclass(exc_type, ViewCVSException):
|
||||
server.header(status=exc.status)
|
||||
|
@ -97,12 +91,12 @@ def PrintException():
|
|||
server.header()
|
||||
desc = ''
|
||||
|
||||
out.write("<h3>An Exception Has Occurred</h3>\n")
|
||||
server.write("<h3>An Exception Has Occurred</h3>\n")
|
||||
|
||||
# put message in a prominent position (rather than at the end of the
|
||||
# stack trace)
|
||||
if desc:
|
||||
out.write(desc)
|
||||
server.write(desc)
|
||||
|
||||
stacktrace = string.join(traceback.format_exception(exc_type,
|
||||
exc,
|
||||
|
@ -116,9 +110,9 @@ def PrintException():
|
|||
# This is all based on 'exc_tb', and we're now done with it. Toss it.
|
||||
del exc_tb
|
||||
|
||||
out.write("<h4>Python Traceback</h4>\n<p><pre>")
|
||||
out.write(server.escape(stacktrace))
|
||||
out.write("</pre></p>\n")
|
||||
server.write("<h4>Python Traceback</h4>\n<p><pre>")
|
||||
server.write(server.escape(stacktrace))
|
||||
server.write("</pre></p>\n")
|
||||
|
||||
|
||||
if SHOW_CHILD_PROCESSES:
|
||||
|
@ -136,11 +130,8 @@ if SHOW_CHILD_PROCESSES:
|
|||
else:
|
||||
sapi.server.pageGlobals['processes'].append(self)
|
||||
|
||||
def DumpChildren():
|
||||
import sapi, os
|
||||
|
||||
out = sys.stdout
|
||||
server = sapi.server.self()
|
||||
def DumpChildren(server):
|
||||
import os
|
||||
|
||||
if not server.pageGlobals.has_key('processes'):
|
||||
return
|
||||
|
@ -151,54 +142,54 @@ if SHOW_CHILD_PROCESSES:
|
|||
|
||||
for k in server.pageGlobals['processes']:
|
||||
i = i + 1
|
||||
out.write("<table border=1>\n")
|
||||
out.write("<tr><td colspan=2>Child Process%i</td></tr>" % i)
|
||||
out.write("<tr>\n <td valign=top>Command Line</td> <td><pre>")
|
||||
out.write(server.escape(k.command))
|
||||
out.write("</pre></td>\n</tr>\n")
|
||||
out.write("<tr>\n <td valign=top>Standard In:</td> <td>")
|
||||
server.write("<table border=1>\n")
|
||||
server.write("<tr><td colspan=2>Child Process%i</td></tr>" % i)
|
||||
server.write("<tr>\n <td valign=top>Command Line</td> <td><pre>")
|
||||
server.write(server.escape(k.command))
|
||||
server.write("</pre></td>\n</tr>\n")
|
||||
server.write("<tr>\n <td valign=top>Standard In:</td> <td>")
|
||||
|
||||
if k.debugIn is lastOut and not lastOut is None:
|
||||
out.write("<i>Output from process %i</i>" % (i - 1))
|
||||
server.write("<i>Output from process %i</i>" % (i - 1))
|
||||
elif k.debugIn:
|
||||
out.write("<pre>")
|
||||
out.write(server.escape(k.debugIn.getvalue()))
|
||||
out.write("</pre>")
|
||||
server.write("<pre>")
|
||||
server.write(server.escape(k.debugIn.getvalue()))
|
||||
server.write("</pre>")
|
||||
|
||||
out.write("</td>\n</tr>\n")
|
||||
server.write("</td>\n</tr>\n")
|
||||
|
||||
if k.debugOut is k.debugErr:
|
||||
out.write("<tr>\n <td valign=top>Standard Out & Error:</td> <td><pre>")
|
||||
server.write("<tr>\n <td valign=top>Standard Out & Error:</td> <td><pre>")
|
||||
if k.debugOut:
|
||||
out.write(server.escape(k.debugOut.getvalue()))
|
||||
out.write("</pre></td>\n</tr>\n")
|
||||
server.write(server.escape(k.debugOut.getvalue()))
|
||||
server.write("</pre></td>\n</tr>\n")
|
||||
|
||||
else:
|
||||
out.write("<tr>\n <td valign=top>Standard Out:</td> <td><pre>")
|
||||
server.write("<tr>\n <td valign=top>Standard Out:</td> <td><pre>")
|
||||
if k.debugOut:
|
||||
out.write(server.escape(k.debugOut.getvalue()))
|
||||
out.write("</pre></td>\n</tr>\n")
|
||||
out.write("<tr>\n <td valign=top>Standard Error:</td> <td><pre>")
|
||||
server.write(server.escape(k.debugOut.getvalue()))
|
||||
server.write("</pre></td>\n</tr>\n")
|
||||
server.write("<tr>\n <td valign=top>Standard Error:</td> <td><pre>")
|
||||
if k.debugErr:
|
||||
out.write(server.escape(k.debugErr.getvalue()))
|
||||
out.write("</pre></td>\n</tr>\n")
|
||||
server.write(server.escape(k.debugErr.getvalue()))
|
||||
server.write("</pre></td>\n</tr>\n")
|
||||
|
||||
out.write("</table>\n")
|
||||
out.flush()
|
||||
server.write("</table>\n")
|
||||
server.flush()
|
||||
lastOut = k.debugOut
|
||||
|
||||
out.write("<table border=1>\n")
|
||||
out.write("<tr><td colspan=2>Environment Variables</td></tr>")
|
||||
server.write("<table border=1>\n")
|
||||
server.write("<tr><td colspan=2>Environment Variables</td></tr>")
|
||||
for k, v in os.environ.items():
|
||||
out.write("<tr>\n <td valign=top><pre>")
|
||||
out.write(server.escape(k))
|
||||
out.write("</pre></td>\n <td valign=top><pre>")
|
||||
out.write(server.escape(v))
|
||||
out.write("</pre></td>\n</tr>")
|
||||
out.write("</table>")
|
||||
server.write("<tr>\n <td valign=top><pre>")
|
||||
server.write(server.escape(k))
|
||||
server.write("</pre></td>\n <td valign=top><pre>")
|
||||
server.write(server.escape(v))
|
||||
server.write("</pre></td>\n</tr>")
|
||||
server.write("</table>")
|
||||
|
||||
else:
|
||||
|
||||
def DumpChildren():
|
||||
def DumpChildren(server):
|
||||
pass
|
||||
|
||||
|
|
|
@ -162,7 +162,7 @@ def pipe_cmds(cmds):
|
|||
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
|
||||
else:
|
||||
ehandle = win32event.CreateEvent(None, 1, 0, None)
|
||||
nextStdIn, hStdOut = win32popen.MakeSpyPipe(None, 1, (dbgOut, sapi.server.getFile()), ehandle)
|
||||
nextStdIn, hStdOut = win32popen.MakeSpyPipe(None, 1, (dbgOut, sapi.server.file()), ehandle)
|
||||
x, hStdErr = win32popen.MakeSpyPipe(None, 1, (dbgErr,))
|
||||
|
||||
command = win32popen.CommandLine(cmd[0], cmd[1:])
|
||||
|
@ -194,7 +194,7 @@ def pipe_cmds(cmds):
|
|||
ehandle = None
|
||||
else:
|
||||
ehandle = win32event.CreateEvent(None, 1, 0, None)
|
||||
x, hStdOut = win32popen.MakeSpyPipe(None, 1, (sapi.server.getFile(),), ehandle)
|
||||
x, hStdOut = win32popen.MakeSpyPipe(None, 1, (sapi.server.file(),), ehandle)
|
||||
|
||||
command = win32popen.CommandLine(cmd[0], cmd[1:])
|
||||
phandle, pid, thandle, tid = win32popen.CreateProcess(command, hStdIn, hStdOut, None)
|
||||
|
|
19
lib/query.py
19
lib/query.py
|
@ -36,7 +36,6 @@ CONF_PATHNAME = None
|
|||
import os
|
||||
import sys
|
||||
import string
|
||||
import sapi
|
||||
import time
|
||||
|
||||
import cvsdb
|
||||
|
@ -278,7 +277,7 @@ def form_to_cvsdb_query(form_data):
|
|||
|
||||
return query
|
||||
|
||||
def build_commit(desc, files, cvsroots):
|
||||
def build_commit(server, desc, files, cvsroots, viewcvs_link):
|
||||
ob = _item(num_files=len(files), files=[])
|
||||
|
||||
if desc:
|
||||
|
@ -311,7 +310,7 @@ def build_commit(desc, files, cvsroots):
|
|||
|
||||
if cvsroot_name:
|
||||
flink = '<a href="%s/%s?root=%s">%s</a>' % (
|
||||
server.pageGlobals['viewcvs_link'], file, cvsroot_name,
|
||||
viewcvs_link, file, cvsroot_name,
|
||||
file_full_path)
|
||||
else:
|
||||
flink = file_full_path
|
||||
|
@ -327,7 +326,7 @@ def build_commit(desc, files, cvsroots):
|
|||
|
||||
return ob
|
||||
|
||||
def run_query(form_data):
|
||||
def run_query(server, form_data, viewcvs_link):
|
||||
query = form_to_cvsdb_query(form_data)
|
||||
db = cvsdb.ConnectDatabaseReadOnly()
|
||||
db.RunQuery(query)
|
||||
|
@ -352,13 +351,13 @@ def run_query(form_data):
|
|||
files.append(commit)
|
||||
continue
|
||||
|
||||
commits.append(build_commit(current_desc, files, cvsroots))
|
||||
commits.append(build_commit(server, current_desc, files, cvsroots, viewcvs_link))
|
||||
|
||||
files = [ commit ]
|
||||
current_desc = desc
|
||||
|
||||
## add the last file group to the commit list
|
||||
commits.append(build_commit(current_desc, files, cvsroots))
|
||||
commits.append(build_commit(server, current_desc, files, cvsroots, viewcvs_link))
|
||||
|
||||
return commits
|
||||
|
||||
|
@ -367,19 +366,15 @@ def handle_config():
|
|||
global cfg
|
||||
cfg = viewcvs.cfg
|
||||
|
||||
def main(viewcvs_link):
|
||||
global server
|
||||
def main(server, viewcvs_link):
|
||||
try:
|
||||
server = sapi.server
|
||||
handle_config()
|
||||
|
||||
server.pageGlobals['viewcvs_link'] = viewcvs_link
|
||||
|
||||
form = server.FieldStorage()
|
||||
form_data = FormData(form)
|
||||
|
||||
if form_data.valid:
|
||||
commits = run_query(form_data)
|
||||
commits = run_query(server, form_data, viewcvs_link)
|
||||
query = None
|
||||
else:
|
||||
commits = [ ]
|
||||
|
|
507
lib/sapi.py
507
lib/sapi.py
|
@ -1,245 +1,54 @@
|
|||
# generic server api - currently supports normal cgi, and active server pages
|
||||
#
|
||||
# Russ Yanofsky -- rey4@columbia.edu
|
||||
# generic server api - currently supports normal cgi, mod_python, and
|
||||
# active server pages
|
||||
|
||||
|
||||
import types
|
||||
import string
|
||||
import os
|
||||
import sys
|
||||
import re
|
||||
|
||||
# global server object. It will be either a CgiServer or an AspServer,
|
||||
# depending on the environment
|
||||
|
||||
# global server object. It will be either a CgiServer or a proxy to
|
||||
# an AspServer or ModPythonServer object.
|
||||
server = None
|
||||
|
||||
class CgiServer:
|
||||
|
||||
class Server:
|
||||
def __init__(self):
|
||||
self.inheritableOut = 1
|
||||
self.header_sent = 0
|
||||
self.pageGlobals = {}
|
||||
|
||||
if os.environ.get('SERVER_SOFTWARE', '')[:13] == 'Microsoft-IIS':
|
||||
self.iis = 1
|
||||
else:
|
||||
self.iis = 0
|
||||
|
||||
if sys.platform == "win32":
|
||||
import msvcrt
|
||||
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
|
||||
|
||||
global server
|
||||
server = self
|
||||
|
||||
global cgi
|
||||
import cgi
|
||||
|
||||
def header(self, content_type='text/html', status='200 OK'):
|
||||
if not self.header_sent:
|
||||
self.header_sent = 1
|
||||
sys.stdout.write('Status: %s\r\nContent-Type: %s\r\n\r\n'
|
||||
% (status, content_type))
|
||||
|
||||
def redirect(self, url):
|
||||
print 'Status: 301 Moved'
|
||||
if self.iis: url = IIS_FixURL(url)
|
||||
sys.stdout.write('Location: ' + url + '\r\n\r\n')
|
||||
print 'This document is located <a href="%s">here</a>.' % url
|
||||
sys.exit(0)
|
||||
|
||||
def params(self):
|
||||
return cgi.parse()
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return cgi.escape(s, quote)
|
||||
|
||||
def getenv(self, name, value=None):
|
||||
# If the viewcvs cgi's are in the /viewcvs/ folder on the web server and a
|
||||
# request looks like
|
||||
#
|
||||
# /viewcvs/viewcvs.cgi/myproject/?someoption
|
||||
#
|
||||
# The CGI environment variables will look like this:
|
||||
#
|
||||
# SCRIPT_NAME = /viewcvs/viewcvs.cgi
|
||||
# PATH_INFO = /viewcvs/viewcvs.cgi/myproject/
|
||||
#
|
||||
# I'm not sure how these variables are supposed to work on a unix server,
|
||||
# but this next statement was needed in order to get existing script
|
||||
# to work properly on windows.
|
||||
|
||||
if self.iis and name == 'PATH_INFO':
|
||||
return os.environ.get('PATH_INFO', '')[len(os.environ.get('SCRIPT_NAME', '')):]
|
||||
else:
|
||||
return os.environ.get(name, value)
|
||||
|
||||
def FieldStorage(fp=None, headers=None, outerboundary="",
|
||||
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||
return cgi.FieldStorage(fp, headers, outerboundary, environ,
|
||||
keep_blank_values, strict_parsing)
|
||||
|
||||
def self(self):
|
||||
return self
|
||||
|
||||
def getFile(self):
|
||||
return sys.stdout
|
||||
|
||||
def close():
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def IIS_FixURL(url):
|
||||
"""When a CGI application under IIS outputs a "Location" header with a url
|
||||
beginning with a forward slash, IIS tries to optimise the redirect by not
|
||||
returning any output from the original CGI script at all and instead just
|
||||
returning the new page in its place. Because of this, the browser does
|
||||
not know it is getting a different page than it requested. As a result,
|
||||
The address bar that appears in the browser window shows the wrong location
|
||||
and if the new page is in a different folder than the old one, any relative
|
||||
links on it will be broken.
|
||||
|
||||
This function can be used to circumvent the IIS "optimization" of local
|
||||
redirects. If it is passed a location that begins with a forward slash it
|
||||
will return a URL constructed with the information in CGI environment.
|
||||
If it is passed a URL or any location that doens't begin with a forward slash
|
||||
it will return just argument unaltered.
|
||||
"""
|
||||
if url[0] == '/':
|
||||
if os.environ['HTTPS'] == 'on':
|
||||
dport = "443"
|
||||
prefix = "https://"
|
||||
else:
|
||||
dport = "80"
|
||||
prefix = "http://"
|
||||
prefix = prefix + os.environ['HTTP_HOST']
|
||||
if os.environ['SERVER_PORT'] != dport:
|
||||
prefix = prefix + ":" + os.environ['SERVER_PORT']
|
||||
return prefix + url
|
||||
return url
|
||||
class ThreadedServer(Server):
|
||||
def __init__(self):
|
||||
Server.__init__(self)
|
||||
|
||||
class AspServer:
|
||||
|
||||
def __init__(self, Server, Request, Response, Application):
|
||||
self.inheritableOut = 0
|
||||
self.header_sent = 0
|
||||
self.server = Server
|
||||
self.request = Request
|
||||
self.response = Response
|
||||
self.application = Application
|
||||
self.pageGlobals = {}
|
||||
|
||||
global server
|
||||
if not isinstance(server, AspProxy):
|
||||
server = AspProxy()
|
||||
if not isinstance(sys.stdout, AspFile):
|
||||
sys.stdout = AspFile(server)
|
||||
|
||||
if not isinstance(server, ThreadedServerProxy):
|
||||
server = ThreadedServerProxy()
|
||||
if not isinstance(sys.stdout, File):
|
||||
sys.stdout = File(server)
|
||||
server.registerThread(self)
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return self.server.HTMLEncode(str(s))
|
||||
|
||||
def params(self):
|
||||
p = {}
|
||||
for i in self.request.Form:
|
||||
p[str(i)] = map(str, self.request.Form[i])
|
||||
for i in self.request.QueryString:
|
||||
p[str(i)] = map(str, self.request.QueryString[i])
|
||||
return p
|
||||
|
||||
def header(self, content_type='text/html', status='200 OK'):
|
||||
### what to do with the status?
|
||||
|
||||
# In normal circumstances setting self.response.ContentType
|
||||
# after headers have already been sent simply results in
|
||||
# an AttributeError exception, but sometimes it leads to
|
||||
# a fatal ASP error. For this reason I'm keeping
|
||||
# the self.header_sent member, and only checking for the
|
||||
# exception as a secondary measure
|
||||
if not self.header_sent:
|
||||
try:
|
||||
self.header_sent = 1
|
||||
self.response.ContentType = content_type
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def redirect(self, url):
|
||||
self.response.Redirect(url)
|
||||
sys.exit()
|
||||
|
||||
def getenv(self, name, value = None):
|
||||
if name == 'PATH_INFO':
|
||||
p = self.request.ServerVariables('PATH_INFO')()
|
||||
s = self.request.ServerVariables('SCRIPT_NAME')()
|
||||
return str(p[len(s):])
|
||||
else:
|
||||
r = self.request.ServerVariables(name)()
|
||||
if type(r) == types.UnicodeType:
|
||||
return str(r)
|
||||
else:
|
||||
return value
|
||||
|
||||
def FieldStorage(self, fp=None, headers=None, outerboundary="",
|
||||
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||
|
||||
# Code based on a very helpful usenet post by "Max M" (maxm@mxm.dk)
|
||||
# Subject "Re: Help! IIS and Python"
|
||||
# http://groups.google.com/groups?selm=3C7C0AB6.2090307%40mxm.dk
|
||||
|
||||
from StringIO import StringIO
|
||||
from cgi import FieldStorage
|
||||
|
||||
environ = {}
|
||||
for i in self.request.ServerVariables:
|
||||
environ[str(i)] = str(self.request.ServerVariables(i)())
|
||||
|
||||
# this would be bad for uploaded files, could use a lot of memory
|
||||
binaryContent, size = self.request.BinaryRead(int(environ['CONTENT_LENGTH']))
|
||||
|
||||
fp = StringIO(str(binaryContent))
|
||||
fs = FieldStorage(fp, None, "", environ, keep_blank_values, strict_parsing)
|
||||
fp.close()
|
||||
return fs
|
||||
|
||||
def getFile(self):
|
||||
return AspFile(self)
|
||||
def file(self):
|
||||
return File(self)
|
||||
|
||||
def close(self):
|
||||
server.unregisterThread()
|
||||
|
||||
class AspFile:
|
||||
def __init__(self, server):
|
||||
self.closed = 0
|
||||
self.mode = 'w'
|
||||
self.name = "<AspFile file>"
|
||||
self.softspace = 0
|
||||
self.server = server
|
||||
|
||||
def flush(self):
|
||||
self.server.response.Flush()
|
||||
|
||||
def write(self, s):
|
||||
t = type(s)
|
||||
if t is types.StringType:
|
||||
s = buffer(s)
|
||||
elif not t is types.BufferType:
|
||||
s = buffer(str(s))
|
||||
|
||||
self.server.response.BinaryWrite(s)
|
||||
|
||||
def writelines(self, list):
|
||||
for str in list:
|
||||
self.server.response.BinaryWrite(str)
|
||||
|
||||
def truncate(self, size):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
class AspProxy:
|
||||
"""In a multithreaded server environment, AspProxy stores the different server
|
||||
objects being used to display pages and transparently forwards access to them
|
||||
based on the current thread id."""
|
||||
class ThreadedServerProxy:
|
||||
"""In a multithreaded server environment, ThreadedServerProxy stores the
|
||||
different server objects being used to display pages and transparently
|
||||
forwards access to them based on the current thread id."""
|
||||
|
||||
def __init__(self):
|
||||
self.__dict__['servers'] = { }
|
||||
|
@ -266,36 +75,194 @@ class AspProxy:
|
|||
def __delattr__(self, key):
|
||||
delattr(self.self(), key)
|
||||
|
||||
class ModPythonServer:
|
||||
def __init__(self, request):
|
||||
self.inheritableOut = 0
|
||||
self.request = request
|
||||
self.pageGlobals = {}
|
||||
|
||||
class File:
|
||||
def __init__(self, server):
|
||||
self.closed = 0
|
||||
self.mode = 'w'
|
||||
self.name = "<AspFile file>"
|
||||
self.softspace = 0
|
||||
self.server = server
|
||||
|
||||
def write(self, s):
|
||||
self.server.write(s)
|
||||
|
||||
def writelines(self, list):
|
||||
for s in list:
|
||||
self.server.write(s)
|
||||
|
||||
def flush(self):
|
||||
self.server.flush()
|
||||
|
||||
def truncate(self, size):
|
||||
pass
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
|
||||
class CgiServer(Server):
|
||||
def __init__(self, inheritableOut = 1):
|
||||
Server.__init__(self)
|
||||
self.headerSent = 0
|
||||
self.inheritableOut = inheritableOut
|
||||
self.iis = os.environ.get('SERVER_SOFTWARE', '')[:13] == 'Microsoft-IIS'
|
||||
|
||||
if sys.platform == "win32" and inheritableOut:
|
||||
import msvcrt
|
||||
msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
|
||||
|
||||
global server
|
||||
if not isinstance(server, AspProxy):
|
||||
server = AspProxy()
|
||||
if not isinstance(sys.stdout, ModPythonFile):
|
||||
sys.stdout = ModPythonFile(server)
|
||||
|
||||
server.registerThread(self)
|
||||
server = self
|
||||
|
||||
global cgi
|
||||
import cgi
|
||||
|
||||
def header(self, content_type='text/html', status='200 OK'):
|
||||
if not self.headerSent:
|
||||
self.headerSent = 1
|
||||
|
||||
# The only way ViewCVS pages and error messages will be visible
|
||||
# under IIS is if a 200 error code is returned. Otherwise it
|
||||
# will send the static error page corresponding to the code number
|
||||
if self.iis:
|
||||
status = '200 OK'
|
||||
|
||||
sys.stdout.write('Status: %s\r\nContent-Type: %s\r\n\r\n'
|
||||
% (status, content_type))
|
||||
|
||||
def redirect(self, url):
|
||||
print 'Status: 301 Moved'
|
||||
if self.iis: url = fix_iis_url(self, url)
|
||||
sys.stdout.write('Location: ' + url + '\r\n\r\n')
|
||||
print 'This document is located <a href="%s">here</a>.' % url
|
||||
sys.exit(0)
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return cgi.escape(s, quote)
|
||||
|
||||
def getenv(self, name, value=None):
|
||||
ret = os.environ.get(name, value)
|
||||
if self.iis and name == 'PATH_INFO' and ret:
|
||||
ret = fix_iis_path_info(self, ret)
|
||||
return ret
|
||||
|
||||
def params(self):
|
||||
import mod_python.util
|
||||
if self.request.args is None:
|
||||
return {}
|
||||
else:
|
||||
return mod_python.util.parse_qs(self.request.args)
|
||||
return cgi.parse()
|
||||
|
||||
def FieldStorage(fp=None, headers=None, outerboundary="",
|
||||
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||
return cgi.FieldStorage(fp, headers, outerboundary, environ,
|
||||
keep_blank_values, strict_parsing)
|
||||
|
||||
def write(self, s):
|
||||
sys.stdout.write(s)
|
||||
|
||||
def flush(self):
|
||||
sys.stdout.flush()
|
||||
|
||||
def file(self):
|
||||
return sys.stdout
|
||||
|
||||
|
||||
class AspServer(ThreadedServer):
|
||||
def __init__(self, Server, Request, Response, Application):
|
||||
ThreadedServer.__init__(self)
|
||||
self.headerSent = 0
|
||||
self.server = Server
|
||||
self.request = Request
|
||||
self.response = Response
|
||||
self.application = Application
|
||||
|
||||
def header(self, content_type='text/html', status='200 OK'):
|
||||
# Normally, setting self.response.ContentType after headers have already
|
||||
# been sent simply results in an AttributeError exception, but sometimes
|
||||
# it leads to a fatal ASP error. For this reason I'm keeping the
|
||||
# self.headerSent member and only checking for the exception as a
|
||||
# secondary measure
|
||||
if not self.headerSent:
|
||||
try:
|
||||
self.headerSent = 1
|
||||
self.response.ContentType = content_type
|
||||
self.response.Status = status
|
||||
except AttributeError:
|
||||
pass
|
||||
|
||||
def redirect(self, url):
|
||||
self.response.Redirect(url)
|
||||
sys.exit()
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return self.server.HTMLEncode(str(s))
|
||||
|
||||
def getenv(self, name, value = None):
|
||||
ret = self.request.ServerVariables(name)()
|
||||
if not type(ret) is types.UnicodeType:
|
||||
return value
|
||||
ret = str(ret)
|
||||
if name == 'PATH_INFO':
|
||||
ret = fix_iis_path_info(self, ret)
|
||||
return ret
|
||||
|
||||
def params(self):
|
||||
p = {}
|
||||
for i in self.request.Form:
|
||||
p[str(i)] = map(str, self.request.Form[i])
|
||||
for i in self.request.QueryString:
|
||||
p[str(i)] = map(str, self.request.QueryString[i])
|
||||
return p
|
||||
|
||||
def FieldStorage(self, fp=None, headers=None, outerboundary="",
|
||||
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||
|
||||
# Code based on a very helpful usenet post by "Max M" (maxm@mxm.dk)
|
||||
# Subject "Re: Help! IIS and Python"
|
||||
# http://groups.google.com/groups?selm=3C7C0AB6.2090307%40mxm.dk
|
||||
|
||||
from StringIO import StringIO
|
||||
from cgi import FieldStorage
|
||||
|
||||
environ = {}
|
||||
for i in self.request.ServerVariables:
|
||||
environ[str(i)] = str(self.request.ServerVariables(i)())
|
||||
|
||||
# this would be bad for uploaded files, could use a lot of memory
|
||||
binaryContent, size = self.request.BinaryRead(int(environ['CONTENT_LENGTH']))
|
||||
|
||||
fp = StringIO(str(binaryContent))
|
||||
fs = FieldStorage(fp, None, "", environ, keep_blank_values, strict_parsing)
|
||||
fp.close()
|
||||
return fs
|
||||
|
||||
def write(self, s):
|
||||
t = type(s)
|
||||
if t is types.StringType:
|
||||
s = buffer(s)
|
||||
elif not t is types.BufferType:
|
||||
s = buffer(str(s))
|
||||
|
||||
self.response.BinaryWrite(s)
|
||||
|
||||
def flush(self):
|
||||
self.response.Flush()
|
||||
|
||||
|
||||
_re_status = re.compile("\\d+")
|
||||
|
||||
|
||||
class ModPythonServer(ThreadedServer):
|
||||
def __init__(self, request):
|
||||
ThreadedServer.__init__(self)
|
||||
self.request = request
|
||||
|
||||
global cgi
|
||||
import cgi
|
||||
|
||||
def header(self, content_type='text/html', status='200 OK'):
|
||||
### what to do with the status?
|
||||
self.request.content_type = content_type
|
||||
m = _re_status.match(status)
|
||||
if not m is None:
|
||||
self.request.status = int(m.group())
|
||||
|
||||
def redirect(self, url):
|
||||
import mod_python.apache
|
||||
|
@ -305,43 +272,81 @@ class ModPythonServer:
|
|||
% (url, url))
|
||||
sys.exit()
|
||||
|
||||
def escape(self, s, quote = None):
|
||||
return cgi.escape(s, quote)
|
||||
|
||||
def getenv(self, name, value = None):
|
||||
try:
|
||||
return self.request.subprocess_env[name]
|
||||
except KeyError:
|
||||
return value
|
||||
|
||||
def params(self):
|
||||
import mod_python.util
|
||||
if self.request.args is None:
|
||||
return {}
|
||||
else:
|
||||
return mod_python.util.parse_qs(self.request.args)
|
||||
|
||||
def FieldStorage(self, fp=None, headers=None, outerboundary="",
|
||||
environ=os.environ, keep_blank_values=0, strict_parsing=0):
|
||||
import mod_python.util
|
||||
return mod_python.util.FieldStorage(self.request, keep_blank_values, strict_parsing)
|
||||
|
||||
def getFile(self):
|
||||
return ModPythonFile(self)
|
||||
|
||||
def close(self, code = 0):
|
||||
server.unregisterThread()
|
||||
|
||||
class ModPythonFile:
|
||||
def __init__(self, server):
|
||||
import StringIO
|
||||
self.closed = 0
|
||||
self.mode = 'w'
|
||||
self.name = "<ModPythonFile file>"
|
||||
self.softspace = 0
|
||||
self.server = server
|
||||
def write(self, s):
|
||||
self.request.write(s)
|
||||
|
||||
def flush(self):
|
||||
pass
|
||||
|
||||
def write(self, s):
|
||||
self.server.request.write(s)
|
||||
|
||||
def writelines(self, ls):
|
||||
raise "not implemented"
|
||||
def fix_iis_url(server, url):
|
||||
"""When a CGI application under IIS outputs a "Location" header with a url
|
||||
beginning with a forward slash, IIS tries to optimise the redirect by not
|
||||
returning any output from the original CGI script at all and instead just
|
||||
returning the new page in its place. Because of this, the browser does
|
||||
not know it is getting a different page than it requested. As a result,
|
||||
The address bar that appears in the browser window shows the wrong location
|
||||
and if the new page is in a different folder than the old one, any relative
|
||||
links on it will be broken.
|
||||
|
||||
def truncate(self, size):
|
||||
pass
|
||||
This function can be used to circumvent the IIS "optimization" of local
|
||||
redirects. If it is passed a location that begins with a forward slash it
|
||||
will return a URL constructed with the information in CGI environment.
|
||||
If it is passed a URL or any location that doens't begin with a forward slash
|
||||
it will return just argument unaltered.
|
||||
"""
|
||||
if url[0] == '/':
|
||||
if server.getenv('HTTPS') == 'on':
|
||||
dport = "443"
|
||||
prefix = "https://"
|
||||
else:
|
||||
dport = "80"
|
||||
prefix = "http://"
|
||||
prefix = prefix + server.getenv('HTTP_HOST')
|
||||
if server.getenv('SERVER_PORT') != dport:
|
||||
prefix = prefix + ":" + server.getenv('SERVER_PORT')
|
||||
return prefix + url
|
||||
return url
|
||||
|
||||
def close(self):
|
||||
pass
|
||||
|
||||
def fix_iis_path_info(server, path_info):
|
||||
"""Fix the PATH_INFO value in IIS"""
|
||||
# If the viewcvs cgi's are in the /viewcvs/ folder on the web server and a
|
||||
# request looks like
|
||||
#
|
||||
# /viewcvs/viewcvs.cgi/myproject/?someoption
|
||||
#
|
||||
# The CGI environment variables on IIS will look like this:
|
||||
#
|
||||
# SCRIPT_NAME = /viewcvs/viewcvs.cgi
|
||||
# PATH_INFO = /viewcvs/viewcvs.cgi/myproject/
|
||||
#
|
||||
# Whereas on Apache they look like:
|
||||
#
|
||||
# SCRIPT_NAME = /viewcvs/viewcvs.cgi
|
||||
# PATH_INFO = /myproject/
|
||||
#
|
||||
# This function converts the IIS PATH_INFO into the nonredundant form
|
||||
# expected by ViewCVS
|
||||
return path_info[len(server.getenv('SCRIPT_NAME', '')):]
|
||||
|
|
|
@ -48,6 +48,7 @@ debug.t_start('imports')
|
|||
import sys
|
||||
import os
|
||||
import sapi
|
||||
import cgi
|
||||
import string
|
||||
import urllib
|
||||
import mimetypes
|
||||
|
@ -113,11 +114,13 @@ else:
|
|||
|
||||
|
||||
class Request:
|
||||
def __init__(self):
|
||||
def __init__(self, server):
|
||||
# global needed because "import vclib.svn" causes the
|
||||
# interpreter to make vclib a local variable
|
||||
global vclib
|
||||
|
||||
self.server = server
|
||||
|
||||
where = server.getenv('PATH_INFO', '')
|
||||
|
||||
# clean it up. this removes duplicate '/' characters and any that may
|
||||
|
@ -299,14 +302,14 @@ def _validate_param(name, value):
|
|||
validator = _legal_params[name]
|
||||
except KeyError:
|
||||
raise debug.ViewcvsException(
|
||||
'An illegal parameter name ("%s") was passed.' % server.escape(name))
|
||||
'An illegal parameter name ("%s") was passed.' % cgi.escape(name))
|
||||
|
||||
# is the validator a regex?
|
||||
if hasattr(validator, 'match'):
|
||||
if not validator.match(value):
|
||||
raise debug.ViewcvsException(
|
||||
'An illegal value ("%s") was passed as a parameter.' %
|
||||
server.escape(value))
|
||||
cgi.escape(value))
|
||||
return
|
||||
|
||||
# the validator must be a function
|
||||
|
@ -318,7 +321,7 @@ def _validate_root(value):
|
|||
raise debug.ViewcvsException(
|
||||
'The root "%s" is unknown. If you believe the value is '
|
||||
'correct, then please double-check your configuration.'
|
||||
% server.escape(value), "404 Repository not found")
|
||||
% cgi.escape(value), "404 Repository not found")
|
||||
|
||||
def _validate_regex(value):
|
||||
# hmm. there isn't anything that we can do here.
|
||||
|
@ -465,7 +468,7 @@ def is_text(mime_type):
|
|||
_re_rewrite_url = re.compile('((http|ftp)(://[-a-zA-Z0-9%.~:_/]+)([?&]([-a-zA-Z0-9%.~:_]+)=([-a-zA-Z0-9%.~:_])+)*(#([-a-zA-Z0-9%.~:_]+)?)?)')
|
||||
_re_rewrite_email = re.compile('([-a-zA-Z0-9_.]+@([-a-zA-Z0-9]+\.)+[A-Za-z]{2,4})')
|
||||
def htmlify(html):
|
||||
html = server.escape(html)
|
||||
html = cgi.escape(html)
|
||||
html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
|
||||
html = re.sub(_re_rewrite_email, r'<a href="mailto:\1">\1</a>', html)
|
||||
return html
|
||||
|
@ -595,7 +598,7 @@ def markup_stream_python(fp):
|
|||
else:
|
||||
### it doesn't escape stuff quite right, nor does it munge URLs and
|
||||
### mailtos as well as we do.
|
||||
html = server.escape(fp.read())
|
||||
html = cgi.escape(fp.read())
|
||||
pp = py2html.PrettyPrint(PyFontify.fontify, "rawhtml", "color")
|
||||
html = pp.fontify(html)
|
||||
html = re.sub(_re_rewrite_url, r'<a href="\1">\1</a>', html)
|
||||
|
@ -835,7 +838,7 @@ def markup_stream(request, fp, revision, mime_type):
|
|||
else:
|
||||
data['tag'] = query_dict.get('only_with_tag')
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.markup, data)
|
||||
|
||||
if mime_type[:6] == 'image/':
|
||||
|
@ -1010,7 +1013,7 @@ def prepare_hidden_values(request, var_list, vars_to_omit_list):
|
|||
value = query_dict.get(varname, '')
|
||||
if value != '' and value != default_settings.get(varname):
|
||||
hidden_values.append('<input type="hidden" name="%s" value="%s" />' %
|
||||
(varname, server.escape(value)))
|
||||
(varname, request.server.escape(value)))
|
||||
return string.join(hidden_values, '')
|
||||
|
||||
def sort_file_data(file_data, sortdir, sortby, fileinfo, roottype):
|
||||
|
@ -1388,7 +1391,7 @@ def view_directory_cvs(request):
|
|||
data['dir_pagestart'] = int(query_dict.get('dir_pagestart',0))
|
||||
data['rows'] = paging(data, 'rows', data['dir_pagestart'], 'name')
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.directory, data)
|
||||
|
||||
def view_directory_svn(request):
|
||||
|
@ -1515,7 +1518,7 @@ def view_directory_svn(request):
|
|||
# the number actually displayed
|
||||
data['files_shown'] = num_displayed
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.directory, data)
|
||||
|
||||
def paging(data, key, pagestart, local_name):
|
||||
|
@ -1695,11 +1698,10 @@ def read_log(full_name, which_rev=None, view_tag=None, logsort='cvs'):
|
|||
_re_is_vendor_branch = re.compile(r'^1\.1\.1\.\d+$')
|
||||
|
||||
def augment_entry(entry, request, file_url, rev_map, rev2tag, branch_points,
|
||||
rev_order, extended):
|
||||
rev_order, extended, name_printed):
|
||||
"Augment the entry with additional, computed data from the log output."
|
||||
|
||||
query_dict = request.query_dict
|
||||
g_name_printed = server.pageGlobals['g_name_printed']
|
||||
|
||||
rev = entry.rev
|
||||
idx = string.rfind(rev, '.')
|
||||
|
@ -1732,9 +1734,9 @@ def augment_entry(entry, request, file_url, rev_map, rev2tag, branch_points,
|
|||
|
||||
if extended:
|
||||
entry.tag_names = rev2tag.get(rev, [ ])
|
||||
if rev2tag.has_key(branch) and not g_name_printed.has_key(branch):
|
||||
if rev2tag.has_key(branch) and not name_printed.has_key(branch):
|
||||
entry.branch_names = rev2tag.get(branch)
|
||||
g_name_printed[branch] = 1
|
||||
name_printed[branch] = 1
|
||||
else:
|
||||
entry.branch_names = [ ]
|
||||
|
||||
|
@ -1907,7 +1909,7 @@ def view_log_svn(request):
|
|||
data['log_pagestart'] = int(query_dict.get('log_pagestart',0))
|
||||
data['entries'] = paging(data, 'entries', data['log_pagestart'], 'rev')
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.log, data)
|
||||
|
||||
def view_log_cvs(request):
|
||||
|
@ -2000,11 +2002,11 @@ def view_log_cvs(request):
|
|||
else:
|
||||
data['head_href'] = download_url(request, file_url, 'HEAD', None)
|
||||
|
||||
server.pageGlobals['g_name_printed'] = { } ### gawd, what a hack...
|
||||
name_printed = { }
|
||||
for entry in show_revs:
|
||||
# augment the entry with (extended=1) info.
|
||||
augment_entry(entry, request, file_url, rev_map, rev2tag, branch_points,
|
||||
rev_order, 1)
|
||||
rev_order, 1, name_printed)
|
||||
|
||||
tagitems = taginfo.items()
|
||||
tagitems.sort()
|
||||
|
@ -2061,7 +2063,7 @@ def view_log_cvs(request):
|
|||
data['log_pagestart'] = int(query_dict.get('log_pagestart',0))
|
||||
data['entries'] = paging(data, 'entries', data['log_pagestart'], 'rev')
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.log, data)
|
||||
|
||||
### suck up other warnings in _re_co_warning?
|
||||
|
@ -2167,7 +2169,7 @@ def view_checkout(request):
|
|||
# use the "real" MIME type
|
||||
markup_stream(request, fp, revision, request.mime_type)
|
||||
else:
|
||||
server.header(mime_type)
|
||||
request.server.header(mime_type)
|
||||
copy_stream(fp)
|
||||
|
||||
def view_annotate(request):
|
||||
|
@ -2184,7 +2186,7 @@ def view_annotate(request):
|
|||
'kv' : request.kv,
|
||||
})
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.annotate, data)
|
||||
|
||||
### be nice to hook this into the template...
|
||||
|
@ -2198,7 +2200,7 @@ def view_annotate(request):
|
|||
def cvsgraph_image(cfg, request):
|
||||
"output the image rendered by cvsgraph"
|
||||
# this function is derived from cgi/cvsgraphmkimg.cgi
|
||||
server.header('image/png')
|
||||
request.server.header('image/png')
|
||||
fp = popen.popen(os.path.normpath(os.path.join(cfg.options.cvsgraph_path,'cvsgraph')),
|
||||
("-c", cfg.options.cvsgraph_conf,
|
||||
"-r", request.repos.rootpath,
|
||||
|
@ -2239,7 +2241,7 @@ def view_cvsgraph(cfg, request):
|
|||
'kv' : request.kv,
|
||||
})
|
||||
|
||||
server.header()
|
||||
request.server.header()
|
||||
generate_page(request, cfg.templates.graph, data)
|
||||
|
||||
def search_files(request, search_re):
|
||||
|
@ -2334,13 +2336,13 @@ def view_doc(request):
|
|||
raise debug.ViewcvsException('help file "%s" not available\n(%s)'
|
||||
% (help_page, str(v)), '404 Not Found')
|
||||
if help_page[-3:] == 'png':
|
||||
server.header('image/png')
|
||||
request.server.header('image/png')
|
||||
elif help_page[-3:] == 'jpg':
|
||||
server.header('image/jpeg')
|
||||
request.server.header('image/jpeg')
|
||||
elif help_page[-3:] == 'gif':
|
||||
server.header('image/gif')
|
||||
request.server.header('image/gif')
|
||||
else: # assume HTML:
|
||||
server.header()
|
||||
request.server.header()
|
||||
copy_stream(fp)
|
||||
fp.close()
|
||||
|
||||
|
@ -2349,7 +2351,7 @@ _re_extract_rev = re.compile(r'^[-+]+ [^\t]+\t([^\t]+)\t((\d+\.)*\d+)$')
|
|||
_re_extract_info = re.compile(r'@@ \-([0-9]+).*\+([0-9]+).*@@(.*)')
|
||||
def human_readable_diff(request, fp, rev1, rev2, sym1, sym2):
|
||||
# do this now, in case we need to print an error
|
||||
server.header()
|
||||
request.server.header()
|
||||
|
||||
query_dict = request.query_dict
|
||||
|
||||
|
@ -2373,12 +2375,12 @@ def human_readable_diff(request, fp, rev1, rev2, sym1, sym2):
|
|||
if line[:4] == '--- ':
|
||||
match = _re_extract_rev.match(line)
|
||||
if match:
|
||||
date1 = ', ' + match.group(1)
|
||||
date1 = match.group(1)
|
||||
log_rev1 = match.group(2)
|
||||
elif line[:4] == '+++ ':
|
||||
match = _re_extract_rev.match(line)
|
||||
if match:
|
||||
date2 = ', ' + match.group(1)
|
||||
date2 = match.group(1)
|
||||
log_rev2 = match.group(2)
|
||||
break
|
||||
|
||||
|
@ -2421,11 +2423,11 @@ def human_readable_diff(request, fp, rev1, rev2, sym1, sym2):
|
|||
# Convert to local time if option is set, otherwise remains UTC
|
||||
if (cfg.options.use_localtime):
|
||||
def time_format(date):
|
||||
date = compat.cvs_strptime(date[-19:])
|
||||
date = compat.cvs_strptime(date)
|
||||
date = compat.timegm(date)
|
||||
localtime = time.localtime(date)
|
||||
date = time.strftime('%Y/%m/%d %H:%M:%S', localtime)
|
||||
return ', ' + date + ' ' + time.tzname[localtime[8]]
|
||||
return date + ' ' + time.tzname[localtime[8]]
|
||||
date1 = time_format(date1)
|
||||
date2 = time_format(date2)
|
||||
else:
|
||||
|
@ -2442,8 +2444,8 @@ def human_readable_diff(request, fp, rev1, rev2, sym1, sym2):
|
|||
'rev2' : rev2,
|
||||
'tag1' : sym1,
|
||||
'tag2' : sym2,
|
||||
'date1' : date1,
|
||||
'date2' : date2,
|
||||
'date1' : ', ' + date1,
|
||||
'date2' : ', ' + date2,
|
||||
'changes' : rcs_diff,
|
||||
'diff_format' : query_dict['diff_format'],
|
||||
'hidden_values' : hidden_values,
|
||||
|
@ -2706,7 +2708,7 @@ def view_diff(request):
|
|||
human_readable_diff(request, fp, rev1, rev2, sym1, sym2)
|
||||
return
|
||||
|
||||
server.header('text/plain')
|
||||
request.server.header('text/plain')
|
||||
|
||||
rootpath = request.repos.rootpath
|
||||
if unified:
|
||||
|
@ -2856,7 +2858,7 @@ def download_tarball(request):
|
|||
|
||||
### look for GZIP binary
|
||||
|
||||
server.header('application/octet-stream')
|
||||
request.server.header('application/octet-stream')
|
||||
sys.stdout.flush()
|
||||
fp = popen.pipe_cmds([('gzip', '-c', '-n')])
|
||||
generate_tarball(fp, request, tar_top, rep_top, [], tag)
|
||||
|
@ -2919,7 +2921,7 @@ def run_viewcvs(server):
|
|||
handle_config()
|
||||
|
||||
# build a Request object, which contains info about the HTTP request
|
||||
request = Request()
|
||||
request = Request(server)
|
||||
|
||||
# most of the startup is done now.
|
||||
debug.t_end('startup')
|
||||
|
@ -3027,30 +3029,21 @@ def run_viewcvs(server):
|
|||
% request.url, '404 Not Found')
|
||||
|
||||
|
||||
def main():
|
||||
### this is a bad hack. various functions expect a runtime global
|
||||
### named 'server' which corresponds to how we generate output.
|
||||
### bleck. the right answer is to make this part of the Request object
|
||||
### and ensure that every function is passed the Request instance.
|
||||
### this would also allow us to toss the AspProxy and its per-thread
|
||||
### nonsense.
|
||||
global server
|
||||
server = sapi.server
|
||||
|
||||
def main(server):
|
||||
try:
|
||||
debug.t_start('main')
|
||||
|
||||
try:
|
||||
run_viewcvs(sapi.server)
|
||||
run_viewcvs(server)
|
||||
except SystemExit, e:
|
||||
return
|
||||
except:
|
||||
debug.PrintException()
|
||||
debug.PrintException(server)
|
||||
html_footer(None)
|
||||
finally:
|
||||
debug.t_end('main')
|
||||
debug.dump()
|
||||
debug.DumpChildren()
|
||||
debug.DumpChildren(server)
|
||||
|
||||
|
||||
class _item:
|
||||
|
|
|
@ -71,16 +71,23 @@ class Options:
|
|||
|
||||
class StandaloneServer(sapi.CgiServer):
|
||||
def __init__(self, handler):
|
||||
sapi.CgiServer.__init__(self)
|
||||
sapi.CgiServer.__init__(self, inheritableOut = sys.platform != "win32")
|
||||
self.handler = handler
|
||||
self.sent = 0
|
||||
self.inheritableOut = sys.platform != "win32"
|
||||
|
||||
def header(self, content_type='text/html'):
|
||||
if not self.sent:
|
||||
def header(self, content_type='text/html', status = '200 OK'):
|
||||
if not self.headerSent:
|
||||
self.headerSent = 1
|
||||
p = string.find(status, ' ')
|
||||
if p < 0:
|
||||
statusCode = status
|
||||
statusText = ''
|
||||
else:
|
||||
statusCode = status[:p]
|
||||
statusText = status[p+1:]
|
||||
self.handler.send_response(statusCode, statusText)
|
||||
self.handler.send_header("Content-type", content_type)
|
||||
self.handler.end_headers()
|
||||
self.sent = 1
|
||||
|
||||
|
||||
def serve(host, port, callback=None):
|
||||
"""start a HTTP server on the given port. call 'callback' when the
|
||||
|
@ -93,7 +100,6 @@ def serve(host, port, callback=None):
|
|||
if not self.path or self.path == "/":
|
||||
self.redirect()
|
||||
elif self.is_viewcvs():
|
||||
StandaloneServer(self)
|
||||
try:
|
||||
self.run_viewcvs()
|
||||
except IOError:
|
||||
|
@ -203,8 +209,6 @@ If this doesn't work, please click on the link above.
|
|||
# XXX Other HTTP_* headers
|
||||
decoded_query = string.replace(query, '+', ' ')
|
||||
|
||||
self.send_response(200)
|
||||
|
||||
# Preserve state, because we execute script in current process:
|
||||
save_argv = sys.argv
|
||||
save_stdin = sys.stdin
|
||||
|
@ -222,7 +226,7 @@ If this doesn't work, please click on the link above.
|
|||
os.close(1)
|
||||
assert os.dup(self.wfile.fileno()) == 1
|
||||
sys.stdin = self.rfile
|
||||
viewcvs.main()
|
||||
viewcvs.main(StandaloneServer(self))
|
||||
finally:
|
||||
sys.argv = save_argv
|
||||
sys.stdin = save_stdin
|
||||
|
|
|
@ -55,7 +55,7 @@ import query
|
|||
|
||||
s = sapi.AspServer(Server, Request, Response, Application)
|
||||
try:
|
||||
query.main('viewcvs.asp')
|
||||
query.main(s, 'viewcvs.asp')
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@ import query
|
|||
|
||||
s = sapi.ModPythonServer(Request)
|
||||
try:
|
||||
query.main('viewcvs.py')
|
||||
query.main(s, 'viewcvs.py')
|
||||
finally:
|
||||
s.close()
|
|
@ -60,7 +60,7 @@ import viewcvs
|
|||
|
||||
s = sapi.AspServer(Server, Request, Response, Application)
|
||||
try:
|
||||
viewcvs.main()
|
||||
viewcvs.main(s)
|
||||
finally:
|
||||
s.close()
|
||||
|
||||
|
|
|
@ -3,6 +3,6 @@ import viewcvs
|
|||
|
||||
s = sapi.ModPythonServer(Request)
|
||||
try:
|
||||
viewcvs.main()
|
||||
viewcvs.main(s)
|
||||
finally:
|
||||
s.close()
|
Loading…
Reference in New Issue