1 /* 2 * Copyright 2022 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.example.androidx.webkit; 18 19 import android.net.Uri; 20 import android.os.Bundle; 21 import android.webkit.WebSettings; 22 import android.webkit.WebView; 23 import android.widget.RadioGroup; 24 25 import androidx.appcompat.app.AppCompatActivity; 26 import androidx.webkit.WebSettingsCompat; 27 import androidx.webkit.WebViewFeature; 28 29 import org.jspecify.annotations.NonNull; 30 import org.jspecify.annotations.Nullable; 31 32 import java.util.Collections; 33 import java.util.Set; 34 35 /** 36 * Demo activity to show how to set an allow-list to preserve the legacy behavior for the {@code 37 * X-Requested-With} header. 38 */ 39 public class RequestedWithHeaderActivity extends AppCompatActivity { 40 41 private HttpServer mServer; 42 private WebView mWebView; 43 44 @Override onCreate(@ullable Bundle savedInstanceState)45 protected void onCreate(@Nullable Bundle savedInstanceState) { 46 super.onCreate(savedInstanceState); 47 setContentView(R.layout.activity_requested_with_header); 48 49 setTitle(R.string.requested_with_activity_title); 50 WebkitHelpers.appendWebViewVersionToTitle(this); 51 52 // Check if allow-list feature is enabled 53 if (!WebViewFeature.isFeatureSupported(WebViewFeature.REQUESTED_WITH_HEADER_ALLOW_LIST)) { 54 WebkitHelpers.showMessageInActivity(this, R.string.webkit_api_not_available); 55 return; 56 } 57 58 // Initialize http server to show us what we requested 59 mServer = new HttpServer(/*port=*/0, HttpServer.EchoRequestHandler::new, null); 60 mServer.start(); 61 62 // Set up our WebView 63 mWebView = findViewById(R.id.requested_with_header_webview); 64 // Disable caching to always get fresh requests to the test server 65 mWebView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); 66 67 // Get the current allow-list to initialize the UI 68 Set<String> allowList = WebSettingsCompat.getRequestedWithHeaderOriginAllowList( 69 mWebView.getSettings()); 70 71 // Wire up the UI 72 RadioGroup radioGroup = findViewById(R.id.requested_with_header_radio_group); 73 // Check the radio button corresponding to the current setting 74 radioGroup.check(allowList.isEmpty() 75 ? R.id.requested_with_header_empty_mode 76 : R.id.requested_with_header_allowlist_mode); 77 // Register a change handler 78 radioGroup.setOnCheckedChangeListener(this::onRadioGroupChanged); 79 80 // Send a request to our echo server to show the headers 81 refreshView(!allowList.isEmpty()); 82 } 83 refreshView(boolean useAllowList)84 private void refreshView(boolean useAllowList) { 85 if (useAllowList) { 86 WebSettingsCompat.setRequestedWithHeaderOriginAllowList(mWebView.getSettings(), 87 Collections.singleton("http://localhost:" + mServer.getPort())); 88 } else { 89 WebSettingsCompat.setRequestedWithHeaderOriginAllowList(mWebView.getSettings(), 90 Collections.emptySet()); 91 } 92 String requestUrl = new Uri.Builder() 93 .scheme("http") 94 .authority("localhost:" + mServer.getPort()) 95 .build() 96 .toString(); 97 mWebView.loadUrl(requestUrl); 98 } 99 100 /** 101 * Handler for selecting a new header mode through the radio group. 102 * @param unused Triggering radio group 103 * @param checkedId ID of checked radio button 104 */ onRadioGroupChanged(@onNull RadioGroup unused, int checkedId)105 public void onRadioGroupChanged(@NonNull RadioGroup unused, int checkedId) { 106 refreshView(checkedId == R.id.requested_with_header_allowlist_mode); 107 } 108 109 @Override onDestroy()110 protected void onDestroy() { 111 if (mServer != null) { 112 mServer.shutdown(); 113 } 114 super.onDestroy(); 115 } 116 } 117