| OLD | NEW |
| 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 Loading... |
| 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 |
| OLD | NEW |