Skip to content

Commit

Permalink
PCM: Switch to JSON report format
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=218634
<rdar://problem/70469923>

Reviewed by Brent Fulgham.

The standards conversation has landed in attribution reports in a JSON
format as opposed to the currently implemented URL format. Discussion
here: privacycg/private-click-measurement#30

Source/WebCore:

No new tests. Existing layout and API tests were updated.

* Headers.cmake:
    Added platform/network/HTTPHeaderValues.h to be able to expose it
    to WebKit.
* WebCore.xcodeproj/project.pbxproj:
    Now exporting platform/network/HTTPHeaderValues.h.
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::handleClick):
    Changed a function call from AdClickAttribution::url() to
    AdClickAttribution::reportURL().
* loader/AdClickAttribution.cpp:
(WebCore::AdClickAttribution::reportURL const):
    The URL no longer carries the report values.
    Renamed from AdClickAttribution::url().
(WebCore::AdClickAttribution::json const):
    New function to generate and return the report JSON.
(WebCore::AdClickAttribution::url const): Deleted.
    Renamed to AdClickAttribution::reportURL().
(WebCore::AdClickAttribution::referrer const): Deleted.
    The referrer is now part of the report JSON.
(WebCore::AdClickAttribution::urlForTesting const): Deleted.
    This class no longer needs to help generate test URLs
    since report values are now in JSON.
* loader/AdClickAttribution.h:
* platform/network/FormData.h:
    Added export of create(const CString&).
* platform/network/HTTPHeaderValues.cpp:
(WebCore::HTTPHeaderValues::applicationJSONContentType):
    Used create the new JSON report request.
* platform/network/HTTPHeaderValues.h:
    Added export of maxAge0().

Source/WebKit:

* NetworkProcess/AdClickAttributionManager.cpp:
(WebKit::AdClickAttributionManager::fireConversionRequest):

Tools:

* TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp:
(TestWebKitAPI::TEST):

LayoutTests:

* http/tests/adClickAttribution/resources/conversionReport.php:
* http/tests/adClickAttribution/send-attribution-conversion-request-expected.txt:


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@269489 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
[email protected] committed Nov 6, 2020
1 parent d3ca0f7 commit 39c86ce
Show file tree
Hide file tree
Showing 16 changed files with 155 additions and 95 deletions.
15 changes: 15 additions & 0 deletions LayoutTests/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
2020-11-05 John Wilander <[email protected]>

PCM: Switch to JSON report format
https://bugs.webkit.org/show_bug.cgi?id=218634
<rdar://problem/70469923>

Reviewed by Brent Fulgham.

The standards conversation has landed in attribution reports in a JSON
format as opposed to the currently implemented URL format. Discussion
here: https://github.com/privacycg/private-click-measurement/issues/30

* http/tests/adClickAttribution/resources/conversionReport.php:
* http/tests/adClickAttribution/send-attribution-conversion-request-expected.txt:

2020-11-05 Chris Dumez <[email protected]>

Expose referrerPolicy attribute on HTMLLinkElement and HTMLAreaElement
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
if ($name === "HTTP_HOST") {
fwrite($conversionFile, "$name: $value\n");
} else if ($name === "REQUEST_URI") {
$positionOfNonce = strpos($value, "&nonce=");
$positionOfNonce = strpos($value, "?nonce=");
if ($positionOfNonce === false)
$outputURL = $value;
else
Expand All @@ -17,11 +17,17 @@
} else if ($name === "HTTP_COOKIE") {
fwrite($conversionFile, "Cookies in conversion request: $value\n");
$cookiesFound = true;
} else if ($name === "CONTENT_TYPE") {
fwrite($conversionFile, "Content type: $value\n");
}
}
if (!$cookiesFound) {
fwrite($conversionFile, "No cookies in conversion request.\n");
}

$requestBody = file_get_contents('php://input');
fwrite($conversionFile, "Request body:\n$requestBody\n");

