def preprocessRequest(self): """Do any request processing that doesn't follow the normal resource lookup procedure. "OPTIONS *" is handled here, for example. This would also be the place to do any CONNECT processing.""" # Always reject HTTP/1.0 - no clients should use it if self.clientproto == (1, 0): raise http.HTTPError(responsecode.BAD_REQUEST) if self.method == "OPTIONS" and self.uri == "*": response = http.Response(responsecode.OK) response.headers.setHeader('allow', ('GET', 'HEAD', 'OPTIONS', 'TRACE')) return response elif self.method == "POST": # Allow other methods to tunnel through using POST and a request header. # See http://code.google.com/apis/gdata/docs/2.0/basics.html if self.headers.hasHeader("X-HTTP-Method-Override"): intendedMethod = self.headers.getRawHeaders( "X-HTTP-Method-Override")[0] if intendedMethod: self.originalMethod = self.method self.method = intendedMethod # This is where CONNECT would go if we wanted it return None
def render(self, req): if req.avatar.username == 'anonymous': if not self.sendOwnHeaders: raise http.HTTPError(responsecode.UNAUTHORIZED) else: return http.Response( responsecode.UNAUTHORIZED, {'www-authenticate': [('basic', {'realm': 'foo'})]}) else: return super(NonAnonymousResource, self).render(req)
def _handleSegment(self, result, res, path, updatepaths): """Handle the result of a locateChild call done in _getChild.""" newres, newpath = result # If the child resource is None then display a error page if newres is None: raise http.HTTPError(responsecode.NOT_FOUND) # If we got a deferred then we need to call back later, once the # child is actually available. if isinstance(newres, defer.Deferred): return newres.addCallback(lambda actualRes: self._handleSegment( (actualRes, newpath), res, path, updatepaths)) if path: url = quote("/" + "/".join(path)) else: url = "/" if newpath is StopTraversal: # We need to rethink how to do this. # if newres is res: return res # else: # raise ValueError("locateChild must not return StopTraversal with a resource other than self.") newres = iweb.IResource(newres) if newres is res: assert newpath is not path, "URL traversal cycle detected when attempting to locateChild %r from resource %r." % ( path, res) assert len(newpath) < len(path), "Infinite loop impending..." if updatepaths: # We found a Resource... update the request.prepath and postpath for _ in xrange(len(path) - len(newpath)): self.prepath.append(self.postpath.pop(0)) url = quote("/" + "/".join(self.prepath) + ("/" if self.prepath and self.prepath[-1] else "")) self._rememberResource(newres, url) else: try: previousURL = self.urlForResource(res) url = quote(previousURL + path[0] + ("/" if path[0] and len(path) > 1 else "")) self._rememberResource(newres, url) except NoURLForResourceError: pass child = self._getChild(None, newres, newpath, updatepaths=updatepaths) return child
def _fixupURLParts(self): _ignore_hostaddr, secure = self.chanRequest.getHostInfo() if not self.scheme: self.scheme = ('http', 'https')[secure] if self.host: self.host, self.port = http.splitHostPort(self.scheme, self.host) self.scheme = ('http', 'https')[self._schemeFromPort(self.port)] else: # If GET line wasn't an absolute URL host = self.headers.getHeader('host') if host: self.host, self.port = http.splitHostPort(self.scheme, host) self.scheme = ('http', 'https')[self._schemeFromPort(self.port)] else: # When no hostname specified anywhere, either raise an # error, or use the interface hostname, depending on # protocol version if self.clientproto >= (1, 1): raise http.HTTPError(responsecode.BAD_REQUEST) # Always require host header even for HTTP/1.0 raise http.HTTPError(responsecode.BAD_REQUEST)
def parsePOSTData(request, maxMem=100 * 1024, maxFields=1024, maxSize=10 * 1024 * 1024): """ Parse data of a POST request. @param request: the request to parse. @type request: L{txweb2.http.Request}. @param maxMem: maximum memory used during the parsing of the data. @type maxMem: C{int} @param maxFields: maximum number of form fields allowed. @type maxFields: C{int} @param maxSize: maximum size of file upload allowed. @type maxSize: C{int} @return: a deferred that will fire when the parsing is done. The deferred itself doesn't hold a return value, the request is modified directly. @rtype: C{defer.Deferred} """ if request.stream.length == 0: return defer.succeed(None) ctype = request.headers.getHeader('content-type') if ctype is None: return defer.succeed(None) def updateArgs(data): args = data request.args.update(args) def updateArgsAndFiles(data): args, files = data request.args.update(args) request.files.update(files) def error(f): f.trap(fileupload.MimeFormatError) raise http.HTTPError( http.StatusResponse(responsecode.BAD_REQUEST, str(f.value))) if (ctype.mediaType == 'application' and ctype.mediaSubtype == 'x-www-form-urlencoded'): d = fileupload.parse_urlencoded(request.stream) d.addCallbacks(updateArgs, error) return d elif (ctype.mediaType == 'multipart' and ctype.mediaSubtype == 'form-data'): boundary = ctype.params.get('boundary') if boundary is None: return defer.fail( http.HTTPError( http.StatusResponse( responsecode.BAD_REQUEST, "Boundary not specified in Content-Type."))) d = fileupload.parseMultipartFormData(request.stream, boundary, maxMem, maxFields, maxSize) d.addCallbacks(updateArgsAndFiles, error) return d else: return defer.fail( http.HTTPError( http.StatusResponse( responsecode.BAD_REQUEST, "Invalid content-type: %s/%s" % (ctype.mediaType, ctype.mediaSubtype))))
def locateResource(self, url): """ Looks up the resource with the given URL. @param uri: The URL of the desired resource. @return: a L{Deferred} resulting in the L{IResource} at the given URL or C{None} if no such resource can be located. @raise HTTPError: If C{url} is not a URL on the site that this request is being applied to. The contained response will have a status code of L{responsecode.BAD_GATEWAY}. @raise HTTPError: If C{url} contains a query or fragment. The contained response will have a status code of L{responsecode.BAD_REQUEST}. """ if url is None: return defer.succeed(None) # # Parse the URL # (_ignore_scheme, _ignore_host, path, query, fragment) = urlsplit(url) if query or fragment: raise http.HTTPError( http.StatusResponse( responsecode.BAD_REQUEST, "URL may not contain a query or fragment: %s" % (url, ))) # Look for cached value cached = self._resourcesByURL.get(path, None) if cached is not None: return defer.succeed(cached) segments = unquote(path).split("/") assert segments[0] == "", "URL path didn't begin with '/': %s" % ( path, ) # Walk the segments up to see if we can find a cached resource to start from preSegments = segments[:-1] postSegments = segments[-1:] cachedParent = None while (len(preSegments)): parentPath = "/".join(preSegments) + "/" cachedParent = self._resourcesByURL.get(parentPath, None) if cachedParent is not None: break else: postSegments.insert(0, preSegments.pop()) if cachedParent is None: cachedParent = self.site.resource postSegments = segments[1:] def notFound(f): f.trap(http.HTTPError) if f.value.response.code != responsecode.NOT_FOUND: return f return None d = defer.maybeDeferred(self._getChild, None, cachedParent, postSegments, updatepaths=False) d.addCallback(self._rememberResource, path) d.addErrback(notFound) return d
def error(f): f.trap(fileupload.MimeFormatError) raise http.HTTPError( http.StatusResponse(responsecode.BAD_REQUEST, str(f.value)))
# # def __init__(self, path): # self.path = path # # def renderHTTP(self, request): # request.startedWriting = 1 # return File(self.path) # # def locateChild(self, request): # return None, () ## # Utilities ## dangerousPathError = http.HTTPError( responsecode.NOT_FOUND) #"Invalid request URL." def isDangerous(path): return path == '..' or '/' in path or os.sep in path def addSlash(request): return "http%s://%s%s/" % (request.isSecure() and 's' or '', request.getHeader("host"), (request.uri.split('?')[0])) def loadMimeTypes(mimetype_locations=['/etc/mime.types']): """ Multiple file locations containing mime-types can be passed as a list.
def _respond(response): return failure.Failure(http.HTTPError(response))