Skip to content
This repository was archived by the owner on May 30, 2024. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
83 commits
Select commit Hold shift + click to select a range
3496bc4
basic project structure
eli-darkly Jun 16, 2022
a413419
javadoc
eli-darkly Jun 16, 2022
a22fc02
misc build fixes
eli-darkly Jun 16, 2022
4b71318
misc build fixes
eli-darkly Jun 16, 2022
95ec684
misc build fixes
eli-darkly Jun 16, 2022
9c82053
misc build fixes
eli-darkly Jun 16, 2022
62c25a4
misc build fixes
eli-darkly Jun 16, 2022
34104bc
temporarily disable Android build
eli-darkly Jun 16, 2022
b98e1eb
fix the Android build for now by removing the problematic dependency
eli-darkly Jun 16, 2022
53a4cda
fix Android test job
eli-darkly Jun 16, 2022
d57e024
fix Android test job some more
eli-darkly Jun 16, 2022
0f4e0a4
fix Android test job some more
eli-darkly Jun 16, 2022
321a7aa
initial move of events/http packages from java-server-sdk 6.0 codebase
eli-darkly Aug 2, 2022
3e64009
all tests must descend from BaseTest for the Android test job to work
eli-darkly Aug 2, 2022
18421a2
copy correct version of test code
eli-darkly Aug 2, 2022
413e97d
disable test coverage enforcement for now
eli-darkly Aug 2, 2022
d9efa50
can't use HTTP test helpers in Android currently
eli-darkly Aug 2, 2022
0f02a42
change Android test configuration to match what we're doing in androi…
eli-darkly Aug 2, 2022
4794aaa
more Android test fixes
eli-darkly Aug 2, 2022
cd4859f
store more test result files
eli-darkly Aug 2, 2022
66b4146
fix CI
eli-darkly Aug 2, 2022
f54bc1f
don't use Hamcrest matcher "samePropertyValuesAs" which isn't support…
eli-darkly Aug 2, 2022
2213a73
fix tests
eli-darkly Aug 2, 2022
7c63d62
can't use nulls in parameterized tests due to Android bug
eli-darkly Aug 2, 2022
83b18bf
revise Android stuff to do things more like we're doing them in andro…
eli-darkly Aug 2, 2022
ecb0eeb
add note on dependencies
eli-darkly Aug 2, 2022
0c90f78
Merge branch 'eb/sc-156592/skeleton' into eb/sc-159592/initial-code-move
eli-darkly Aug 2, 2022
0829b06
Merge branch 'eb/debugging' into eb/sc-159592/initial-code-move
eli-darkly Aug 2, 2022
3163e0b
Android JUnit seems to have a problem with commas in parameterized te…
eli-darkly Aug 2, 2022
60a57f8
clarify comment
eli-darkly Aug 5, 2022
5c67725
make more event processor behaviors configurable to support Android (…
eli-darkly Aug 18, 2022
f61bada
better system for switching various event functionality on or off
eli-darkly Aug 19, 2022
49e8bae
fix dependencies: don't want Guava or SLF4J
eli-darkly Aug 19, 2022
78f090d
add HTTP properties required by Android (header transformer, shared c…
eli-darkly Aug 19, 2022
8303621
set snapshot version to avoid accidentally releasing 1.0.0
eli-darkly Aug 19, 2022
41968e5
surface blocking flush method
eli-darkly Aug 19, 2022
d0c871f
add interface to allow mocking
eli-darkly Aug 19, 2022
4296d3a
make event request paths configurable
eli-darkly Aug 25, 2022
8c62540
comments
eli-darkly Aug 26, 2022
bd0f115
rm unnecessary build job dependency
eli-darkly Aug 29, 2022
f734c2a
Merge pull request #1 from launchdarkly/eb/sc-156592/skeleton
eli-darkly Aug 29, 2022
b0b5d9a
use newer CircleCI orbs for Android and Windows (#4)
eli-darkly Aug 30, 2022
b5b1906
comment typo
eli-darkly Sep 28, 2022
7572e26
rm obsolete test
eli-darkly Sep 28, 2022
df4db15
Merge pull request #2 from launchdarkly/eb/sc-159592/initial-code-move
eli-darkly Sep 28, 2022
c201d25
Merge pull request #3 from launchdarkly/eb/sc-163010/android-config-o…
eli-darkly Sep 28, 2022
eb8a45f
don't use Gson reflection to write diagnostic events
eli-darkly Sep 29, 2022
a02a856
disable Windows Java 11 build
eli-darkly Oct 3, 2022
0969f84
Merge pull request #6 from launchdarkly/eb/sc-171428/no-windows-jdk11
eli-darkly Oct 4, 2022
595d0fa
Merge branch 'main' into eb/sc-171019/no-gson-reflection
eli-darkly Oct 4, 2022
6d08708
Merge pull request #5 from launchdarkly/eb/sc-171019/no-gson-reflection
eli-darkly Oct 5, 2022
c566ffa
allow some access to diagnostic event data for tests
eli-darkly Oct 7, 2022
8ee965d
Merge pull request #7 from launchdarkly/eb/sc-171019/json-diag-event
eli-darkly Oct 7, 2022
421d70b
remove secondary meta-attribute
eli-darkly Oct 21, 2022
0e5ddbb
Merge pull request #8 from launchdarkly/eb/sc-156589/no-secondary
eli-darkly Oct 21, 2022
27e6f16
allow some more diagnostic config properties that are used in Android
eli-darkly Nov 10, 2022
2cecf7f
Merge pull request #10 from launchdarkly/eb/sc-165440/android-diag-co…
eli-darkly Nov 14, 2022
a42011b
update java-sdk-common dependency
eli-darkly Dec 1, 2022
ad8c6e4
Merge branch 'main' of github.com:launchdarkly/java-sdk-internal
eli-darkly Dec 2, 2022
dfd1156
Merge branch 'main' of github.com:launchdarkly/java-sdk-internal
eli-darkly Dec 2, 2022
c7eb327
Merge branch 'main' of github.com:launchdarkly/java-sdk-internal
eli-darkly Dec 3, 2022
6fc4671
Merge branch 'main' of github.com:launchdarkly/java-sdk-internal
eli-darkly Dec 5, 2022
a4b36a8
merge from public after release
Dec 5, 2022
f31d8df
update Gradle to 7.6 + fix snapshot releases (#11)
eli-darkly Jan 3, 2023
ff56368
Added addQueryParam in http helpers and some additional tests
tanderson-ld Mar 15, 2023
2e09091
Added additional AddQueryParamToUri case and other non-behavior changes
tanderson-ld Mar 20, 2023
3af5580
Merge pull request #12 from launchdarkly/ta/sc-191398/support-flag-fi…
tanderson-ld Mar 21, 2023
559f708
merge from public after release
Mar 21, 2023
ae380f1
Bumping Guava to fix CVE-2023-2976
tanderson-ld Jun 26, 2023
f27bd43
Add file CODEOWNERS
ld-repository-standards[bot] Jun 26, 2023
4ea1955
Add file CODEOWNERS (#14)
kparkinson-ld Jun 26, 2023
08eca0f
Bumping Guava to fix CVE-2023-2976 (#13)
tanderson-ld Jun 27, 2023
6b901ff
merge from public after release
Jun 27, 2023
f5752c9
chore: Fix Windows CI. (#16)
kinyoklion Sep 6, 2023
2ba514f
chore: Update CODEOWNERS (#21)
kinyoklion Oct 11, 2023
e06d726
feat: Add support for migrations. (#20)
kinyoklion Oct 11, 2023
7c165c8
chore: Remove extra blank lines. (#22)
kinyoklion Oct 11, 2023
6210e61
merge from public after release
Oct 11, 2023
f122c40
Updating SDKCommon dependency to get NPE fix
tanderson-ld Nov 13, 2023
041d5b2
Updating SDKCommon dependency to get NPE fix (#23)
tanderson-ld Nov 13, 2023
9ab3ab5
merge from public after release
Nov 14, 2023
fe3e1f0
feat: Always inline contexts for feature events (#24)
keelerm84 Jan 16, 2024
60a37f6
feat: Redact anonymous attributes within feature events (#25)
keelerm84 Jan 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public final class DefaultEventSender implements EventSender {
* Default value for {@code retryDelayMillis} parameter.
*/
public static final long DEFAULT_RETRY_DELAY_MILLIS = 1000;

/**
* Default value for {@code analyticsRequestPath} parameter, for the server-side SDK.
* The Android SDK should modify this value.
Expand All @@ -46,7 +46,7 @@ public final class DefaultEventSender implements EventSender {
* The Android SDK should modify this value.
*/
public static final String DEFAULT_DIAGNOSTIC_REQUEST_PATH = "/diagnostic";

private static final String EVENT_SCHEMA_HEADER = "X-LaunchDarkly-Event-Schema";
private static final String EVENT_SCHEMA_VERSION = "4";
private static final String EVENT_PAYLOAD_ID_HEADER = "X-LaunchDarkly-Payload-ID";
Expand All @@ -65,7 +65,7 @@ public final class DefaultEventSender implements EventSender {

/**
* Creates an instance.
*
*
* @param httpProperties the HTTP configuration
* @param analyticsRequestPath the request path for posting analytics events
* @param diagnosticRequestPath the request path for posting diagnostic events
Expand All @@ -91,20 +91,20 @@ public DefaultEventSender(
this.baseHeaders = httpProperties.toHeadersBuilder()
.add("Content-Type", "application/json")
.build();

this.analyticsRequestPath = analyticsRequestPath == null ? DEFAULT_ANALYTICS_REQUEST_PATH : analyticsRequestPath;
this.diagnosticRequestPath = diagnosticRequestPath == null ? DEFAULT_DIAGNOSTIC_REQUEST_PATH : diagnosticRequestPath;

this.retryDelayMillis = retryDelayMillis <= 0 ? DEFAULT_RETRY_DELAY_MILLIS : retryDelayMillis;
}

@Override
public void close() throws IOException {
if (shouldCloseHttpClient) {
HttpProperties.shutdownHttpClient(httpClient);
}
}

@Override
public Result sendAnalyticsEvents(byte[] data, int eventCount, URI eventsBaseUri) {
return sendEventData(false, data, eventCount, eventsBaseUri);
Expand All @@ -114,33 +114,33 @@ public Result sendAnalyticsEvents(byte[] data, int eventCount, URI eventsBaseUri
public Result sendDiagnosticEvent(byte[] data, URI eventsBaseUri) {
return sendEventData(true, data, 1, eventsBaseUri);
}

private Result sendEventData(boolean isDiagnostic, byte[] data, int eventCount, URI eventsBaseUri) {
if (data == null || data.length == 0) {
// DefaultEventProcessor won't normally pass us an empty payload, but if it does, don't bother sending
return new Result(true, false, null);
}

Headers.Builder headersBuilder = baseHeaders.newBuilder();
String path;
String description;

if (isDiagnostic) {
path = diagnosticRequestPath;
description = "diagnostic event";
description = "diagnostic event";
} else {
path = analyticsRequestPath;
String eventPayloadId = UUID.randomUUID().toString();
headersBuilder.add(EVENT_PAYLOAD_ID_HEADER, eventPayloadId);
headersBuilder.add(EVENT_SCHEMA_HEADER, EVENT_SCHEMA_VERSION);
description = String.format("%d event(s)", eventCount);
}

URI uri = HttpHelpers.concatenateUriPath(eventsBaseUri, path);
Headers headers = headersBuilder.build();
RequestBody body = RequestBody.create(data, JSON_CONTENT_TYPE);
boolean mustShutDown = false;

logger.debug("Posting {} to {} with payload: {}", description, uri,
LogValues.defer(new LazilyPrintedUtf8Data(data)));

Expand All @@ -162,15 +162,15 @@ private Result sendEventData(boolean isDiagnostic, byte[] data, int eventCount,
long startTime = System.currentTimeMillis();
String nextActionMessage = attempt == 0 ? "will retry" : "some events were dropped";
String errorContext = "posting " + description;

try (Response response = httpClient.newCall(request).execute()) {
long endTime = System.currentTimeMillis();
logger.debug("{} delivery took {} ms, response status {}", description, endTime - startTime, response.code());

if (response.isSuccessful()) {
return new Result(true, false, parseResponseDate(response));
}

String errorDesc = httpErrorDescription(response.code());
boolean recoverable = checkIfErrorIsRecoverableAndLog(
logger,
Expand All @@ -187,10 +187,10 @@ private Result sendEventData(boolean isDiagnostic, byte[] data, int eventCount,
checkIfErrorIsRecoverableAndLog(logger, e.toString(), errorContext, 0, nextActionMessage);
}
}

return new Result(false, mustShutDown, null);
}

private final Date parseResponseDate(Response response) {
String dateStr = response.header("Date");
if (dateStr != null) {
Expand All @@ -205,10 +205,10 @@ private final Date parseResponseDate(Response response) {
}
return null;
}

private final class LazilyPrintedUtf8Data implements LogValues.StringProvider {
private final byte[] data;

LazilyPrintedUtf8Data(byte[] data) {
this.data = data;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,25 +30,25 @@ class EventContextFormatter {
this.allAttributesPrivate = allAttributesPrivate;
this.globalPrivateAttributes = globalPrivateAttributes == null ? new AttributeRef[0] : globalPrivateAttributes;
}
public void write(LDContext c, JsonWriter w) throws IOException {

public void write(LDContext c, JsonWriter w, boolean redactAnonymous) throws IOException {
if (c.isMultiple()) {
w.beginObject();
w.name("kind").value("multi");
for (int i = 0; i < c.getIndividualContextCount(); i++) {
LDContext c1 = c.getIndividualContext(i);
w.name(c1.getKind().toString());
writeSingleKind(c1, w, false);
writeSingleKind(c1, w, false, redactAnonymous);
}
w.endObject();
} else {
writeSingleKind(c, w, true);
writeSingleKind(c, w, true, redactAnonymous);
}
}
private void writeSingleKind(LDContext c, JsonWriter w, boolean includeKind) throws IOException {

private void writeSingleKind(LDContext c, JsonWriter w, boolean includeKind, boolean redactAnonymous) throws IOException {
w.beginObject();

// kind, key, and anonymous are never redacted
if (includeKind) {
w.name("kind").value(c.getKind().toString());
Expand All @@ -57,21 +57,20 @@ private void writeSingleKind(LDContext c, JsonWriter w, boolean includeKind) thr
if (c.isAnonymous()) {
w.name("anonymous").value(true);
}

List<String> redacted = null;

if (c.getName() != null) {
if (isAttributeEntirelyPrivate(c, "name")) {
if (isAttributeEntirelyPrivate(c, "name", redactAnonymous)) {
redacted = addOrCreate(redacted, "name");
} else {
w.name("name").value(c.getName());
}
}

for (String attrName: c.getCustomAttributeNames()) {
redacted = writeOrRedactAttribute(w, c, attrName, c.getValue(attrName), redacted);
redacted = writeOrRedactAttribute(w, c, attrName, c.getValue(attrName), redacted, redactAnonymous);
}

boolean haveRedacted = redacted != null && !redacted.isEmpty();
if (haveRedacted) {
w.name("_meta").beginObject();
Expand All @@ -82,31 +81,36 @@ private void writeSingleKind(LDContext c, JsonWriter w, boolean includeKind) thr
w.endArray();
w.endObject();
}

w.endObject();
}
private boolean isAttributeEntirelyPrivate(LDContext c, String attrName) {

private boolean isAttributeEntirelyPrivate(LDContext c, String attrName, boolean redactAnonymous) {
if (allAttributesPrivate) {
return true;
} else if (redactAnonymous && c.isAnonymous()) {
return true;
}
AttributeRef privateRef = findPrivateRef(c, 1, attrName, null);
return privateRef != null && privateRef.getDepth() == 1;
}

private List<String> writeOrRedactAttribute(
JsonWriter w,
LDContext c,
String attrName,
LDValue value,
List<String> redacted
List<String> redacted,
boolean redactAnonymous
) throws IOException {
if (allAttributesPrivate) {
return addOrCreate(redacted, attrName);
} else if (redactAnonymous && c.isAnonymous()) {
return addOrCreate(redacted, attrName);
}
return writeRedactedValue(w, c, 0, attrName, value, null, redacted);
}

// This method implements the context-aware attribute redaction logic, in which an attribute
// can be 1. written as-is, 2. fully redacted, or 3. (for a JSON object) partially redacted.
// It returns the updated redacted attribute list.
Expand Down
Loading