1 /* 2 * Copyright (C) 2020 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.server.wifi.hotspot2.anqp; 18 19 import android.text.TextUtils; 20 import android.util.Log; 21 22 import com.android.internal.annotations.VisibleForTesting; 23 import com.android.server.wifi.ByteBufferReader; 24 25 import java.net.ProtocolException; 26 import java.net.URL; 27 import java.nio.BufferUnderflowException; 28 import java.nio.ByteBuffer; 29 import java.nio.charset.StandardCharsets; 30 import java.util.HashMap; 31 import java.util.Map; 32 33 /** 34 * The Venue URL ANQP Element, IEEE802.11-2016 section 9.4.5.20. 35 * 36 * Format: 37 * 38 * | Venue URL Duples | 39 * variable 40 * 41 * Venue URL Duple: 42 * | Length | Venue Number | Venue URL Duple #1 (optional) | ... 43 * 1 1 variable 44 */ 45 public class VenueUrlElement extends ANQPElement { 46 private final Map<Integer, URL> mVenueUrls; 47 private static final String TAG = "VenueUrlElement"; 48 49 @VisibleForTesting VenueUrlElement(Map<Integer, URL> venueUrls)50 public VenueUrlElement(Map<Integer, URL> venueUrls) { 51 super(Constants.ANQPElementType.ANQPVenueUrl); 52 mVenueUrls = venueUrls; 53 } 54 55 /** 56 * Parse a VenueUrlElement from the given buffer. 57 * 58 * @param payload The byte buffer to read from 59 * @return {@link VenueUrlElement} 60 * @throws BufferUnderflowException 61 * @throws ProtocolException 62 */ parse(ByteBuffer payload)63 public static VenueUrlElement parse(ByteBuffer payload) 64 throws ProtocolException, BufferUnderflowException { 65 Map<Integer, URL> venueUrls = new HashMap<>(); 66 while (payload.remaining() >= 2) { 67 int length = payload.get() & 0xFF; 68 int venueNumber = payload.get() & 0xFF; 69 if (venueNumber == 0) { 70 // In case no Venue Name Tuple subfield was returned in the Venue Name ANQP-element 71 break; 72 } 73 String parsedUrl = ByteBufferReader.readString(payload, length - 1, 74 StandardCharsets.UTF_8); 75 URL url; 76 try { 77 url = new URL(parsedUrl); 78 } catch (java.net.MalformedURLException e) { 79 Log.e(TAG, "Malformed venue URL: " + parsedUrl + " at index " + venueNumber); 80 throw new ProtocolException("Malformed venue URL: " + parsedUrl + " at index " 81 + venueNumber); 82 } 83 // Reject URLs that are not HTTPS 84 String protocol = url.getProtocol(); 85 if (!TextUtils.equals(protocol, "https")) { 86 Log.w(TAG, "Non-HTTPS Venue URL dropped: " + url); 87 } else { 88 venueUrls.put(Integer.valueOf(venueNumber), url); 89 } 90 } 91 92 return new VenueUrlElement(venueUrls); 93 } 94 getVenueUrls()95 public Map<Integer, URL> getVenueUrls() { 96 return mVenueUrls; 97 } 98 99 @Override equals(Object thatObject)100 public boolean equals(Object thatObject) { 101 if (this == thatObject) { 102 return true; 103 } 104 if (!(thatObject instanceof VenueUrlElement)) { 105 return false; 106 } 107 VenueUrlElement that = (VenueUrlElement) thatObject; 108 return mVenueUrls.equals(that.mVenueUrls); 109 } 110 111 @Override hashCode()112 public int hashCode() { 113 return mVenueUrls.hashCode(); 114 } 115 116 @Override toString()117 public String toString() { 118 return "VenueUrl{ mUrlList=" + mVenueUrls + "}"; 119 } 120 121 } 122