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