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 "core/loader/BeaconLoader.h"
7
8 #include "core/FetchInitiatorTypeNames.h"
9 #include "core/fetch/CrossOriginAccessControl.h"
10 #include "core/fetch/FetchContext.h"
11 #include "core/fileapi/File.h"
12 #include "core/frame/LocalFrame.h"
13 #include "core/html/DOMFormData.h"
14 #include "platform/network/FormData.h"
15 #include "platform/network/ParsedContentType.h"
16 #include "platform/network/ResourceRequest.h"
17 #include "public/platform/WebURLRequest.h"
18 #include "wtf/ArrayBufferView.h"
19
20 namespace blink {
21
prepareRequest(LocalFrame * frame,ResourceRequest & request)22 void BeaconLoader::prepareRequest(LocalFrame* frame, ResourceRequest& request)
23 {
24 request.setRequestContext(WebURLRequest::RequestContextBeacon);
25 request.setHTTPMethod("POST");
26 request.setHTTPHeaderField("Cache-Control", "max-age=0");
27 request.setAllowStoredCredentials(true);
28 frame->loader().fetchContext().addAdditionalRequestHeaders(frame->document(), request, FetchSubresource);
29 frame->loader().fetchContext().setFirstPartyForCookies(request);
30 }
31
issueRequest(LocalFrame * frame,ResourceRequest & request)32 void BeaconLoader::issueRequest(LocalFrame* frame, ResourceRequest& request)
33 {
34 FetchInitiatorInfo initiatorInfo;
35 initiatorInfo.name = FetchInitiatorTypeNames::beacon;
36
37 PingLoader::start(frame, request, initiatorInfo);
38 }
39
sendBeacon(LocalFrame * frame,int allowance,const KURL & beaconURL,const String & data,int & payloadLength)40 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beaconURL, const String& data, int& payloadLength)
41 {
42 ResourceRequest request(beaconURL);
43 prepareRequest(frame, request);
44
45 RefPtr<FormData> entityBody = FormData::create(data.utf8());
46 unsigned long long entitySize = entityBody->sizeInBytes();
47 if (allowance > 0 && static_cast<unsigned>(allowance) < entitySize)
48 return false;
49
50 request.setHTTPBody(entityBody);
51 request.setHTTPContentType("text/plain;charset=UTF-8");
52
53 issueRequest(frame, request);
54 payloadLength = entitySize;
55 return true;
56 }
57
sendBeacon(LocalFrame * frame,int allowance,const KURL & beaconURL,PassRefPtr<ArrayBufferView> & data,int & payloadLength)58 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beaconURL, PassRefPtr<ArrayBufferView>& data, int& payloadLength)
59 {
60 ASSERT(data);
61 unsigned long long entitySize = data->byteLength();
62 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize)
63 return false;
64
65 ResourceRequest request(beaconURL);
66 prepareRequest(frame, request);
67
68 RefPtr<FormData> entityBody = FormData::create(data->baseAddress(), data->byteLength());
69 request.setHTTPBody(entityBody.release());
70
71 // FIXME: a reasonable choice, but not in the spec; should it give a default?
72 AtomicString contentType = AtomicString("application/octet-stream");
73 request.setHTTPContentType(contentType);
74
75 issueRequest(frame, request);
76 payloadLength = entitySize;
77 return true;
78 }
79
sendBeacon(LocalFrame * frame,int allowance,const KURL & beaconURL,PassRefPtrWillBeRawPtr<Blob> & data,int & payloadLength)80 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beaconURL, PassRefPtrWillBeRawPtr<Blob>& data, int& payloadLength)
81 {
82 ASSERT(data);
83 unsigned long long entitySize = data->size();
84 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize)
85 return false;
86
87 ResourceRequest request(beaconURL);
88 prepareRequest(frame, request);
89
90 RefPtr<FormData> entityBody = FormData::create();
91 if (data->hasBackingFile())
92 entityBody->appendFile(toFile(data.get())->path());
93 else
94 entityBody->appendBlob(data->uuid(), data->blobDataHandle());
95
96 request.setHTTPBody(entityBody.release());
97
98 AtomicString contentType;
99 const String& blobType = data->type();
100 if (!blobType.isEmpty() && isValidContentType(blobType))
101 request.setHTTPContentType(AtomicString(contentType));
102
103 issueRequest(frame, request);
104 payloadLength = entitySize;
105 return true;
106 }
107
sendBeacon(LocalFrame * frame,int allowance,const KURL & beaconURL,PassRefPtrWillBeRawPtr<DOMFormData> & data,int & payloadLength)108 bool BeaconLoader::sendBeacon(LocalFrame* frame, int allowance, const KURL& beaconURL, PassRefPtrWillBeRawPtr<DOMFormData>& data, int& payloadLength)
109 {
110 ASSERT(data);
111 ResourceRequest request(beaconURL);
112 prepareRequest(frame, request);
113
114 RefPtr<FormData> entityBody = data->createMultiPartFormData();
115
116 unsigned long long entitySize = entityBody->sizeInBytes();
117 if (allowance > 0 && static_cast<unsigned long long>(allowance) < entitySize)
118 return false;
119
120 AtomicString contentType = AtomicString("multipart/form-data; boundary=", AtomicString::ConstructFromLiteral) + entityBody->boundary().data();
121 request.setHTTPBody(entityBody.release());
122 request.setHTTPContentType(contentType);
123
124 issueRequest(frame, request);
125 payloadLength = entitySize;
126 return true;
127 }
128
129 } // namespace blink
130