def __init__(self, webapp, server, outs): self.webapp = webapp # not a weakref, because a response object is short-lived. self.server = server self._outs = self.outs = outs self.content_type = "text/html" self.content_encoding = None self.content_length = -1 self.content_disposition = None self.header_written = False self.error_sent = False self.redirection_performed = False self.__being_redirected = False self.response_code = 200 self.response_string = "OK" self.userHeaders = NormalizedHeaderDict() self.cookies = Cookie.SimpleCookie() self.__outputsstack = []
def __init__(self, webapp, server, outs): self.webapp=webapp # not a weakref, because a response object is short-lived. self.server=server self._outs=self.outs=outs self.content_type="text/html" self.content_encoding=None self.content_length=-1 self.content_disposition=None self.header_written=False self.error_sent=False self.redirection_performed=False self.__being_redirected=False self.response_code=200 self.response_string="OK" self.userHeaders=NormalizedHeaderDict() self.cookies=Cookie.SimpleCookie() self.__outputsstack=[]
class Response(object): def __init__(self, webapp, server, outs): self.webapp=webapp # not a weakref, because a response object is short-lived. self.server=server self._outs=self.outs=outs self.content_type="text/html" self.content_encoding=None self.content_length=-1 self.content_disposition=None self.header_written=False self.error_sent=False self.redirection_performed=False self.__being_redirected=False self.response_code=200 self.response_string="OK" self.userHeaders=NormalizedHeaderDict() self.cookies=Cookie.SimpleCookie() self.__outputsstack=[] def setContentType(self, type): self.content_type=type def setContentDisposition(self, disposition): self.content_disposition=disposition def setContentLength(self, length, force=False): if not force and self.content_encoding: raise IOError("cannot set content length if a custom output encoding has been specified") self.content_length=length if self.server: self.server.content_length=length def getEncoding(self): return self.content_encoding def setEncoding(self, encoding): if self.__being_redirected or self.content_encoding==encoding: # We're being used in a redirection/inclusion, or the specified encoding # is already set. Do not change the encoding in both cases. return self.content_encoding=encoding if self.content_length>=0: raise IOError("cannot set custom output encoding if contentlength has been specified") if encoding: self.outs=codecs.getwriter(encoding)(self._outs, errors="xmlcharrefreplace") else: self.outs=self._outs # remove codec def forceEncoding(self, encoding): # set an encoding. No checks! Danger! Normal usage should be setEncoding. self.content_encoding = encoding def guessMimeType(self, filename): return self.server.guess_type(filename) def setHeader(self, header, value): self.userHeaders[header]=value def getHeader(self, header): return self.userHeaders.get(header) def setResponse(self, code, msg="Snakelet output follows"): self.response_code=code self.response_string=msg def HTTPredirect(self, URL): if self.header_written: raise RuntimeError('can not redirect when getOutput() has been called') self.setResponse(302) # HTTP 302=redirect (Found) self.userHeaders["Location"]=URL out=self.getOutput() out.write("<html><head><title>Redirection</title></head>\n" "<body><h1>Redirection</h1>\nYou're being <a href=\""+URL+"\">redirected</a>.</body></html>") self.setRedirectionDone() def writeHeader(self): # minimalistic HTTP response header if self.header_written: raise RuntimeError("header has already been written") self.server.send_response(self.response_code, self.response_string) contentType=self.content_type if self.content_encoding: contentType+="; charset="+self.content_encoding self.userHeaders["Content-Type"]=contentType if self.content_disposition: self.userHeaders["Content-Disposition"]=self.content_disposition if self.content_length>=0: self.userHeaders["Content-Length"]=str(self.content_length) for (h,v) in self.userHeaders.iteritems(): self.server.send_header(h,v) for c in self.cookies.values(): self.server.send_header("Set-Cookie",c.OutputString()) self.server.end_headers() self.header_written=True def getOutput(self): if self.redirection_performed: raise RuntimeError('cannot write after redirect() call') if not self.header_written: self.writeHeader() return self.outs def sendError(self, code, message=None): if not self.header_written: self.error_sent=True self.header_written=True self.server.send_error(code, message, self.userHeaders) else: raise RuntimeError("cannot send error after header has been written") def getCookies(self): return self.cookies def setCookie(self, name, value, path=None, domain=None, maxAge=None, comment=None, secure=None): self.cookies[name]=value self.cookies[name]["version"]=1 self.cookies[name]["path"]='' self.cookies[name]["domain"]='' self.cookies[name]["max-age"]='' self.cookies[name]["expires"]='' self.cookies[name]["comment"]='' self.cookies[name]["secure"]='' if path: self.cookies[name]["path"]=path if domain: self.cookies[name]["domain"]=domain if maxAge!=None: self.cookies[name]["max-age"]=maxAge # for modern browsers if maxAge>0: self.cookies[name]["expires"]=maxAge # for Internet Explorer else: # discard cookie, set expires to a time far in the past self.cookies[name]["expires"]="Mon, 01-Jan-1900 00:00:00 GMT" # for Internet Explorer if comment: self.cookies[name]["comment"]=comment if secure: self.cookies[name]["secure"]=secure self.userHeaders["P3P"]="CP='CUR ADM OUR NOR STA NID'" # P3P compact policy def delCookie(self, name, path=None, domain=None, comment=None, secure=None): # delete the cookie by setting maxAge to zero. self.setCookie(name, "", path, domain, 0, comment, secure) def setRedirectionDone(self): self.__being_redirected=False self.redirection_performed=True def beingRedirected(self): return self.__being_redirected def used(self): return self.redirection_performed or self.header_written or self.error_sent def kill(self): self.server.kill() self.error_sent=True def initiateRedirection(self,url, isInclude=False): self.__being_redirected = True if self.header_written: self.outs.flush() else: if isInclude: self.writeHeader() #else: # XXX we used to send a Content-Location header, but the handling is inconsistent # among the web-browsers. Opera does it "right" (follows # the RFC http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14 # but other browsers such as IE/Mozilla/Firefox do NOT follow the RFC. # See https://bugzilla.mozilla.org/show_bug.cgi?id=109553 # So we don't send this header, and all will be right. I hope. # self.userHeaders["Content-Location"]=url def wasErrorSent(self): return self.error_sent def YpushOutput(self, output): self.__outputsstack.append(self._outs) # save old output self._outs=self.outs=output def YpopOutput(self): oldOut = self.__outputsstack.pop() self._outs=self.outs=oldOut def forceFlush(self, stream): # force response flush to output stream out=self.getOutput() stream.flush() if hasattr(out, 'fileno'): if out.fileno()==stream.fileno(): # using direct stream, we're done return else: del out, stream raise IOError("response is a stream but not the socket. Don't know how to handle this. Bail out") # we're using a custom output buffer such as a StringIO. Flush that. out.seek(0) self.server.copyfile(out, stream, not self.__being_redirected) # don't close when being redirected.. # now clear the output buffer out.seek(0) out.truncate()
class Response(object): def __init__(self, webapp, server, outs): self.webapp = webapp # not a weakref, because a response object is short-lived. self.server = server self._outs = self.outs = outs self.content_type = "text/html" self.content_encoding = None self.content_length = -1 self.content_disposition = None self.header_written = False self.error_sent = False self.redirection_performed = False self.__being_redirected = False self.response_code = 200 self.response_string = "OK" self.userHeaders = NormalizedHeaderDict() self.cookies = Cookie.SimpleCookie() self.__outputsstack = [] def setContentType(self, type): self.content_type = type def setContentDisposition(self, disposition): self.content_disposition = disposition def setContentLength(self, length, force=False): if not force and self.content_encoding: raise IOError( "cannot set content length if a custom output encoding has been specified" ) self.content_length = length if self.server: self.server.content_length = length def getEncoding(self): return self.content_encoding def setEncoding(self, encoding): if self.__being_redirected or self.content_encoding == encoding: # We're being used in a redirection/inclusion, or the specified encoding # is already set. Do not change the encoding in both cases. return self.content_encoding = encoding if self.content_length >= 0: raise IOError( "cannot set custom output encoding if contentlength has been specified" ) if encoding: self.outs = codecs.getwriter(encoding)(self._outs, errors="xmlcharrefreplace") else: self.outs = self._outs # remove codec def forceEncoding(self, encoding): # set an encoding. No checks! Danger! Normal usage should be setEncoding. self.content_encoding = encoding def guessMimeType(self, filename): return self.server.guess_type(filename) def setHeader(self, header, value): self.userHeaders[header] = value def getHeader(self, header): return self.userHeaders.get(header) def setResponse(self, code, msg="Snakelet output follows"): self.response_code = code self.response_string = msg def HTTPredirect(self, URL): if self.header_written: raise RuntimeError( 'cannot redirect when getOutput() has been called') self.setResponse(302) # HTTP 302=redirect (Found) self.userHeaders["Location"] = URL out = self.getOutput() out.write("<html><head><title>Redirection</title></head>\n" "<body><h1>Redirection</h1>\nYou're being <a href=\"" + URL + "\">redirected</a>.</body></html>") self.setRedirectionDone() def writeHeader(self): # minimalistic HTTP response header if self.header_written: raise RuntimeError("header has already been written") self.server.send_response(self.response_code, self.response_string) contentType = self.content_type if self.content_encoding: contentType += "; charset=" + self.content_encoding self.userHeaders["Content-Type"] = contentType if self.content_disposition: self.userHeaders["Content-Disposition"] = self.content_disposition if self.content_length >= 0: self.userHeaders["Content-Length"] = str(self.content_length) for (h, v) in self.userHeaders.iteritems(): self.server.send_header(h, v) for c in self.cookies.values(): self.server.send_header("Set-Cookie", c.OutputString()) self.server.end_headers() self.header_written = True def getOutput(self): if self.redirection_performed: raise RuntimeError('cannot write after redirect() call') if not self.header_written: self.writeHeader() return self.outs def sendError(self, code, message=None): if not self.header_written: self.error_sent = True self.header_written = True self.server.send_error(code, message, self.userHeaders) else: raise RuntimeError( "cannot send error after header has been written") def getCookies(self): return self.cookies def setCookie(self, name, value, path=None, domain=None, maxAge=None, comment=None, secure=None): self.cookies[name] = value self.cookies[name]["version"] = 1 self.cookies[name]["path"] = '' self.cookies[name]["domain"] = '' self.cookies[name]["max-age"] = '' self.cookies[name]["expires"] = '' self.cookies[name]["comment"] = '' self.cookies[name]["secure"] = '' if path: self.cookies[name]["path"] = path if domain: self.cookies[name]["domain"] = domain if maxAge != None: self.cookies[name]["max-age"] = maxAge # for modern browsers if maxAge > 0: self.cookies[name]["expires"] = maxAge # for Internet Explorer else: # discard cookie, set expires to a time far in the past self.cookies[name][ "expires"] = "Mon, 01-Jan-1900 00:00:00 GMT" # for Internet Explorer if comment: self.cookies[name]["comment"] = comment if secure: self.cookies[name]["secure"] = secure self.userHeaders[ "P3P"] = "CP='CUR ADM OUR NOR STA NID'" # P3P compact policy def delCookie(self, name, path=None, domain=None, comment=None, secure=None): # delete the cookie by setting maxAge to zero. self.setCookie(name, "", path, domain, 0, comment, secure) def setRedirectionDone(self): self.__being_redirected = False self.redirection_performed = True def beingRedirected(self): return self.__being_redirected def used(self): return self.redirection_performed or self.header_written or self.error_sent def kill(self): self.server.kill() self.error_sent = True def initiateRedirection(self, url, isInclude=False): self.__being_redirected = True if self.header_written: self.outs.flush() else: if isInclude: self.writeHeader() #else: # XXX we used to send a Content-Location header, but the handling is inconsistent # among the web-browsers. Opera does it "right" (follows # the RFC http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.14 # but other browsers such as IE/Mozilla/Firefox do NOT follow the RFC. # See https://bugzilla.mozilla.org/show_bug.cgi?id=109553 # So we don't send this header, and all will be right. I hope. # self.userHeaders["Content-Location"]=url def wasErrorSent(self): return self.error_sent def YpushOutput(self, output): self.__outputsstack.append(self._outs) # save old output self._outs = self.outs = output def YpopOutput(self): oldOut = self.__outputsstack.pop() self._outs = self.outs = oldOut def forceFlush(self, stream): # force response flush to output stream out = self.getOutput() stream.flush() if hasattr(out, 'fileno'): if out.fileno() == stream.fileno(): # using direct stream, we're done return else: del out, stream raise IOError( "response is a stream but not the socket. Don't know how to handle this. Bail out" ) # we're using a custom output buffer such as a StringIO. Flush that. out.seek(0) self.server.copyfile( out, stream, not self.__being_redirected) # don't close when being redirected.. # now clear the output buffer out.seek(0) out.truncate()