17aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller/* 27aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * Copyright (C) 2015 Square, Inc. 37aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * 47aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * Licensed under the Apache License, Version 2.0 (the "License"); 57aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * you may not use this file except in compliance with the License. 67aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * You may obtain a copy of the License at 77aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * 87aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * http://www.apache.org/licenses/LICENSE-2.0 97aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * 107aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * Unless required by applicable law or agreed to in writing, software 117aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * distributed under the License is distributed on an "AS IS" BASIS, 127aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * See the License for the specific language governing permissions and 147aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * limitations under the License. 157aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller */ 167aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerpackage com.squareup.okhttp; 177aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 187aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerimport java.io.EOFException; 197aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerimport java.io.IOException; 207aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerimport java.util.ArrayList; 217aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerimport java.util.List; 227aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerimport okio.Buffer; 237aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerimport okio.BufferedSource; 247aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 257aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller/** 267aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * A test from the <a href="https://github.com/w3c/web-platform-tests/tree/master/url">Web Platform 277aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * URL test suite</a>. Each test is a line of the file {@code urltestdata.txt}; the format is 287aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * informally specified by its JavaScript parser {@code urltestparser.js}; with which this class 297aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * attempts to be compatible. 307aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * 317aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * <p>Each line of the urltestdata.text file specifies a test. Lines look like this: <pre> {@code 3271b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller * 337aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller * http://example\t.\norg http://example.org/foo/bar s:http h:example.org p:/ 3471b9f47b26fb57ac3e436a19519c6e3ec70e86ebNeil Fuller * }</pre> 357aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller */ 367aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fullerpublic final class WebPlatformUrlTestData { 377aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String input; 387aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String base; 397aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String scheme = ""; 407aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String username = ""; 417aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String password = null; 427aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String host = ""; 437aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String port = ""; 447aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String path = ""; 457aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String query = ""; 467aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String fragment = ""; 477aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 487aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller public boolean expectParseFailure() { 497aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller return scheme.isEmpty(); 507aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 517aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 527aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller private void set(String name, String value) { 537aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller switch (name) { 547aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "s": 557aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller scheme = value; 567aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 577aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "u": 587aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller username = value; 597aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 607aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "pass": 617aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller password = value; 627aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 637aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "h": 647aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller host = value; 657aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 667aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "port": 677aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller port = value; 687aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 697aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "p": 707aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller path = value; 717aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 727aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "q": 737aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller query = value; 747aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 757aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case "f": 767aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller fragment = value; 777aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 787aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller default: 797aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller throw new IllegalArgumentException("unexpected attribute: " + value); 807aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 817aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 827aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 837aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller @Override public String toString() { 847aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller return String.format("Parsing: <%s> against <%s>", input, base); 857aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 867aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 877aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller public static List<WebPlatformUrlTestData> load(BufferedSource source) throws IOException { 887aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller List<WebPlatformUrlTestData> list = new ArrayList<>(); 897aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller for (String line; (line = source.readUtf8Line()) != null; ) { 907aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller if (line.isEmpty() || line.startsWith("#")) continue; 917aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 927aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller int i = 0; 937aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String[] parts = line.split(" "); 947aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller WebPlatformUrlTestData element = new WebPlatformUrlTestData(); 957aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller element.input = unescape(parts[i++]); 967aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 977aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String base = i < parts.length ? parts[i++] : null; 987aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller element.base = (base == null || base.isEmpty()) 997aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller ? list.get(list.size() - 1).base 1007aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller : unescape(base); 1017aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 1027aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller for (; i < parts.length; i++) { 1037aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String piece = parts[i]; 1047aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller if (piece.startsWith("#")) continue; 1057aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller String[] nameAndValue = piece.split(":", 2); 1067aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller element.set(nameAndValue[0], unescape(nameAndValue[1])); 1077aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1087aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 1097aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller list.add(element); 1107aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1117aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller return list; 1127aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1137aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 1147aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller private static String unescape(String s) throws EOFException { 1157aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller Buffer in = new Buffer().writeUtf8(s); 1167aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller StringBuilder result = new StringBuilder(); 1177aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller while (!in.exhausted()) { 1187aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller int c = in.readUtf8CodePoint(); 1197aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller if (c != '\\') { 1207aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append((char) c); 1217aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller continue; 1227aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1237aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 1247aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller switch (in.readUtf8CodePoint()) { 1257aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case '\\': 1267aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append('\\'); 1277aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1287aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case '#': 1297aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append('#'); 1307aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1317aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case 'n': 1327aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append('\n'); 1337aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1347aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case 'r': 1357aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append('\r'); 1367aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1377aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case 's': 1387aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append(' '); 1397aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1407aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case 't': 1417aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append('\t'); 1427aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1437aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case 'f': 1447aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append('\f'); 1457aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1467aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller case 'u': 1477aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller result.append((char) Integer.parseInt(in.readUtf8(4), 16)); 1487aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller break; 1497aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller default: 1507aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller throw new IllegalArgumentException("unexpected escape character in " + s); 1517aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1527aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1537aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller 1547aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller return result.toString(); 1557aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller } 1567aeaaefc891f6221f4b2cce536b1c1e816e09794Neil Fuller} 157