Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(139)

Side by Side Diff: third_party/WebKit/Source/core/loader/BeaconLoader.cpp

Issue 2177383006: Update and fix sendBeacon() redirect behavior. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: improve content type initialization Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/WebKit/Source/core/loader/BeaconLoader.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "core/loader/BeaconLoader.h" 5 #include "core/loader/BeaconLoader.h"
6 6
7 #include "core/dom/DOMArrayBufferView.h" 7 #include "core/dom/DOMArrayBufferView.h"
8 #include "core/dom/Document.h" 8 #include "core/dom/Document.h"
9 #include "core/fetch/CrossOriginAccessControl.h" 9 #include "core/fetch/CrossOriginAccessControl.h"
10 #include "core/fetch/FetchContext.h" 10 #include "core/fetch/FetchContext.h"
11 #include "core/fetch/FetchInitiatorTypeNames.h" 11 #include "core/fetch/FetchInitiatorTypeNames.h"
12 #include "core/fetch/FetchUtils.h"
12 #include "core/fetch/ResourceFetcher.h" 13 #include "core/fetch/ResourceFetcher.h"
13 #include "core/fileapi/File.h" 14 #include "core/fileapi/File.h"
14 #include "core/frame/LocalFrame.h" 15 #include "core/frame/LocalFrame.h"
15 #include "core/html/FormData.h" 16 #include "core/html/FormData.h"
16 #include "core/inspector/ConsoleMessage.h" 17 #include "core/inspector/ConsoleMessage.h"
17 #include "core/loader/MixedContentChecker.h" 18 #include "core/loader/MixedContentChecker.h"
18 #include "platform/exported/WrappedResourceRequest.h" 19 #include "platform/exported/WrappedResourceRequest.h"
19 #include "platform/exported/WrappedResourceResponse.h" 20 #include "platform/exported/WrappedResourceResponse.h"
20 #include "platform/network/EncodedFormData.h" 21 #include "platform/network/EncodedFormData.h"
21 #include "platform/network/ParsedContentType.h" 22 #include "platform/network/ParsedContentType.h"
22 #include "platform/network/ResourceRequest.h" 23 #include "platform/network/ResourceRequest.h"
23 #include "public/platform/WebURLRequest.h" 24 #include "public/platform/WebURLRequest.h"
24 #include "wtf/Functional.h" 25 #include "wtf/Functional.h"
25 26
26 namespace blink { 27 namespace blink {
27 28
28 namespace { 29 namespace {
29 30
30 class Beacon { 31 class Beacon {
32 STACK_ALLOCATED();
31 public: 33 public:
32 virtual bool serialize(ResourceRequest&, int, int&) const = 0; 34 virtual bool serialize(ResourceRequest&, int, int&) const = 0;
33 virtual unsigned long long size() const = 0; 35 virtual unsigned long long size() const = 0;
36 virtual const AtomicString getContentType() const = 0;
34 }; 37 };
35 38
36 class BeaconString final : public Beacon { 39 class BeaconString final : public Beacon {
37 public: 40 public:
38 BeaconString(const String& data) 41 explicit BeaconString(const String& data)
39 : m_data(data) 42 : m_data(data)
40 { 43 {
41 } 44 }
42 45
43 unsigned long long size() const override 46 unsigned long long size() const override
44 { 47 {
45 return m_data.sizeInBytes(); 48 return m_data.sizeInBytes();
46 } 49 }
47 50
48 bool serialize(ResourceRequest& request, int, int&) const override 51 bool serialize(ResourceRequest& request, int, int&) const override
49 { 52 {
50 RefPtr<EncodedFormData> entityBody = EncodedFormData::create(m_data.utf8 ()); 53 RefPtr<EncodedFormData> entityBody = EncodedFormData::create(m_data.utf8 ());
51 request.setHTTPBody(entityBody); 54 request.setHTTPBody(entityBody);
52 request.setHTTPContentType("text/plain;charset=UTF-8"); 55 request.setHTTPContentType(getContentType());
53 return true; 56 return true;
54 } 57 }
55 58
59 const AtomicString getContentType() const { return AtomicString("text/plain; charset=UTF-8"); }
60
56 private: 61 private:
57 const String m_data; 62 const String m_data;
58 }; 63 };
59 64
60 class BeaconBlob final : public Beacon { 65 class BeaconBlob final : public Beacon {
61 public: 66 public:
62 BeaconBlob(Blob* data) 67 explicit BeaconBlob(Blob* data)
63 : m_data(data) 68 : m_data(data)
64 { 69 {
70 const String& blobType = m_data->type();
71 if (!blobType.isEmpty() && isValidContentType(blobType))
72 m_contentType = AtomicString(blobType);
65 } 73 }
66 74
67 unsigned long long size() const override 75 unsigned long long size() const override
68 { 76 {
69 return m_data->size(); 77 return m_data->size();
70 } 78 }
71 79
72 bool serialize(ResourceRequest& request, int, int&) const override 80 bool serialize(ResourceRequest& request, int, int&) const override
73 { 81 {
74 ASSERT(m_data); 82 ASSERT(m_data);
75 RefPtr<EncodedFormData> entityBody = EncodedFormData::create(); 83 RefPtr<EncodedFormData> entityBody = EncodedFormData::create();
76 if (m_data->hasBackingFile()) 84 if (m_data->hasBackingFile())
77 entityBody->appendFile(toFile(m_data)->path()); 85 entityBody->appendFile(toFile(m_data)->path());
78 else 86 else
79 entityBody->appendBlob(m_data->uuid(), m_data->blobDataHandle()); 87 entityBody->appendBlob(m_data->uuid(), m_data->blobDataHandle());
80 88
81 request.setHTTPBody(entityBody.release()); 89 request.setHTTPBody(entityBody.release());
82 90
83 const String& blobType = m_data->type(); 91 if (!m_contentType.isEmpty())
84 if (!blobType.isEmpty() && isValidContentType(blobType)) 92 request.setHTTPContentType(m_contentType);
85 request.setHTTPContentType(AtomicString(blobType));
86 93
87 return true; 94 return true;
88 } 95 }
89 96
97 const AtomicString getContentType() const { return m_contentType; }
98
90 private: 99 private:
91 const Persistent<Blob> m_data; 100 const Member<Blob> m_data;
101 AtomicString m_contentType;
92 }; 102 };
93 103
94 class BeaconDOMArrayBufferView final : public Beacon { 104 class BeaconDOMArrayBufferView final : public Beacon {
95 public: 105 public:
96 BeaconDOMArrayBufferView(DOMArrayBufferView* data) 106 explicit BeaconDOMArrayBufferView(DOMArrayBufferView* data)
97 : m_data(data) 107 : m_data(data)
98 { 108 {
99 } 109 }
100 110
101 unsigned long long size() const override 111 unsigned long long size() const override
102 { 112 {
103 return m_data->byteLength(); 113 return m_data->byteLength();
104 } 114 }
105 115
106 bool serialize(ResourceRequest& request, int, int&) const override 116 bool serialize(ResourceRequest& request, int, int&) const override
107 { 117 {
108 ASSERT(m_data); 118 ASSERT(m_data);
109 RefPtr<EncodedFormData> entityBody = EncodedFormData::create(m_data->bas eAddress(), m_data->byteLength()); 119 RefPtr<EncodedFormData> entityBody = EncodedFormData::create(m_data->bas eAddress(), m_data->byteLength());
110 request.setHTTPBody(entityBody.release()); 120 request.setHTTPBody(entityBody.release());
111 121
112 // FIXME: a reasonable choice, but not in the spec; should it give a def ault? 122 // FIXME: a reasonable choice, but not in the spec; should it give a def ault?
113 AtomicString contentType = AtomicString("application/octet-stream"); 123 AtomicString contentType = AtomicString("application/octet-stream");
114 request.setHTTPContentType(contentType); 124 request.setHTTPContentType(contentType);
115 125
116 return true; 126 return true;
117 } 127 }
118 128
129 const AtomicString getContentType() const { return nullAtom; }
130
119 private: 131 private:
120 const Persistent<DOMArrayBufferView> m_data; 132 const Member<DOMArrayBufferView> m_data;
121 }; 133 };
122 134
123 class BeaconFormData final : public Beacon { 135 class BeaconFormData final : public Beacon {
124 public: 136 public:
125 BeaconFormData(FormData* data) 137 explicit BeaconFormData(FormData* data)
126 : m_data(data) 138 : m_data(data)
139 , m_entityBody(m_data->encodeMultiPartFormData())
127 { 140 {
141 m_contentType = AtomicString("multipart/form-data; boundary=") + m_entit yBody->boundary().data();
128 } 142 }
129 143
130 unsigned long long size() const override 144 unsigned long long size() const override
131 { 145 {
132 // FormData's size cannot be determined until serialized. 146 // FormData's size cannot be determined until serialized.
133 return 0; 147 return 0;
134 } 148 }
135 149
136 bool serialize(ResourceRequest& request, int allowance, int& payloadLength) const override 150 bool serialize(ResourceRequest& request, int allowance, int& payloadLength) const override
137 { 151 {
138 ASSERT(m_data); 152 unsigned long long entitySize = m_entityBody->sizeInBytes();
139 RefPtr<EncodedFormData> entityBody = m_data->encodeMultiPartFormData();
140 unsigned long long entitySize = entityBody->sizeInBytes();
141 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entity Size) 153 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entity Size)
142 return false; 154 return false;
143 155
144 AtomicString contentType = AtomicString("multipart/form-data; boundary=" ) + entityBody->boundary().data(); 156 request.setHTTPBody(m_entityBody.get());
145 request.setHTTPBody(entityBody.release()); 157 request.setHTTPContentType(m_contentType);
146 request.setHTTPContentType(contentType);
147 158
148 payloadLength = entitySize; 159 payloadLength = entitySize;
149 return true; 160 return true;
150 } 161 }
151 162
163 const AtomicString getContentType() const { return m_contentType; }
164
152 private: 165 private:
153 const Persistent<FormData> m_data; 166 const Member<FormData> m_data;
167 RefPtr<EncodedFormData> m_entityBody;
168 AtomicString m_contentType;
154 }; 169 };
155 170
156 } // namespace 171 } // namespace
157 172
158 class BeaconLoader::Sender { 173 class BeaconLoader::Sender {
159 public: 174 public:
160 static bool send(LocalFrame* frame, int allowance, const KURL& beaconURL, co nst Beacon& beacon, int& payloadLength) 175 static bool send(LocalFrame* frame, int allowance, const KURL& beaconURL, co nst Beacon& beacon, int& payloadLength)
161 { 176 {
162 if (!frame->document()) 177 if (!frame->document())
163 return false; 178 return false;
(...skipping 10 matching lines...) Expand all
174 frame->document()->fetcher()->context().addAdditionalRequestHeaders(requ est, FetchSubresource); 189 frame->document()->fetcher()->context().addAdditionalRequestHeaders(requ est, FetchSubresource);
175 frame->document()->fetcher()->context().populateRequestData(request); 190 frame->document()->fetcher()->context().populateRequestData(request);
176 191
177 if (MixedContentChecker::shouldBlockFetch(frame, request, request.url()) ) 192 if (MixedContentChecker::shouldBlockFetch(frame, request, request.url()) )
178 return false; 193 return false;
179 194
180 payloadLength = entitySize; 195 payloadLength = entitySize;
181 if (!beacon.serialize(request, allowance, payloadLength)) 196 if (!beacon.serialize(request, allowance, payloadLength))
182 return false; 197 return false;
183 198
199 const AtomicString contentType = beacon.getContentType();
200 CORSEnabled corsEnabled = IsCORSEnabled;
201 if (!contentType.isNull() && FetchUtils::isSimpleHeader(AtomicString("co ntent-type"), contentType))
202 corsEnabled = NotCORSEnabled;
203
184 FetchInitiatorInfo initiatorInfo; 204 FetchInitiatorInfo initiatorInfo;
185 initiatorInfo.name = FetchInitiatorTypeNames::beacon; 205 initiatorInfo.name = FetchInitiatorTypeNames::beacon;
186 206
187 // The loader keeps itself alive until it receives a response and dispos es itself. 207 // The loader keeps itself alive until it receives a response and dispos es itself.
188 BeaconLoader* loader = new BeaconLoader(frame, request, initiatorInfo, A llowStoredCredentials); 208 BeaconLoader* loader = new BeaconLoader(frame, request, initiatorInfo, A llowStoredCredentials, corsEnabled);
189 ASSERT_UNUSED(loader, loader); 209 ASSERT_UNUSED(loader, loader);
190 return true; 210 return true;
191 } 211 }
192 }; 212 };
193 213
194 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, const String& data, int& payloadLength) 214 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, const String& data, int& payloadLength)
195 { 215 {
196 BeaconString beacon(data); 216 BeaconString beacon(data);
197 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); 217 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength);
198 } 218 }
199 219
200 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, DOMArrayBufferView* data, int& payloadLength) 220 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, DOMArrayBufferView* data, int& payloadLength)
201 { 221 {
202 BeaconDOMArrayBufferView beacon(data); 222 BeaconDOMArrayBufferView beacon(data);
203 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); 223 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength);
204 } 224 }
205 225
206 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, FormData* data, int& payloadLength) 226 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, FormData* data, int& payloadLength)
207 { 227 {
208 BeaconFormData beacon(data); 228 BeaconFormData beacon(data);
209 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); 229 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength);
210 } 230 }
211 231
212 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, Blob* data, int& payloadLength) 232 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac onURL, Blob* data, int& payloadLength)
213 { 233 {
214 BeaconBlob beacon(data); 234 BeaconBlob beacon(data);
215 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); 235 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength);
216 } 236 }
217 237
218 BeaconLoader::BeaconLoader(LocalFrame* frame, ResourceRequest& request, const Fe tchInitiatorInfo& initiatorInfo, StoredCredentials credentialsAllowed) 238 BeaconLoader::BeaconLoader(LocalFrame* frame, ResourceRequest& request, const Fe tchInitiatorInfo& initiatorInfo, StoredCredentials credentialsAllowed, CORSEnabl ed corsMode)
219 : PingLoader(frame, request, initiatorInfo, credentialsAllowed) 239 : PingLoader(frame, request, initiatorInfo, credentialsAllowed)
220 , m_beaconOrigin(frame->document()->getSecurityOrigin()) 240 , m_beaconOrigin(frame->document()->getSecurityOrigin())
241 , m_redirectsFollowCORS(corsMode == IsCORSEnabled)
221 { 242 {
222 } 243 }
223 244
224 void BeaconLoader::willFollowRedirect(WebURLLoader*, WebURLRequest& passedNewReq uest, const WebURLResponse& passedRedirectResponse, int64_t encodedDataLength) 245 void BeaconLoader::willFollowRedirect(WebURLLoader*, WebURLRequest& passedNewReq uest, const WebURLResponse& passedRedirectResponse, int64_t encodedDataLength)
225 { 246 {
226 passedNewRequest.setAllowStoredCredentials(true); 247 passedNewRequest.setAllowStoredCredentials(true);
248 if (!m_redirectsFollowCORS)
249 return;
250
227 ResourceRequest& newRequest(passedNewRequest.toMutableResourceRequest()); 251 ResourceRequest& newRequest(passedNewRequest.toMutableResourceRequest());
228 const ResourceResponse& redirectResponse(passedRedirectResponse.toResourceRe sponse()); 252 const ResourceResponse& redirectResponse(passedRedirectResponse.toResourceRe sponse());
229 253
230 ASSERT(!newRequest.isNull()); 254 ASSERT(!newRequest.isNull());
231 ASSERT(!redirectResponse.isNull()); 255 ASSERT(!redirectResponse.isNull());
232 256
233 String errorDescription; 257 String errorDescription;
234 StoredCredentials withCredentials = AllowStoredCredentials; 258 StoredCredentials withCredentials = AllowStoredCredentials;
235 ResourceLoaderOptions options; 259 ResourceLoaderOptions options;
236 if (!CrossOriginAccessControl::handleRedirect(m_beaconOrigin.get(), newReque st, redirectResponse, withCredentials, options, errorDescription)) { 260 if (!CrossOriginAccessControl::handleRedirect(m_beaconOrigin.get(), newReque st, redirectResponse, withCredentials, options, errorDescription)) {
237 if (LocalFrame* localFrame = frame()) { 261 if (LocalFrame* localFrame = frame()) {
238 if (localFrame->document()) 262 if (localFrame->document())
239 localFrame->document()->addConsoleMessage(ConsoleMessage::create (JSMessageSource, ErrorMessageLevel, errorDescription)); 263 localFrame->document()->addConsoleMessage(ConsoleMessage::create (JSMessageSource, ErrorMessageLevel, errorDescription));
240 } 264 }
241 // Cancel the load and self destruct. 265 // Cancel the load and self destruct.
242 dispose(); 266 dispose();
267 // Signal WebURLLoader that the redirect musn't be followed.
268 passedNewRequest = WebURLRequest();
243 return; 269 return;
244 } 270 }
245 // FIXME: http://crbug.com/427429 is needed to correctly propagate 271 // FIXME: http://crbug.com/427429 is needed to correctly propagate
246 // updates of Origin: following this successful redirect. 272 // updates of Origin: following this successful redirect.
247 } 273 }
248 274
249 } // namespace blink 275 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/loader/BeaconLoader.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698