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 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 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 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 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 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 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