/* * Copyright (C) 2015 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.android.statementservice.retriever; import org.json.JSONObject; import java.net.MalformedURLException; import java.net.URL; import java.util.Locale; /** * Immutable value type that names a web asset. * *

A web asset can be named by its protocol, domain, and port using this JSON string: * { "namespace": "web", * "site": "[protocol]://[fully-qualified domain]{:[optional port]}" } * *

For example, a website hosted on a https server at www.test.com can be named using * { "namespace": "web", * "site": "https://www.test.com" } * *

The only protocol supported now are https and http. If the optional port is not specified, * the default for each protocol will be used (i.e. 80 for http and 443 for https). */ /* package private */ final class WebAsset extends AbstractAsset { private static final String MISSING_FIELD_FORMAT_STRING = "Expected %s to be set."; private static final String SCHEME_HTTP = "http"; private final URL mUrl; private WebAsset(URL url) { int port = url.getPort() != -1 ? url.getPort() : url.getDefaultPort(); try { mUrl = new URL(url.getProtocol().toLowerCase(), url.getHost().toLowerCase(), port, ""); } catch (MalformedURLException e) { throw new AssertionError( "Url should always be validated before calling the constructor."); } } public String getDomain() { return mUrl.getHost(); } public String getPath() { return mUrl.getPath(); } public String getScheme() { return mUrl.getProtocol(); } public int getPort() { return mUrl.getPort(); } @Override public String toJson() { AssetJsonWriter writer = new AssetJsonWriter(); writer.writeFieldLower(Utils.NAMESPACE_FIELD, Utils.NAMESPACE_WEB); writer.writeFieldLower(Utils.WEB_ASSET_FIELD_SITE, mUrl.toExternalForm()); return writer.closeAndGetString(); } @Override public String toString() { StringBuilder asset = new StringBuilder(); asset.append("WebAsset: "); asset.append(toJson()); return asset.toString(); } @Override public boolean equals(Object o) { if (!(o instanceof WebAsset)) { return false; } return ((WebAsset) o).toJson().equals(toJson()); } @Override public int hashCode() { return toJson().hashCode(); } @Override public int lookupKey() { return toJson().hashCode(); } @Override public boolean followInsecureInclude() { // Only allow insecure include file if the asset scheme is http. return SCHEME_HTTP.equals(getScheme()); } /** * Checks that the input is a valid web asset. * * @throws AssociationServiceException if the asset is not well formatted. */ protected static WebAsset create(JSONObject asset) throws AssociationServiceException { if (asset.optString(Utils.WEB_ASSET_FIELD_SITE).equals("")) { throw new AssociationServiceException(String.format(MISSING_FIELD_FORMAT_STRING, Utils.WEB_ASSET_FIELD_SITE)); } URL url; try { url = new URL(asset.optString(Utils.WEB_ASSET_FIELD_SITE)); } catch (MalformedURLException e) { throw new AssociationServiceException("Url is not well formatted.", e); } String scheme = url.getProtocol().toLowerCase(Locale.US); if (!scheme.equals("https") && !scheme.equals("http")) { throw new AssociationServiceException("Expected scheme to be http or https."); } if (url.getUserInfo() != null) { throw new AssociationServiceException("The url should not contain user info."); } String path = url.getFile(); // This is url.getPath() + url.getQuery(). if (!path.equals("/") && !path.equals("")) { throw new AssociationServiceException( "Site should only have scheme, domain, and port."); } return new WebAsset(url); } }