18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
28e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Copyright (C) 2004, 2007, 2008 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "KURL.h"
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextEncoding.h"
31dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include <wtf/text/CString.h>
32d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <wtf/HashMap.h>
332bde8e466a4451c7319e3a072d118917957d6554Steve Block#include <wtf/HexNumber.h>
34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/StdLibExtras.h>
35f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include <wtf/text/StringHash.h>
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if USE(ICU_UNICODE)
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <unicode/uidna.h>
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#elif USE(QT4_UNICODE)
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <QUrl>
41d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(GLIB_UNICODE)
42d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <glib.h>
43dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "GOwnPtr.h"
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <stdio.h>
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WTF;
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef Vector<char, 512> CharBuffer;
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef Vector<UChar, 512> UCharBuffer;
558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic const unsigned maximumValidPortNumber = 0xFFFE;
5781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic const unsigned invalidPortNumber = 0xFFFF;
5881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#if !USE(GOOGLEURL)
6081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: This file makes too much use of the + operator on String.
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// We either have to optimize that operator so it doesn't involve
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// so many allocations, or change this to use Vector<UChar> instead.
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectenum URLCharacterClasses {
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // alpha
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SchemeFirstChar = 1 << 0,
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // ( alpha | digit | "+" | "-" | "." )
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SchemeChar = 1 << 1,
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // unreserved  = alphanum | mark
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // ( unreserved | escaped | ";" | ":" | "&" | "=" | "+" | "$" | "," )
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UserInfoChar = 1 << 2,
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // alnum | "." | "-" | "%"
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The above is what the specification says, but we are lenient to
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // match existing practice and also allow:
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // "_"
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HostnameChar = 1 << 3,
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // hexdigit | ":" | "%"
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IPv6Char = 1 << 4,
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // "#" | "?" | "/" | nul
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    PathSegmentEndChar = 1 << 5,
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // not allowed in path
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BadChar = 1 << 6
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic const unsigned char characterClassTable[256] = {
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 0 nul */ PathSegmentEndChar,    /* 1 soh */ BadChar,
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 2 stx */ BadChar,    /* 3 etx */ BadChar,
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 4 eot */ BadChar,    /* 5 enq */ BadChar,    /* 6 ack */ BadChar,    /* 7 bel */ BadChar,
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 8 bs */ BadChar,     /* 9 ht */ BadChar,     /* 10 nl */ BadChar,    /* 11 vt */ BadChar,
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 12 np */ BadChar,    /* 13 cr */ BadChar,    /* 14 so */ BadChar,    /* 15 si */ BadChar,
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 16 dle */ BadChar,   /* 17 dc1 */ BadChar,   /* 18 dc2 */ BadChar,   /* 19 dc3 */ BadChar,
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 20 dc4 */ BadChar,   /* 21 nak */ BadChar,   /* 22 syn */ BadChar,   /* 23 etb */ BadChar,
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 24 can */ BadChar,   /* 25 em */ BadChar,    /* 26 sub */ BadChar,   /* 27 esc */ BadChar,
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 28 fs */ BadChar,    /* 29 gs */ BadChar,    /* 30 rs */ BadChar,    /* 31 us */ BadChar,
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 32 sp */ BadChar,    /* 33  ! */ UserInfoChar,
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 34  " */ BadChar,    /* 35  # */ PathSegmentEndChar | BadChar,
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 36  $ */ UserInfoChar,    /* 37  % */ UserInfoChar | HostnameChar | IPv6Char | BadChar,
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 38  & */ UserInfoChar,    /* 39  ' */ UserInfoChar,
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 40  ( */ UserInfoChar,    /* 41  ) */ UserInfoChar,
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 42  * */ UserInfoChar,    /* 43  + */ SchemeChar | UserInfoChar,
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 44  , */ UserInfoChar,
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 45  - */ SchemeChar | UserInfoChar | HostnameChar,
111643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    /* 46  . */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 47  / */ PathSegmentEndChar,
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 48  0 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 49  1 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 50  2 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 51  3 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 52  4 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 53  5 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 54  6 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 55  7 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 56  8 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 57  9 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 58  : */ UserInfoChar | IPv6Char,    /* 59  ; */ UserInfoChar,
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 60  < */ BadChar,    /* 61  = */ UserInfoChar,
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 62  > */ BadChar,    /* 63  ? */ PathSegmentEndChar | BadChar,
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 64  @ */ 0,
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 65  A */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 66  B */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 67  C */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 68  D */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 69  E */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 70  F */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 71  G */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 72  H */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 73  I */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 74  J */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 75  K */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 76  L */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 77  M */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 78  N */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 79  O */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 80  P */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 81  Q */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 82  R */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 83  S */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 84  T */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 85  U */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 86  V */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 87  W */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 88  X */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 89  Y */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 90  Z */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 91  [ */ 0,
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 92  \ */ 0,    /* 93  ] */ 0,
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 94  ^ */ 0,
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 95  _ */ UserInfoChar | HostnameChar,
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 96  ` */ 0,
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 97  a */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 98  b */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 99  c */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 100  d */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 101  e */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 102  f */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 103  g */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 104  h */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 105  i */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 106  j */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 107  k */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 108  l */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 109  m */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 110  n */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 111  o */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 112  p */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 113  q */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 114  r */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 115  s */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 116  t */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 117  u */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 118  v */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 119  w */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 120  x */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 121  y */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 122  z */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 123  { */ 0,
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 124  | */ 0,   /* 125  } */ 0,   /* 126  ~ */ UserInfoChar,   /* 127 del */ BadChar,
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 128 */ BadChar, /* 129 */ BadChar, /* 130 */ BadChar, /* 131 */ BadChar,
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 132 */ BadChar, /* 133 */ BadChar, /* 134 */ BadChar, /* 135 */ BadChar,
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 136 */ BadChar, /* 137 */ BadChar, /* 138 */ BadChar, /* 139 */ BadChar,
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 140 */ BadChar, /* 141 */ BadChar, /* 142 */ BadChar, /* 143 */ BadChar,
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 144 */ BadChar, /* 145 */ BadChar, /* 146 */ BadChar, /* 147 */ BadChar,
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 148 */ BadChar, /* 149 */ BadChar, /* 150 */ BadChar, /* 151 */ BadChar,
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 152 */ BadChar, /* 153 */ BadChar, /* 154 */ BadChar, /* 155 */ BadChar,
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 156 */ BadChar, /* 157 */ BadChar, /* 158 */ BadChar, /* 159 */ BadChar,
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 160 */ BadChar, /* 161 */ BadChar, /* 162 */ BadChar, /* 163 */ BadChar,
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 164 */ BadChar, /* 165 */ BadChar, /* 166 */ BadChar, /* 167 */ BadChar,
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 168 */ BadChar, /* 169 */ BadChar, /* 170 */ BadChar, /* 171 */ BadChar,
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 172 */ BadChar, /* 173 */ BadChar, /* 174 */ BadChar, /* 175 */ BadChar,
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 176 */ BadChar, /* 177 */ BadChar, /* 178 */ BadChar, /* 179 */ BadChar,
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 180 */ BadChar, /* 181 */ BadChar, /* 182 */ BadChar, /* 183 */ BadChar,
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 184 */ BadChar, /* 185 */ BadChar, /* 186 */ BadChar, /* 187 */ BadChar,
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 188 */ BadChar, /* 189 */ BadChar, /* 190 */ BadChar, /* 191 */ BadChar,
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 192 */ BadChar, /* 193 */ BadChar, /* 194 */ BadChar, /* 195 */ BadChar,
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 196 */ BadChar, /* 197 */ BadChar, /* 198 */ BadChar, /* 199 */ BadChar,
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 200 */ BadChar, /* 201 */ BadChar, /* 202 */ BadChar, /* 203 */ BadChar,
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 204 */ BadChar, /* 205 */ BadChar, /* 206 */ BadChar, /* 207 */ BadChar,
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 208 */ BadChar, /* 209 */ BadChar, /* 210 */ BadChar, /* 211 */ BadChar,
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 212 */ BadChar, /* 213 */ BadChar, /* 214 */ BadChar, /* 215 */ BadChar,
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 216 */ BadChar, /* 217 */ BadChar, /* 218 */ BadChar, /* 219 */ BadChar,
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 220 */ BadChar, /* 221 */ BadChar, /* 222 */ BadChar, /* 223 */ BadChar,
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 224 */ BadChar, /* 225 */ BadChar, /* 226 */ BadChar, /* 227 */ BadChar,
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 228 */ BadChar, /* 229 */ BadChar, /* 230 */ BadChar, /* 231 */ BadChar,
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 232 */ BadChar, /* 233 */ BadChar, /* 234 */ BadChar, /* 235 */ BadChar,
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 236 */ BadChar, /* 237 */ BadChar, /* 238 */ BadChar, /* 239 */ BadChar,
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 240 */ BadChar, /* 241 */ BadChar, /* 242 */ BadChar, /* 243 */ BadChar,
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 244 */ BadChar, /* 245 */ BadChar, /* 246 */ BadChar, /* 247 */ BadChar,
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 248 */ BadChar, /* 249 */ BadChar, /* 250 */ BadChar, /* 251 */ BadChar,
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 252 */ BadChar, /* 253 */ BadChar, /* 254 */ BadChar, /* 255 */ BadChar
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd);
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void encodeRelativeString(const String& rel, const TextEncoding&, CharBuffer& ouput);
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic String substituteBackslashes(const String&);
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeFirstChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeFirstChar; }
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeFirstChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeFirstChar); }
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeChar; }
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeChar); }
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isUserInfoChar(unsigned char c) { return characterClassTable[c] & UserInfoChar; }
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isHostnameChar(unsigned char c) { return characterClassTable[c] & HostnameChar; }
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isIPv6Char(unsigned char c) { return characterClassTable[c] & IPv6Char; }
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isPathSegmentEndChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & PathSegmentEndChar; }
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isPathSegmentEndChar(UChar c) { return c <= 0xff && (characterClassTable[c] & PathSegmentEndChar); }
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isBadChar(unsigned char c) { return characterClassTable[c] & BadChar; }
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline int hexDigitValue(UChar c)
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isASCIIHexDigit(c));
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c < 'A')
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return c - '0';
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (c - 'A' + 10) & 0xF; // handle both upper and lower case without a branch
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Copies the source to the destination, assuming all the source characters are
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ASCII. The destination buffer must be large enough. Null characters are allowed
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// in the source string, and no attempt is made to null-terminate the result.
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void copyASCII(const UChar* src, int length, char* dest)
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < length; i++)
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        dest[i] = static_cast<char>(src[i]);
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
252635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void appendASCII(const String& base, const char* rel, size_t len, CharBuffer& buffer)
253635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    buffer.resize(base.length() + len + 1);
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    copyASCII(base.characters(), base.length(), buffer.data());
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    memcpy(buffer.data() + base.length(), rel, len);
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    buffer[buffer.size() - 1] = '\0';
258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: Move to PlatformString.h eventually.
2618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Returns the index of the first index in string |s| of any of the characters
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// in |toFind|. |toFind| should be a null-terminated string, all characters up
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// to the null will be searched. Returns int if not found.
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int findFirstOf(const UChar* s, int sLen, int startPos, const char* toFind)
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = startPos; i < sLen; i++) {
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* cur = toFind;
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (*cur) {
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (s[i] == *(cur++))
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return i;
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return -1;
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
276635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifndef NDEBUG
277635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void checkEncodedString(const String& url)
278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (unsigned i = 0; i < url.length(); ++i)
280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ASSERT(!(url[i] & ~0x7F));
281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(!url.length() || isSchemeFirstChar(url[0]));
283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#else
285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic inline void checkEncodedString(const String&)
286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline bool KURL::protocolIs(const String& string, const char* protocol)
2918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return WebCore::protocolIs(string, protocol);
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::invalidate()
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_isValid = false;
2988f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    m_protocolInHTTPFamily = false;
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_schemeEnd = 0;
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_userStart = 0;
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_userEnd = 0;
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_passwordEnd = 0;
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_hostEnd = 0;
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_portEnd = 0;
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathEnd = 0;
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathAfterLastSlash = 0;
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_queryEnd = 0;
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_fragmentEnd = 0;
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
311231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockKURL::KURL(ParsedURLStringTag, const char* url)
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
313635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    parse(url, 0);
314635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(url == m_string);
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
317231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockKURL::KURL(ParsedURLStringTag, const String& url)
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
319635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    parse(url);
320635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(url == m_string);
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3232fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockKURL::KURL(ParsedURLStringTag, const URLString& url)
3242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
3252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    parse(url.string());
3262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ASSERT(url.string() == m_string);
3272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
3282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectKURL::KURL(const KURL& base, const String& relative)
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    init(base, relative, UTF8Encoding());
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectKURL::KURL(const KURL& base, const String& relative, const TextEncoding& encoding)
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
336635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // For UTF-{7,16,32}, we want to use UTF-8 for the query part as
337635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // we do when submitting a form. A form with GET method
338635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // has its contents added to a URL as query params and it makes sense
339635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // to be consistent.
340635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    init(base, relative, encoding.encodingForFormSubmission());
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
34381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic bool shouldTrimFromURL(unsigned char c)
34481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
34581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Browsers ignore leading/trailing whitespace and control
34681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // characters from URLs.  Note that c is an *unsigned* char here
34781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // so this comparison should only catch control characters.
34881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return c <= ' ';
34981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
35081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::init(const KURL& base, const String& relative, const TextEncoding& encoding)
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Allow resolutions with a null or empty base URL, but not with any other invalid one.
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Is this a good rule?
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!base.m_isValid && !base.isEmpty()) {
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = relative;
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For compatibility with Win IE, treat backslashes as if they were slashes,
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // as long as we're not dealing with javascript: or data: URLs.
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String rel = relative;
3645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (rel.contains('\\') && !(protocolIsJavaScript(rel) || protocolIs(rel, "data")))
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        rel = substituteBackslashes(rel);
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String* originalString = &rel;
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool allASCII = charactersAreAllASCII(rel.characters(), rel.length());
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CharBuffer strBuffer;
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* str;
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    size_t len;
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (allASCII) {
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        len = rel.length();
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        strBuffer.resize(len + 1);
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        copyASCII(rel.characters(), len, strBuffer.data());
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        strBuffer[len] = 0;
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str = strBuffer.data();
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        originalString = 0;
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        encodeRelativeString(rel, encoding, strBuffer);
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str = strBuffer.data();
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        len = strlen(str);
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
38681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Get rid of leading whitespace and control characters.
38781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    while (len && shouldTrimFromURL(*str)) {
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        originalString = 0;
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str++;
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        --len;
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
39381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Get rid of trailing whitespace and control characters.
39481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    while (len && shouldTrimFromURL(str[len - 1])) {
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        originalString = 0;
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str[--len] = '\0';
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // According to the RFC, the reference should be interpreted as an
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // absolute URI if possible, using the "leftmost, longest"
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // algorithm. If the URI reference is absolute it will have a
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // scheme, meaning that it will have a colon before the first
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // non-scheme element.
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool absolute = false;
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = str;
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isSchemeFirstChar(*p)) {
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ++p;
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (isSchemeChar(*p)) {
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ++p;
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (*p == ':') {
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (p[1] != '/' && equalIgnoringCase(base.protocol(), String(str, p - str)) && base.isHierarchical()) {
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                str = p + 1;
4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                originalString = 0;
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                absolute = true;
4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
420635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CharBuffer parseBuffer;
421635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
4228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (absolute) {
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parse(str, originalString);
4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
4258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If the base is empty or opaque (e.g. data: or javascript:), then the URL is invalid
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // unless the relative URL is a single fragment.
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!base.isHierarchical()) {
428635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (str[0] == '#') {
429635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer);
430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
431635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            } else {
4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_string = relative;
4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                invalidate();
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        switch (str[0]) {
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case '\0':
4405e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block            // The reference is empty, so this is a reference to the same document with any fragment identifier removed.
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *this = base;
4425e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block            removeFragmentIdentifier();
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
444635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        case '#': {
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // must be fragment-only reference
446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer);
447635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            parse(parseBuffer.data(), 0);
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
450635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        case '?': {
4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // query-only reference, special case needed for non-URL results
452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            appendASCII(base.m_string.left(base.m_pathEnd), str, len, parseBuffer);
453635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            parse(parseBuffer.data(), 0);
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
455635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case '/':
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // must be net-path or absolute-path reference
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (str[1] == '/') {
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // net-path
460635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                appendASCII(base.m_string.left(base.m_schemeEnd + 1), str, len, parseBuffer);
461635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // abs-path
464635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                appendASCII(base.m_string.left(base.m_portEnd), str, len, parseBuffer);
465635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        default:
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            {
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // must be relative-path reference
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Base part plus relative part plus one possible slash added in between plus terminating \0 byte.
473635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parseBuffer.resize(base.m_pathEnd + 1 + len + 1);
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
475635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                char* bufferPos = parseBuffer.data();
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // first copy everything before the path from the base
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                unsigned baseLength = base.m_string.length();
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const UChar* baseCharacters = base.m_string.characters();
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                CharBuffer baseStringBuffer(baseLength);
481635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                copyASCII(baseCharacters, baseLength, baseStringBuffer.data());
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* baseString = baseStringBuffer.data();
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* baseStringStart = baseString;
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* pathStart = baseStringStart + base.m_portEnd;
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (baseStringStart < pathStart)
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    *bufferPos++ = *baseStringStart++;
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                char* bufferPathStart = bufferPos;
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // now copy the base path
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* baseStringEnd = baseString + base.m_pathEnd;
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // go back to the last slash
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/')
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    baseStringEnd--;
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (baseStringEnd == baseStringStart) {
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // no path in base, add a path separator if necessary
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (base.m_schemeEnd + 1 != base.m_pathEnd && *str && *str != '?' && *str != '#')
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        *bufferPos++ = '/';
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else {
5018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    bufferPos += copyPathRemovingDots(bufferPos, baseStringStart, 0, baseStringEnd - baseStringStart);
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* relStringStart = str;
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* relStringPos = relStringStart;
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (*relStringPos && *relStringPos != '?' && *relStringPos != '#') {
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (relStringPos[0] == '.' && bufferPos[-1] == '/') {
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        if (isPathSegmentEndChar(relStringPos[1])) {
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // skip over "." segment
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            relStringPos += 1;
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            if (relStringPos[0] == '/')
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                relStringPos++;
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            continue;
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        } else if (relStringPos[1] == '.' && isPathSegmentEndChar(relStringPos[2])) {
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // skip over ".." segment and rewind the last segment
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // the RFC leaves it up to the app to decide what to do with excess
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // ".." segments - we choose to drop them since some web content
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // relies on this.
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            relStringPos += 2;
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            if (relStringPos[0] == '/')
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                relStringPos++;
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            if (bufferPos > bufferPathStart + 1)
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                bufferPos--;
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            while (bufferPos > bufferPathStart + 1  && bufferPos[-1] != '/')
5268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                bufferPos--;
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            continue;
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        }
5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    }
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    *bufferPos = *relStringPos;
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    relStringPos++;
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    bufferPos++;
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // all done with the path work, now copy any remainder
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // of the relative reference; this will also add a null terminator
5388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                strcpy(bufferPos, relStringPos);
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
540635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
542635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                ASSERT(strlen(parseBuffer.data()) + 1 <= parseBuffer.size());
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                break;
5448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
549635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectKURL KURL::copy() const
550635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
551635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    KURL result = *this;
552231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    result.m_string = result.m_string.crossThreadString();
553635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return result;
554635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
555635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
5568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool KURL::hasPath() const
5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_pathEnd != m_portEnd;
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::lastPathComponent() const
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!hasPath())
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
566f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned end = m_pathEnd - 1;
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_string[end] == '/')
5688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        --end;
5698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
570f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t start = m_string.reverseFind('/', end);
571f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (start < static_cast<unsigned>(m_portEnd))
5728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
5738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ++start;
5748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string.substring(start, end - start + 1);
5768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::protocol() const
5798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string.left(m_schemeEnd);
5818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::host() const
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int start = hostStart();
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(start, m_hostEnd - start));
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectunsigned short KURL::port() const
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
591dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // We return a port of 0 if there is no port specified. This can happen in two situations:
592dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 1) The URL contains no colon after the host name and before the path component of the URL.
593dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 2) The URL contains a colon but there's no port number before the path component of the URL begins.
594dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (m_hostEnd == m_portEnd || m_hostEnd == m_portEnd - 1)
5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
597dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const UChar* stringData = m_string.characters();
598dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool ok = false;
599dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    unsigned number = charactersToUIntStrict(stringData + m_hostEnd + 1, m_portEnd - m_hostEnd - 1, &ok);
600dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!ok || number > maximumValidPortNumber)
601dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return invalidPortNumber;
6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return number;
6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::pass() const
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_passwordEnd == m_userEnd)
6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1));
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::user() const
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(m_userStart, m_userEnd - m_userStart));
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochString KURL::fragmentIdentifier() const
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_fragmentEnd == m_queryEnd)
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string.substring(m_queryEnd + 1, m_fragmentEnd - (m_queryEnd + 1));
6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool KURL::hasFragmentIdentifier() const
6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_fragmentEnd != m_queryEnd;
6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
631a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid KURL::copyParsedQueryTo(ParsedURLParameters& parameters) const
632a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
633a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const UChar* pos = m_string.characters() + m_pathEnd + 1;
634a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const UChar* end = m_string.characters() + m_queryEnd;
635a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    while (pos < end) {
636a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* parameterStart = pos;
637a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        while (pos < end && *pos != '&')
638a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ++pos;
639a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* parameterEnd = pos;
640a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (pos < end) {
641a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ASSERT(*pos == '&');
642a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ++pos;
643a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
644a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (parameterStart == parameterEnd)
645a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            continue;
646a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* nameStart = parameterStart;
647a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* equalSign = parameterStart;
648a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        while (equalSign < parameterEnd && *equalSign != '=')
649a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ++equalSign;
650a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (equalSign == nameStart)
651a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            continue;
652a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        String name(nameStart, equalSign - nameStart);
653a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        String value = equalSign == parameterEnd ? String() : String(equalSign + 1, parameterEnd - equalSign - 1);
654a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        parameters.set(name, value);
655a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
656a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
657a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6588f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianString KURL::baseAsString() const
6598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian{
6608f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return m_string.left(m_pathAfterLastSlash);
6618f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian}
6628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
663635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifdef NDEBUG
664635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
665635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic inline void assertProtocolIsGood(const char*)
666635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
667635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
668635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
669635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#else
670635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
671635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void assertProtocolIsGood(const char* protocol)
6728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* p = protocol;
6748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (*p) {
6758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z'));
6768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ++p;
6778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
680635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
681635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
6828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool KURL::protocolIs(const char* protocol) const
6838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    assertProtocolIsGood(protocol);
6855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // JavaScript URLs are "valid" and should be executed even if KURL decides they are invalid.
6875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // The free function protocolIsJavaScript() should be used instead.
688643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ASSERT(!equalIgnoringCase(protocol, String("javascript")));
6895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
6918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
6925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Do the comparison without making a new string object.
6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < m_schemeEnd; ++i) {
6958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!protocol[i] || toASCIILower(m_string[i]) != protocol[i])
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return !protocol[m_schemeEnd]; // We should have consumed all characters in the argument.
6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::query() const
7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7038f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (m_queryEnd == m_pathEnd)
7048f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return String();
7058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
7068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return m_string.substring(m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1));
7078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::path() const
7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
711e48d279609693b4d164199748c93ad791547c649Steve Block    return m_string.substring(m_portEnd, m_pathEnd - m_portEnd);
7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
714d0825bca7fe65beaee391d30da42e937db621564Steve Blockbool KURL::setProtocol(const String& s)
7158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
716d0825bca7fe65beaee391d30da42e937db621564Steve Block    // Firefox and IE remove everything after the first ':'.
717f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t separatorPosition = s.find(':');
718d0825bca7fe65beaee391d30da42e937db621564Steve Block    String newProtocol = s.substring(0, separatorPosition);
719d0825bca7fe65beaee391d30da42e937db621564Steve Block
720d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (!isValidProtocol(newProtocol))
721d0825bca7fe65beaee391d30da42e937db621564Steve Block        return false;
722635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid) {
724d0825bca7fe65beaee391d30da42e937db621564Steve Block        parse(newProtocol + ":" + m_string);
725d0825bca7fe65beaee391d30da42e937db621564Steve Block        return true;
7268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
728d0825bca7fe65beaee391d30da42e937db621564Steve Block    parse(newProtocol + m_string.substring(m_schemeEnd));
729d0825bca7fe65beaee391d30da42e937db621564Steve Block    return true;
7308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setHost(const String& s)
7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
737635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
738635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just the host.
739635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
7418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(m_hostEnd));
7438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
745643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid KURL::removePort()
746643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
747643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (m_hostEnd == m_portEnd)
748643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
749643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd));
750643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
751643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
7528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setPort(unsigned short i)
7538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
757643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    bool colonNeeded = m_portEnd == m_hostEnd;
758643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1);
7598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
760643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd));
7618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setHostAndPort(const String& hostAndPort)
7648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
768635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
769635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just host and port.
770635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
7728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + hostAndPort + m_string.substring(m_portEnd));
7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setUser(const String& user)
7778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
781635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
782635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just the user login.
7838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String u;
7848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int end = m_userEnd;
7858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!user.isEmpty()) {
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        u = user;
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userStart == m_schemeEnd + 1)
7888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            u = "//" + u;
7898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Add '@' if we didn't have one before.
7908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@'))
7918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            u.append('@');
7928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
7938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remove '@' if we now have neither user nor password.
7948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userEnd == m_passwordEnd && end != m_hostEnd && m_string[end] == '@')
7958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end += 1;
7968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_userStart) + u + m_string.substring(end));
7988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setPass(const String& password)
8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
805635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
806635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just the user password.
8078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String p;
8088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int end = m_passwordEnd;
8098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!password.isEmpty()) {
8108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = ":" + password + "@";
8118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userEnd == m_schemeEnd + 1)
8128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p = "//" + p;
8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Eat the existing '@' since we are going to add our own.
8148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (end != m_hostEnd && m_string[end] == '@')
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end += 1;
8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remove '@' if we now have neither user nor password.
8188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userStart == m_userEnd && end != m_hostEnd && m_string[end] == '@')
8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end += 1;
8208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_userEnd) + p + m_string.substring(end));
8228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8240bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid KURL::setFragmentIdentifier(const String& s)
8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
828635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
829635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations.
8300bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    parse(m_string.left(m_queryEnd) + "#" + s);
8318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8330bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid KURL::removeFragmentIdentifier()
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_queryEnd));
8388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setQuery(const String& query)
8418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
845635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: '#' and non-ASCII characters must be encoded and escaped.
846635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Usually, the query is encoded using document encoding, not UTF-8, but we don't have
847635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // access to the document in this function.
8488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ((query.isEmpty() || query[0] != '?') && !query.isNull())
8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parse(m_string.left(m_pathEnd) + "?" + query + m_string.substring(m_queryEnd));
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
8518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parse(m_string.left(m_pathEnd) + query + m_string.substring(m_queryEnd));
8528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setPath(const String& s)
8568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
860635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: encodeWithURLEscapeSequences does not correctly escape '#' and '?', so fragment and query parts
861635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // may be inadvertently affected.
8622bde8e466a4451c7319e3a072d118917957d6554Steve Block    String path = s;
8632bde8e466a4451c7319e3a072d118917957d6554Steve Block    if (path.isEmpty() || path[0] != '/')
8642bde8e466a4451c7319e3a072d118917957d6554Steve Block        path = "/" + path;
8652bde8e466a4451c7319e3a072d118917957d6554Steve Block
8662bde8e466a4451c7319e3a072d118917957d6554Steve Block    parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(path) + m_string.substring(m_pathEnd));
8678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8696ed1fdfa7999878a811b09cdd647fbeace4353b8Steve BlockString KURL::deprecatedString() const
8708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return m_string;
8738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar> result;
8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    append(result, protocol());
8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.append(':');
8788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar> authority;
8808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_hostEnd != m_passwordEnd) {
8828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userEnd != m_userStart) {
8838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            append(authority, user());
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            authority.append('@');
8858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        append(authority, host());
887643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (hasPort()) {
8888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            authority.append(':');
8898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            append(authority, String::number(port()));
8908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!authority.isEmpty()) {
8948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(authority);
8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (protocolIs("file")) {
8988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
9008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    append(result, path());
9038f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
9048f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (m_pathEnd != m_queryEnd) {
9058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        result.append('?');
9068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        append(result, query());
9078f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
9088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_fragmentEnd != m_queryEnd) {
9108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('#');
9110bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        append(result, fragmentIdentifier());
9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return String::adopt(result);
9158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString decodeURLEscapeSequences(const String& str)
9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(str, UTF8Encoding());
9208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
9238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar> result;
9258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CharBuffer buffer;
9278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
928f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned length = str.length();
929f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned decodedPosition = 0;
930f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned searchPosition = 0;
931f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t encodedRunPosition;
932f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    while ((encodedRunPosition = str.find('%', searchPosition)) != notFound) {
9338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find the sequence of %-escape codes.
934f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        unsigned encodedRunEnd = encodedRunPosition;
9358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (length - encodedRunEnd >= 3
9368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && str[encodedRunEnd] == '%'
9378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && isASCIIHexDigit(str[encodedRunEnd + 1])
9388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && isASCIIHexDigit(str[encodedRunEnd + 2]))
9398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            encodedRunEnd += 3;
9402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        searchPosition = encodedRunEnd;
9418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (encodedRunEnd == encodedRunPosition) {
9428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ++searchPosition;
9438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
9448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Decode the %-escapes into bytes.
9478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned runLength = (encodedRunEnd - encodedRunPosition) / 3;
9488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer.resize(runLength);
9498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char* p = buffer.data();
9508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UChar* q = str.characters() + encodedRunPosition;
9518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (unsigned i = 0; i < runLength; ++i) {
9528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = (hexDigitValue(q[1]) << 4) | hexDigitValue(q[2]);
9538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            q += 3;
9548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Decode the bytes into Unicode characters.
9578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        String decoded = (encoding.isValid() ? encoding : UTF8Encoding()).decode(buffer.data(), p - buffer.data());
9588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (decoded.isEmpty())
9598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Build up the string with what we just skipped and what we just decoded.
9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(str.characters() + decodedPosition, encodedRunPosition - decodedPosition);
9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(decoded.characters(), decoded.length());
9648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        decodedPosition = encodedRunEnd;
9658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.append(str.characters() + decodedPosition, length - decodedPosition);
9688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return String::adopt(result);
9708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// Caution: This function does not bounds check.
9732fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic void appendEscapedChar(char*& buffer, unsigned char c)
9742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
9752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    *buffer++ = '%';
9762bde8e466a4451c7319e3a072d118917957d6554Steve Block    placeByteAsHex(c, buffer);
9772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
9782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void appendEscapingBadChars(char*& buffer, const char* strStart, size_t length)
9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = buffer;
9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* str = strStart;
9848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* strEnd = strStart + length;
9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (str < strEnd) {
9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = *str++;
9878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isBadChar(c)) {
9882fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if (c == '%' || c == '?')
9898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *p++ = c;
9902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            else if (c != 0x09 && c != 0x0a && c != 0x0d)
9912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                appendEscapedChar(p, c);
9922fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        } else
9938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = c;
9942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
9952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    buffer = p;
9972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
9982fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
999e48d279609693b4d164199748c93ad791547c649Steve Blockstatic void escapeAndAppendNonHierarchicalPart(char*& buffer, const char* strStart, size_t length)
10002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
10012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    char* p = buffer;
10022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const char* str = strStart;
10042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const char* strEnd = strStart + length;
10052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    while (str < strEnd) {
10062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        unsigned char c = *str++;
10072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Strip CR, LF and Tab from fragments, per:
10082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // https://bugs.webkit.org/show_bug.cgi?id=8770
10092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (c == 0x09 || c == 0x0a || c == 0x0d)
10102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            continue;
10112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Chrome and IE allow non-ascii characters in fragments, however doing
10132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // so would hit an ASSERT in checkEncodedString, so for now we don't.
10142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (c < 0x20 || c >= 127) {
10152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            appendEscapedChar(p, c);
10162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            continue;
10178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        *p++ = c;
10198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer = p;
10228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// copy a path, accounting for "." and ".." segments
10258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd)
10268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* bufferPathStart = dst;
10288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // empty path is a special case, and need not have a leading slash
10308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (srcStart != srcEnd) {
10318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* baseStringStart = src + srcStart;
10328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* baseStringEnd = src + srcEnd;
10338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* baseStringPos = baseStringStart;
10348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // this code is unprepared for paths that do not begin with a
10368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // slash and we should always have one in the source string
10378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(baseStringPos[0] == '/');
10388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy the leading slash into the destination
10408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *dst = *baseStringPos;
10418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        baseStringPos++;
10428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        dst++;
10438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (baseStringPos < baseStringEnd) {
10458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (baseStringPos[0] == '.' && dst[-1] == '/') {
10468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (baseStringPos[1] == '/' || baseStringPos + 1 == baseStringEnd) {
10478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // skip over "." segment
10488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    baseStringPos += 2;
10498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    continue;
10508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else if (baseStringPos[1] == '.' && (baseStringPos[2] == '/' ||
10518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                       baseStringPos + 2 == baseStringEnd)) {
10528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // skip over ".." segment and rewind the last segment
10538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // the RFC leaves it up to the app to decide what to do with excess
10548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // ".." segments - we choose to drop them since some web content
10558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // relies on this.
10568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    baseStringPos += 3;
10578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (dst > bufferPathStart + 1)
10588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        dst--;
10598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    while (dst > bufferPathStart && dst[-1] != '/')
10608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        dst--;
10618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    continue;
10628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
10638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
10648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *dst = *baseStringPos;
10668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            baseStringPos++;
10678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            dst++;
10688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *dst = '\0';
10718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return dst - bufferPathStart;
10728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool hasSlashDotOrDotDot(const char* str)
10758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned char* p = reinterpret_cast<const unsigned char*>(str);
10778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!*p)
10788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
10798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned char pc = *p;
10808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (unsigned char c = *++p) {
10818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '.' && (pc == '/' || pc == '.'))
10828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return true;
10838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pc = c;
10848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
10868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool matchLetter(char c, char lowercaseLetter)
10898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (c | 0x20) == lowercaseLetter;
10918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::parse(const String& string)
10948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1095635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    checkEncodedString(string);
1096635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1097635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CharBuffer buffer(string.length() + 1);
1098635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    copyASCII(string.characters(), string.length(), buffer.data());
1099635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    buffer[string.length()] = '\0';
11008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(buffer.data(), &string);
11018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11032fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic inline bool equal(const char* a, size_t lenA, const char* b, size_t lenB)
11042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
11052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (lenA != lenB)
11062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return false;
11072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return !strncmp(a, b, lenA);
11082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
11092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
11102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// List of default schemes is taken from google-url:
11112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// http://code.google.com/p/google-url/source/browse/trunk/src/url_canon_stdurl.cc#120
11122fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic inline bool isDefaultPortForScheme(const char* port, size_t portLength, const char* scheme, size_t schemeLength)
11132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
11142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // This switch is theoretically a performance optimization.  It came over when
11152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // the code was moved from google-url, but may be removed later.
11162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    switch (schemeLength) {
11172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 2:
11182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("ws", 2, scheme, schemeLength) && equal("80", 2, port, portLength);
11192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 3:
11202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (equal("ftp", 3, scheme, schemeLength))
11212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            return equal("21", 2, port, portLength);
11222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (equal("wss", 3, scheme, schemeLength))
11232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            return equal("443", 3, port, portLength);
11242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        break;
11252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 4:
11262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("http", 4, scheme, schemeLength) && equal("80", 2, port, portLength);
11272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 5:
11282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("https", 5, scheme, schemeLength) && equal("443", 3, port, portLength);
11292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 6:
11302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("gopher", 6, scheme, schemeLength) && equal("70", 2, port, portLength);
11312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
11322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return false;
11332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
11342fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
11352bde8e466a4451c7319e3a072d118917957d6554Steve Blockstatic inline bool hostPortIsEmptyButCredentialsArePresent(int hostStart, int portEnd, char userEndChar)
11362bde8e466a4451c7319e3a072d118917957d6554Steve Block{
11372bde8e466a4451c7319e3a072d118917957d6554Steve Block    return userEndChar == '@' && hostStart == portEnd;
11382bde8e466a4451c7319e3a072d118917957d6554Steve Block}
11392bde8e466a4451c7319e3a072d118917957d6554Steve Block
1140db951b2c4c8fce1304a13d97dec4ae14be629380Steve Blockstatic bool isNonFileHierarchicalScheme(const char* scheme, size_t schemeLength)
1141db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block{
1142db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    switch (schemeLength) {
1143db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    case 2:
1144db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        return equal("ws", 2, scheme, schemeLength);
1145db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    case 3:
1146db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        return equal("ftp", 3, scheme, schemeLength) || equal("wss", 3, scheme, schemeLength);
1147db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    case 4:
1148db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        return equal("http", 4, scheme, schemeLength);
1149db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    case 5:
1150db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        return equal("https", 5, scheme, schemeLength);
1151db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    case 6:
1152db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        return equal("gopher", 6, scheme, schemeLength);
1153db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    }
1154db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    return false;
1155db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block}
1156db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block
11578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::parse(const char* url, const String* originalString)
11588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!url || url[0] == '\0') {
11608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // valid URL must be non-empty
11618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = originalString ? *originalString : url;
11628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
11638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!isSchemeFirstChar(url[0])) {
11678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // scheme must start with an alphabetic character
11688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = originalString ? *originalString : url;
11698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
11708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int schemeEnd = 0;
11748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (isSchemeChar(url[schemeEnd]))
11758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        schemeEnd++;
11768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (url[schemeEnd] != ':') {
11788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = originalString ? *originalString : url;
11798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
11808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int userStart = schemeEnd + 1;
11848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int userEnd;
11858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int passwordStart;
11868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int passwordEnd;
11878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostStart;
11888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostEnd;
11898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int portStart;
11908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int portEnd;
11918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool hierarchical = url[schemeEnd + 1] == '/';
1193db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    bool hasSecondSlash = hierarchical && url[schemeEnd + 2] == '/';
11948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool isFile = schemeEnd == 4
11968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[0], 'f')
11978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[1], 'i')
11988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[2], 'l')
11998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[3], 'e');
12008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12018f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    m_protocolInHTTPFamily = matchLetter(url[0], 'h')
12028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[1], 't')
12038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[2], 't')
12048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[3], 'p')
12058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && (url[4] == ':' || (matchLetter(url[4], 's') && url[5] == ':'));
12068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1207db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    if ((hierarchical && hasSecondSlash) || isNonFileHierarchicalScheme(url, schemeEnd)) {
12088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The part after the scheme is either a net_path or an abs_path whose first path segment is empty.
12098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Attempt to find an authority.
12108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: Authority characters may be scanned twice, and it would be nice to be faster.
1211db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block
1212db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        if (hierarchical)
1213db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block            userStart++;
1214db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block        if (hasSecondSlash)
1215db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block            userStart++;
12168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        userEnd = userStart;
12178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int colonPos = 0;
12198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (isUserInfoChar(url[userEnd])) {
12208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (url[userEnd] == ':' && colonPos == 0)
12218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                colonPos = userEnd;
12228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userEnd++;
12238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (url[userEnd] == '@') {
12268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // actual end of the userinfo, start on the host
12278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (colonPos != 0) {
12288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                passwordEnd = userEnd;
12298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                userEnd = colonPos;
12308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                passwordStart = colonPos + 1;
12318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else
12328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                passwordStart = passwordEnd = userEnd;
12338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostStart = passwordEnd + 1;
12358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else if (url[userEnd] == '[' || isPathSegmentEndChar(url[userEnd])) {
12368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // hit the end of the authority, must have been no user
12378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // or looks like an IPv6 hostname
12388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // either way, try to parse it as a hostname
12398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userEnd = userStart;
12408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            passwordStart = passwordEnd = userEnd;
12418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostStart = userStart;
12428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
12438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // invalid character
12448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_string = originalString ? *originalString : url;
12458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            invalidate();
12468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
12478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostEnd = hostStart;
12508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // IPV6 IP address
12528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (url[hostEnd] == '[') {
12538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostEnd++;
12548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (isIPv6Char(url[hostEnd]))
12558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostEnd++;
12568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (url[hostEnd] == ']')
12578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostEnd++;
12588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else {
12598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // invalid character
12608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_string = originalString ? *originalString : url;
12618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                invalidate();
12628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
12638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
12648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
12658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (isHostnameChar(url[hostEnd]))
12668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostEnd++;
12678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (url[hostEnd] == ':') {
12708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portStart = portEnd = hostEnd + 1;
12718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // possible start of port
12738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portEnd = portStart;
12748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (isASCIIDigit(url[portEnd]))
12758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                portEnd++;
12768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else
12778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portStart = portEnd = hostEnd;
12788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!isPathSegmentEndChar(url[portEnd])) {
12808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // invalid character
12818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_string = originalString ? *originalString : url;
12828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            invalidate();
12838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
12848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12862bde8e466a4451c7319e3a072d118917957d6554Steve Block        if (hostPortIsEmptyButCredentialsArePresent(hostStart, portEnd, url[userEnd])) {
12872bde8e466a4451c7319e3a072d118917957d6554Steve Block            // in this circumstance, act as if there is an erroneous hostname containing an '@'
12882bde8e466a4451c7319e3a072d118917957d6554Steve Block            userEnd = userStart;
12892bde8e466a4451c7319e3a072d118917957d6554Steve Block            hostStart = userEnd;
12902bde8e466a4451c7319e3a072d118917957d6554Steve Block        }
12912bde8e466a4451c7319e3a072d118917957d6554Steve Block
12928f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        if (userStart == portEnd && !m_protocolInHTTPFamily && !isFile) {
12938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // No authority found, which means that this is not a net_path, but rather an abs_path whose first two
12948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // path segments are empty. For file, http and https only, an empty authority is allowed.
12958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userStart -= 2;
12968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userEnd = userStart;
12978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            passwordStart = userEnd;
12988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            passwordEnd = passwordStart;
12998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostStart = passwordEnd;
13008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostEnd = hostStart;
13018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portStart = hostEnd;
13028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portEnd = hostEnd;
13038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
13048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
13058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // the part after the scheme must be an opaque_part or an abs_path
13068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        userEnd = userStart;
13078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        passwordStart = passwordEnd = userEnd;
13088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostStart = hostEnd = passwordEnd;
13098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        portStart = portEnd = hostEnd;
13108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
13118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int pathStart = portEnd;
13138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int pathEnd = pathStart;
13148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (url[pathEnd] && url[pathEnd] != '?' && url[pathEnd] != '#')
13158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd++;
13168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int queryStart = pathEnd;
13188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int queryEnd = queryStart;
13198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (url[queryStart] == '?') {
13208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (url[queryEnd] && url[queryEnd] != '#')
13218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            queryEnd++;
13228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
13238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int fragmentStart = queryEnd;
13258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int fragmentEnd = fragmentStart;
13268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (url[fragmentStart] == '#') {
13278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fragmentStart++;
13288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fragmentEnd = fragmentStart;
13298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (url[fragmentEnd])
13308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            fragmentEnd++;
13318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
13328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // assemble it all, remembering the real ranges
13348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<char, 4096> buffer(fragmentEnd * 3 + 1);
13368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char *p = buffer.data();
13388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char *strPtr = url;
13398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // copy in the scheme
13418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char *schemeEndPtr = url + schemeEnd;
13428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (strPtr < schemeEndPtr)
13432fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        *p++ = toASCIILower(*strPtr++);
13448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_schemeEnd = p - buffer.data();
13458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool hostIsLocalHost = portEnd - userStart == 9
13478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart], 'l')
13488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+1], 'o')
13498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+2], 'c')
13508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+3], 'a')
13518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+4], 'l')
13528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+5], 'h')
13538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+6], 'o')
13548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+7], 's')
13558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+8], 't');
13568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // File URLs need a host part unless it is just file:// or file://localhost
13588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool degenFilePath = pathStart == pathEnd && (hostStart == hostEnd || hostIsLocalHost);
13598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool haveNonHostAuthorityPart = userStart != userEnd || passwordStart != passwordEnd || portStart != portEnd;
13618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add ":" after scheme
13638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *p++ = ':';
13648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // if we have at least one authority part or a file URL - add "//" and authority
13668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isFile ? !degenFilePath : (haveNonHostAuthorityPart || hostStart != hostEnd)) {
13678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '/';
13688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '/';
13698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_userStart = p - buffer.data();
13718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy in the user
13738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        strPtr = url + userStart;
13748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* userEndPtr = url + userEnd;
13758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (strPtr < userEndPtr)
13768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = *strPtr++;
13778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_userEnd = p - buffer.data();
13788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy in the password
13808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (passwordEnd != passwordStart) {
13818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = ':';
13828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            strPtr = url + passwordStart;
13838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const char* passwordEndPtr = url + passwordEnd;
13848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (strPtr < passwordEndPtr)
13858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *p++ = *strPtr++;
13868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
13878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_passwordEnd = p - buffer.data();
13888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If we had any user info, add "@"
13908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (p - buffer.data() != m_userStart)
13918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = '@';
13928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy in the host, except in the case of a file URL with authority="localhost"
13948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!(isFile && hostIsLocalHost && !haveNonHostAuthorityPart)) {
13958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            strPtr = url + hostStart;
13968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const char* hostEndPtr = url + hostEnd;
13978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (strPtr < hostEndPtr)
13988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *p++ = *strPtr++;
13998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
14008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_hostEnd = p - buffer.data();
14018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Copy in the port if the URL has one (and it's not default).
14038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hostEnd != portStart) {
14042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            const char* portStr = url + portStart;
14052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            size_t portLength = portEnd - portStart;
14062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if (portLength && !isDefaultPortForScheme(portStr, portLength, buffer.data(), m_schemeEnd)) {
14072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                *p++ = ':';
14082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                const char* portEndPtr = url + portEnd;
14092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                while (portStr < portEndPtr)
14102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    *p++ = *portStr++;
14112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            }
14128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
14138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_portEnd = p - buffer.data();
14148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
14158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_userStart = m_userEnd = m_passwordEnd = m_hostEnd = m_portEnd = p - buffer.data();
14168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For canonicalization, ensure we have a '/' for no path.
1418db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    // Do this only for URL with protocol http or https.
1419db951b2c4c8fce1304a13d97dec4ae14be629380Steve Block    if (m_protocolInHTTPFamily && pathEnd == pathStart)
14208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '/';
14218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add path, escaping bad characters
1423e48d279609693b4d164199748c93ad791547c649Steve Block    if (!hierarchical)
1424e48d279609693b4d164199748c93ad791547c649Steve Block        escapeAndAppendNonHierarchicalPart(p, url + pathStart, pathEnd - pathStart);
1425e48d279609693b4d164199748c93ad791547c649Steve Block    else if (!hasSlashDotOrDotDot(url))
14268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        appendEscapingBadChars(p, url + pathStart, pathEnd - pathStart);
14278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
14288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CharBuffer pathBuffer(pathEnd - pathStart + 1);
14298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        size_t length = copyPathRemovingDots(pathBuffer.data(), url, pathStart, pathEnd);
14308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        appendEscapingBadChars(p, pathBuffer.data(), length);
14318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathEnd = p - buffer.data();
14348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find the position after the last slash in the path, or
14368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // the position before the path if there are no slashes in it.
14378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
14388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = m_pathEnd; i > m_portEnd; --i) {
14398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (buffer[i - 1] == '/')
14408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
14418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathAfterLastSlash = i;
14438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add query, escaping bad characters
14458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    appendEscapingBadChars(p, url + queryStart, queryEnd - queryStart);
14468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_queryEnd = p - buffer.data();
14478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add fragment, escaping bad characters
14498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fragmentEnd != queryEnd) {
14508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '#';
1451e48d279609693b4d164199748c93ad791547c649Steve Block        escapeAndAppendNonHierarchicalPart(p, url + fragmentStart, fragmentEnd - fragmentStart);
14528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_fragmentEnd = p - buffer.data();
14548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
14568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If we didn't end up actually changing the original string and
14588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // it was already in a String, reuse it to avoid extra allocation.
14598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (originalString && originalString->length() == static_cast<unsigned>(m_fragmentEnd) && strncmp(buffer.data(), url, m_fragmentEnd) == 0)
14608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = *originalString;
14618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
14628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = String(buffer.data(), m_fragmentEnd);
14638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_isValid = true;
14658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14670bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool equalIgnoringFragmentIdentifier(const KURL& a, const KURL& b)
14688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (a.m_queryEnd != b.m_queryEnd)
14708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
14718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned queryLength = a.m_queryEnd;
14728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (unsigned i = 0; i < queryLength; ++i)
14738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (a.string()[i] != b.string()[i])
14748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
14758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
14768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool protocolHostAndPortAreEqual(const KURL& a, const KURL& b)
14798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (a.m_schemeEnd != b.m_schemeEnd)
14818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
148221939df44de1705786c545cd1bf519d47250322dBen Murdoch
14838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostStartA = a.hostStart();
148421939df44de1705786c545cd1bf519d47250322dBen Murdoch    int hostLengthA = a.hostEnd() - hostStartA;
14858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostStartB = b.hostStart();
148621939df44de1705786c545cd1bf519d47250322dBen Murdoch    int hostLengthB = b.hostEnd() - b.hostStart();
148721939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (hostLengthA != hostLengthB)
14888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
14898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check the scheme
14918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < a.m_schemeEnd; ++i)
14928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (a.string()[i] != b.string()[i])
14938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
149421939df44de1705786c545cd1bf519d47250322dBen Murdoch
14958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // And the host
149621939df44de1705786c545cd1bf519d47250322dBen Murdoch    for (int i = 0; i < hostLengthA; ++i)
149721939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (a.string()[hostStartA + i] != b.string()[hostStartB + i])
14988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
149921939df44de1705786c545cd1bf519d47250322dBen Murdoch
15008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (a.port() != b.port())
15018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
15028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
15048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
15058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString encodeWithURLEscapeSequences(const String& notEncodedString)
15078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
15088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CString asUTF8 = notEncodedString.utf8();
15098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CharBuffer buffer(asUTF8.length() * 3 + 1);
15118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = buffer.data();
15128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* str = asUTF8.data();
15148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* strEnd = str + asUTF8.length();
15158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (str < strEnd) {
15168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = *str++;
15172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (isBadChar(c))
15182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            appendEscapedChar(p, c);
15192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        else
15208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = c;
15218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
15228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
15248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return String(buffer.data(), p - buffer.data());
15268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
15278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Appends the punycoded hostname identified by the given string and length to
15298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// the output buffer. The result will not be null terminated.
15308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void appendEncodedHostname(UCharBuffer& buffer, const UChar* str, unsigned strLen)
15318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
15328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Needs to be big enough to hold an IDN-encoded name.
15338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
15348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned hostnameBufferLength = 2048;
15358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (strLen > hostnameBufferLength || charactersAreAllASCII(str, strLen)) {
15378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer.append(str, strLen);
15388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
15398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
15408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if USE(ICU_UNICODE)
15428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UChar hostnameBuffer[hostnameBufferLength];
15438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UErrorCode error = U_ZERO_ERROR;
15448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int32_t numCharactersConverted = uidna_IDNToASCII(str, strLen, hostnameBuffer,
15458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostnameBufferLength, UIDNA_ALLOW_UNASSIGNED, 0, &error);
15468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (error == U_ZERO_ERROR)
15478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer.append(hostnameBuffer, numCharactersConverted);
15488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#elif USE(QT4_UNICODE)
15498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    QByteArray result = QUrl::toAce(String(str, strLen));
15508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.append(result.constData(), result.length());
1551d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(GLIB_UNICODE)
1552d0825bca7fe65beaee391d30da42e937db621564Steve Block    GOwnPtr<gchar> utf8Hostname;
1553d0825bca7fe65beaee391d30da42e937db621564Steve Block    GOwnPtr<GError> utf8Err;
1554d0825bca7fe65beaee391d30da42e937db621564Steve Block    utf8Hostname.set(g_utf16_to_utf8(str, strLen, 0, 0, &utf8Err.outPtr()));
1555d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (utf8Err)
1556d0825bca7fe65beaee391d30da42e937db621564Steve Block        return;
1557d0825bca7fe65beaee391d30da42e937db621564Steve Block
1558d0825bca7fe65beaee391d30da42e937db621564Steve Block    GOwnPtr<gchar> encodedHostname;
1559d0825bca7fe65beaee391d30da42e937db621564Steve Block    encodedHostname.set(g_hostname_to_ascii(utf8Hostname.get()));
1560d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (!encodedHostname)
1561d0825bca7fe65beaee391d30da42e937db621564Steve Block        return;
1562d0825bca7fe65beaee391d30da42e937db621564Steve Block
1563d0825bca7fe65beaee391d30da42e937db621564Steve Block    buffer.append(encodedHostname.get(), strlen(encodedHostname.get()));
15648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
15658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
15668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void findHostnamesInMailToURL(const UChar* str, int strLen, Vector<pair<int, int> >& nameRanges)
15688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
15698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // In a mailto: URL, host names come after a '@' character and end with a '>' or ',' or '?' or end of string character.
15708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Skip quoted strings so that characters in them don't confuse us.
15718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // When we find a '?' character, we are past the part of the URL that contains host names.
15728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    nameRanges.clear();
15748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int p = 0;
15768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
15778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find start of host name or of quoted string.
15788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int hostnameOrStringStart = findFirstOf(str, strLen, p, "\"@?");
15798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hostnameOrStringStart == -1)
15808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
15818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar c = str[hostnameOrStringStart];
15828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = hostnameOrStringStart + 1;
15838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '?')
15858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
15868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '@') {
15888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Find end of host name.
15898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int hostnameStart = p;
15908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int hostnameEnd = findFirstOf(str, strLen, p, ">,?");
15918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            bool done;
15928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (hostnameEnd == -1) {
15938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostnameEnd = strLen;
15948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                done = true;
15958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
15968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                p = hostnameEnd;
15978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                done = false;
15988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
15998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            nameRanges.append(make_pair(hostnameStart, hostnameEnd));
16018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (done)
16038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
16048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
16058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Skip quoted string.
16068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(c == '"');
16078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (1) {
16088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                int escapedCharacterOrStringEnd = findFirstOf(str, strLen, p, "\"\\");
16098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (escapedCharacterOrStringEnd == -1)
16108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
16118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                c = str[escapedCharacterOrStringEnd];
16138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                p = escapedCharacterOrStringEnd + 1;
16148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // If we are the end of the string, then break from the string loop back to the host name loop.
16168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (c == '"')
16178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    break;
16188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Skip escaped character.
16208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                ASSERT(c == '\\');
16218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (p == strLen)
16228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
16238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                ++p;
16258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
16268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
16278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
16298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool findHostnameInHierarchicalURL(const UChar* str, int strLen, int& startOffset, int& endOffset)
16318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
16328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find the host name in a hierarchical URL.
16338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // It comes after a "://" sequence, with scheme characters preceding, and
16348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // this should be the first colon in the string.
16358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // It ends with the end of the string or a ":" or a path segment ending character.
16368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If there is a "@" character, the host part is just the part after the "@".
16378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int separator = findFirstOf(str, strLen, 0, ":");
16388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (separator == -1 || separator + 2 >= strLen ||
16398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str[separator + 1] != '/' || str[separator + 2] != '/')
16408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
16418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check that all characters before the :// are valid scheme characters.
16438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!isSchemeFirstChar(str[0]))
16448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
16458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 1; i < separator; ++i) {
16468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!isSchemeChar(str[i]))
16478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
16488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Start after the separator.
16518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int authorityStart = separator + 3;
16528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find terminating character.
16548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostnameEnd = strLen;
16558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = authorityStart; i < strLen; ++i) {
16568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar c = str[i];
16578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == ':' || (isPathSegmentEndChar(c) && c != 0)) {
16588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostnameEnd = i;
16598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
16608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
16618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find "@" for the start of the host name.
16648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int userInfoTerminator = findFirstOf(str, strLen, authorityStart, "@");
16658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostnameStart;
16668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (userInfoTerminator == -1 || userInfoTerminator > hostnameEnd)
16678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostnameStart = authorityStart;
16688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
16698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostnameStart = userInfoTerminator + 1;
16708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    startOffset = hostnameStart;
16728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    endOffset = hostnameEnd;
16738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
16748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
16758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Converts all hostnames found in the given input to punycode, preserving the
16778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// rest of the URL unchanged. The output will NOT be null-terminated.
16788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void encodeHostnames(const String& str, UCharBuffer& output)
16798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
16808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    output.clear();
16818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (protocolIs(str, "mailto")) {
16838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Vector<pair<int, int> > hostnameRanges;
16848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        findHostnamesInMailToURL(str.characters(), str.length(), hostnameRanges);
16858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int n = hostnameRanges.size();
16868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int p = 0;
16878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (int i = 0; i < n; ++i) {
16888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const pair<int, int>& r = hostnameRanges[i];
16898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(&str.characters()[p], r.first - p);
16908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            appendEncodedHostname(output, &str.characters()[r.first], r.second - r.first);
16918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p = r.second;
16928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
16938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // This will copy either everything after the last hostname, or the
16948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // whole thing if there is no hostname.
16958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        output.append(&str.characters()[p], str.length() - p);
16968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
16978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int hostStart, hostEnd;
16988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (findHostnameInHierarchicalURL(str.characters(), str.length(), hostStart, hostEnd)) {
16998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(str.characters(), hostStart); // Before hostname.
17008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            appendEncodedHostname(output, &str.characters()[hostStart], hostEnd - hostStart);
17018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(&str.characters()[hostEnd], str.length() - hostEnd); // After hostname.
17028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
17038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // No hostname to encode, return the input.
17048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(str.characters(), str.length());
17058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
17068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
17078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void encodeRelativeString(const String& rel, const TextEncoding& encoding, CharBuffer& output)
17108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UCharBuffer s;
17128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    encodeHostnames(rel, s);
17138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    TextEncoding pathEncoding(UTF8Encoding()); // Path is always encoded as UTF-8; other parts may depend on the scheme.
17158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int pathEnd = -1;
17175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIsJavaScript(rel)) {
17188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find the first instance of either # or ?, keep pathEnd at -1 otherwise.
17198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = findFirstOf(s.data(), s.size(), 0, "#?");
17208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
17218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (pathEnd == -1) {
17238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CString decoded = pathEncoding.encode(s.data(), s.size(), URLEncodedEntitiesForUnencodables);
17248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        output.resize(decoded.length());
17258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memcpy(output.data(), decoded.data(), decoded.length());
17268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
17278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CString pathDecoded = pathEncoding.encode(s.data(), pathEnd, URLEncodedEntitiesForUnencodables);
17288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Unencodable characters in URLs are represented by converting
17298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // them to XML entities and escaping non-alphanumeric characters.
17308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CString otherDecoded = encoding.encode(s.data() + pathEnd, s.size() - pathEnd, URLEncodedEntitiesForUnencodables);
17318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        output.resize(pathDecoded.length() + otherDecoded.length());
17338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memcpy(output.data(), pathDecoded.data(), pathDecoded.length());
17348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memcpy(output.data() + pathDecoded.length(), otherDecoded.data(), otherDecoded.length());
17358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
17368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    output.append('\0'); // null-terminate the output.
17378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic String substituteBackslashes(const String& string)
17408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1741f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t questionPos = string.find('?');
1742f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t hashPos = string.find('#');
1743f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned pathEnd;
17448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1745f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (hashPos != notFound && (questionPos == notFound || questionPos > hashPos))
17468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = hashPos;
1747f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    else if (questionPos != notFound)
17488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = questionPos;
17498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
17508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = string.length();
17518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return string.left(pathEnd).replace('\\','/') + string.substring(pathEnd);
17538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool KURL::isHierarchical() const
17568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
17588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
17598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_string[m_schemeEnd] == ':');
17608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string[m_schemeEnd + 1] == '/';
17618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::copyToBuffer(CharBuffer& buffer) const
17648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This throws away the high bytes of all the characters in the string!
17668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // That's fine for a valid URL, which is all ASCII, but not for invalid URLs.
17678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.resize(m_string.length());
17688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    copyASCII(m_string.characters(), m_string.length(), buffer.data());
17698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool protocolIs(const String& url, const char* protocol)
17728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Do the comparison without making a new string object.
17748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    assertProtocolIsGood(protocol);
17758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; ; ++i) {
17768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!protocol[i])
17778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return url[i] == ':';
17788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (toASCIILower(url[i]) != protocol[i])
17798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
17808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
17818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1783643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool isValidProtocol(const String& protocol)
1784643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
1785d0825bca7fe65beaee391d30da42e937db621564Steve Block    // RFC3986: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
1786d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (protocol.isEmpty())
1787d0825bca7fe65beaee391d30da42e937db621564Steve Block        return false;
1788643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!isSchemeFirstChar(protocol[0]))
1789643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return false;
1790643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned protocolLength = protocol.length();
1791643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (unsigned i = 1; i < protocolLength; i++) {
1792643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (!isSchemeChar(protocol[i]))
1793643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return false;
1794643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
1795643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return true;
1796643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
1797643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
179881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#ifndef NDEBUG
179981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid KURL::print() const
180081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
180181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    printf("%s\n", m_string.utf8().data());
180281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
180381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#endif
180481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
180581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#endif // !USE(GOOGLEURL)
180681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
180781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString KURL::strippedForUseAsReferrer() const
180881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
180981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    KURL referrer(*this);
181081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    referrer.setUser(String());
181181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    referrer.setPass(String());
181281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    referrer.removeFragmentIdentifier();
181381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return referrer.string();
181481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
181581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
181681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool KURL::isLocalFile() const
181781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
181881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Including feed here might be a bad idea since drag and drop uses this check
181981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // and including feed would allow feeds to potentially let someone's blog
182081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // read the contents of the clipboard on a drag, even without a drop.
182181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Likewise with using the FrameLoader::shouldTreatURLAsLocal() function.
182281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return protocolIs("file");
182381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
182481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
182581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool protocolIsJavaScript(const String& url)
182681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
182781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return protocolIs(url, "javascript");
182881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
182981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
183081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochconst KURL& blankURL()
183181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
183281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    DEFINE_STATIC_LOCAL(KURL, staticBlankURL, (ParsedURLString, "about:blank"));
183381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return staticBlankURL;
183481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
183581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1836643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool isDefaultPortForProtocol(unsigned short port, const String& protocol)
1837643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
1838643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (protocol.isEmpty())
1839643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return false;
1840643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1841643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    typedef HashMap<String, unsigned, CaseFoldingHash> DefaultPortsMap;
1842643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ());
1843643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (defaultPorts.isEmpty()) {
1844643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("http", 80);
1845643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("https", 443);
1846643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("ftp", 21);
1847643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("ftps", 990);
1848643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
1849643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return defaultPorts.get(protocol) == port;
1850643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
1851643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1852643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool portAllowed(const KURL& url)
1853643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
1854643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned short port = url.port();
1855643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1856643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Since most URLs don't have a port, return early for the "no port" case.
1857643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!port)
1858643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1859643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1860643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // This blocked port list matches the port blocking that Mozilla implements.
1861643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information.
1862643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    static const unsigned short blockedPortList[] = {
1863643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        1,    // tcpmux
1864643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        7,    // echo
1865643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        9,    // discard
1866643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        11,   // systat
1867643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        13,   // daytime
1868643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        15,   // netstat
1869643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        17,   // qotd
1870643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        19,   // chargen
1871643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        20,   // FTP-data
1872643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        21,   // FTP-control
1873643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        22,   // SSH
1874643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        23,   // telnet
1875643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        25,   // SMTP
1876643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        37,   // time
1877643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        42,   // name
1878643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        43,   // nicname
1879643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        53,   // domain
1880643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        77,   // priv-rjs
1881643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        79,   // finger
1882643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        87,   // ttylink
1883643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        95,   // supdup
1884643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        101,  // hostriame
1885643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        102,  // iso-tsap
1886643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        103,  // gppitnp
1887643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        104,  // acr-nema
1888643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        109,  // POP2
1889643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        110,  // POP3
1890643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        111,  // sunrpc
1891643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        113,  // auth
1892643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        115,  // SFTP
1893643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        117,  // uucp-path
1894643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        119,  // nntp
1895643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        123,  // NTP
1896643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        135,  // loc-srv / epmap
1897643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        139,  // netbios
1898643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        143,  // IMAP2
1899643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        179,  // BGP
1900643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        389,  // LDAP
1901643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        465,  // SMTP+SSL
1902643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        512,  // print / exec
1903643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        513,  // login
1904643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        514,  // shell
1905643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        515,  // printer
1906643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        526,  // tempo
1907643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        530,  // courier
1908643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        531,  // Chat
1909643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        532,  // netnews
1910643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        540,  // UUCP
1911643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        556,  // remotefs
1912643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        563,  // NNTP+SSL
1913643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        587,  // ESMTP
1914643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        601,  // syslog-conn
1915643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        636,  // LDAP+SSL
1916643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        993,  // IMAP+SSL
1917643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        995,  // POP3+SSL
1918643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        2049, // NFS
1919643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        3659, // apple-sasl / PasswordServer [Apple addition]
1920643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        4045, // lockd
1921643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        6000, // X11
19225e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6665, // Alternate IRC [Apple addition]
19235e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6666, // Alternate IRC [Apple addition]
19245e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6667, // Standard IRC [Apple addition]
19255e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6668, // Alternate IRC [Apple addition]
19265e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6669, // Alternate IRC [Apple addition]
1927dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        invalidPortNumber, // Used to block all invalid port numbers
1928643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    };
19294576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    const unsigned short* const blockedPortListEnd = blockedPortList + WTF_ARRAY_LENGTH(blockedPortList);
1930643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1931643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#ifndef NDEBUG
1932643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // The port list must be sorted for binary_search to work.
1933643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    static bool checkedPortList = false;
1934643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!checkedPortList) {
1935643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        for (const unsigned short* p = blockedPortList; p != blockedPortListEnd - 1; ++p)
1936643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            ASSERT(*p < *(p + 1));
1937643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        checkedPortList = true;
1938643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
1939643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#endif
1940643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1941643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // If the port is not in the blocked port list, allow it.
1942643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!binary_search(blockedPortList, blockedPortListEnd, port))
1943643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1944643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1945643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Allow ports 21 and 22 for FTP URLs, as Mozilla does.
1946643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if ((port == 21 || port == 22) && url.protocolIs("ftp"))
1947643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1948643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1949643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Allow any port number in a file URL, since the port number is ignored.
1950643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (url.protocolIs("file"))
1951643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1952643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1953643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return false;
1954643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
1955643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
19568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString mimeTypeFromDataURL(const String& url)
19578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
19588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(protocolIs(url, "data"));
1959f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t index = url.find(';');
1960f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (index == notFound)
19618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        index = url.find(',');
1962f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (index != notFound) {
1963f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        if (index > 5)
1964f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick            return url.substring(5, index - 5);
19658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return "text/plain"; // Data URLs with no MIME type are considered text/plain.
19668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
19678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return "";
19688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
19698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
19708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1971