def __set__(self, obj, value): value = native(value) if value is not None else '' if ';' not in value: original = native(super(ContentType, self).__get__(obj, None), 'ascii') if ';' in original: value += ';' + original.split(';', 1)[1] super(ContentType, self).__set__(obj, bytestring(value, 'ascii'))
def compose_response(self): # log.debug("Composing response.") env = self.environ for filter_ in self.protocol.ingress: filter_(env) status, headers, body = self.protocol.application(env) for filter_ in self.protocol.egress: status, headers, body = filter_(env, status, headers, body) # Canonicalize the names of the headers returned by the application. present = [i[0].lower() for i in headers] # These checks are optional; if the application is well-behaved they can be disabled. # Of course, if disabled, m.s.http isn't WSGI 2 compliant. (But it is faster!) assert isinstance(status, binary), "Response status must be a bytestring." for i, j in headers: assert isinstance(i, binary), "Response header names must be bytestrings." assert isinstance(j, binary), "Response header values must be bytestrings." assert b'transfer-encoding' not in present, "Applications must not set the Transfer-Encoding header." assert b'connection' not in present, "Applications must not set the Connection header." if b'server' not in present: headers.append((b'Server', VERSION_STRING)) if b'date' not in present: headers.append((b'Date', bytestring(formatdate(time.time(), False, True)))) is_head = env.get('marrow.head', False) if is_head: try: body.close() except AttributeError: pass body = [] if env['SERVER_PROTOCOL'] == "HTTP/1.1" and b'content-length' not in present: headers.append((b"Transfer-Encoding", b"chunked")) headers = env['SERVER_PROTOCOL'].encode('iso-8859-1') + b" " + status + CRLF + CRLF.join([(i + b': ' + j) for i, j in headers]) + dCRLF return headers, partial(self.write_body if is_head else self.write_body_chunked, body, iter(body)) headers = env['SERVER_PROTOCOL'].encode('iso-8859-1') + b" " + status + CRLF + CRLF.join([(i + b': ' + j) for i, j in headers]) + dCRLF return headers, partial(self.write_body, body, iter(body))
def write_body_chunked(self, original, body): try: chunk = next(body) assert isinstance(chunk, binary), "Body iterators must yield bytestrings." chunk = bytestring(hex(len(chunk))[2:]) + CRLF + chunk + CRLF self.client.write(chunk, partial(self.write_body_chunked, original, body)) except StopIteration: try: original.close() except AttributeError: pass self.client.write(b"0" + dCRLF, self.finish) except: # pragma: no cover TODO EDGE CASE try: original.close() except AttributeError: pass raise
def __set__(self, obj, value): if not value: self.__delete__(obj) return value = native(value) content_type = native(super(Charset, self).__get__(obj, None), 'ascii') charset_match = CHARSET_RE.search(content_type) if content_type else None if charset_match: content_type = content_type[:charset_match.start(1)] + value + content_type[charset_match.end(1):] # TODO: Examine what action browsers take. # elif ';' in content_type: # content_type += ', charset="%s"' % charset elif content_type: content_type += '; charset="' + value + '"' else: content_type = '; charset="' + value + '"' super(Charset, self).__set__(obj, bytestring(content_type, 'ascii'))
def __call__(self, environ, start_response=None): if start_response: start_resopnse(b'%d %s' % (self.code, self.status), self.headers) return self.body return bytestring(str(self.code), 'ascii') + b' ' + self.status, self.headers, [bytestring(self.body)]
def __str__(self): return bytestring(self.render())
def __get__(self, obj, cls, strip=True): value = native(super(ContentType, self).__get__(obj, cls)) if not value: return None return bytestring(value.split(';', 1)[0] if strip else value)