from urlparse import urlparse, urlsplit from cgi import parse_qs import cStringIO as StringIO from twisted.internet import defer from twisted.web import server, resource, client def encodeFormData(arg, value): """Encode data as a multipart/form-data """ BOUNDARY = '----------BOUNDARY' l = [] l.append('--' + BOUNDARY) l.append('Content-Disposition: form-data; name="%s"' % arg) l.append('') l.append(value) l.append('--' + BOUNDARY + '--') l.append('') body = '\r\n'.join(l) contentType = 'multipart/form-data; boundary=%s' % BOUNDARY return body, contentType class FakeTransport(object): def __init__(self): self.io = StringIO.StringIO() def writeSequence(self, sequence): self.io.writelines(sequence) def write(self, data): self.io.write(data) def getData(self): return self.io.getvalue() class MarkupValidator(resource.Resource): """A simple gateway to a validator service for Twisted Web. """ # Please, install a validator on your server! uri = 'http://validator.w3.org/check' arg = 'fragment' def __init__(self, site): """site is the site object of your twisted.web server """ self.site = site def render_GET(self, request): def finish(data): # Write the data back to our client request.clientproto = clientproto transport.write(data) transport.loseConnection() # Get the referer and parse it referer = request.getHeader('referer') scheme, netloc, path, parameters, query, fragment = urlparse(referer) args = parse_qs(query) transport = request.transport clientproto = request.clientproto # Modify the original request request.uri = referer request.path = path request.args = args request.clientproto = 'HTTP/1.0' # we don't want chunk encoding request.transport = FakeTransport() # Reload the modified request on the server, without using HTTP deferred = request.notifyFinish() request.process() # XXX TODO handle errors deferred.addCallback(lambda _: request.transport.getData() ).addCallback(self.validate, request ).addCallback(finish) return server.NOT_DONE_YET def validate(self, data, request): # We need only the body data = data[data.find('\r\n\r\n') + 4:] # Build the request for the validator service, using the # original request as the base headers = request.received_headers data, contentType = encodeFormData(self.arg, data) headers['content-type'] = contentType headers.pop('cookie', None) headers.pop('referer', None) headers.pop('host', None) return client.getPage( self.uri, method='POST', headers=headers, postdata=data ) if __name__ == '__main__': """A simple usage example. """ from twisted.web import server from twisted.internet import reactor class Simple(resource.Resource): def render_GET(self, request): return """ twvalidator example

twvalidator example

validate

""" def getChild(self, name, request): if name == '': return self return resource.Resource.getChild( self, name, request) root = Simple() site = server.Site(root) root.putChild('validate', MarkupValidator(site)) reactor.listenTCP(8080, site) reactor.run()