Home | History | Annotate | Download | only in retriever
      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 
     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 
     56     public String getDomain() {
     57         return mUrl.getHost();
     58     }
     59 
     60     public String getPath() {
     61         return mUrl.getPath();
     62     }
     63 
     64     public String getScheme() {
     65         return mUrl.getProtocol();
     66     }
     67 
     68     public int getPort() {
     69         return mUrl.getPort();
     70     }
     71 
     72     @Override
     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
     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
     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
    100     public int hashCode() {
    101         return toJson().hashCode();
    102     }
    103 
    104     @Override
    105     public int lookupKey() {
    106         return toJson().hashCode();
    107     }
    108 
    109     @Override
    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      */
    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