Chris@0
|
1 <?php
|
Chris@0
|
2
|
Chris@0
|
3 namespace Drupal\big_pipe\Render;
|
Chris@0
|
4
|
Chris@0
|
5 use Drupal\Core\Render\HtmlResponse;
|
Chris@0
|
6
|
Chris@0
|
7 /**
|
Chris@0
|
8 * A response that is sent in chunks by the BigPipe service.
|
Chris@0
|
9 *
|
Chris@0
|
10 * Note we cannot use \Symfony\Component\HttpFoundation\StreamedResponse because
|
Chris@0
|
11 * it makes the content inaccessible (hidden behind a callback), which means no
|
Chris@0
|
12 * middlewares are able to modify the content anymore.
|
Chris@0
|
13 *
|
Chris@0
|
14 * @see \Drupal\big_pipe\Render\BigPipe
|
Chris@0
|
15 *
|
Chris@0
|
16 * @internal
|
Chris@0
|
17 * This is a temporary solution until a generic response emitter interface is
|
Chris@0
|
18 * created in https://www.drupal.org/node/2577631. Only code internal to
|
Chris@0
|
19 * BigPipe should instantiate or type hint to this class.
|
Chris@0
|
20 */
|
Chris@0
|
21 class BigPipeResponse extends HtmlResponse {
|
Chris@0
|
22
|
Chris@0
|
23 /**
|
Chris@0
|
24 * The BigPipe service.
|
Chris@0
|
25 *
|
Chris@0
|
26 * @var \Drupal\big_pipe\Render\BigPipe
|
Chris@0
|
27 */
|
Chris@0
|
28 protected $bigPipe;
|
Chris@0
|
29
|
Chris@0
|
30 /**
|
Chris@0
|
31 * The original HTML response.
|
Chris@0
|
32 *
|
Chris@0
|
33 * Still contains placeholders. Its cacheability metadata and attachments are
|
Chris@0
|
34 * for everything except the placeholders (since those are not yet rendered).
|
Chris@0
|
35 *
|
Chris@0
|
36 * @see \Drupal\Core\Render\StreamedResponseInterface
|
Chris@0
|
37 * @see ::getStreamedResponse()
|
Chris@0
|
38 *
|
Chris@0
|
39 * @var \Drupal\Core\Render\HtmlResponse
|
Chris@0
|
40 */
|
Chris@0
|
41 protected $originalHtmlResponse;
|
Chris@0
|
42
|
Chris@0
|
43 /**
|
Chris@0
|
44 * Constructs a new BigPipeResponse.
|
Chris@0
|
45 *
|
Chris@0
|
46 * @param \Drupal\Core\Render\HtmlResponse $response
|
Chris@0
|
47 * The original HTML response.
|
Chris@0
|
48 */
|
Chris@0
|
49 public function __construct(HtmlResponse $response) {
|
Chris@0
|
50 parent::__construct('', $response->getStatusCode(), []);
|
Chris@0
|
51
|
Chris@0
|
52 $this->originalHtmlResponse = $response;
|
Chris@0
|
53
|
Chris@0
|
54 $this->populateBasedOnOriginalHtmlResponse();
|
Chris@0
|
55 }
|
Chris@0
|
56
|
Chris@0
|
57 /**
|
Chris@0
|
58 * Returns the original HTML response.
|
Chris@0
|
59 *
|
Chris@0
|
60 * @return \Drupal\Core\Render\HtmlResponse
|
Chris@0
|
61 * The original HTML response.
|
Chris@0
|
62 */
|
Chris@0
|
63 public function getOriginalHtmlResponse() {
|
Chris@0
|
64 return $this->originalHtmlResponse;
|
Chris@0
|
65 }
|
Chris@0
|
66
|
Chris@0
|
67 /**
|
Chris@0
|
68 * Populates this BigPipeResponse object based on the original HTML response.
|
Chris@0
|
69 */
|
Chris@0
|
70 protected function populateBasedOnOriginalHtmlResponse() {
|
Chris@0
|
71 // Clone the HtmlResponse's data into the new BigPipeResponse.
|
Chris@0
|
72 $this->headers = clone $this->originalHtmlResponse->headers;
|
Chris@0
|
73 $this
|
Chris@0
|
74 ->setStatusCode($this->originalHtmlResponse->getStatusCode())
|
Chris@0
|
75 ->setContent($this->originalHtmlResponse->getContent())
|
Chris@0
|
76 ->setAttachments($this->originalHtmlResponse->getAttachments())
|
Chris@0
|
77 ->addCacheableDependency($this->originalHtmlResponse->getCacheableMetadata());
|
Chris@0
|
78
|
Chris@0
|
79 // A BigPipe response can never be cached, because it is intended for a
|
Chris@0
|
80 // single user.
|
Chris@0
|
81 // @see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.1
|
Chris@0
|
82 $this->setPrivate();
|
Chris@0
|
83
|
Chris@0
|
84 // Inform surrogates how they should handle BigPipe responses:
|
Chris@0
|
85 // - "no-store" specifies that the response should not be stored in cache;
|
Chris@0
|
86 // it is only to be used for the original request
|
Chris@0
|
87 // - "content" identifies what processing surrogates should perform on the
|
Chris@0
|
88 // response before forwarding it. We send, "BigPipe/1.0", which surrogates
|
Chris@0
|
89 // should not process at all, and in fact, they should not even buffer it
|
Chris@0
|
90 // at all.
|
Chris@0
|
91 // @see http://www.w3.org/TR/edge-arch/
|
Chris@0
|
92 $this->headers->set('Surrogate-Control', 'no-store, content="BigPipe/1.0"');
|
Chris@0
|
93
|
Chris@0
|
94 // Add header to support streaming on NGINX + php-fpm (nginx >= 1.5.6).
|
Chris@0
|
95 $this->headers->set('X-Accel-Buffering', 'no');
|
Chris@0
|
96 }
|
Chris@0
|
97
|
Chris@0
|
98 /**
|
Chris@0
|
99 * Sets the BigPipe service to use.
|
Chris@0
|
100 *
|
Chris@0
|
101 * @param \Drupal\big_pipe\Render\BigPipe $big_pipe
|
Chris@0
|
102 * The BigPipe service.
|
Chris@0
|
103 */
|
Chris@0
|
104 public function setBigPipeService(BigPipe $big_pipe) {
|
Chris@0
|
105 $this->bigPipe = $big_pipe;
|
Chris@0
|
106 }
|
Chris@0
|
107
|
Chris@0
|
108 /**
|
Chris@0
|
109 * {@inheritdoc}
|
Chris@0
|
110 */
|
Chris@0
|
111 public function sendContent() {
|
Chris@0
|
112 $this->bigPipe->sendContent($this);
|
Chris@0
|
113
|
Chris@0
|
114 // All BigPipe placeholders are processed, so update this response's
|
Chris@0
|
115 // attachments.
|
Chris@0
|
116 unset($this->attachments['big_pipe_placeholders']);
|
Chris@0
|
117 unset($this->attachments['big_pipe_nojs_placeholders']);
|
Chris@0
|
118
|
Chris@0
|
119 return $this;
|
Chris@0
|
120 }
|
Chris@0
|
121
|
Chris@0
|
122 }
|