| 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 "config.h" | 5 #include "config.h" |
| 6 #include "core/loader/BeaconLoader.h" | 6 #include "core/loader/BeaconLoader.h" |
| 7 | 7 |
| 8 #include "core/FetchInitiatorTypeNames.h" | 8 #include "core/FetchInitiatorTypeNames.h" |
| 9 #include "core/dom/DOMArrayBufferView.h" | 9 #include "core/dom/DOMArrayBufferView.h" |
| 10 #include "core/fetch/FetchContext.h" | 10 #include "core/fetch/FetchContext.h" |
| 11 #include "core/fileapi/File.h" | 11 #include "core/fileapi/File.h" |
| 12 #include "core/frame/LocalFrame.h" | 12 #include "core/frame/LocalFrame.h" |
| 13 #include "core/html/DOMFormData.h" | 13 #include "core/html/DOMFormData.h" |
| 14 #include "platform/network/FormData.h" | 14 #include "platform/network/FormData.h" |
| 15 #include "platform/network/ParsedContentType.h" | 15 #include "platform/network/ParsedContentType.h" |
| 16 #include "platform/network/ResourceRequest.h" | 16 #include "platform/network/ResourceRequest.h" |
| 17 #include "public/platform/WebURLRequest.h" | 17 #include "public/platform/WebURLRequest.h" |
| 18 #include "wtf/Functional.h" |
| 18 | 19 |
| 19 namespace blink { | 20 namespace blink { |
| 20 | 21 |
| 21 void BeaconLoader::prepareRequest(LocalFrame* frame, ResourceRequest& request) | 22 namespace { |
| 22 { | |
| 23 request.setRequestContext(WebURLRequest::RequestContextBeacon); | |
| 24 request.setHTTPMethod("POST"); | |
| 25 request.setHTTPHeaderField("Cache-Control", "max-age=0"); | |
| 26 request.setAllowStoredCredentials(true); | |
| 27 frame->loader().fetchContext().addAdditionalRequestHeaders(frame->document()
, request, FetchSubresource); | |
| 28 frame->loader().fetchContext().setFirstPartyForCookies(request); | |
| 29 } | |
| 30 | 23 |
| 31 void BeaconLoader::issueRequest(LocalFrame* frame, ResourceRequest& request) | 24 class Beacon { |
| 32 { | 25 public: |
| 33 FetchInitiatorInfo initiatorInfo; | 26 virtual bool serialize(ResourceRequest&, int, int&) const = 0; |
| 34 initiatorInfo.name = FetchInitiatorTypeNames::beacon; | 27 virtual unsigned long long size() const = 0; |
| 35 | 28 |
| 36 PingLoader::start(frame, request, initiatorInfo); | 29 protected: |
| 37 } | 30 static unsigned long long beaconSize(const String&); |
| 31 static unsigned long long beaconSize(Blob*); |
| 32 static unsigned long long beaconSize(PassRefPtr<DOMArrayBufferView>); |
| 33 static unsigned long long beaconSize(PassRefPtrWillBeRawPtr<DOMFormData>); |
| 34 |
| 35 static bool serialize(const String&, ResourceRequest&, int, int&); |
| 36 static bool serialize(Blob*, ResourceRequest&, int, int&); |
| 37 static bool serialize(PassRefPtr<DOMArrayBufferView>, ResourceRequest&, int,
int&); |
| 38 static bool serialize(PassRefPtrWillBeRawPtr<DOMFormData>, ResourceRequest&,
int, int&); |
| 39 }; |
| 40 |
| 41 template<typename Payload> |
| 42 class BeaconData final : public Beacon { |
| 43 public: |
| 44 BeaconData(const Payload& data) |
| 45 : m_data(data) |
| 46 { |
| 47 } |
| 48 |
| 49 bool serialize(ResourceRequest& request, int allowance, int& payloadLength)
const override |
| 50 { |
| 51 return Beacon::serialize(m_data, request, allowance, payloadLength); |
| 52 } |
| 53 |
| 54 unsigned long long size() const override |
| 55 { |
| 56 return beaconSize(m_data); |
| 57 } |
| 58 |
| 59 private: |
| 60 const typename WTF::ParamStorageTraits<Payload>::StorageType m_data; |
| 61 }; |
| 62 |
| 63 } // namespace |
| 64 |
| 65 class BeaconLoader::Sender { |
| 66 public: |
| 67 static bool send(LocalFrame* frame, int allowance, const KURL& beaconURL, co
nst Beacon& beacon, int& payloadLength) |
| 68 { |
| 69 unsigned long long entitySize = beacon.size(); |
| 70 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entity
Size) |
| 71 return false; |
| 72 |
| 73 ResourceRequest request(beaconURL); |
| 74 request.setRequestContext(WebURLRequest::RequestContextBeacon); |
| 75 request.setHTTPMethod("POST"); |
| 76 request.setHTTPHeaderField("Cache-Control", "max-age=0"); |
| 77 request.setAllowStoredCredentials(true); |
| 78 frame->loader().fetchContext().addAdditionalRequestHeaders(frame->docume
nt(), request, FetchSubresource); |
| 79 frame->loader().fetchContext().setFirstPartyForCookies(request); |
| 80 |
| 81 payloadLength = entitySize; |
| 82 if (!beacon.serialize(request, allowance, payloadLength)) |
| 83 return false; |
| 84 |
| 85 FetchInitiatorInfo initiatorInfo; |
| 86 initiatorInfo.name = FetchInitiatorTypeNames::beacon; |
| 87 |
| 88 PingLoader::start(frame, request, initiatorInfo); |
| 89 return true; |
| 90 } |
| 91 }; |
| 38 | 92 |
| 39 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, const String& data, int& payloadLength) | 93 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, const String& data, int& payloadLength) |
| 40 { | 94 { |
| 41 ResourceRequest request(beaconURL); | 95 BeaconData<decltype(data)> beacon(data); |
| 42 prepareRequest(frame, request); | 96 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); |
| 43 | |
| 44 RefPtr<FormData> entityBody = FormData::create(data.utf8()); | |
| 45 unsigned long long entitySize = entityBody->sizeInBytes(); | |
| 46 if (allowance > 0 && static_cast<unsigned>(allowance) < entitySize) | |
| 47 return false; | |
| 48 | |
| 49 request.setHTTPBody(entityBody); | |
| 50 request.setHTTPContentType("text/plain;charset=UTF-8"); | |
| 51 | |
| 52 issueRequest(frame, request); | |
| 53 payloadLength = entitySize; | |
| 54 return true; | |
| 55 } | 97 } |
| 56 | 98 |
| 57 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, PassRefPtr<DOMArrayBufferView> data, int& payloadLength) | 99 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, PassRefPtr<DOMArrayBufferView> data, int& payloadLength) |
| 58 { | 100 { |
| 59 ASSERT(data); | 101 BeaconData<decltype(data)> beacon(data); |
| 60 unsigned long long entitySize = data->byteLength(); | 102 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); |
| 61 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize
) | 103 } |
| 62 return false; | |
| 63 | 104 |
| 64 ResourceRequest request(beaconURL); | 105 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, PassRefPtrWillBeRawPtr<DOMFormData> data, int& payloadLength) |
| 65 prepareRequest(frame, request); | 106 { |
| 66 | 107 BeaconData<decltype(data)> beacon(data); |
| 67 RefPtr<FormData> entityBody = FormData::create(data->baseAddress(), data->by
teLength()); | 108 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); |
| 68 request.setHTTPBody(entityBody.release()); | |
| 69 | |
| 70 // FIXME: a reasonable choice, but not in the spec; should it give a default
? | |
| 71 AtomicString contentType = AtomicString("application/octet-stream"); | |
| 72 request.setHTTPContentType(contentType); | |
| 73 | |
| 74 issueRequest(frame, request); | |
| 75 payloadLength = entitySize; | |
| 76 return true; | |
| 77 } | 109 } |
| 78 | 110 |
| 79 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, Blob* data, int& payloadLength) | 111 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, Blob* data, int& payloadLength) |
| 80 { | 112 { |
| 113 BeaconData<decltype(data)> beacon(data); |
| 114 return Sender::send(frame, allowance, beaconURL, beacon, payloadLength); |
| 115 } |
| 116 |
| 117 namespace { |
| 118 |
| 119 unsigned long long Beacon::beaconSize(const String& data) |
| 120 { |
| 121 return data.sizeInBytes(); |
| 122 } |
| 123 |
| 124 bool Beacon::serialize(const String& data, ResourceRequest& request, int, int&) |
| 125 { |
| 126 RefPtr<FormData> entityBody = FormData::create(data.utf8()); |
| 127 request.setHTTPBody(entityBody); |
| 128 request.setHTTPContentType("text/plain;charset=UTF-8"); |
| 129 return true; |
| 130 } |
| 131 |
| 132 unsigned long long Beacon::beaconSize(Blob* data) |
| 133 { |
| 134 return data->size(); |
| 135 } |
| 136 |
| 137 bool Beacon::serialize(Blob* data, ResourceRequest& request, int, int&) |
| 138 { |
| 81 ASSERT(data); | 139 ASSERT(data); |
| 82 unsigned long long entitySize = data->size(); | |
| 83 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize
) | |
| 84 return false; | |
| 85 | |
| 86 ResourceRequest request(beaconURL); | |
| 87 prepareRequest(frame, request); | |
| 88 | |
| 89 RefPtr<FormData> entityBody = FormData::create(); | 140 RefPtr<FormData> entityBody = FormData::create(); |
| 90 if (data->hasBackingFile()) | 141 if (data->hasBackingFile()) |
| 91 entityBody->appendFile(toFile(data)->path()); | 142 entityBody->appendFile(toFile(data)->path()); |
| 92 else | 143 else |
| 93 entityBody->appendBlob(data->uuid(), data->blobDataHandle()); | 144 entityBody->appendBlob(data->uuid(), data->blobDataHandle()); |
| 94 | 145 |
| 95 request.setHTTPBody(entityBody.release()); | 146 request.setHTTPBody(entityBody.release()); |
| 96 | 147 |
| 97 AtomicString contentType; | 148 AtomicString contentType; |
| 98 const String& blobType = data->type(); | 149 const String& blobType = data->type(); |
| 99 if (!blobType.isEmpty() && isValidContentType(blobType)) | 150 if (!blobType.isEmpty() && isValidContentType(blobType)) |
| 100 request.setHTTPContentType(AtomicString(contentType)); | 151 request.setHTTPContentType(AtomicString(contentType)); |
| 101 | 152 |
| 102 issueRequest(frame, request); | |
| 103 payloadLength = entitySize; | |
| 104 return true; | 153 return true; |
| 105 } | 154 } |
| 106 | 155 |
| 107 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beac
onURL, PassRefPtrWillBeRawPtr<DOMFormData> data, int& payloadLength) | 156 unsigned long long Beacon::beaconSize(PassRefPtr<DOMArrayBufferView> data) |
| 157 { |
| 158 return data->byteLength(); |
| 159 } |
| 160 |
| 161 bool Beacon::serialize(PassRefPtr<DOMArrayBufferView> data, ResourceRequest& req
uest, int, int&) |
| 108 { | 162 { |
| 109 ASSERT(data); | 163 ASSERT(data); |
| 110 ResourceRequest request(beaconURL); | 164 RefPtr<FormData> entityBody = FormData::create(data->baseAddress(), data->by
teLength()); |
| 111 prepareRequest(frame, request); | 165 request.setHTTPBody(entityBody.release()); |
| 112 | 166 |
| 167 // FIXME: a reasonable choice, but not in the spec; should it give a default
? |
| 168 AtomicString contentType = AtomicString("application/octet-stream"); |
| 169 request.setHTTPContentType(contentType); |
| 170 |
| 171 return true; |
| 172 } |
| 173 |
| 174 unsigned long long Beacon::beaconSize(PassRefPtrWillBeRawPtr<DOMFormData> data) |
| 175 { |
| 176 // DOMFormData's size cannot be determined until serialized. |
| 177 return 0; |
| 178 } |
| 179 |
| 180 bool Beacon::serialize(PassRefPtrWillBeRawPtr<DOMFormData> data, ResourceRequest
& request, int allowance, int& payloadLength) |
| 181 { |
| 182 ASSERT(data); |
| 113 RefPtr<FormData> entityBody = data->createMultiPartFormData(); | 183 RefPtr<FormData> entityBody = data->createMultiPartFormData(); |
| 114 | |
| 115 unsigned long long entitySize = entityBody->sizeInBytes(); | 184 unsigned long long entitySize = entityBody->sizeInBytes(); |
| 116 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize
) | 185 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize
) |
| 117 return false; | 186 return false; |
| 118 | 187 |
| 119 AtomicString contentType = AtomicString("multipart/form-data; boundary=", At
omicString::ConstructFromLiteral) + entityBody->boundary().data(); | 188 AtomicString contentType = AtomicString("multipart/form-data; boundary=", At
omicString::ConstructFromLiteral) + entityBody->boundary().data(); |
| 120 request.setHTTPBody(entityBody.release()); | 189 request.setHTTPBody(entityBody.release()); |
| 121 request.setHTTPContentType(contentType); | 190 request.setHTTPContentType(contentType); |
| 122 | 191 |
| 123 issueRequest(frame, request); | |
| 124 payloadLength = entitySize; | 192 payloadLength = entitySize; |
| 125 return true; | 193 return true; |
| 126 } | 194 } |
| 127 | 195 |
| 196 } // namespace |
| 197 |
| 128 } // namespace blink | 198 } // namespace blink |
| OLD | NEW |