def _parse_cookie(self): cookiestr = self.environ.get('HTTP_COOKIE', '') if not cookiestr: return cookies = SimpleCookie(cookiestr) for c in cookies.values(): self.cookie[c.key] = c.value
class CookieHandler(object): def __init__(self, *args, **kw): # Somewhere to store cookies between consecutive requests self.cookies = SimpleCookie() super(CookieHandler, self).__init__(*args, **kw) def httpCookie(self, path): """Return self.cookies as an HTTP_COOKIE environment value.""" l = [m.OutputString().split(';')[0] for m in self.cookies.values() if path.startswith(m['path'])] return '; '.join(l) def loadCookies(self, envstring): self.cookies.load(envstring) def saveCookies(self, response): """Save cookies from the response.""" # Urgh - need to play with the response's privates to extract # cookies that have been set # TODO: extend the IHTTPRequest interface to allow access to all # cookies # TODO: handle cookie expirations for k, v in response._cookies.items(): k = k.encode('utf8') self.cookies[k] = v['value'].encode('utf8') if 'path' in v: self.cookies[k]['path'] = v['path']
class CookieHandler(object): def __init__(self, *args, **kw): # Somewhere to store cookies between consecutive requests self.cookies = SimpleCookie() super(CookieHandler, self).__init__(*args, **kw) def httpCookie(self, path): """Return self.cookies as an HTTP_COOKIE environment value.""" l = [m.OutputString() for m in self.cookies.values() if path.startswith(m['path'])] return '; '.join(l) def loadCookies(self, envstring): self.cookies.load(envstring) def saveCookies(self, response): """Save cookies from the response.""" # Urgh - need to play with the response's privates to extract # cookies that have been set for k,v in response._cookies.items(): k = k.encode('utf8') self.cookies[k] = v['value'].encode('utf8') if self.cookies[k].has_key('Path'): self.cookies[k]['Path'] = v['Path']
class Response(object): def __init__(self, content='', status=200, mimetype='text/html', charset='utf-8'): self.content = content self.status = status self.mimetype= mimetype self.headers = {'X-Powered-By':'QF/'+version} self.cookies = SimpleCookie() self.charset = charset self.headers['Content-Type'] = '%s; charset=%s' % (self.mimetype, self.charset) # TODO secure 没有实现 def set_cookie(self, key, value='', secure=None, **options): ''' option : max_age, expires, path, domain, httponly ''' self.cookies[key] = value self.cookies[key]['path'] = '/' for k, v in options.items(): if v: if k == 'expires': if isinstance(v, (datetime.date, datetime.datetime)): v = v.timetuple() elif isinstance(v, (int, float)): v = time.gmtime(v) v = time.strftime("%a, %d %b %Y %H:%M:%S GMT", v) self.cookies[key][k.replace('_', '-')] = v def del_cookie(self, key, **kwargs): kwargs['max_age'] = -1 kwargs['expires'] = 0 self.set_cookie(key, '', **kwargs) def write(self, data): if type(data) == types.UnicodeType: self.content += data.encode(self.charset) else: self.content += data def length(self): return len(self.content) def redirect(self, url): url = url.encode(self.charset) if isinstance(url,unicode) else str(url) self.status = 302 self.headers['Location'] = url def __call__(self, environ, start_response): statusstr = '%d %s' % (self.status, HTTP_STATUS_CODES.get(self.status, '')) self.headers['Content-Length'] = str(len(self.content)) headers = self.headers.items() # add cookie if self.cookies: for c in self.cookies.values(): headers.append(('Set-Cookie', c.OutputString())) start_response(statusstr, headers) return [self.content]
def wrapped_start_response(status, response_headers, exc_info=None): sid = self.factory.save(environ["wsgi.session"]) cookies = SimpleCookie() cookies["session_id"] = sid cookie = cookies["session_id"] cookie["path"] = cookie_path cookie["httponly"] = 1 response_headers.extend(("set-cookie", morsel.OutputString()) for morsel in cookies.values()) return start_response(status, response_headers, exc_info)
def session_response(status, headers, exc_info=None): sid = data.session.save() if sid: cookie = SimpleCookie() cookie[self.cookie_name] = sid cookie[self.cookie_name]['path'] = '/' cookie[self.cookie_name]['expires'] = self.ttl headers.append(('Set-Cookie', morsel.OutputString()) for morsel in cookie.values()) return start_response(status, headers, exc_info)
def _handle_cookies(self, response): # type: (httplib.HTTPResponse) -> None """ Parse cookies from |HTTP| response and store for next request. :param httplib.HTTPResponse: The |HTTP| response. """ # FIXME: this cookie handling doesn't respect path, domain and expiry cookies = SimpleCookie() cookies.load(response.getheader('set-cookie', '')) self.cookies.update(dict((cookie.key, cookie.value) for cookie in cookies.values()))
class BaseController(WSGIController): title = None def __call__(self, environ, start_response): # Insert any code to be run per request here. The Routes match # is under environ['pylons.routes_dict'] should you want to check # the action or route vars here self._cookies = SimpleCookie() def repl_start_response(status, headers, exc_info=None): for c in self._cookies.values(): headers.append( 'Set-Cookie', c.output(header='')) return start_response(status, headers, exc_info) return WSGIController.__call__(self, environ, repl_start_response) def __before__(self): request.charset = 'utf8' c.self = self if self.title is None: c.title = self.__class__.__name__[:-len('Controller')] else: c.title = self.title c.url = URL.from_environ( request.environ, script_name=request.environ['paste.recursive.script_name'], with_path_info=False) c.session = session if 'bundle' in request.urlvars: self.bundle = model.Bundle.get(request.urlvars['bundle']) c.bundle_url = c.url[self.bundle.name] else: self.bundle = None c.bundle_url = None if request.cookies.get('flash'): c.flash = request.cookies['flash'] self.delete_cookie('flash') else: c.flash = None def flash(self, msg): self.set_cookie('flash', msg) def set_cookie(self, key, value='', **kw): kw.setdefault('path', '/') self._cookies[key] = value for var_name, var_value in kw.items(): if var_value is not None and var_value is not False: self._cookies[key][var_name.replace('_', '-')] = var_value def delete_cookie(self, key, path='/', domain=None): self.set_cookie(key, '', path=path, domain=domain, expires=0, max_age=0)
def _handle_set_cookie(self, response): headers = filter(lambda h: h[0].lower() == 'set-cookie', response.getheaders()) values = [] for header in headers: cookie = SimpleCookie(header[1]) for morsel in cookie.values(): values.append((dict(key=morsel.key, value=morsel.value))) self.cookies = values self._inject_cookies(values)
def set(self, username, expires=None): s = username + ":" + self.req._ENV.get('REMOTE_ADDR', '-') s_hash = hashlib.sha1(s + config.secret).hexdigest() session_cookie = SimpleCookie() session_cookie['clamsession'] = s + ":" + s_hash session_cookie['clamsession']["path"] = '/' session_cookie['clamsession']["httponly"] = True if expires: session_cookie['clamsession']["expires"] = expires self.req.headers += [("set-cookie", m.OutputString()) for m in session_cookie.values()] return True
def __call__(self, environ, start_response): path = environ.get('PATH_INFO', '') if not path.startswith("/tale/"): # paths not under /tale/ won't get a session return self.app(environ, start_response) cookie = SimpleCookie() if 'HTTP_COOKIE' in environ: cookie.load(environ['HTTP_COOKIE']) sid = None if "session_id" in cookie: sid = cookie["session_id"].value environ["wsgi.session"] = self.factory.load(sid) # If the server runs behind a reverse proxy, you can configure the proxy # to pass along the uri that it exposes (our internal uri can be different) # via the X-Forwarded-Uri header. If we find this header we use it to # replace the "/tale" uri base by the one from the header, to use as cookie path. forwarded_uri = environ.get("HTTP_X_FORWARDED_URI", "/tale/") cookie_path = "/" + forwarded_uri.split("/", 2)[1] def wrapped_start_response(status, response_headers, exc_info=None): sid = self.factory.save(environ["wsgi.session"]) cookies = SimpleCookie() cookies["session_id"] = sid cookie = cookies["session_id"] cookie["path"] = cookie_path cookie["httponly"] = 1 response_headers.extend(("set-cookie", morsel.OutputString()) for morsel in cookies.values()) return start_response(status, response_headers, exc_info) try: return self.app(environ, wrapped_start_response) except SessionMiddleware.CloseSession as x: self.factory.delete(sid) # clear the browser cookie cookies = SimpleCookie() cookies["session_id"] = "deleted" cookie = cookies["session_id"] cookie["path"] = cookie_path cookie["httponly"] = 1 cookie["expires"] = "Thu, 01-Jan-1970 00:00:00 GMT" response_headers = [('Content-Type', x.content_type)] response_headers.extend(("set-cookie", morsel.OutputString()) for morsel in cookies.values()) start_response("200 OK", response_headers) return [str(x).encode("utf-8")]
class Rs(threading.local): def b(self, s, app): self.s=s;self.app=app;self.status=status(200);self.header={} self.content_type='text/html; charset=UTF-8' self.cookies=SimpleCookie() def headers(self): a=map(lambda c:('Set-Cookie',c.OutputString()),self.cookies.values()) return list(self.header.iteritems())+a def c(self):return self.header['Content-Type'] def d(self, v):self.header['Content-Type']=v content_type=property(c,d,None,c.__doc__) def set_cookie(self, k, v, **kargs): self.cookies[k]=cookie_encode(v,self.app.config['SECURECOOKIE_KEY']) for i,j in kargs.iteritems():self.cookies[k][i.replace('_','-')]=j
def get_the_cookie(url, username=None, password=None): req = urlopen(url) data = req.read() hidden_inputs = re.findall('<INPUT.*HIDDEN.*NAME="(.*)".*VALUE="(.*)">', data) if username is None: username = raw_input('Username: '******'username', username)) hidden_inputs.append(('passcode', password)) qs = urlencode(hidden_inputs) action = urljoin(url, re.findall('<FORM action="([^"]*)" .*>', data)[0]) req2 = urlopen(action, data=qs) cookie = SimpleCookie(req2.info()['set-cookie']) return cookie.keys()[0] + "=" + cookie.values()[0].value
def __init__(self, url, request_text, proxy=None): #还是要求url算了 self.rfile = StringIO(request_text) self.raw_requestline = self.rfile.readline() self.parse_request() ###parameters that needed in repeater request self.proxy = proxy self.method = self.command #self.data = self.rfile.read(int(self.headers['content-length'])) #固定长度 self.data = self.rfile.read() #变动长度,直到结束;适合数据包修改之后。 self.header = self.headers.dict self.header["content-length"] = str(len( self.data)) # 更新content-length,数据包修改过后 if "cookie" in self.header.keys(): cookie_string = self.header["cookie"] cookie = SimpleCookie(cookie_string) self.cookie = {i.key: i.value for i in cookie.values()} #self.cookie = Cookie.Cookie() #self.cookie.load(cookie_string) else: self.cookie = None #####do some check on url and request raw if url: print urlparse.urlparse(url) TextPath = "{0}?{1}".format( urlparse.urlparse(url).path, urlparse.urlparse(url).query) if TextPath == self.path: self.url = url else: print "Error! url is different from the request text" elif "origin" in self.headers.keys(): self.url = self.headers["origin"] elif "referer" in self.header.keys() and "host" in self.header.keys(): if urlparse.urlparse( self.headers["referer"]).netloc == self.headers["host"]: scheme = urlparse.urlparse(self.headers["origin"]).scheme self.url = "{0}{1}{2}".format(scheme, self.headers["host"], self.path) else: print("please specify the url")
class Response(object): """ Response object which `start_response`. """ def bind(self, code=200, content_type="text/html; charset=UTF-8"): self.status = _HTTP_STATUS.get(code, "UNKNOWN") self.headers = [("Content-Type", content_type)] self._response = [] def redirect(self, url): self.headers.append(("Location", url)) def write(self, msg): self._response.append(msg) def set_cookie(self, key, value="", max_age=None, expires=None, path="/", domain=None, secure=None): if not hasattr(self, "_cookies"): self._cookies = SimpleCookie() self._cookies[key] = value if max_age: self._cookies[key]["max-age"] = max_age if expires: self._cookies[key]["expires"] = _format_gmt_time(expires) if path: self._cookies[key]["path"] = path if domain: self._cookies[key]["domain"] = domain if secure: self._cookies[key]["secure"] = secure def delete_cookie(self, key): if self._cookies is None: self._cookies = SimpleCookie() if not key in self._cookies: self._cookies[key] = "" self._cookies[key]["max-age"] = 0 def __call__(self, start_response): self.headers.append(("Content-Length", str(sum(len(n) for n in self._response)))) if hasattr(self, "_cookies"): for morsel in self._cookies.values(): self.headers.append(("Set-Cookie", morsel.output(header=""))) start_response(self.status, self.headers) return self._response
class Response(object): status_code = 200 def __init__(self, content='', status=None, content_type='text/html; charset=utf8'): self.content = content if status: self.status_code = status self.headers = {'Content-Type': content_type} self.cookies = SimpleCookie() def __str__(self): return '\n'.join(['%s: %s' % (key, value) for key, value in self.headers.items()]) + '\n\n' + self.content def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=False): self.cookies[key] = value if max_age is not None: self.cookies[key]['max-age'] = max_age if expires is not None: self.cookies[key]['expires'] = expires if path is not None: self.cookies[key]['path'] = path if domain is not None: self.cookies[key]['domain'] = domain if secure: self.cookies[key]['secure'] = True def delete_cookie(self, key, path='/', domain=None): self.set_cookie(key, max_age=0, path=path, domain=domain, expires='Thu, 01-Jan-1970 00:00:00 GMT') def headers_items(self): headers = self.headers.items() for cookie in self.cookies.values(): headers.append(('Set-Cookie', str(cookie.output(header='')))) return headers
def COOKIES(self): cookies = SimpleCookie(self._environ.get('HTTP_COOKIE','')) self._COOKIES = {} for cookie in cookies.values(): self._COOKIES[cookie.key] = cookie.value return self._COOKIES
class HttpResponse(object): """ The Response object is used to collect the data to be written back to the HTTP client. """ def __init__(self, response=None, headers=None, status=200): if response is None: self.response = [] elif isinstance(response, basestring): self.response = [response] else: self.response = response if headers is None: self.headers = HttpHeaders([]) elif isinstance(headers, list): self.headers = HttpHeaders(headers) elif isinstance(headers, HttpHeaders): self.headers = headers else: raise TypeError('invalid header format') self.status = status self._cookies = None def __setitem__(self, name, value): self.headers[name] = value def __getitem__(self, name): self.headers.get(name) def __delitem__(self, name): del self.headers[name] def __contains__(self, name): return name in self.headers def __len__(self): if isinstance(self.response, list): length = 0 for item in self.response: length += len(item) return length try: return len(self.response) except: return 0 def write(self, d): if not isinstance(self.response, list): raise TypeError('read only or dynamic response object') elif isinstance(d, basestring): self.response.append(d) else: raise TypeError('str or unicode required') def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None): if self._cookies is None: self._cookies = SimpleCookie() self._cookies[key] = value if not max_age is None: self._cookies[key]['max-age'] = max_age if not expires is None: if isinstance(expires, basestring): self._cookies[key]['expires'] = expires expires = None elif isinstance(expires, datetime): expires = expires.utctimetuple() elif not isinstance(expires, (int, long)): expires = gmtime(expires) else: raise ValueError('datetime or integer required') if not expires is None: now = gmtime() month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][now.tm_mon - 1] day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][expires.tm_wday] date = '%02d-%s-%s' % ( now.tm_mday, month, str(now.tm_year)[-2:] ) d = '%s, %s %02d:%02d:%02d GMT' % (day, date, now.tm_hour, now.tm_min, now.tm_sec) self._cookies[key]['expires'] = d if not path is None: self._cookies[key]['path'] = path if not domain is None: self._cookies[key]['domain'] = domain if not secure is None: self._cookies[key]['secure'] = secure def delete_cookie(self, key): if self._cookies is None: self._cookies = SimpleCookie() if not key in self._cookies: self._cookies[key] = '' self._cookies[key]['max-age'] = 0 def __call__(self, request): if not 'Content-Type' in self.headers: self.headers['Content-Type'] = 'text/html; charset=%s' % \ str(request.charset) headers = self.headers.get() if not self._cookies is None: for morsel in self._cookies.values(): headers.append(('Set-Cookie', morsel.output(header=''))) status = '%d %s' % (self.status, HTTP_STATUS_CODES.get(self.status, 'UNKNOWN')) request.start_response(status, headers) if self.response is None: yield '' elif isinstance(self.response, unicode): yield self.response.encode(request.charset) elif isinstance(self.response, str): yield self.response else: try: iterator = iter(self.response) except TypeError: raise TypeError('%r is not an valid response' % self.response) for line in iterator: if isinstance(line, unicode): yield line.encode(request.charset) elif isinstance(line, str): yield line else: raise TypeError('%r is not string or unicode' % line)
class Controller(object): """ Moar's Controller class. Aims to be useful. Extend this for your own controllers. Any class that implements the get_response_start() method can be used in place of this one. """ def __init__(self, config, request): """ Set up basics and defaults, like status codes and headers. """ self.config = config self.request = request self.code = 200 self.headers = [] self.view = {} self.cookie = SimpleCookie() self.user = None self.parse_cookie() def parse_cookie(self): """ Helper for parsing cookie data. """ self.cookie = SimpleCookie() if 'HTTP_COOKIE' in self.request: self.cookie.load(self.request['HTTP_COOKIE']) def get_body_params(self): """ Helper function for parsing body params. Body params are only used if the right Content-Type header (application/x-www-form-urlencoded) is set. """ if 'CONTENT_TYPE' not in self.request: return {} if self.request['CONTENT_TYPE'] != 'application/x-www-form-urlencoded': return {} content_length = int(self.request.get('CONTENT_LENGTH', 0)) return parse_params(self.request['wsgi.input'].read(content_length)) def get_params(self): """ Parse all parameters and return them. """ params = parse_params(self.request['QUERY_STRING']) params.update(self.get_body_params()) return params def get_response_start(self): """ Build a status code string and headers to send. """ send_headers = list(self.headers) for morsel in self.cookie.values(): send_headers.append( ('Set-Cookie', morsel.output(header='').strip())) return self.code, send_headers def get_template_path(self, method, ext=None): """ Build a path to where the templates for this class/method live. Can pass an optional file extension. """ if not ext: ext = 'tpl' obj_name = self.__class__.__name__.lower().replace('controller', '') return '%s/%s.%s' % (obj_name, method, ext) def render_raw(self, data, method, ext=None): """ Render a template for the current class and given method. Can pass an optional file extension. """ request = Environment(loader=FileSystemLoader('templates')) template_path = self.get_template_path(method, ext) template = request.get_template(template_path) view_vars = dict(data) view_vars['user'] = self.user return template.render(**view_vars) def render(self, method, ext=None): """ Render a template for the current class and given method. Use the object's view member variable as a data provider. Can pass an optional file extension. """ return self.render_raw(self.view, method, ext)
class Request(object): ''' Base request object that provides an abstraction layer over a WSGI interface. Request handlers inherit from this class. ''' STATUS_CODES = { 200: 'OK', 201: 'Created', 204: 'No Content', 301: 'Moved Permanently', 302: 'Found', 303: 'See Other', 400: 'Bad Request', 401: 'Unauthorized', 403: 'Forbidden', 404: 'Not Found', 405: 'Method Not Allowed', 500: 'Internal Server Error', 503: 'Service Unavailable', } METHODS = ('GET', 'POST', 'PUT', 'DELETE', 'HEAD', 'OPTIONS') def __init__(self): self.environ = None self.response_cookies = SimpleCookie() self.request_cookies = SimpleCookie() self.unpacked_cookies = {} self.parsed_cookies = False self.post_data = {} self.parsed_post = False self.querystring = {} def _get_response(self, environ, start_response, method, uri, uri_kwargs): self.environ = environ self.querystring = parse_qs(environ.get('QUERY_STRING', '')) if method not in self.METHODS: raise MethodNotPermitted response_data, status_code, extra_headers = self._run_hander(method, uri_kwargs) status_text = self.STATUS_CODES.get(status_code) if not status_text: raise InternalServerError headers = self._get_response_headers(status_code, extra_headers) start_response('{} {}'.format(status_code, status_text), headers) return [response_data] def _run_hander(self, method, uri_kwargs): handler = getattr(self, method.lower(), None) if not handler: raise MethodNotPermitted raw_response = handler(self.environ, **uri_kwargs) response_data, status_code, extra_headers = b'', 200, {} if type(raw_response) == tuple: if len(raw_response) == 3: response_data, status_code, extra_headers = raw_response elif len(raw_response) == 2: response_data, status_code = raw_response else: raise InternalServerError else: response_data = raw_response return response_data, status_code, extra_headers def _get_response_headers(self, status_code, extra_headers): headers = [] has_content_type = False has_server = False if type(extra_headers) == dict: extra_headers = extra_headers.iteritems() for (k, v) in extra_headers: k = k.lower().replace('_', '-') headers.append((k, v)) if k == 'content-type': has_content_type = True elif k == 'server': has_server = True if not has_content_type: headers.append(('content-type', 'text/html')) if not has_server: headers.append(('server', 'crumb mirco wsgi framework')) headers.extend(('set-cookie', c.OutputString()) for c in self.response_cookies.values()) return headers def set_cookie(self, name='', value=None, expires=0, path='/'): self.response_cookies[name] = value self.response_cookies[name]['path'] = path if expires > 0: self.response_cookies[name]['expires'] = expires def get_cookie(self, name=''): if not self.parsed_cookies: self.unpack_cookies() return getattr(self.request_cookies.get(name), 'value', None) def unpack_cookies(self): raw_cookies = self.environ.get('HTTP_COOKIE') if raw_cookies: try: self.request_cookies.load(raw_cookies) except CookieError: raise BadRequest def get_post(self, name='', lazy_unpack=True): if not self.parsed_post: self.unpack_post() d = self.post_data.get(name) if d and len(d) == 1 and lazy_unpack: return d[0] return d def iter_post(self): if not self.parsed_post: self.unpack_post() return self.post_data.iteritems() def unpack_post(self): try: content_length = int(self.environ.get('CONTENT_LENGTH', '0')) except ValueError: raise BadRequest reader = getattr(self.environ.get('wsgi.input'), 'read', lambda x: '') post_data = reader(content_length) try: self.post_data = parse_qs(post_data, True) except ValueError, TypeError: raise BadRequest
class Response(Exception): """Represent an HTTP Response message. """ request = None def __init__(self, code=200, body="", headers=None, charset="UTF-8"): """Takes an int, a string, a dict, and a basestring. - code an HTTP response code, e.g., 404 - body the message body as a string - headers a Headers instance - charset string that will be set in the Content-Type in the future at some point but not now Code is first because when you're raising your own Responses, they're usually error conditions. Body is second because one more often wants to specify a body without headers, than a header without a body. """ if not isinstance(code, int): raise TypeError("'code' must be an integer") elif not isinstance(body, str) and not hasattr(body, "__iter__"): raise TypeError("'body' must be a bytestring or iterable of " "bytestrings") elif headers is not None and not isinstance(headers, (dict, list)): raise TypeError("'headers' must be a dictionary or a list of " + "2-tuples") elif charset_re.match(charset) is None: raise TypeError("'charset' must match " + charset_re.pattern) Exception.__init__(self) self.code = code self.body = body self.headers = Headers("") self.charset = charset if headers: if isinstance(headers, dict): headers = headers.items() for k, v in headers: self.headers[k] = v self.cookie = SimpleCookie() try: self.cookie.load(self.headers.get("Cookie", "")) except CookieError: pass def __call__(self, environ, start_response): wsgi_status = str(self) for morsel in self.cookie.values(): self.headers["Set-Cookie"] = morsel.OutputString() wsgi_headers = [] for k, vals in self.headers.iteritems(): try: # XXX This is a hack. It's red hot, baby. k = k.encode("US-ASCII") except UnicodeEncodeError: k = ascii_dammit(k) raise ValueError("Header key %s must be US-ASCII.") for v in vals: try: # XXX This also is a hack. It is also red hot, baby. v = v.encode("US-ASCII") except UnicodeEncodeError: v = ascii_dammit(v) raise ValueError("Header value %s must be US-ASCII.") wsgi_headers.append((k, v)) start_response(wsgi_status, wsgi_headers) body = self.body if isinstance(body, str): body = [body] return CloseWrapper(self.request, body) def __repr__(self): return "<Response: %s>" % str(self) def __str__(self): return "%d %s" % (self.code, self._status()) def _status(self): return status_strings.get(self.code, "Unknown HTTP status") def _to_http(self, version): """Given a version string like 1.1, return an HTTP message, a string. """ status_line = "HTTP/%s" % version headers = self.headers.raw body = self.body if self.headers.get("Content-Type", "").startswith("text/"): body = body.replace("\n", "\r\n") body = body.replace("\r\r", "\r") return "\r\n".join([status_line, headers, "", body])
class WSGIResponse(object): """A basic HTTP response with content, headers, and out-bound cookies The class variable ``defaults`` specifies default values for ``content_type``, ``charset`` and ``errors``. These can be overridden for the current request via the registry. """ defaults = StackedObjectProxy( default=dict(content_type='text/html', charset='utf-8', errors='strict', headers={'Cache-Control':'no-cache'}) ) def __init__(self, content='', mimetype=None, code=200): self._iter = None self._is_str_iter = True self.content = content self.headers = HeaderDict() self.cookies = SimpleCookie() self.status_code = code defaults = self.defaults._current_obj() if not mimetype: mimetype = defaults.get('content_type', 'text/html') charset = defaults.get('charset') if charset: mimetype = '%s; charset=%s' % (mimetype, charset) self.headers.update(defaults.get('headers', {})) self.headers['Content-Type'] = mimetype self.errors = defaults.get('errors', 'strict') def __str__(self): """Returns a rendition of the full HTTP message, including headers. When the content is an iterator, the actual content is replaced with the output of str(iterator) (to avoid exhausting the iterator). """ if self._is_str_iter: content = ''.join(self.get_content()) else: content = str(self.content) return '\n'.join(['%s: %s' % (key, value) for key, value in self.headers.headeritems()]) \ + '\n\n' + content def __call__(self, environ, start_response): """Convenience call to return output and set status information Conforms to the WSGI interface for calling purposes only. Example usage: .. code-block:: python def wsgi_app(environ, start_response): response = WSGIResponse() response.write("Hello world") response.headers['Content-Type'] = 'latin1' return response(environ, start_response) """ status_text = STATUS_CODE_TEXT[self.status_code] status = '%s %s' % (self.status_code, status_text) response_headers = self.headers.headeritems() for c in self.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) is_file = isinstance(self.content, file) if 'wsgi.file_wrapper' in environ and is_file: return environ['wsgi.file_wrapper'](self.content) elif is_file: return iter(lambda: self.content.read(), '') return self.get_content() def determine_charset(self): """ Determine the encoding as specified by the Content-Type's charset parameter, if one is set """ charset_match = _CHARSET_RE.search(self.headers.get('Content-Type', '')) if charset_match: return charset_match.group(1) def has_header(self, header): """ Case-insensitive check for a header """ warnings.warn('WSGIResponse.has_header is deprecated, use ' 'WSGIResponse.headers.has_key instead', DeprecationWarning, 2) return self.headers.has_key(header) def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=None): """ Define a cookie to be sent via the outgoing HTTP headers """ self.cookies[key] = value for var_name, var_value in [ ('max_age', max_age), ('path', path), ('domain', domain), ('secure', secure), ('expires', expires), ('httponly', httponly)]: if var_value is not None and var_value is not False: self.cookies[key][var_name.replace('_', '-')] = var_value def delete_cookie(self, key, path='/', domain=None): """ Notify the browser the specified cookie has expired and should be deleted (via the outgoing HTTP headers) """ self.cookies[key] = '' if path is not None: self.cookies[key]['path'] = path if domain is not None: self.cookies[key]['domain'] = domain self.cookies[key]['expires'] = 0 self.cookies[key]['max-age'] = 0 def _set_content(self, content): if hasattr(content, '__iter__'): self._iter = content if isinstance(content, list): self._is_str_iter = True else: self._is_str_iter = False else: self._iter = [content] self._is_str_iter = True content = property(lambda self: self._iter, _set_content, doc='Get/set the specified content, where content can ' 'be: a string, a list of strings, a generator function ' 'that yields strings, or an iterable object that ' 'produces strings.') def get_content(self): """ Returns the content as an iterable of strings, encoding each element of the iterator from a Unicode object if necessary. """ charset = self.determine_charset() if charset: return encode_unicode_app_iter(self.content, charset, self.errors) else: return self.content def wsgi_response(self): """ Return this WSGIResponse as a tuple of WSGI formatted data, including: (status, headers, iterable) """ status_text = STATUS_CODE_TEXT[self.status_code] status = '%s %s' % (self.status_code, status_text) response_headers = self.headers.headeritems() for c in self.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) return status, response_headers, self.get_content() # The remaining methods partially implement the file-like object interface. # See http://docs.python.org/lib/bltin-file-objects.html def write(self, content): if not self._is_str_iter: raise IOError, "This %s instance's content is not writable: (content " \ 'is an iterator)' % self.__class__.__name__ self.content.append(content) def flush(self): pass def tell(self): if not self._is_str_iter: raise IOError, 'This %s instance cannot tell its position: (content ' \ 'is an iterator)' % self.__class__.__name__ return sum([len(chunk) for chunk in self._iter]) ######################################## ## Content-type and charset def charset__get(self): """ Get/set the charset (in the Content-Type) """ header = self.headers.get('content-type') if not header: return None match = _CHARSET_RE.search(header) if match: return match.group(1) return None def charset__set(self, charset): if charset is None: del self.charset return try: header = self.headers.pop('content-type') except KeyError: raise AttributeError( "You cannot set the charset when no content-type is defined") match = _CHARSET_RE.search(header) if match: header = header[:match.start()] + header[match.end():] header += '; charset=%s' % charset self.headers['content-type'] = header def charset__del(self): try: header = self.headers.pop('content-type') except KeyError: # Don't need to remove anything return match = _CHARSET_RE.search(header) if match: header = header[:match.start()] + header[match.end():] self.headers['content-type'] = header charset = property(charset__get, charset__set, charset__del, doc=charset__get.__doc__) def content_type__get(self): """ Get/set the Content-Type header (or None), *without* the charset or any parameters. If you include parameters (or ``;`` at all) when setting the content_type, any existing parameters will be deleted; otherwise they will be preserved. """ header = self.headers.get('content-type') if not header: return None return header.split(';', 1)[0] def content_type__set(self, value): if ';' not in value: header = self.headers.get('content-type', '') if ';' in header: params = header.split(';', 1)[1] value += ';' + params self.headers['content-type'] = value def content_type__del(self): try: del self.headers['content-type'] except KeyError: pass content_type = property(content_type__get, content_type__set, content_type__del, doc=content_type__get.__doc__)
class Response(Exception): """Represent an HTTP Response message. """ def __init__(self, code=200, body='', headers=None): """Takes an int, a string, and a dict (or list of tuples). - code an HTTP response code, e.g., 404 - body the message body as a string - headers a Headers instance - cookie a Cookie.SimpleCookie instance Code is first because when you're raising your own Responses, they're usually error conditions. Body is second because one more often wants to specify a body without headers, than a header without a body. """ if not isinstance(code, int): raise TypeError("'code' must be an integer") elif not isinstance(body, basestring): raise TypeError("'body' must be a string") elif headers is not None and not isinstance(headers, (dict, list)): raise TypeError("'headers' must be a dictionary or a list of " + "2-tuples") Exception.__init__(self) self.code = code self.body = body self.headers = Headers('') if headers: if isinstance(headers, dict): headers = headers.items() for k, v in headers: self.headers.add(k, v) self.cookie = SimpleCookie() try: self.cookie.load(self.headers.one('Cookie', '')) except CookieError: pass def __repr__(self): return "<Response: %s>" % str(self) def __str__(self): return "%d %s" % (self.code, self._status()) def _status(self): return status_strings.get(self.code, ('???','Unknown HTTP status')) def _to_diesel(self, _diesel_request): """This actually sends bits over the wire(!). """ for morsel in self.cookie.values(): self.headers.add('Set-Cookie', morsel.OutputString()) self.headers._diesel_headers._headers = self.headers._dict return DieselResponse( _diesel_request , self.code , self.headers._diesel_headers , self.body ) def _to_http(self, version): status_line = "HTTP/%s" % version headers = self.headers.to_http() body = self.body if self.headers.one('Content-Type', '').startswith('text/'): body = body.replace('\n', '\r\n') body = body.replace('\r\r', '\r') return '\r\n'.join([status_line, headers, '', body])
class WSGIResponse(object): """A basic HTTP response with content, headers, and out-bound cookies The class variable ``defaults`` specifies default values for ``content_type``, ``charset`` and ``errors``. These can be overridden for the current request via the registry. """ defaults = StackedObjectProxy( default=dict(content_type='text/html', charset='utf-8', errors='strict', headers={'Cache-Control':'no-cache'}) ) def __init__(self, content='', mimetype=None, code=200): self._iter = None self._is_str_iter = True self.content = content self.headers = HeaderDict() self.cookies = SimpleCookie() self.status_code = code defaults = self.defaults._current_obj() if not mimetype: mimetype = defaults.get('content_type', 'text/html') charset = defaults.get('charset') if charset: mimetype = '%s; charset=%s' % (mimetype, charset) self.headers.update(defaults.get('headers', {})) self.headers['Content-Type'] = mimetype self.errors = defaults.get('errors', 'strict') def __str__(self): """Returns a rendition of the full HTTP message, including headers. When the content is an iterator, the actual content is replaced with the output of str(iterator) (to avoid exhausting the iterator). """ if self._is_str_iter: content = ''.join(self.get_content()) else: content = str(self.content) return '\n'.join(['%s: %s' % (key, value) for key, value in self.headers.headeritems()]) \ + '\n\n' + content def __call__(self, environ, start_response): """Convenience call to return output and set status information Conforms to the WSGI interface for calling purposes only. Example usage: .. code-block:: Python def wsgi_app(environ, start_response): response = WSGIResponse() response.write("Hello world") response.headers['Content-Type'] = 'latin1' return response(environ, start_response) """ status_text = STATUS_CODE_TEXT[self.status_code] status = '%s %s' % (self.status_code, status_text) response_headers = self.headers.headeritems() for c in self.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) start_response(status, response_headers) is_file = isinstance(self.content, file) if 'wsgi.file_wrapper' in environ and is_file: return environ['wsgi.file_wrapper'](self.content) elif is_file: return iter(lambda: self.content.read(), '') return self.get_content() def determine_charset(self): """ Determine the encoding as specified by the Content-Type's charset parameter, if one is set """ charset_match = _CHARSET_RE.search(self.headers.get('Content-Type', '')) if charset_match: return charset_match.group(1) def has_header(self, header): """ Case-insensitive check for a header """ warnings.warn('WSGIResponse.has_header is deprecated, use ' 'WSGIResponse.headers.has_key instead', DeprecationWarning, 2) return self.headers.has_key(header) def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None): """ Define a cookie to be sent via the outgoing HTTP headers """ self.cookies[key] = value for var_name, var_value in [ ('max_age', max_age), ('path', path), ('domain', domain), ('secure', secure), ('expires', expires)]: if var_value is not None and var_value is not False: self.cookies[key][var_name.replace('_', '-')] = var_value def delete_cookie(self, key, path='/', domain=None): """ Notify the browser the specified cookie has expired and should be deleted (via the outgoing HTTP headers) """ self.cookies[key] = '' if path is not None: self.cookies[key]['path'] = path if domain is not None: self.cookies[key]['domain'] = path self.cookies[key]['expires'] = 0 self.cookies[key]['max-age'] = 0 def _set_content(self, content): if hasattr(content, '__iter__'): self._iter = content if isinstance(content, list): self._is_str_iter = True else: self._is_str_iter = False else: self._iter = [content] self._is_str_iter = True content = property(lambda self: self._iter, _set_content, doc='Get/set the specified content, where content can ' 'be: a string, a list of strings, a generator function ' 'that yields strings, or an iterable object that ' 'produces strings.') def get_content(self): """ Returns the content as an iterable of strings, encoding each element of the iterator from a Unicode object if necessary. """ charset = self.determine_charset() if charset: return encode_unicode_app_iter(self.content, charset, self.errors) else: return self.content def wsgi_response(self): """ Return this WSGIResponse as a tuple of WSGI formatted data, including: (status, headers, iterable) """ status_text = STATUS_CODE_TEXT[self.status_code] status = '%s %s' % (self.status_code, status_text) response_headers = self.headers.headeritems() for c in self.cookies.values(): response_headers.append(('Set-Cookie', c.output(header=''))) return status, response_headers, self.get_content() # The remaining methods partially implement the file-like object interface. # See http://docs.python.org/lib/bltin-file-objects.html def write(self, content): if not self._is_str_iter: raise IOError, "This %s instance's content is not writable: (content " \ 'is an iterator)' % self.__class__.__name__ self.content.append(content) def flush(self): pass def tell(self): if not self._is_str_iter: raise IOError, 'This %s instance cannot tell its position: (content ' \ 'is an iterator)' % self.__class__.__name__ return sum([len(chunk) for chunk in self._iter]) ######################################## ## Content-type and charset def charset__get(self): """ Get/set the charset (in the Content-Type) """ header = self.headers.get('content-type') if not header: return None match = _CHARSET_RE.search(header) if match: return match.group(1) return None def charset__set(self, charset): if charset is None: del self.charset return try: header = self.headers.pop('content-type') except KeyError: raise AttributeError( "You cannot set the charset when no content-type is defined") match = _CHARSET_RE.search(header) if match: header = header[:match.start()] + header[match.end():] header += '; charset=%s' % charset self.headers['content-type'] = header def charset__del(self): try: header = self.headers.pop('content-type') except KeyError: # Don't need to remove anything return match = _CHARSET_RE.search(header) if match: header = header[:match.start()] + header[match.end():] self.headers['content-type'] = header charset = property(charset__get, charset__set, charset__del, doc=charset__get.__doc__) def content_type__get(self): """ Get/set the Content-Type header (or None), *without* the charset or any parameters. If you include parameters (or ``;`` at all) when setting the content_type, any existing parameters will be deleted; otherwise they will be preserved. """ header = self.headers.get('content-type') if not header: return None return header.split(';', 1)[0] def content_type__set(self, value): if ';' not in value: header = self.headers.get('content-type', '') if ';' in header: params = header.split(';', 1)[1] value += ';' + params self.headers['content-type'] = value def content_type__del(self): try: del self.headers['content-type'] except KeyError: pass content_type = property(content_type__get, content_type__set, content_type__del, doc=content_type__get.__doc__)
def add_cookie(self, name, value, path='/', expires=None): cookie = SimpleCookie() cookie[name] = value cookie[name]['path'] = path cookie[name]['expires'] = expires self.response.headers['Set-Cookie'] = cookie.values()[0].OutputString()
class Response(object): charset = 'utf-8' default_mimetype = 'text/html' def __init__(self, response=None, headers=None, status=200, mimetype=None): if response is None: self.response = [] elif isinstance(response, basestring): self.response = [response] else: self.response = iter(response) if not headers: self.headers = Headers() elif isinstance(headers, Headers): self.headers = headers else: self.headers = Headers(headers) if mimetype is None and 'Content-Type' not in self.headers: mimetype = self.default_mimetype if mimetype is not None: if 'charset=' not in mimetype and mimetype.startswith('text/'): mimetype += '; charset=' + self.charset self.headers['Content-Type'] = mimetype self.status = status self._cookies = None def write(self, value): if not isinstance(self.response, list): raise RuntimeError('cannot write to streaming response') self.write = self.response.append self.response.append(value) def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None): if self._cookies is None: self._cookies = SimpleCookie() if isinstance(value, unicode): value = value.encode(self.charset) self._cookies[key] = value if max_age is not None: self._cookies[key]['max-age'] = max_age if expires is not None: if isinstance(expires, basestring): self._cookies[key]['expires'] = expires expires = None elif isinstance(expires, datetime): expires = expires.utctimetuple() elif not isinstance(expires, (int, long)): expires = gmtime(expires) else: raise ValueError('datetime or integer required') month = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'][expires.tm_mon - 1] day = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][expires.tm_wday] date = '%02d-%s-%s' % ( expires.tm_mday, month, str(expires.tm_year)[-2:] ) d = '%s, %s %02d:%02d:%02d GMT' % (day, date, expires.tm_hour, expires.tm_min, expires.tm_sec) self._cookies[key]['expires'] = d if path is not None: self._cookies[key]['path'] = path if domain is not None: self._cookies[key]['domain'] = domain if secure is not None: self._cookies[key]['secure'] = secure def delete_cookie(self, key): if self._cookies is None: self._cookies = SimpleCookie() if key not in self._cookies: self._cookies[key] = '' self._cookies[key]['max-age'] = 0 def __call__(self, environ, start_response): req = environ['werkzeug.request'] if req.session.worth_saving: req.session.save() self.set_cookie(SID_COOKIE_NAME, req.session.sid) headers = self.headers.to_list(self.charset) if self._cookies is not None: for morsel in self._cookies.values(): headers.append(('Set-Cookie', morsel.output(header=''))) status = '%d %s' % (self.status, HTTP_STATUS_CODES[self.status]) charset = self.charset or 'ascii' start_response(status, headers) for item in self.response: if isinstance(item, unicode): yield item.encode(charset) else: yield str(item)
def _handle_cookies(self, response): # FIXME: this cookie handling doesn't respect path, domain and expiry cookies = SimpleCookie() cookies.load(response.getheader('set-cookie', '')) self.cookies.update(dict((cookie.key, cookie.value) for cookie in cookies.values()))
class Response(object): charset = 'utf-8' default_mimetype = 'text/html' def __init__(self, response=None, headers=None, status=200, mimetype=None): if response is None: self.response = [] elif isinstance(response, basestring): self.response = [response] else: self.response = iter(response) if not headers: self.headers = Headers() elif isinstance(headers, Headers): self.headers = headers else: self.headers = Headers(headers) if mimetype is None and 'Content-Type' not in self.headers: mimetype = self.default_mimetype if mimetype is not None: if 'charset=' not in mimetype and mimetype.startswith('text/'): mimetype += '; charset=' + self.charset self.headers['Content-Type'] = mimetype self.status = status self._cookies = None def write(self, value): if not isinstance(self.response, list): raise RuntimeError('cannot write to streaming response') self.write = self.response.append self.response.append(value) def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None): if self._cookies is None: self._cookies = SimpleCookie() if isinstance(value, unicode): value = value.encode(self.charset) self._cookies[key] = value if max_age is not None: self._cookies[key]['max-age'] = max_age if expires is not None: if isinstance(expires, basestring): self._cookies[key]['expires'] = expires expires = None elif isinstance(expires, datetime): expires = expires.utctimetuple() elif not isinstance(expires, (int, long)): expires = gmtime(expires) else: raise ValueError('datetime or integer required') month = [ 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ][expires.tm_mon - 1] day = [ 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday' ][expires.tm_wday] date = '%02d-%s-%s' % (expires.tm_mday, month, str( expires.tm_year)[-2:]) d = '%s, %s %02d:%02d:%02d GMT' % (day, date, expires.tm_hour, expires.tm_min, expires.tm_sec) self._cookies[key]['expires'] = d if path is not None: self._cookies[key]['path'] = path if domain is not None: self._cookies[key]['domain'] = domain if secure is not None: self._cookies[key]['secure'] = secure def delete_cookie(self, key): if self._cookies is None: self._cookies = SimpleCookie() if key not in self._cookies: self._cookies[key] = '' self._cookies[key]['max-age'] = 0 def __call__(self, environ, start_response): req = environ['werkzeug.request'] if req.session.worth_saving: req.session.save() self.set_cookie(SID_COOKIE_NAME, req.session.sid) headers = self.headers.to_list(self.charset) if self._cookies is not None: for morsel in self._cookies.values(): headers.append(('Set-Cookie', morsel.output(header=''))) status = '%d %s' % (self.status, HTTP_STATUS_CODES[self.status]) charset = self.charset or 'ascii' start_response(status, headers) for item in self.response: if isinstance(item, unicode): yield item.encode(charset) else: yield str(item)
from Cookie import SimpleCookie session_cookie = SimpleCookie() session_cookie['session'] = "somedata" session_cookie['session']["Path"] = '/' headers = {} headers.update(("set-cookie", morsel.OutputString()) for morsel in session_cookie.values()) print headers
class WSGIResponse(object): """ A basic HTTP response with content, headers, and out-bound cookies The class variable ``defaults`` specifies default values for ``content_type``, ``charset`` and ``errors``. These can be overridden for the current request via the registry. """ # See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html HTTP_MAPPINGS = { 100: 'CONTINUE', 101: 'SWITCHING PROTOCOLS', 200: 'OK', 201: 'CREATED', 202: 'ACCEPTED', 203: 'NON-AUTHORITATIVE INFORMATION', 204: 'NO CONTENT', 205: 'RESET CONTENT', 206: 'PARTIAL CONTENT', 226: 'IM USED', 300: 'MULTIPLE CHOICES', 301: 'MOVED PERMANENTLY', 302: 'FOUND', 303: 'SEE OTHER', 304: 'NOT MODIFIED', 305: 'USE PROXY', 306: 'RESERVED', 307: 'TEMPORARY REDIRECT', 400: 'BAD REQUEST', 401: 'UNAUTHORIZED', 402: 'PAYMENT REQUIRED', 403: 'FORBIDDEN', 404: 'NOT FOUND', 405: 'METHOD NOT ALLOWED', 406: 'NOT ACCEPTABLE', 407: 'PROXY AUTHENTICATION REQUIRED', 408: 'REQUEST TIMEOUT', 409: 'CONFLICT', 410: 'GONE', 411: 'LENGTH REQUIRED', 412: 'PRECONDITION FAILED', 413: 'REQUEST ENTITY TOO LARGE', 414: 'REQUEST-URI TOO LONG', 415: 'UNSUPPORTED MEDIA TYPE', 416: 'REQUESTED RANGE NOT SATISFIABLE', 417: 'EXPECTATION FAILED', 500: 'INTERNAL SERVER ERROR', 501: 'NOT IMPLEMENTED', 502: 'BAD GATEWAY', 503: 'SERVICE UNAVAILABLE', 504: 'GATEWAY TIMEOUT', 505: 'HTTP VERSION NOT SUPPORTED' } def __init__(self, content='', headers={}, status_code=200): "Initialise our response, assuming everything is fine" self.status_code = status_code self.set_content(content) self._headers = headers self._headers['content-length'] = str(len(content)) self.cookies = SimpleCookie() # lets assume text/html unless told otherwise if not 'content-type' in self.headers: self._headers['content-type'] = 'text/html' def get_status(self): "Get the status code and message, but make sure it's valid first" if self.status_code not in self.HTTP_MAPPINGS: # invalid code, so something has gone wrong self.status_code = 500 return "%s %s" % (self.status_code, self.HTTP_MAPPINGS[self.status_code]) def set_status(self, code): "API setter method" if self.status_code not in self.HTTP_MAPPINGS: # invalid code, so something has gone wrong self.status_code = 500 else: self.status_code = code def get_headers(self): "Return the headers as a list" return list(self._headers.iteritems()) def set_headers(self, *args): "Set the response headers, takes either a key/value or a dictionary" if type(args[0]).__name__ == 'dict': self._headers.update(args[0]) else: key, value = args self._headers[key] = value def get_content(self): "Return the body of the response in a useful format" return [self._content, '\n'] def set_content(self, value): "Set the body of the response, ensuring we're using utf-8" # http://www.python.org/dev/peps/pep-0333/#unicode-issues if isinstance(value, unicode): value = value.encode('utf-8') self._content = value def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=None, httponly=None): """ Define a cookie to be sent via the outgoing HTTP headers """ self.cookies[key] = value for var_name, var_value in [ ('max_age', max_age), ('path', path), ('domain', domain), ('secure', secure), ('expires', expires), ('httponly', httponly)]: if var_value is not None and var_value is not False: self.cookies[key][var_name.replace('_', '-')] = var_value def delete_cookie(self, key, path='/', domain=None): """ Notify the browser the specified cookie has expired and should be deleted (via the outgoing HTTP headers) """ self.cookies[key] = '' if path is not None: self.cookies[key]['path'] = path if domain is not None: self.cookies[key]['domain'] = domain self.cookies[key]['expires'] = 0 self.cookies[key]['max-age'] = 0 content = property(get_content, set_content) status = property(get_status, set_status) headers = property(get_headers, set_headers) def __str__(self): """Returns a rendition of the full HTTP message, including headers. When the content is an iterator, the actual content is replaced with the output of str(iterator) (to avoid exhausting the iterator). """ if self._is_str_iter: content = ''.join(self.get_content()) else: content = str(self.content) return '\n'.join(['%s: %s' % (key, value) for key, value in self.headers.headeritems()]) \ + '\n\n' + content def __call__(self, environ, start_response): """ Convenience call to return output and set status information Conforms to the WSGI interface for calling purposes only. Example usage: .. code-block:: python def wsgi_app(environ, start_response): response = WSGIResponse() response.write("Hello world") response.headers['Content-Type'] = 'latin1' return response(environ, start_response) """ for c in self.cookies.values(): self.headers.append(('Set-Cookie', c.output(header=''))) start_response(self.status, self.headers) is_file = isinstance(self.content, file) if 'wsgi.file_wrapper' in environ and is_file: return environ['wsgi.file_wrapper'](self.content) elif is_file: return iter(lambda: self.content.read(), '') return self.get_content()
class Response(Exception): """Represent an HTTP Response message. """ def __init__(self, code=200, body='', headers=None): """Takes an int, a string, and a dict (or list of tuples). - code an HTTP response code, e.g., 404 - body the message body as a string - headers a Headers instance - cookie a Cookie.SimpleCookie instance Code is first because when you're raising your own Responses, they're usually error conditions. Body is second because one more often wants to specify a body without headers, than a header without a body. """ if not isinstance(code, int): raise TypeError("'code' must be an integer") elif not isinstance(body, basestring): raise TypeError("'body' must be a string") elif headers is not None and not isinstance(headers, (dict, list)): raise TypeError("'headers' must be a dictionary or a list of " + "2-tuples") Exception.__init__(self) self.code = code self.body = body self.headers = Headers('') if headers: if isinstance(headers, dict): headers = headers.items() for k, v in headers: self.headers.add(k, v) self.cookie = SimpleCookie() try: self.cookie.load(self.headers.one('Cookie', '')) except CookieError: pass def __call__(self, environ, start_response): wsgi_status = str(self) for morsel in self.cookie.values(): self.headers.add('Set-Cookie', morsel.OutputString()) wsgi_headers = [] for k, vals in self.headers._dict.items(): for v in vals: wsgi_headers.append((k, v)) start_response(wsgi_status, wsgi_headers) return [self.body] def __repr__(self): return "<Response: %s>" % str(self) def __str__(self): return "%d %s" % (self.code, self._status()) def _status(self): return status_strings.get(self.code, 'Unknown HTTP status') def _to_http(self, version): """Given a version string like 1.1, return an HTTP message, a string. """ status_line = "HTTP/%s" % version headers = self.headers.to_http() body = self.body if self.headers.one('Content-Type', '').startswith('text/'): body = body.replace('\n', '\r\n') body = body.replace('\r\r', '\r') return '\r\n'.join([status_line, headers, '', body])
class Response(object): def __init__(self, content=None, status=200, content_type='text/html', encoding='utf-8', headers=None): #, default_type='text/html', default_encoding='utf-8'): status = int(status) self.content = content self.status = status if status in STATUSES else 200 self.content_type = content_type self.encoding = encoding self.headers = headers or {} #self.default_type = default_type #self.default_encoding = default_encoding self.cookies = SimpleCookie() def set_cookie(self, key, value='', max_age=None, expires=None, path='/', domain=None, secure=False): if expires: t = type(expires) if t == date: expires = datetime(expires.year, expires.month, expires.day) elif t == time: expires = datetime.now().replace(hour=expires.hour, minute=expires.minute, second=expires.second) elif t in (int, long): expires = datetime.fromtimestamp(expires) else: Exception('Cookie expire time has incorrect type') if not (hasattr(expires, 'tzinfo') and expires.tzinfo): expires = expires.replace(tzinfo=dateutil.tz.tzlocal()) expires = expires.strftime('%a, %d %b %Y %H:%M:%S %z') self.cookies[key] = value cookie = self.cookies[key] if max_age is not None: cookie['max-age'] = max_age if expires is not None: cookie['expires'] = expires if path is not None: cookie['path'] = path if domain is not None: cookie['domain'] = domain if secure: cookie['secure'] = True def delete_cookie(self, key, path='/', domain=None): self.set_cookie(key, max_age=0, path=path, domain=domain, expires=datetime(1970, 1, 1)) def prepare(self): #self.content_type = self.content_type or self.default_type #self.encoding = self.encoding or self.default_encoding if isinstance(self.content, unicode): self.content = self.content.encode(self.encoding) elif not isinstance(self.content, str): self.content = str(self.content) def do_respond_wsgi(self, start_response): self.prepare() status = '%s %s' % (self.status, STATUSES[self.status]) headers = self.headers.items() if self.content_type: if self.encoding: headers.append( ('Content-type', '%s; charset=%s' % (self.content_type, self.encoding)) ) else: headers.append( ('Content-type', '%s' % self.content_type) ) if self.cookies: for c in self.cookies.values(): headers.append(('Set-Cookie', str(c.output(header='')))) start_response(status, headers) return self.content