Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
9 contributors

Users who have contributed to this file

@djmitche @rodrigc @vrutkovs @tomprince @rjarry @p12tic @tardyp @jvlomax @sa2ajj
125 lines (98 sloc) 3.79 KB
# This file is part of Buildbot. Buildbot is free software: you can
# redistribute it and/or modify it under the terms of the GNU General Public
# License as published by the Free Software Foundation, version 2.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
# details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 51
# Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright Buildbot Team Members
import re
from twisted.internet import defer
from twisted.python import log
from twisted.web import resource
from twisted.web import server
from twisted.web.error import Error
from buildbot.util import unicode2bytes
_CR_LF_RE = re.compile(br"[\r\n]+.*")
def protect_redirect_url(url):
return _CR_LF_RE.sub(b"", url)
class Redirect(Error):
def __init__(self, url):
super().__init__(302, "redirect")
self.url = protect_redirect_url(unicode2bytes(url))
class Resource(resource.Resource):
# if this is true for a class, then instances will have their
# reconfigResource(new_config) methods called on reconfig.
needsReconfig = False
# as a convenience, subclasses have a ``master`` attribute, a
# ``base_url`` attribute giving Buildbot's base URL,
# and ``static_url`` attribute giving Buildbot's static files URL
@property
def base_url(self):
return self.master.config.buildbotURL
def __init__(self, master):
super().__init__()
self.master = master
if self.needsReconfig and master is not None:
master.www.resourceNeedsReconfigs(self)
def reconfigResource(self, new_config):
raise NotImplementedError
def asyncRenderHelper(self, request, _callable, writeError=None):
def writeErrorDefault(msg, errcode=400):
request.setResponseCode(errcode)
request.setHeader(b'content-type', b'text/plain; charset=utf-8')
request.write(msg)
request.finish()
if writeError is None:
writeError = writeErrorDefault
try:
d = _callable(request)
except Exception as e:
d = defer.fail(e)
@d.addCallback
def finish(s):
try:
if s is not None:
request.write(s)
request.finish()
except RuntimeError: # pragma: no cover
# this occurs when the client has already disconnected; ignore
# it (see #2027)
log.msg("http client disconnected before results were sent")
@d.addErrback
def failHttpRedirect(f):
f.trap(Redirect)
request.redirect(f.value.url)
request.finish()
return None
@d.addErrback
def failHttpError(f):
f.trap(Error)
e = f.value
message = unicode2bytes(e.message)
writeError(message, errcode=int(e.status))
@d.addErrback
def fail(f):
log.err(f, 'While rendering resource:')
try:
writeError(b'internal error - see logs', errcode=500)
except Exception:
try:
request.finish()
except Exception:
pass
return server.NOT_DONE_YET
class RedirectResource(Resource):
def __init__(self, master, basepath):
super().__init__(master)
self.basepath = basepath
def render(self, request):
redir = self.base_url + self.basepath
request.redirect(protect_redirect_url(redir))
return redir
You can’t perform that action at this time.