Skip to content
This repository was archived by the owner on Jan 31, 2022. It is now read-only.

Commit 749a9d8

Browse files
Clément Le ProvostPLNech
authored andcommitted
Improve handling of User-Agent header (#124)
- Expose it as a structured list of library versions. - Migrate to new format (semicolon-separated with parentheses). - Add operating system’s version to the list. Fixes #121.
1 parent bcbb20a commit 749a9d8

File tree

3 files changed

+106
-3
lines changed

3 files changed

+106
-3
lines changed

algoliasearch/src/main/java/com/algolia/search/saas/Client.java

Lines changed: 91 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,41 @@
6565
public class Client {
6666
private final static String version = "3.3.0";
6767

68-
protected String userAgent = "Algolia for Android " + version;
68+
/**
69+
* The user agents as a raw string. This is what is passed in request headers.
70+
* WARNING: It is stored for efficiency purposes. It should not be modified directly.
71+
*/
72+
private String userAgentRaw;
73+
74+
/***
75+
* A version of a software library.
76+
* Used to construct the <code>User-Agent</code> header.
77+
*/
78+
public static class LibraryVersion {
79+
public final @NonNull String name;
80+
public final @NonNull String version;
81+
82+
public LibraryVersion(@NonNull String name, @NonNull String version) {
83+
this.name = name;
84+
this.version = version;
85+
}
86+
87+
@Override
88+
public boolean equals(Object object) {
89+
if (!(object instanceof LibraryVersion))
90+
return false;
91+
LibraryVersion other = (LibraryVersion)object;
92+
return this.name.equals(other.name) && this.version.equals(other.version);
93+
}
94+
95+
@Override
96+
public int hashCode() {
97+
return name.hashCode() ^ version.hashCode();
98+
}
99+
}
100+
101+
/** The user agents, as a structured list of library versions. */
102+
private List<LibraryVersion> userAgents = new ArrayList<>();
69103

70104
/** Connect timeout (ms). */
71105
private int connectTimeout = 2000;
@@ -120,6 +154,8 @@ public Client(@NonNull String applicationID, @NonNull String apiKey) {
120154
public Client(@NonNull String applicationID, @NonNull String apiKey, String[] hosts) {
121155
this.applicationID = applicationID;
122156
this.apiKey = apiKey;
157+
this.addUserAgent(new LibraryVersion("Algolia for Android", version));
158+
this.addUserAgent(new LibraryVersion("Android", Build.VERSION.RELEASE));
123159
if (hosts != null) {
124160
setReadHosts(hosts);
125161
setWriteHosts(hosts);
@@ -280,6 +316,59 @@ public Index initIndex(@NonNull String indexName) {
280316
return new Index(this, indexName);
281317
}
282318

319+
/**
320+
* Add a software library to the list of user agents.
321+
*
322+
* @param userAgent The library to add.
323+
*/
324+
public void addUserAgent(@NonNull LibraryVersion userAgent) {
325+
userAgents.add(userAgent);
326+
updateUserAgents();
327+
}
328+
329+
/**
330+
* Remove a software library from the list of user agents.
331+
*
332+
* @param userAgent The library to remove.
333+
*/
334+
public void removeUserAgent(@NonNull LibraryVersion userAgent) {
335+
userAgents.remove(userAgent);
336+
updateUserAgents();
337+
}
338+
339+
/**
340+
* Retrieve the list of declared user agents.
341+
*
342+
* @return The declared user agents.
343+
*/
344+
public @NonNull LibraryVersion[] getUserAgents() {
345+
return userAgents.toArray(new LibraryVersion[userAgents.size()]);
346+
}
347+
348+
/**
349+
* Test whether a user agent is declared.
350+
*
351+
* @param userAgent The user agent to look for.
352+
* @return true if it is declared on this client, false otherwise.
353+
*/
354+
public boolean hasUserAgent(@NonNull LibraryVersion userAgent) {
355+
return userAgents.contains(userAgent);
356+
}
357+
358+
private void updateUserAgents() {
359+
StringBuilder s = new StringBuilder();
360+
for (LibraryVersion userAgent : userAgents) {
361+
if (s.length() != 0) {
362+
s.append("; ");
363+
}
364+
s.append(userAgent.name);
365+
s.append(" (");
366+
s.append(userAgent.version);
367+
s.append(")");
368+
}
369+
userAgentRaw = s.toString();
370+
}
371+
283372
// ----------------------------------------------------------------------
284373
// Public operations
285374
// ----------------------------------------------------------------------
@@ -679,7 +768,7 @@ private byte[] _requestRaw(Method m, String url, String json, List<String> hosts
679768
}
680769

681770
// set user agent
682-
hostConnection.setRequestProperty("User-Agent", userAgent);
771+
hostConnection.setRequestProperty("User-Agent", userAgentRaw);
683772

684773
// write JSON entity
685774
if (json != null) {

algoliasearch/src/offline/java/com/algolia/search/saas/OfflineClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ public OfflineClient(@NonNull Context context, @NonNull String applicationID, @N
104104
} else {
105105
this.rootDataDir = getDefaultDataDir();
106106
}
107-
userAgent += ";algoliasearch-offline-core-android " + Sdk.getInstance().getVersionString();
107+
this.addUserAgent(new LibraryVersion("algoliasearch-offline-core-android", Sdk.getInstance().getVersionString()));
108108
}
109109

110110
/**

algoliasearch/src/test/java/com/algolia/search/saas/IndexTest.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,4 +851,18 @@ public void requestCompleted(JSONObject content, AlgoliaException error) {
851851
});
852852
assertTrue("No callback was called", signal.await(Helpers.wait, TimeUnit.SECONDS));
853853
}
854+
855+
@Test
856+
public void testUserAgent() throws Exception {
857+
// Test the default value.
858+
String userAgent = (String)Whitebox.getInternalState(client, "userAgentRaw");
859+
assertTrue(userAgent.matches("^Algolia for Android \\([0-9.]+\\); Android \\(([0-9.]+|unknown)\\)$"));
860+
861+
// Manipulate the list.
862+
assertFalse(client.hasUserAgent(new Client.LibraryVersion("toto", "6.6.6")));
863+
client.addUserAgent(new Client.LibraryVersion("toto", "6.6.6"));
864+
assertTrue(client.hasUserAgent(new Client.LibraryVersion("toto", "6.6.6")));
865+
userAgent = (String)Whitebox.getInternalState(client, "userAgentRaw");
866+
assertTrue(userAgent.matches("^.*; toto \\(6.6.6\\)$"));
867+
}
854868
}

0 commit comments

Comments
 (0)