OLD | NEW |
| (Empty) |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "config.h" | |
6 #include "FetchResponseData.h" | |
7 | |
8 #include "core/dom/DOMArrayBuffer.h" | |
9 #include "core/fetch/CrossOriginAccessControl.h" | |
10 #include "modules/serviceworkers/BodyStreamBuffer.h" | |
11 #include "modules/serviceworkers/FetchHeaderList.h" | |
12 #include "public/platform/WebServiceWorkerResponse.h" | |
13 | |
14 namespace blink { | |
15 | |
16 namespace { | |
17 | |
18 WebServiceWorkerResponseType fetchTypeToWebType(FetchResponseData::Type fetchTyp
e) | |
19 { | |
20 WebServiceWorkerResponseType webType = WebServiceWorkerResponseTypeDefault; | |
21 switch (fetchType) { | |
22 case FetchResponseData::BasicType: | |
23 webType = WebServiceWorkerResponseTypeBasic; | |
24 break; | |
25 case FetchResponseData::CORSType: | |
26 webType = WebServiceWorkerResponseTypeCORS; | |
27 break; | |
28 case FetchResponseData::DefaultType: | |
29 webType = WebServiceWorkerResponseTypeDefault; | |
30 break; | |
31 case FetchResponseData::ErrorType: | |
32 webType = WebServiceWorkerResponseTypeError; | |
33 break; | |
34 case FetchResponseData::OpaqueType: | |
35 webType = WebServiceWorkerResponseTypeOpaque; | |
36 break; | |
37 } | |
38 return webType; | |
39 } | |
40 | |
41 class StreamTeePump : public BodyStreamBuffer::Observer { | |
42 public: | |
43 StreamTeePump(BodyStreamBuffer* inBuffer, BodyStreamBuffer* outBuffer1, Body
StreamBuffer* outBuffer2) | |
44 : m_inBuffer(inBuffer) | |
45 , m_outBuffer1(outBuffer1) | |
46 , m_outBuffer2(outBuffer2) | |
47 { | |
48 } | |
49 void onWrite() override | |
50 { | |
51 while (RefPtr<DOMArrayBuffer> buf = m_inBuffer->read()) { | |
52 m_outBuffer1->write(buf); | |
53 m_outBuffer2->write(buf); | |
54 } | |
55 } | |
56 void onClose() override | |
57 { | |
58 m_outBuffer1->close(); | |
59 m_outBuffer2->close(); | |
60 cleanup(); | |
61 } | |
62 void onError() override | |
63 { | |
64 m_outBuffer1->error(m_inBuffer->exception()); | |
65 m_outBuffer2->error(m_inBuffer->exception()); | |
66 cleanup(); | |
67 } | |
68 void trace(Visitor* visitor) override | |
69 { | |
70 BodyStreamBuffer::Observer::trace(visitor); | |
71 visitor->trace(m_inBuffer); | |
72 visitor->trace(m_outBuffer1); | |
73 visitor->trace(m_outBuffer2); | |
74 } | |
75 void start() | |
76 { | |
77 m_inBuffer->registerObserver(this); | |
78 onWrite(); | |
79 if (m_inBuffer->hasError()) | |
80 return onError(); | |
81 if (m_inBuffer->isClosed()) | |
82 return onClose(); | |
83 } | |
84 | |
85 private: | |
86 void cleanup() | |
87 { | |
88 m_inBuffer->unregisterObserver(); | |
89 m_inBuffer.clear(); | |
90 m_outBuffer1.clear(); | |
91 m_outBuffer2.clear(); | |
92 } | |
93 Member<BodyStreamBuffer> m_inBuffer; | |
94 Member<BodyStreamBuffer> m_outBuffer1; | |
95 Member<BodyStreamBuffer> m_outBuffer2; | |
96 }; | |
97 | |
98 } // namespace | |
99 | |
100 FetchResponseData* FetchResponseData::create() | |
101 { | |
102 // "Unless stated otherwise, a response's url is null, status is 200, status | |
103 // message is `OK`, header list is an empty header list, and body is null." | |
104 return new FetchResponseData(DefaultType, 200, "OK"); | |
105 } | |
106 | |
107 FetchResponseData* FetchResponseData::createNetworkErrorResponse() | |
108 { | |
109 // "A network error is a response whose status is always 0, status message | |
110 // is always the empty byte sequence, header list is aways an empty list, | |
111 // and body is always null." | |
112 return new FetchResponseData(ErrorType, 0, ""); | |
113 } | |
114 | |
115 FetchResponseData* FetchResponseData::createWithBuffer(BodyStreamBuffer* buffer) | |
116 { | |
117 FetchResponseData* response = FetchResponseData::create(); | |
118 response->m_buffer = buffer; | |
119 return response; | |
120 } | |
121 | |
122 FetchResponseData* FetchResponseData::createBasicFilteredResponse() | |
123 { | |
124 // "A basic filtered response is a filtered response whose type is |basic|, | |
125 // header list excludes any headers in internal response's header list whose | |
126 // name is `Set-Cookie` or `Set-Cookie2`." | |
127 FetchResponseData* response = new FetchResponseData(BasicType, m_status, m_s
tatusMessage); | |
128 response->m_url = m_url; | |
129 for (size_t i = 0; i < m_headerList->size(); ++i) { | |
130 const FetchHeaderList::Header* header = m_headerList->list()[i].get(); | |
131 if (header->first == "set-cookie" || header->first == "set-cookie2") | |
132 continue; | |
133 response->m_headerList->append(header->first, header->second); | |
134 } | |
135 response->m_blobDataHandle = m_blobDataHandle; | |
136 response->m_buffer = m_buffer; | |
137 response->m_contentTypeForBuffer = m_contentTypeForBuffer; | |
138 response->m_internalResponse = this; | |
139 return response; | |
140 } | |
141 | |
142 FetchResponseData* FetchResponseData::createCORSFilteredResponse() | |
143 { | |
144 // "A CORS filtered response is a filtered response whose type is |CORS|, | |
145 // header list excludes all headers in internal response's header list, | |
146 // except those whose name is either one of `Cache-Control`, | |
147 // `Content-Language`, `Content-Type`, `Expires`, `Last-Modified`, and | |
148 // `Pragma`, and except those whose name is one of the values resulting from | |
149 // parsing `Access-Control-Expose-Headers` in internal response's header | |
150 // list." | |
151 FetchResponseData* response = new FetchResponseData(CORSType, m_status, m_st
atusMessage); | |
152 response->m_url = m_url; | |
153 HTTPHeaderSet accessControlExposeHeaderSet; | |
154 String accessControlExposeHeaders; | |
155 if (m_headerList->get("access-control-expose-headers", accessControlExposeHe
aders)) | |
156 parseAccessControlExposeHeadersAllowList(accessControlExposeHeaders, acc
essControlExposeHeaderSet); | |
157 for (size_t i = 0; i < m_headerList->size(); ++i) { | |
158 const FetchHeaderList::Header* header = m_headerList->list()[i].get(); | |
159 if (!isOnAccessControlResponseHeaderWhitelist(header->first) && !accessC
ontrolExposeHeaderSet.contains(header->first)) | |
160 continue; | |
161 response->m_headerList->append(header->first, header->second); | |
162 } | |
163 response->m_blobDataHandle = m_blobDataHandle; | |
164 response->m_buffer = m_buffer; | |
165 response->m_contentTypeForBuffer = m_contentTypeForBuffer; | |
166 response->m_internalResponse = this; | |
167 return response; | |
168 } | |
169 | |
170 FetchResponseData* FetchResponseData::createOpaqueFilteredResponse() | |
171 { | |
172 // "An opaque filtered response is a filtered response whose type is | |
173 // |opaque|, status is 0, status message is the empty byte sequence, header | |
174 // list is an empty list, and body is null." | |
175 FetchResponseData* response = new FetchResponseData(OpaqueType, 0, ""); | |
176 response->m_internalResponse = this; | |
177 return response; | |
178 } | |
179 | |
180 String FetchResponseData::contentTypeForBuffer() const | |
181 { | |
182 return m_contentTypeForBuffer; | |
183 } | |
184 | |
185 PassRefPtr<BlobDataHandle> FetchResponseData::internalBlobDataHandle() const | |
186 { | |
187 if (m_internalResponse) { | |
188 return m_internalResponse->m_blobDataHandle; | |
189 } | |
190 return m_blobDataHandle; | |
191 } | |
192 | |
193 BodyStreamBuffer* FetchResponseData::internalBuffer() const | |
194 { | |
195 if (m_internalResponse) { | |
196 return m_internalResponse->m_buffer; | |
197 } | |
198 return m_buffer; | |
199 } | |
200 | |
201 String FetchResponseData::internalContentTypeForBuffer() const | |
202 { | |
203 if (m_internalResponse) { | |
204 return m_internalResponse->contentTypeForBuffer(); | |
205 } | |
206 return m_contentTypeForBuffer; | |
207 } | |
208 | |
209 FetchResponseData* FetchResponseData::clone() | |
210 { | |
211 FetchResponseData* newResponse = create(); | |
212 newResponse->m_type = m_type; | |
213 if (m_terminationReason) { | |
214 newResponse->m_terminationReason = adoptPtr(new TerminationReason); | |
215 *newResponse->m_terminationReason = *m_terminationReason; | |
216 } | |
217 newResponse->m_url = m_url; | |
218 newResponse->m_status = m_status; | |
219 newResponse->m_statusMessage = m_statusMessage; | |
220 newResponse->m_headerList = m_headerList->createCopy(); | |
221 newResponse->m_blobDataHandle = m_blobDataHandle; | |
222 newResponse->m_contentTypeForBuffer = m_contentTypeForBuffer; | |
223 if (!m_internalResponse) { | |
224 if (!m_buffer) | |
225 return newResponse; | |
226 BodyStreamBuffer* original = m_buffer; | |
227 m_buffer = new BodyStreamBuffer(); | |
228 newResponse->m_buffer = new BodyStreamBuffer(); | |
229 StreamTeePump* teePump = new StreamTeePump(original, m_buffer, newRespon
se->m_buffer); | |
230 teePump->start(); | |
231 return newResponse; | |
232 } | |
233 | |
234 ASSERT(!m_buffer || m_buffer == m_internalResponse->m_buffer); | |
235 newResponse->m_internalResponse = m_internalResponse->clone(); | |
236 if (m_buffer) { | |
237 m_buffer = m_internalResponse->m_buffer; | |
238 newResponse->m_buffer = newResponse->m_internalResponse->m_buffer; | |
239 } | |
240 return newResponse; | |
241 } | |
242 | |
243 void FetchResponseData::populateWebServiceWorkerResponse(WebServiceWorkerRespons
e& response) | |
244 { | |
245 if (m_internalResponse) { | |
246 m_internalResponse->populateWebServiceWorkerResponse(response); | |
247 response.setResponseType(fetchTypeToWebType(m_type)); | |
248 return; | |
249 } | |
250 | |
251 response.setURL(url()); | |
252 response.setStatus(status()); | |
253 response.setStatusText(statusMessage()); | |
254 response.setResponseType(fetchTypeToWebType(m_type)); | |
255 for (size_t i = 0; i < headerList()->size(); ++i) { | |
256 const FetchHeaderList::Header* header = headerList()->list()[i].get(); | |
257 response.appendHeader(header->first, header->second); | |
258 } | |
259 response.setBlobDataHandle(m_blobDataHandle); | |
260 } | |
261 | |
262 FetchResponseData::FetchResponseData(Type type, unsigned short status, AtomicStr
ing statusMessage) | |
263 : m_type(type) | |
264 , m_status(status) | |
265 , m_statusMessage(statusMessage) | |
266 , m_headerList(FetchHeaderList::create()) | |
267 { | |
268 } | |
269 | |
270 void FetchResponseData::setBlobDataHandle(PassRefPtr<BlobDataHandle> blobDataHan
dle) | |
271 { | |
272 ASSERT(!m_buffer); | |
273 m_blobDataHandle = blobDataHandle; | |
274 } | |
275 | |
276 void FetchResponseData::trace(Visitor* visitor) | |
277 { | |
278 visitor->trace(m_headerList); | |
279 visitor->trace(m_internalResponse); | |
280 visitor->trace(m_buffer); | |
281 } | |
282 | |
283 } // namespace blink | |
OLD | NEW |