fclose($conversionFile);
rename($conversionFilePath . ".tmp", $conversionFilePath);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,11 @@ Frame: '<!--frame2-->'
--------
Conversion received.
HTTP_HOST: 127.0.0.1:8000
REQUEST_URI: /adClickAttribution/resources/conversionReport.php?conversion=12&campaign=3
Content type: application/json
REQUEST_URI: /adClickAttribution/resources/conversionReport.php
No cookies in conversion request.
Request body:
{"content-type":"click","content-site":"127.0.0.1","content-id":3,"conversion-site":"localhost","conversion-data":12,"report-version":1}


--------
Expand Down
45 changes: 45 additions & 0 deletions Source/WebCore/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,48 @@
2020-11-05 John Wilander <[email protected]>

PCM: Switch to JSON report format
https://bugs.webkit.org/show_bug.cgi?id=218634
<rdar://problem/70469923>

Reviewed by Brent Fulgham.

The standards conversation has landed in attribution reports in a JSON
format as opposed to the currently implemented URL format. Discussion
here: https://github.com/privacycg/private-click-measurement/issues/30

No new tests. Existing layout and API tests were updated.

* Headers.cmake:
Added platform/network/HTTPHeaderValues.h to be able to expose it
to WebKit.
* WebCore.xcodeproj/project.pbxproj:
Now exporting platform/network/HTTPHeaderValues.h.
* html/HTMLAnchorElement.cpp:
(WebCore::HTMLAnchorElement::handleClick):
Changed a function call from AdClickAttribution::url() to
AdClickAttribution::reportURL().
* loader/AdClickAttribution.cpp:
(WebCore::AdClickAttribution::reportURL const):
The URL no longer carries the report values.
Renamed from AdClickAttribution::url().
(WebCore::AdClickAttribution::json const):
New function to generate and return the report JSON.
(WebCore::AdClickAttribution::url const): Deleted.
Renamed to AdClickAttribution::reportURL().
(WebCore::AdClickAttribution::referrer const): Deleted.
The referrer is now part of the report JSON.
(WebCore::AdClickAttribution::urlForTesting const): Deleted.
This class no longer needs to help generate test URLs
since report values are now in JSON.
* loader/AdClickAttribution.h:
* platform/network/FormData.h:
Added export of create(const CString&).
* platform/network/HTTPHeaderValues.cpp:
(WebCore::HTTPHeaderValues::applicationJSONContentType):
Used create the new JSON report request.
* platform/network/HTTPHeaderValues.h:
Added export of maxAge0().

2020-11-05 Brian Burg <[email protected]>

[Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
Expand Down
1 change: 1 addition & 0 deletions Source/WebCore/Headers.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -1343,6 +1343,7 @@ set(WebCore_PRIVATE_FRAMEWORK_HEADERS
platform/network/FormData.h
platform/network/HTTPCookieAcceptPolicy.h
platform/network/HTTPHeaderMap.h
platform/network/HTTPHeaderValues.h
platform/network/HTTPParsers.h
platform/network/NetworkLoadInformation.h
platform/network/NetworkLoadMetrics.h
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/WebCore.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -1067,7 +1067,7 @@
4157EBFB1E3AB67F00AC9FE9 /* MockLibWebRTCPeerConnection.h in Headers */ = {isa = PBXBuildFile; fileRef = 4157EBF81E3AB06800AC9FE9 /* MockLibWebRTCPeerConnection.h */; };
415864A023BF7CBF00A0A61E /* RealtimeVideoUtilities.h in Headers */ = {isa = PBXBuildFile; fileRef = 41D1938F2152C561006F14CA /* RealtimeVideoUtilities.h */; settings = {ATTRIBUTES = (Private, ); }; };
415CDAF51E6B8F8B004F11EE /* CanvasCaptureMediaStreamTrack.h in Headers */ = {isa = PBXBuildFile; fileRef = 41C7E1061E6A54360027B4DE /* CanvasCaptureMediaStreamTrack.h */; };
41614A791DA64241004AD06F /* HTTPHeaderValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 41614A771DA64236004AD06F /* HTTPHeaderValues.h */; };
41614A791DA64241004AD06F /* HTTPHeaderValues.h in Headers */ = {isa = PBXBuildFile; fileRef = 41614A771DA64236004AD06F /* HTTPHeaderValues.h */; settings = {ATTRIBUTES = (Private, ); }; };
4161E2D51FE48DC500EC2E96 /* FetchLoader.h in Headers */ = {isa = PBXBuildFile; fileRef = 4147E2B51C89912600A7E715 /* FetchLoader.h */; settings = {ATTRIBUTES = (Private, ); }; };
4162A451101145AE00DFF3ED /* DedicatedWorkerGlobalScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 4162A44E101145AE00DFF3ED /* DedicatedWorkerGlobalScope.h */; };
4162A4581011464700DFF3ED /* JSDedicatedWorkerGlobalScope.h in Headers */ = {isa = PBXBuildFile; fileRef = 4162A4561011464700DFF3ED /* JSDedicatedWorkerGlobalScope.h */; };
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/html/HTMLAnchorElement.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ void HTMLAnchorElement::handleClick(Event& event)
auto adClickAttribution = parseAdClickAttribution();
// A matching conversion event needs to happen before the complete ad click attributionURL can be
// created. Thus, it should be empty for now.
ASSERT(!adClickAttribution || adClickAttribution->url().isNull());
ASSERT(!adClickAttribution || adClickAttribution->reportURL().isNull());

frame->loader().changeLocation(completedURL, effectiveTarget, &event, LockHistory::No, LockBackForwardList::No, referrerPolicy, document().shouldOpenExternalURLsPolicyToPropagate(), newFrameOpenerPolicy, downloadAttribute, systemPreviewInfo, WTFMove(adClickAttribution));

Expand Down
44 changes: 13 additions & 31 deletions Source/WebCore/loader/AdClickAttribution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ bool AdClickAttribution::hasHigherPriorityThan(const AdClickAttribution& other)
return m_conversion->priority > other.m_conversion->priority;
}

URL AdClickAttribution::url() const
URL AdClickAttribution::reportURL() const
{
if (!isValid())
return URL();
Expand All @@ -156,9 +156,6 @@ URL AdClickAttribution::url() const
builder.appendLiteral("https://");
builder.append(m_source.registrableDomain.string());
builder.appendLiteral(adClickAttributionPathPrefix);
builder.appendNumber(m_conversion.value().data);
builder.append('/');
builder.appendNumber(m_campaign.id);

URL url { URL(), builder.toString() };
if (url.isValid())
Expand All @@ -167,34 +164,19 @@ URL AdClickAttribution::url() const
return URL();
}

URL AdClickAttribution::referrer() const
{
if (!isValid())
return URL();

StringBuilder builder;
builder.appendLiteral("https://");
builder.append(m_destination.registrableDomain.string());
builder.append('/');

URL url { URL(), builder.toString() };
if (url.isValid())
return url;

return URL();
}

URL AdClickAttribution::urlForTesting(const URL& baseURL) const
Ref<JSON::Object> AdClickAttribution::json() const
{
auto host = m_source.registrableDomain.string();
if (host != "localhost" && host != "127.0.0.1")
return URL();
String relativeURL;
if (!baseURL.hasQuery())
relativeURL = makeString("?conversion=", m_conversion.value().data, "&campaign=", m_campaign.id);
else
relativeURL = makeString("?conversion=", m_conversion.value().data, "&campaign=", m_campaign.id, '&', baseURL.query());
return URL(baseURL, relativeURL);
auto reportDetails = JSON::Object::create();
if (!m_conversion)
return reportDetails;

reportDetails->setString("content-type"_s, "click"_s);
reportDetails->setString("content-site"_s, m_source.registrableDomain.string());
reportDetails->setInteger("content-id"_s, m_campaign.id);
reportDetails->setString("conversion-site"_s, m_destination.registrableDomain.string());
reportDetails->setInteger("conversion-data"_s, m_conversion->data);
reportDetails->setInteger("report-version"_s, 1);
return reportDetails;
}

