1 /* 2 * Copyright (C) 2015 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.statementservice.retriever; 18 19 import org.json.JSONObject; 20 21 import java.net.MalformedURLException; 22 import java.net.URL; 23 import java.util.Locale; 24 25 /** 26 * Immutable value type that names a web asset. 27 * 28 * <p>A web asset can be named by its protocol, domain, and port using this JSON string: 29 * { "namespace": "web", 30 * "site": "[protocol]://[fully-qualified domain]{:[optional port]}" } 31 * 32 * <p>For example, a website hosted on a https server at www.test.com can be named using 33 * { "namespace": "web", 34 * "site": "https://www.test.com" } 35 * 36 * <p>The only protocol supported now are https and http. If the optional port is not specified, 37 * the default for each protocol will be used (i.e. 80 for http and 443 for https). 38 */ 39 /* package private */ final class WebAsset extends AbstractAsset { 40 41 private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set."; 42 private static final String SCHEME_HTTP = "http"; 43 44 private final URL mUrl; 45 WebAsset(URL url)46 private WebAsset(URL url) { 47 int port = url.getPort() != -1 ? url.getPort() : url.getDefaultPort(); 48 try { 49 mUrl = new URL(url.getProtocol().toLowerCase(), url.getHost().toLowerCase(), port, ""); 50 } catch (MalformedURLException e) { 51 throw new AssertionError( 52 "Url should always be validated before calling the constructor."); 53 } 54 } 55 getDomain()56 public String getDomain() { 57 return mUrl.getHost(); 58 } 59 getPath()60 public String getPath() { 61 return mUrl.getPath(); 62 } 63 getScheme()64 public String getScheme() { 65 return mUrl.getProtocol(); 66 } 67 getPort()68 public int getPort() { 69 return mUrl.getPort(); 70 } 71 72 @Override toJson()73 public String toJson() { 74 AssetJsonWriter writer = new AssetJsonWriter(); 75 76 writer.writeFieldLower(Utils.NAMESPACE_FIELD, Utils.NAMESPACE_WEB); 77 writer.writeFieldLower(Utils.WEB_ASSET_FIELD_SITE, mUrl.toExternalForm()); 78 79 return writer.closeAndGetString(); 80 } 81 82 @Override toString()83 public String toString() { 84 StringBuilder asset = new StringBuilder(); 85 asset.append("WebAsset: "); 86 asset.append(toJson()); 87 return asset.toString(); 88 } 89 90 @Override equals(Object o)91 public boolean equals(Object o) { 92 if (!(o instanceof WebAsset)) { 93 return false; 94 } 95 96 return ((WebAsset) o).toJson().equals(toJson()); 97 } 98 99 @Override hashCode()100 public int hashCode() { 101 return toJson().hashCode(); 102 } 103 104 @Override lookupKey()105 public int lookupKey() { 106 return toJson().hashCode(); 107 } 108 109 @Override followInsecureInclude()110 public boolean followInsecureInclude() { 111 // Only allow insecure include file if the asset scheme is http. 112 return SCHEME_HTTP.equals(getScheme()); 113 } 114 115 /** 116 * Checks that the input is a valid web asset. 117 * 118 * @throws AssociationServiceException if the asset is not well formatted. 119 */ create(JSONObject asset)120 protected static WebAsset create(JSONObject asset) 121 throws AssociationServiceException { 122 if (asset.optString(Utils.WEB_ASSET_FIELD_SITE).equals("")) { 123 throw new AssociationServiceException(String.format(MISSING_FIELD_FORMAT_STRING, 124 Utils.WEB_ASSET_FIELD_SITE)); 125 } 126 127 URL url; 128 try { 129 url = new URL(asset.optString(Utils.WEB_ASSET_FIELD_SITE)); 130 } catch (MalformedURLException e) { 131 throw new AssociationServiceException("Url is not well formatted.", e); 132 } 133 134 String scheme = url.getProtocol().toLowerCase(Locale.US); 135 if (!scheme.equals("https") && !scheme.equals("http")) { 136 throw new AssociationServiceException("Expected scheme to be http or https."); 137 } 138 139 if (url.getUserInfo() != null) { 140 throw new AssociationServiceException("The url should not contain user info."); 141 } 142 143 String path = url.getFile(); // This is url.getPath() + url.getQuery(). 144 if (!path.equals("/") && !path.equals("")) { 145 throw new AssociationServiceException( 146 "Site should only have scheme, domain, and port."); 147 } 148 149 return new WebAsset(url); 150 } 151 } 152