• Home
  • History
  • Annotate
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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