mirror of
https://github.com/django/daphne.git
synced 2024-11-21 15:36:33 +03:00
Match to the new ASGI-HTTP spec.
This commit is contained in:
parent
7fb3e9a167
commit
20ff8fec28
|
@ -1,7 +1,6 @@
|
|||
import sys
|
||||
import argparse
|
||||
import logging
|
||||
import importlib
|
||||
from .server import Server
|
||||
from .endpoints import build_endpoint_description_strings
|
||||
from .access import AccessLogGenerator
|
||||
|
|
|
@ -198,7 +198,7 @@ class WebRequest(http.Request):
|
|||
"""
|
||||
if "type" not in message:
|
||||
raise ValueError("Message has no type defined")
|
||||
if message["type"] == "http.response":
|
||||
if message["type"] == "http.response.start":
|
||||
if self._response_started:
|
||||
raise ValueError("HTTP response has already been started")
|
||||
self._response_started = True
|
||||
|
@ -213,33 +213,31 @@ class WebRequest(http.Request):
|
|||
header = header.encode("latin1")
|
||||
self.responseHeaders.addRawHeader(header, value)
|
||||
logger.debug("HTTP %s response started for %s", message["status"], self.client_addr)
|
||||
elif message["type"] == "http.response.hunk":
|
||||
elif message["type"] == "http.response.content":
|
||||
if not self._response_started:
|
||||
raise ValueError("HTTP response has not yet been started but got %s" % message["type"])
|
||||
raise ValueError("HTTP response has not yet been started but got %s" % message["type"])# Write out body
|
||||
http.Request.write(self, message.get("content", b""))
|
||||
|
||||
# End if there's no more content
|
||||
if not message.get("more_content", False):
|
||||
self.finish()
|
||||
logger.debug("HTTP response complete for %s", self.client_addr)
|
||||
try:
|
||||
self.server.log_action("http", "complete", {
|
||||
"path": self.uri.decode("ascii"),
|
||||
"status": self.code,
|
||||
"method": self.method.decode("ascii"),
|
||||
"client": "%s:%s" % tuple(self.client_addr) if self.client_addr else None,
|
||||
"time_taken": self.duration(),
|
||||
"size": self.sentLength,
|
||||
})
|
||||
except Exception as e:
|
||||
logging.error(traceback.format_exc())
|
||||
else:
|
||||
logger.debug("HTTP response chunk for %s", self.client_addr)
|
||||
else:
|
||||
raise ValueError("Cannot handle message type %s!" % message["type"])
|
||||
|
||||
# Write out body
|
||||
http.Request.write(self, message.get("content", b""))
|
||||
|
||||
# End if there's no more content
|
||||
if not message.get("more_content", False):
|
||||
self.finish()
|
||||
logger.debug("HTTP response complete for %s", self.client_addr)
|
||||
try:
|
||||
self.server.log_action("http", "complete", {
|
||||
"path": self.uri.decode("ascii"),
|
||||
"status": self.code,
|
||||
"method": self.method.decode("ascii"),
|
||||
"client": "%s:%s" % tuple(self.client_addr) if self.client_addr else None,
|
||||
"time_taken": self.duration(),
|
||||
"size": self.sentLength,
|
||||
})
|
||||
except Exception as e:
|
||||
logging.error(traceback.format_exc())
|
||||
else:
|
||||
logger.debug("HTTP response chunk for %s", self.client_addr)
|
||||
|
||||
def handle_exception(self, exception):
|
||||
"""
|
||||
Called by the server when our application tracebacks
|
||||
|
@ -298,12 +296,14 @@ class WebRequest(http.Request):
|
|||
Responds with a server-level error page (very basic)
|
||||
"""
|
||||
self.handle_reply({
|
||||
"type": "http.response",
|
||||
"type": "http.response.start",
|
||||
"status": status,
|
||||
"status_text": status_text,
|
||||
"headers": [
|
||||
(b"Content-Type", b"text/html; charset=utf-8"),
|
||||
],
|
||||
})
|
||||
self.handle_reply({
|
||||
"type": "http.response.content",
|
||||
"content": (self.error_template % {
|
||||
"title": six.text_type(status) + " " + status_text.decode("ascii"),
|
||||
"body": body,
|
||||
|
|
|
@ -158,7 +158,10 @@ class DaphneTestCase(unittest.TestCase):
|
|||
body=body,
|
||||
headers=headers,
|
||||
xff=xff,
|
||||
responses=[{"type": "http.response", "status": 200, "content": b"OK"}],
|
||||
responses=[
|
||||
{"type": "http.response.start", "status": 200},
|
||||
{"type": "http.response.content", "content": b"OK"},
|
||||
],
|
||||
)
|
||||
return scope, messages
|
||||
|
||||
|
@ -247,7 +250,6 @@ class DaphneTestCase(unittest.TestCase):
|
|||
frame += b"\0\0\0\0"
|
||||
# Payload
|
||||
frame += value
|
||||
print("sending %r" % frame)
|
||||
sock.sendall(frame)
|
||||
|
||||
def receive_from_socket(self, sock, length, timeout=1):
|
||||
|
|
|
@ -27,8 +27,11 @@ class TestHTTPResponse(DaphneTestCase):
|
|||
"""
|
||||
response = self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response",
|
||||
"type": "http.response.start",
|
||||
"status": 200,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"hello world",
|
||||
},
|
||||
])
|
||||
|
@ -45,7 +48,10 @@ class TestHTTPResponse(DaphneTestCase):
|
|||
with self.assertRaises(ValueError):
|
||||
self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response",
|
||||
"type": "http.response.start",
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"hello world",
|
||||
},
|
||||
])
|
||||
|
@ -56,14 +62,65 @@ class TestHTTPResponse(DaphneTestCase):
|
|||
"""
|
||||
response = self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response",
|
||||
"type": "http.response.start",
|
||||
"status": 201,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"i made a thing!",
|
||||
},
|
||||
])
|
||||
self.assertEqual(response.status, 201)
|
||||
self.assertEqual(response.read(), b"i made a thing!")
|
||||
|
||||
def test_chunked_response(self):
|
||||
"""
|
||||
Tries sending a response in multiple parts.
|
||||
"""
|
||||
response = self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response.start",
|
||||
"status": 201,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"chunk 1 ",
|
||||
"more_content": True,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"chunk 2",
|
||||
},
|
||||
])
|
||||
self.assertEqual(response.status, 201)
|
||||
self.assertEqual(response.read(), b"chunk 1 chunk 2")
|
||||
|
||||
def test_chunked_response_empty(self):
|
||||
"""
|
||||
Tries sending a response in multiple parts and an empty end.
|
||||
"""
|
||||
response = self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response.start",
|
||||
"status": 201,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"chunk 1 ",
|
||||
"more_content": True,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": b"chunk 2",
|
||||
"more_content": True,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
},
|
||||
])
|
||||
self.assertEqual(response.status, 201)
|
||||
self.assertEqual(response.read(), b"chunk 1 chunk 2")
|
||||
|
||||
@given(body=http_strategies.http_body())
|
||||
@settings(max_examples=5, deadline=2000)
|
||||
def test_body(self, body):
|
||||
|
@ -72,8 +129,11 @@ class TestHTTPResponse(DaphneTestCase):
|
|||
"""
|
||||
response = self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response",
|
||||
"type": "http.response.start",
|
||||
"status": 200,
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
"content": body,
|
||||
},
|
||||
])
|
||||
|
@ -86,10 +146,13 @@ class TestHTTPResponse(DaphneTestCase):
|
|||
# The ASGI spec requires us to lowercase our header names
|
||||
response = self.run_daphne_response([
|
||||
{
|
||||
"type": "http.response",
|
||||
"type": "http.response.start",
|
||||
"status": 200,
|
||||
"headers": self.normalize_headers(headers),
|
||||
},
|
||||
{
|
||||
"type": "http.response.content",
|
||||
},
|
||||
])
|
||||
# Check headers in a sensible way. Ignore transfer-encoding.
|
||||
self.assertEqual(
|
||||
|
|
Loading…
Reference in New Issue
Block a user