Skip to content

Commit c10a565

Browse files
committed
move conversion of relative URLs to absolute to Picasso request transformer
1 parent f090d21 commit c10a565

File tree

6 files changed

+49
-16
lines changed

6 files changed

+49
-16
lines changed

app/src/main/java/co/tinode/tindroid/MembersAdapter.java

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,10 +169,14 @@ static class Member {
169169
Member(int position, String unique, String displayName, String avatar, boolean removable) {
170170
this.position = position;
171171
this.unique = unique;
172+
this.removable = removable;
172173
this.displayName = displayName;
173174
this.avatarBitmap = null;
174-
this.avatarUri = avatar != null ? Uri.parse(avatar) : null;
175-
this.removable = removable;
175+
if (avatar != null) {
176+
this.avatarUri = Uri.parse(avatar);
177+
} else {
178+
this.avatarUri = null;
179+
}
176180
}
177181

178182
Member(int position, String unique, VxCard pub, boolean removable) {

app/src/main/java/co/tinode/tindroid/TindroidApp.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import android.net.Network;
2323
import android.net.NetworkCapabilities;
2424
import android.net.NetworkRequest;
25+
import android.net.Uri;
2526
import android.os.AsyncTask;
2627
import android.os.Build;
2728
import android.os.Handler;
@@ -36,6 +37,7 @@
3637

3738
import java.io.File;
3839
import java.io.IOException;
40+
import java.net.URL;
3941
import java.util.Date;
4042
import java.util.Map;
4143

@@ -55,6 +57,7 @@
5557
import co.tinode.tinodesdk.Tinode;
5658
import co.tinode.tinodesdk.model.MsgServerData;
5759
import co.tinode.tinodesdk.model.MsgServerInfo;
60+
5861
import okhttp3.OkHttpClient;
5962
import okhttp3.Request;
6063

@@ -267,10 +270,11 @@ public void onInfoMessage(MsgServerInfo info) {
267270
OkHttpClient client = new OkHttpClient.Builder()
268271
.cache(new okhttp3.Cache(createDefaultCacheDir(this), PICASSO_CACHE_SIZE))
269272
.addInterceptor(chain -> {
273+
Tinode tinode = Cache.getTinode();
270274
Request picassoReq = chain.request();
271275
Map<String, String> headers;
272-
if (Cache.getTinode().isTrustedURL(picassoReq.url().url()) &&
273-
(headers = Cache.getTinode().getRequestHeaders()) != null) {
276+
if (tinode.isTrustedURL(picassoReq.url().url())) {
277+
headers = tinode.getRequestHeaders();
274278
Request.Builder builder = picassoReq.newBuilder();
275279
for (Map.Entry<String, String> el : headers.entrySet()) {
276280
builder = builder.addHeader(el.getKey(), el.getValue());
@@ -282,6 +286,16 @@ public void onInfoMessage(MsgServerInfo info) {
282286
})
283287
.build();
284288
Picasso.setSingletonInstance(new Picasso.Builder(this)
289+
.requestTransformer(request -> {
290+
// Rewrite relative URIs to absolute.
291+
if (request.uri != null && Tinode.isUrlRelative(request.uri.toString())) {
292+
URL url = Cache.getTinode().toAbsoluteURL(request.uri.toString());
293+
if (url != null) {
294+
return request.buildUpon().setUri(Uri.parse(url.toString())).build();
295+
}
296+
}
297+
return Picasso.RequestTransformer.IDENTITY.transformRequest(request);
298+
})
285299
.downloader(new OkHttp3Downloader(client))
286300
.build());
287301

app/src/main/java/co/tinode/tindroid/UiUtils.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ private static void constructToolbarLogo(final Activity activity, final VxCard p
239239
Drawable placeholder = bmp != null ?
240240
(new RoundImageDrawable(res, bmp)) :
241241
ResourcesCompat.getDrawable(res, R.drawable.disk, null);
242-
layers.setUrlByLayerId(res, LOGO_LAYER_AVATAR, Cache.getTinode().toAbsoluteURL(ref).toString(),
243-
placeholder, R.drawable.ic_broken_image_round);
242+
layers.setUrlByLayerId(res, LOGO_LAYER_AVATAR, ref, placeholder,
243+
R.drawable.ic_broken_image_round);
244244
}
245245

246246
if (online != null) {
@@ -732,19 +732,19 @@ static void acceptAvatar(final Activity activity, final ImageView avatarContaine
732732
// Construct avatar from VxCard and set it to the provided ImageView.
733733
static void setAvatar(ImageView avatarView, VxCard pub, String address, boolean disabled) {
734734
Bitmap avatar = null;
735-
URL ref = null;
735+
String ref = null;
736736
String fullName = null;
737737
if (pub != null) {
738738
avatar = pub.getBitmap();
739739
fullName = pub.fn;
740-
ref = Cache.getTinode().toAbsoluteURL(pub.getPhotoRef());
740+
ref = pub.getPhotoRef();
741741
}
742742

743743
Drawable local = avatarDrawable(avatarView.getContext(), avatar, fullName, address, disabled);
744744
if (ref != null) {
745745
Picasso
746746
.get()
747-
.load(ref.toString())
747+
.load(ref)
748748
.resize(UiUtils.MAX_AVATAR_SIZE, UiUtils.MAX_AVATAR_SIZE)
749749
.placeholder(local)
750750
.error(R.drawable.ic_broken_image_round)
@@ -837,11 +837,11 @@ public static Bitmap avatarBitmap(Context context, VxCard pub, Topic.TopicType t
837837
String fullName = null;
838838
if (pub != null) {
839839
fullName = pub.fn;
840-
URL ref = Cache.getTinode().toAbsoluteURL(pub.getPhotoRef());
840+
String ref = pub.getPhotoRef();
841841
if (ref != null) {
842842
try {
843843
bitmap = Picasso.get()
844-
.load(ref.toString())
844+
.load(ref)
845845
.resize(size, size).get();
846846
} catch (IOException ex) {
847847
Log.w(TAG, "Failed to load avatar", ex);

app/src/main/java/co/tinode/tindroid/account/ContactOperations.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ ContactOperations addAvatar(byte[] avatar, final Tinode tinode, final String ref
223223
if (ref != null) {
224224
try {
225225
avatar = UiUtils.bitmapToBytes(Picasso.get()
226-
.load(tinode.toAbsoluteURL(ref).toString())
226+
.load(ref)
227227
.resize(UiUtils.MAX_AVATAR_SIZE, UiUtils.MAX_AVATAR_SIZE).centerCrop()
228228
.get(), mimeType);
229229
} catch (IOException ex) {

app/src/main/java/co/tinode/tindroid/format/ThumbnailTransformer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ public Drafty.Node transform(Drafty.Node node) {
6060
components = new LinkedList<>();
6161
}
6262
components.add(done);
63-
Picasso.get().load(Cache.getTinode().toAbsoluteURL((String) val).toString()).into(new Target() {
63+
Picasso.get().load((String) val).into(new Target() {
6464
@Override
6565
public void onBitmapLoaded(Bitmap bmp, Picasso.LoadedFrom from) {
6666
bmp = UiUtils.scaleSquareBitmap(bmp, UiUtils.REPLY_THUMBNAIL_DIM);

tinodesdk/src/main/java/co/tinode/tinodesdk/Tinode.java

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.util.Vector;
4242
import java.util.concurrent.ConcurrentHashMap;
4343
import java.util.concurrent.ConcurrentMap;
44+
import java.util.regex.Pattern;
4445

4546
import co.tinode.tinodesdk.model.AuthScheme;
4647
import co.tinode.tinodesdk.model.ClientMessage;
@@ -2191,20 +2192,34 @@ protected ServerMessage parseServerMessageFromJson(String jsonMessage) {
21912192
return msg.isValid() ? msg : null;
21922193
}
21932194

2195+
2196+
/**
2197+
* Checks if URL is a relative url, i.e. has no 'scheme://', including the case of missing scheme '//'.
2198+
* The scheme is expected to be RFC-compliant, e.g. [a-z][a-z0-9+.-]*
2199+
* example.html - ok
2200+
* https:example.com - not ok.
2201+
* http:/example.com - not ok.
2202+
* ↲ https://example.com' - not ok. (↲ means carriage return)
2203+
*/
2204+
public static boolean isUrlRelative(@NotNull String url) {
2205+
Pattern re = Pattern.compile("^\\s*([a-z][a-z0-9+.-]*:|//)",
2206+
Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
2207+
return !re.matcher(url).matches();
2208+
}
2209+
21942210
/**
21952211
* Convert relative URL to absolute URL using Tinode server address as base.
21962212
* If the URL is already absolute it's left unchanged.
21972213
*
21982214
* @param origUrl possibly relative URL to convert to absolute.
21992215
* @return absolute URL or {@code null} if origUrl is invalid.
22002216
*/
2201-
public URL toAbsoluteURL(String origUrl) {
2217+
public @Nullable URL toAbsoluteURL(@NotNull String origUrl) {
22022218
URL url = null;
22032219
try {
22042220
url = new URL(getBaseUrl(), origUrl);
22052221
} catch (MalformedURLException ignored) {
22062222
}
2207-
22082223
return url;
22092224
}
22102225

@@ -2224,7 +2239,7 @@ public boolean isTrustedURL(@NotNull URL url) {
22242239
*
22252240
* @return Map with API key, authentication headers and User agent.
22262241
*/
2227-
public Map<String, String> getRequestHeaders() {
2242+
public @NotNull Map<String, String> getRequestHeaders() {
22282243
HashMap<String, String> headers = new HashMap<>();
22292244
if (mApiKey != null) {
22302245
headers.put("X-Tinode-APIKey", mApiKey);

0 commit comments

Comments
 (0)