void AdClickAttribution::markConversionAsSent()
Expand Down
6 changes: 3 additions & 3 deletions Source/WebCore/loader/AdClickAttribution.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "RegistrableDomain.h"
#include <wtf/CompletionHandler.h>
#include <wtf/Forward.h>
#include <wtf/JSONValues.h>
#include <wtf/Optional.h>
#include <wtf/URL.h>
#include <wtf/WallTime.h>
Expand Down Expand Up @@ -243,9 +244,8 @@ class AdClickAttribution {
WEBCORE_EXPORT static Expected<Conversion, String> parseConversionRequest(const URL& redirectURL);
WEBCORE_EXPORT Optional<Seconds> convertAndGetEarliestTimeToSend(Conversion&&);
WEBCORE_EXPORT bool hasHigherPriorityThan(const AdClickAttribution&) const;
WEBCORE_EXPORT URL url() const;
WEBCORE_EXPORT URL urlForTesting(const URL& baseURLForTesting) const;
WEBCORE_EXPORT URL referrer() const;
WEBCORE_EXPORT URL reportURL() const;
WEBCORE_EXPORT Ref<JSON::Object> json() const;
const Source& source() const { return m_source; };
const Destination& destination() const { return m_destination; };
Optional<WallTime> earliestTimeToSend() const { return m_earliestTimeToSend; };
Expand Down
2 changes: 1 addition & 1 deletion Source/WebCore/platform/network/FormData.h
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ class FormData : public RefCounted<FormData> {

WEBCORE_EXPORT static Ref<FormData> create();
WEBCORE_EXPORT static Ref<FormData> create(const void*, size_t);
static Ref<FormData> create(const CString&);
WEBCORE_EXPORT static Ref<FormData> create(const CString&);
static Ref<FormData> create(Vector<char>&&);
static Ref<FormData> create(const Vector<char>&);
static Ref<FormData> create(const Vector<uint8_t>&);
Expand Down
7 changes: 7 additions & 0 deletions Source/WebCore/platform/network/HTTPHeaderValues.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,13 @@ const String& formURLEncodedContentType()
return contentType;
}

const String& applicationJSONContentType()
{
// The default encoding is UTF-8: https://www.ietf.org/rfc/rfc4627.txt.
static NeverDestroyed<const String> contentType(MAKE_STATIC_STRING_IMPL("application/json"));
return contentType;
}

const String& noCache()
{
static NeverDestroyed<const String> value(MAKE_STATIC_STRING_IMPL("no-cache"));
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/platform/network/HTTPHeaderValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,9 @@ namespace HTTPHeaderValues {

const String& textPlainContentType();
const String& formURLEncodedContentType();
WEBCORE_EXPORT const String& applicationJSONContentType();
const String& noCache();
const String& maxAge0();
WEBCORE_EXPORT const String& maxAge0();
}

}
15 changes: 15 additions & 0 deletions Source/WebKit/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
2020-11-05 John Wilander <[email protected]>

PCM: Switch to JSON report format
https://bugs.webkit.org/show_bug.cgi?id=218634
<rdar://problem/70469923>

Reviewed by Brent Fulgham.

The standards conversation has landed in attribution reports in a JSON
format as opposed to the currently implemented URL format. Discussion
here: https://github.com/privacycg/private-click-measurement/issues/30

* NetworkProcess/AdClickAttributionManager.cpp:
(WebKit::AdClickAttributionManager::fireConversionRequest):

2020-11-05 Brian Burg <[email protected]>

[Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
Expand Down
20 changes: 7 additions & 13 deletions Source/WebKit/NetworkProcess/AdClickAttributionManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <JavaScriptCore/ConsoleTypes.h>
#include <WebCore/FetchOptions.h>
#include <WebCore/FormData.h>
#include <WebCore/HTTPHeaderValues.h>
#include <WebCore/ResourceError.h>
#include <WebCore/ResourceRequest.h>
#include <WebCore/ResourceResponse.h>
Expand Down Expand Up @@ -171,19 +172,17 @@ void AdClickAttributionManager::convert(const Source& source, const Destination&

void AdClickAttributionManager::fireConversionRequest(const AdClickAttribution& attribution)
{
auto conversionURL = m_conversionBaseURLForTesting ? attribution.urlForTesting(*m_conversionBaseURLForTesting) : attribution.url();
auto conversionURL = m_conversionBaseURLForTesting ? *m_conversionBaseURLForTesting : attribution.reportURL();
if (conversionURL.isEmpty() || !conversionURL.isValid())
return;

auto conversionReferrerURL = attribution.referrer();
if (conversionReferrerURL.isEmpty() || !conversionReferrerURL.isValid())
return;

ResourceRequest request { conversionURL };
ResourceRequest request { WTFMove(conversionURL) };

request.setHTTPMethod("POST"_s);
request.setHTTPHeaderField(HTTPHeaderName::CacheControl, "max-age=0"_s);
request.setHTTPReferrer(conversionReferrerURL.string());
request.setHTTPHeaderField(HTTPHeaderName::CacheControl, WebCore::HTTPHeaderValues::maxAge0());

request.setHTTPContentType(WebCore::HTTPHeaderValues::applicationJSONContentType());
request.setHTTPBody(WebCore::FormData::create(attribution.json()->toJSONString().utf8().data()));

FetchOptions options;
options.credentials = FetchOptions::Credentials::Omit;
Expand All @@ -194,17 +193,12 @@ void AdClickAttributionManager::fireConversionRequest(const AdClickAttribution&
NetworkResourceLoadParameters loadParameters;
loadParameters.identifier = ++identifier;
loadParameters.request = request;
loadParameters.sourceOrigin = SecurityOrigin::create(conversionReferrerURL);
loadParameters.parentPID = presentingApplicationPID();
loadParameters.storedCredentialsPolicy = StoredCredentialsPolicy::EphemeralStateless;
loadParameters.options = options;
loadParameters.shouldClearReferrerOnHTTPSToHTTPRedirect = true;
loadParameters.shouldRestrictHTTPResponseAccess = false;

#if ENABLE(CONTENT_EXTENSIONS)
loadParameters.mainDocumentURL = WTFMove(conversionReferrerURL);
#endif

if (UNLIKELY(debugModeEnabled())) {
RELEASE_LOG_INFO(AdClickAttribution, "About to fire an attribution request for a conversion.");
m_networkProcess->broadcastConsoleMessage(m_sessionID, MessageSource::AdClickAttribution, MessageLevel::Error, "[Ad Click Attribution] About to fire an attribution request for a conversion."_s);
Expand Down
15 changes: 15 additions & 0 deletions Tools/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
2020-11-05 John Wilander <[email protected]>

PCM: Switch to JSON report format
https://bugs.webkit.org/show_bug.cgi?id=218634
<rdar://problem/70469923>

Reviewed by Brent Fulgham.

The standards conversation has landed in attribution reports in a JSON
format as opposed to the currently implemented URL format. Discussion
here: https://github.com/privacycg/private-click-measurement/issues/30

* TestWebKitAPI/Tests/WebCore/AdClickAttribution.cpp:
(TestWebKitAPI::TEST):

2020-11-05 Brian Burg <[email protected]>

[Cocoa] Inspector Extensions: Add _WKInspectorExtension and related plumbing
Expand Down

0 comments on commit 39c86ce

Please sign in to comment.