• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices.service.measurement.registration;
18 
19 import android.net.Uri;
20 
21 import java.util.ArrayList;
22 import java.util.List;
23 import java.util.Map;
24 
25 /** Class for handling redirects */
26 public class AsyncRedirects {
27     public static final String HEADER_ATTRIBUTION_REPORTING_REDIRECT_CONFIG =
28             "Attribution-Reporting-Redirect-Config";
29     public static final String REDIRECT_302_TO_WELL_KNOWN = "redirect-302-to-well-known";
30     public static final String WELL_KNOWN_PATH_SEGMENT =
31             ".well-known/attribution-reporting/register-redirect";
32     public static final String WELL_KNOWN_QUERY_PARAM = "302_url";
33     public static final String REDIRECT_LIST_HEADER_KEY = "Attribution-Reporting-Redirect";
34     public static final String REDIRECT_LOCATION_HEADER_KEY = "Location";
35     private final List<AsyncRedirect> mLocationRedirects;
36     private final List<AsyncRedirect> mListRedirects;
37 
AsyncRedirects()38     public AsyncRedirects() {
39         mLocationRedirects = new ArrayList<>();
40         mListRedirects = new ArrayList<>();
41     }
42 
43     /** Return flattened list of {@link AsyncRedirect} */
getRedirects()44     public List<AsyncRedirect> getRedirects() {
45         List<AsyncRedirect> allRedirects = new ArrayList<>(mListRedirects);
46         allRedirects.addAll(mLocationRedirects);
47 
48         return allRedirects;
49     }
50 
51     /** Get list of {@link AsyncRedirect} by redirect type */
getRedirectsByType(AsyncRegistration.RedirectType redirectType)52     public List<AsyncRedirect> getRedirectsByType(AsyncRegistration.RedirectType redirectType) {
53         if (redirectType == AsyncRegistration.RedirectType.LOCATION) {
54             return new ArrayList<>(mLocationRedirects);
55         } else {
56             return new ArrayList<>(mListRedirects);
57         }
58     }
59 
60     /** Process redirects based on the given headers */
configure(Map<String, List<String>> headers, AsyncRegistration parentRegistration)61     public void configure(Map<String, List<String>> headers, AsyncRegistration parentRegistration) {
62         if (!parentRegistration.shouldProcessRedirects()) {
63             return;
64         }
65 
66         Map<AsyncRegistration.RedirectType, List<Uri>> urisByType =
67                 FetcherUtil.parseRedirects(headers);
68 
69         for (Uri locationRedirectUri : urisByType.get(AsyncRegistration.RedirectType.LOCATION)) {
70             if (shouldRedirect302ToWellKnown(headers, parentRegistration)) {
71                 mLocationRedirects.add(
72                         new AsyncRedirect(
73                                 getLocationRedirectToWellKnownUri(locationRedirectUri),
74                                 AsyncRedirect.RedirectBehavior.LOCATION_TO_WELL_KNOWN));
75             } else {
76                 mLocationRedirects.add(
77                         new AsyncRedirect(
78                                 locationRedirectUri, AsyncRedirect.RedirectBehavior.AS_IS));
79             }
80         }
81 
82         for (Uri listRedirectUri : urisByType.get(AsyncRegistration.RedirectType.LIST)) {
83             mListRedirects.add(
84                     new AsyncRedirect(listRedirectUri, AsyncRedirect.RedirectBehavior.AS_IS));
85         }
86     }
87 
shouldRedirect302ToWellKnown( Map<String, List<String>> headers, AsyncRegistration parentRegistration)88     private static boolean shouldRedirect302ToWellKnown(
89             Map<String, List<String>> headers, AsyncRegistration parentRegistration) {
90         boolean isParentRegistrationRedirectsToWellKnown =
91                 AsyncRedirect.RedirectBehavior.LOCATION_TO_WELL_KNOWN.equals(
92                         parentRegistration.getRedirectBehavior());
93 
94         return isParentRegistrationRedirectsToWellKnown || isRedirect302ToWellKnownPath(headers);
95     }
96 
97     /**
98      * Return true if the given headers indicate redirects should prepend well known prefix to the
99      * path.
100      */
isRedirect302ToWellKnownPath(Map<String, List<String>> headers)101     private static boolean isRedirect302ToWellKnownPath(Map<String, List<String>> headers) {
102         if (!headers.containsKey(HEADER_ATTRIBUTION_REPORTING_REDIRECT_CONFIG)) {
103             return false;
104         }
105         List<String> config = headers.get(HEADER_ATTRIBUTION_REPORTING_REDIRECT_CONFIG);
106         if (config == null || config.size() != 1) {
107             return false;
108         }
109 
110         return config.get(0).equalsIgnoreCase(REDIRECT_302_TO_WELL_KNOWN);
111     }
112 
getLocationRedirectToWellKnownUri(Uri redirectUri)113     private Uri getLocationRedirectToWellKnownUri(Uri redirectUri) {
114         return redirectUri
115                 .buildUpon()
116                 .encodedPath(WELL_KNOWN_PATH_SEGMENT)
117                 .clearQuery()
118                 .appendQueryParameter(WELL_KNOWN_QUERY_PARAM, redirectUri.toString())
119                 .build();
120     }
121 }
122