KURL.cpp revision 81bc750723a18f21cd17d1b173cd2a4dda9cea6e
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>
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/StdLibExtras.h>
34f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick#include <wtf/text/StringHash.h>
358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if USE(ICU_UNICODE)
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <unicode/uidna.h>
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#elif USE(QT4_UNICODE)
398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <QUrl>
40d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(GLIB_UNICODE)
41d0825bca7fe65beaee391d30da42e937db621564Steve Block#include <glib.h>
42dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "GOwnPtr.h"
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include <stdio.h>
468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace std;
488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace WTF;
498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef Vector<char, 512> CharBuffer;
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projecttypedef Vector<UChar, 512> UCharBuffer;
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic const unsigned maximumValidPortNumber = 0xFFFE;
5681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic const unsigned invalidPortNumber = 0xFFFF;
5781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
5881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#if !USE(GOOGLEURL)
5981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: This file makes too much use of the + operator on String.
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// We either have to optimize that operator so it doesn't involve
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// so many allocations, or change this to use Vector<UChar> instead.
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectenum URLCharacterClasses {
658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // alpha
668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SchemeFirstChar = 1 << 0,
678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // ( alpha | digit | "+" | "-" | "." )
698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    SchemeChar = 1 << 1,
708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // mark        = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // unreserved  = alphanum | mark
738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // ( unreserved | escaped | ";" | ":" | "&" | "=" | "+" | "$" | "," )
748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UserInfoChar = 1 << 2,
758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // alnum | "." | "-" | "%"
778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The above is what the specification says, but we are lenient to
788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // match existing practice and also allow:
798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // "_"
808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    HostnameChar = 1 << 3,
818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // hexdigit | ":" | "%"
838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    IPv6Char = 1 << 4,
848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // "#" | "?" | "/" | nul
868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    PathSegmentEndChar = 1 << 5,
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // not allowed in path
898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    BadChar = 1 << 6
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic const char hexDigits[17] = "0123456789ABCDEF";
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic const unsigned char characterClassTable[256] = {
958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 0 nul */ PathSegmentEndChar,    /* 1 soh */ BadChar,
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 2 stx */ BadChar,    /* 3 etx */ BadChar,
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 4 eot */ BadChar,    /* 5 enq */ BadChar,    /* 6 ack */ BadChar,    /* 7 bel */ BadChar,
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 8 bs */ BadChar,     /* 9 ht */ BadChar,     /* 10 nl */ BadChar,    /* 11 vt */ BadChar,
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 12 np */ BadChar,    /* 13 cr */ BadChar,    /* 14 so */ BadChar,    /* 15 si */ BadChar,
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 16 dle */ BadChar,   /* 17 dc1 */ BadChar,   /* 18 dc2 */ BadChar,   /* 19 dc3 */ BadChar,
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 20 dc4 */ BadChar,   /* 21 nak */ BadChar,   /* 22 syn */ BadChar,   /* 23 etb */ BadChar,
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 24 can */ BadChar,   /* 25 em */ BadChar,    /* 26 sub */ BadChar,   /* 27 esc */ BadChar,
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 28 fs */ BadChar,    /* 29 gs */ BadChar,    /* 30 rs */ BadChar,    /* 31 us */ BadChar,
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 32 sp */ BadChar,    /* 33  ! */ UserInfoChar,
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 34  " */ BadChar,    /* 35  # */ PathSegmentEndChar | BadChar,
1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 36  $ */ UserInfoChar,    /* 37  % */ UserInfoChar | HostnameChar | IPv6Char | BadChar,
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 38  & */ UserInfoChar,    /* 39  ' */ UserInfoChar,
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 40  ( */ UserInfoChar,    /* 41  ) */ UserInfoChar,
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 42  * */ UserInfoChar,    /* 43  + */ SchemeChar | UserInfoChar,
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 44  , */ UserInfoChar,
1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 45  - */ SchemeChar | UserInfoChar | HostnameChar,
112643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    /* 46  . */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 47  / */ PathSegmentEndChar,
1148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 48  0 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 49  1 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 50  2 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 51  3 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 52  4 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 53  5 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 54  6 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 55  7 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 56  8 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 57  9 */ SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 58  : */ UserInfoChar | IPv6Char,    /* 59  ; */ UserInfoChar,
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 60  < */ BadChar,    /* 61  = */ UserInfoChar,
1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 62  > */ BadChar,    /* 63  ? */ PathSegmentEndChar | BadChar,
1278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 64  @ */ 0,
1288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 65  A */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 66  B */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 67  C */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 68  D */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 69  E */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 70  F */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 71  G */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 72  H */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 73  I */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 74  J */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 75  K */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 76  L */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 77  M */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 78  N */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 79  O */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 80  P */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 81  Q */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 82  R */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 83  S */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 84  T */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 85  U */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 86  V */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 87  W */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 88  X */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 89  Y */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 90  Z */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 91  [ */ 0,
1558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 92  \ */ 0,    /* 93  ] */ 0,
1568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 94  ^ */ 0,
1578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 95  _ */ UserInfoChar | HostnameChar,
1588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 96  ` */ 0,
1598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 97  a */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 98  b */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 99  c */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 100  d */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 101  e */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 102  f */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar | IPv6Char,
1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 103  g */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 104  h */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 105  i */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 106  j */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 107  k */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 108  l */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 109  m */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 110  n */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 111  o */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 112  p */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 113  q */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 114  r */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 115  s */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 116  t */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 117  u */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 118  v */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 119  w */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 120  x */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 121  y */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 122  z */ SchemeFirstChar | SchemeChar | UserInfoChar | HostnameChar,
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 123  { */ 0,
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 124  | */ 0,   /* 125  } */ 0,   /* 126  ~ */ UserInfoChar,   /* 127 del */ BadChar,
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 128 */ BadChar, /* 129 */ BadChar, /* 130 */ BadChar, /* 131 */ BadChar,
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 132 */ BadChar, /* 133 */ BadChar, /* 134 */ BadChar, /* 135 */ BadChar,
1898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 136 */ BadChar, /* 137 */ BadChar, /* 138 */ BadChar, /* 139 */ BadChar,
1908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 140 */ BadChar, /* 141 */ BadChar, /* 142 */ BadChar, /* 143 */ BadChar,
1918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 144 */ BadChar, /* 145 */ BadChar, /* 146 */ BadChar, /* 147 */ BadChar,
1928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 148 */ BadChar, /* 149 */ BadChar, /* 150 */ BadChar, /* 151 */ BadChar,
1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 152 */ BadChar, /* 153 */ BadChar, /* 154 */ BadChar, /* 155 */ BadChar,
1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 156 */ BadChar, /* 157 */ BadChar, /* 158 */ BadChar, /* 159 */ BadChar,
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 160 */ BadChar, /* 161 */ BadChar, /* 162 */ BadChar, /* 163 */ BadChar,
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 164 */ BadChar, /* 165 */ BadChar, /* 166 */ BadChar, /* 167 */ BadChar,
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 168 */ BadChar, /* 169 */ BadChar, /* 170 */ BadChar, /* 171 */ BadChar,
1988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 172 */ BadChar, /* 173 */ BadChar, /* 174 */ BadChar, /* 175 */ BadChar,
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 176 */ BadChar, /* 177 */ BadChar, /* 178 */ BadChar, /* 179 */ BadChar,
2008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 180 */ BadChar, /* 181 */ BadChar, /* 182 */ BadChar, /* 183 */ BadChar,
2018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 184 */ BadChar, /* 185 */ BadChar, /* 186 */ BadChar, /* 187 */ BadChar,
2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 188 */ BadChar, /* 189 */ BadChar, /* 190 */ BadChar, /* 191 */ BadChar,
2038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 192 */ BadChar, /* 193 */ BadChar, /* 194 */ BadChar, /* 195 */ BadChar,
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 196 */ BadChar, /* 197 */ BadChar, /* 198 */ BadChar, /* 199 */ BadChar,
2058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 200 */ BadChar, /* 201 */ BadChar, /* 202 */ BadChar, /* 203 */ BadChar,
2068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 204 */ BadChar, /* 205 */ BadChar, /* 206 */ BadChar, /* 207 */ BadChar,
2078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 208 */ BadChar, /* 209 */ BadChar, /* 210 */ BadChar, /* 211 */ BadChar,
2088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 212 */ BadChar, /* 213 */ BadChar, /* 214 */ BadChar, /* 215 */ BadChar,
2098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 216 */ BadChar, /* 217 */ BadChar, /* 218 */ BadChar, /* 219 */ BadChar,
2108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 220 */ BadChar, /* 221 */ BadChar, /* 222 */ BadChar, /* 223 */ BadChar,
2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 224 */ BadChar, /* 225 */ BadChar, /* 226 */ BadChar, /* 227 */ BadChar,
2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 228 */ BadChar, /* 229 */ BadChar, /* 230 */ BadChar, /* 231 */ BadChar,
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 232 */ BadChar, /* 233 */ BadChar, /* 234 */ BadChar, /* 235 */ BadChar,
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 236 */ BadChar, /* 237 */ BadChar, /* 238 */ BadChar, /* 239 */ BadChar,
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 240 */ BadChar, /* 241 */ BadChar, /* 242 */ BadChar, /* 243 */ BadChar,
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 244 */ BadChar, /* 245 */ BadChar, /* 246 */ BadChar, /* 247 */ BadChar,
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 248 */ BadChar, /* 249 */ BadChar, /* 250 */ BadChar, /* 251 */ BadChar,
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    /* 252 */ BadChar, /* 253 */ BadChar, /* 254 */ BadChar, /* 255 */ BadChar
2198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project};
2208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd);
2228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void encodeRelativeString(const String& rel, const TextEncoding&, CharBuffer& ouput);
2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic String substituteBackslashes(const String&);
224d0825bca7fe65beaee391d30da42e937db621564Steve Blockstatic bool isValidProtocol(const String&);
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeFirstChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeFirstChar; }
2278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeFirstChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeFirstChar); }
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & SchemeChar; }
2298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isSchemeChar(UChar c) { return c <= 0xff && (characterClassTable[c] & SchemeChar); }
2308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isUserInfoChar(unsigned char c) { return characterClassTable[c] & UserInfoChar; }
2318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isHostnameChar(unsigned char c) { return characterClassTable[c] & HostnameChar; }
2328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isIPv6Char(unsigned char c) { return characterClassTable[c] & IPv6Char; }
2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isPathSegmentEndChar(char c) { return characterClassTable[static_cast<unsigned char>(c)] & PathSegmentEndChar; }
2348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isPathSegmentEndChar(UChar c) { return c <= 0xff && (characterClassTable[c] & PathSegmentEndChar); }
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool isBadChar(unsigned char c) { return characterClassTable[c] & BadChar; }
2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline int hexDigitValue(UChar c)
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(isASCIIHexDigit(c));
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c < 'A')
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return c - '0';
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (c - 'A' + 10) & 0xF; // handle both upper and lower case without a branch
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Copies the source to the destination, assuming all the source characters are
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ASCII. The destination buffer must be large enough. Null characters are allowed
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// in the source string, and no attempt is made to null-terminate the result.
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void copyASCII(const UChar* src, int length, char* dest)
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < length; i++)
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        dest[i] = static_cast<char>(src[i]);
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
254635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void appendASCII(const String& base, const char* rel, size_t len, CharBuffer& buffer)
255635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
256635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    buffer.resize(base.length() + len + 1);
257635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    copyASCII(base.characters(), base.length(), buffer.data());
258635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    memcpy(buffer.data() + base.length(), rel, len);
259635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    buffer[buffer.size() - 1] = '\0';
260635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
261635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: Move to PlatformString.h eventually.
2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Returns the index of the first index in string |s| of any of the characters
2648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// in |toFind|. |toFind| should be a null-terminated string, all characters up
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// to the null will be searched. Returns int if not found.
2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int findFirstOf(const UChar* s, int sLen, int startPos, const char* toFind)
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = startPos; i < sLen; i++) {
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* cur = toFind;
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (*cur) {
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (s[i] == *(cur++))
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return i;
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return -1;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
278635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifndef NDEBUG
279635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void checkEncodedString(const String& url)
280635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
281635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    for (unsigned i = 0; i < url.length(); ++i)
282635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        ASSERT(!(url[i] & ~0x7F));
283635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
284635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(!url.length() || isSchemeFirstChar(url[0]));
285635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
286635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#else
287635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic inline void checkEncodedString(const String&)
288635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
289635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
290635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
291635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectinline bool KURL::protocolIs(const String& string, const char* protocol)
2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return WebCore::protocolIs(string, protocol);
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::invalidate()
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_isValid = false;
3008f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    m_protocolInHTTPFamily = false;
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_schemeEnd = 0;
3028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_userStart = 0;
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_userEnd = 0;
3048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_passwordEnd = 0;
3058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_hostEnd = 0;
3068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_portEnd = 0;
3078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathEnd = 0;
3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathAfterLastSlash = 0;
3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_queryEnd = 0;
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_fragmentEnd = 0;
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
313231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockKURL::KURL(ParsedURLStringTag, const char* url)
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
315635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    parse(url, 0);
316635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(url == m_string);
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
319231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve BlockKURL::KURL(ParsedURLStringTag, const String& url)
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
321635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    parse(url);
322635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    ASSERT(url == m_string);
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3252fc2651226baac27029e38c9d6ef883fa32084dbSteve BlockKURL::KURL(ParsedURLStringTag, const URLString& url)
3262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
3272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    parse(url.string());
3282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    ASSERT(url.string() == m_string);
3292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
3302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectKURL::KURL(const KURL& base, const String& relative)
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    init(base, relative, UTF8Encoding());
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectKURL::KURL(const KURL& base, const String& relative, const TextEncoding& encoding)
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
338635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // For UTF-{7,16,32}, we want to use UTF-8 for the query part as
339635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // we do when submitting a form. A form with GET method
340635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // has its contents added to a URL as query params and it makes sense
341635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // to be consistent.
342635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    init(base, relative, encoding.encodingForFormSubmission());
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
34581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochstatic bool shouldTrimFromURL(unsigned char c)
34681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
34781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Browsers ignore leading/trailing whitespace and control
34881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // characters from URLs.  Note that c is an *unsigned* char here
34981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // so this comparison should only catch control characters.
35081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return c <= ' ';
35181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
35281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::init(const KURL& base, const String& relative, const TextEncoding& encoding)
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Allow resolutions with a null or empty base URL, but not with any other invalid one.
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: Is this a good rule?
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!base.m_isValid && !base.isEmpty()) {
3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = relative;
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For compatibility with Win IE, treat backslashes as if they were slashes,
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // as long as we're not dealing with javascript: or data: URLs.
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String rel = relative;
3665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (rel.contains('\\') && !(protocolIsJavaScript(rel) || protocolIs(rel, "data")))
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        rel = substituteBackslashes(rel);
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String* originalString = &rel;
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool allASCII = charactersAreAllASCII(rel.characters(), rel.length());
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CharBuffer strBuffer;
3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* str;
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    size_t len;
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (allASCII) {
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        len = rel.length();
3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        strBuffer.resize(len + 1);
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        copyASCII(rel.characters(), len, strBuffer.data());
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        strBuffer[len] = 0;
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str = strBuffer.data();
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        originalString = 0;
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        encodeRelativeString(rel, encoding, strBuffer);
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str = strBuffer.data();
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        len = strlen(str);
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
38881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Get rid of leading whitespace and control characters.
38981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    while (len && shouldTrimFromURL(*str)) {
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        originalString = 0;
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str++;
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        --len;
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
39581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Get rid of trailing whitespace and control characters.
39681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    while (len && shouldTrimFromURL(str[len - 1])) {
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        originalString = 0;
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str[--len] = '\0';
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // According to the RFC, the reference should be interpreted as an
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // absolute URI if possible, using the "leftmost, longest"
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // algorithm. If the URI reference is absolute it will have a
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // scheme, meaning that it will have a colon before the first
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // non-scheme element.
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool absolute = false;
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = str;
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isSchemeFirstChar(*p)) {
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ++p;
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (isSchemeChar(*p)) {
4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ++p;
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (*p == ':') {
4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (p[1] != '/' && equalIgnoringCase(base.protocol(), String(str, p - str)) && base.isHierarchical()) {
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                str = p + 1;
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                originalString = 0;
4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                absolute = true;
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
422635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CharBuffer parseBuffer;
423635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (absolute) {
4258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parse(str, originalString);
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If the base is empty or opaque (e.g. data: or javascript:), then the URL is invalid
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // unless the relative URL is a single fragment.
4298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!base.isHierarchical()) {
430635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            if (str[0] == '#') {
431635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer);
432635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
433635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            } else {
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_string = relative;
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                invalidate();
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        switch (str[0]) {
4418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case '\0':
4425e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block            // The reference is empty, so this is a reference to the same document with any fragment identifier removed.
4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *this = base;
4445e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block            removeFragmentIdentifier();
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
446635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        case '#': {
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // must be fragment-only reference
448635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            appendASCII(base.m_string.left(base.m_queryEnd), str, len, parseBuffer);
449635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            parse(parseBuffer.data(), 0);
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
451635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
452635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        case '?': {
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // query-only reference, special case needed for non-URL results
454635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            appendASCII(base.m_string.left(base.m_pathEnd), str, len, parseBuffer);
455635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            parse(parseBuffer.data(), 0);
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
457635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        }
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        case '/':
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // must be net-path or absolute-path reference
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (str[1] == '/') {
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // net-path
462635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                appendASCII(base.m_string.left(base.m_schemeEnd + 1), str, len, parseBuffer);
463635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // abs-path
466635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                appendASCII(base.m_string.left(base.m_portEnd), str, len, parseBuffer);
467635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        default:
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            {
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // must be relative-path reference
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Base part plus relative part plus one possible slash added in between plus terminating \0 byte.
475635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parseBuffer.resize(base.m_pathEnd + 1 + len + 1);
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
477635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                char* bufferPos = parseBuffer.data();
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // first copy everything before the path from the base
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                unsigned baseLength = base.m_string.length();
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const UChar* baseCharacters = base.m_string.characters();
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                CharBuffer baseStringBuffer(baseLength);
483635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                copyASCII(baseCharacters, baseLength, baseStringBuffer.data());
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* baseString = baseStringBuffer.data();
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* baseStringStart = baseString;
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* pathStart = baseStringStart + base.m_portEnd;
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (baseStringStart < pathStart)
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    *bufferPos++ = *baseStringStart++;
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                char* bufferPathStart = bufferPos;
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // now copy the base path
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* baseStringEnd = baseString + base.m_pathEnd;
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // go back to the last slash
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (baseStringEnd > baseStringStart && baseStringEnd[-1] != '/')
4968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    baseStringEnd--;
4978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (baseStringEnd == baseStringStart) {
4998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // no path in base, add a path separator if necessary
5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (base.m_schemeEnd + 1 != base.m_pathEnd && *str && *str != '?' && *str != '#')
5018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        *bufferPos++ = '/';
5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else {
5038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    bufferPos += copyPathRemovingDots(bufferPos, baseStringStart, 0, baseStringEnd - baseStringStart);
5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* relStringStart = str;
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                const char* relStringPos = relStringStart;
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (*relStringPos && *relStringPos != '?' && *relStringPos != '#') {
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (relStringPos[0] == '.' && bufferPos[-1] == '/') {
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        if (isPathSegmentEndChar(relStringPos[1])) {
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // skip over "." segment
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            relStringPos += 1;
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            if (relStringPos[0] == '/')
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                relStringPos++;
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            continue;
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        } else if (relStringPos[1] == '.' && isPathSegmentEndChar(relStringPos[2])) {
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // skip over ".." segment and rewind the last segment
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // the RFC leaves it up to the app to decide what to do with excess
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // ".." segments - we choose to drop them since some web content
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            // relies on this.
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            relStringPos += 2;
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            if (relStringPos[0] == '/')
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                relStringPos++;
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            if (bufferPos > bufferPathStart + 1)
5268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                bufferPos--;
5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            while (bufferPos > bufferPathStart + 1  && bufferPos[-1] != '/')
5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                bufferPos--;
5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                            continue;
5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        }
5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    }
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    *bufferPos = *relStringPos;
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    relStringPos++;
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    bufferPos++;
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // all done with the path work, now copy any remainder
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // of the relative reference; this will also add a null terminator
5408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                strcpy(bufferPos, relStringPos);
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
542635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                parse(parseBuffer.data(), 0);
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
544635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                ASSERT(strlen(parseBuffer.data()) + 1 <= parseBuffer.size());
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                break;
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
551635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectKURL KURL::copy() const
552635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
553635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    KURL result = *this;
554231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block    result.m_string = result.m_string.crossThreadString();
555635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return result;
556635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
557635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool KURL::hasPath() const
5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_pathEnd != m_portEnd;
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::lastPathComponent() const
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!hasPath())
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
5678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
568f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned end = m_pathEnd - 1;
5698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_string[end] == '/')
5708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        --end;
5718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
572f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t start = m_string.reverseFind('/', end);
573f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (start < static_cast<unsigned>(m_portEnd))
5748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
5758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ++start;
5768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string.substring(start, end - start + 1);
5788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::protocol() const
5818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string.left(m_schemeEnd);
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::host() const
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int start = hostStart();
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(start, m_hostEnd - start));
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectunsigned short KURL::port() const
5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
593dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // We return a port of 0 if there is no port specified. This can happen in two situations:
594dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 1) The URL contains no colon after the host name and before the path component of the URL.
595dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    // 2) The URL contains a colon but there's no port number before the path component of the URL begins.
596dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (m_hostEnd == m_portEnd || m_hostEnd == m_portEnd - 1)
5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
599dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    const UChar* stringData = m_string.characters();
600dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    bool ok = false;
601dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    unsigned number = charactersToUIntStrict(stringData + m_hostEnd + 1, m_portEnd - m_hostEnd - 1, &ok);
602dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    if (!ok || number > maximumValidPortNumber)
603dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        return invalidPortNumber;
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return number;
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::pass() const
6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_passwordEnd == m_userEnd)
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(m_userEnd + 1, m_passwordEnd - m_userEnd - 1));
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::user() const
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(m_userStart, m_userEnd - m_userStart));
6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6200bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochString KURL::fragmentIdentifier() const
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_fragmentEnd == m_queryEnd)
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return String();
6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string.substring(m_queryEnd + 1, m_fragmentEnd - (m_queryEnd + 1));
6268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool KURL::hasFragmentIdentifier() const
6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_fragmentEnd != m_queryEnd;
6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
633a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid KURL::copyParsedQueryTo(ParsedURLParameters& parameters) const
634a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
635a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const UChar* pos = m_string.characters() + m_pathEnd + 1;
636a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const UChar* end = m_string.characters() + m_queryEnd;
637a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    while (pos < end) {
638a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* parameterStart = pos;
639a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        while (pos < end && *pos != '&')
640a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ++pos;
641a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* parameterEnd = pos;
642a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (pos < end) {
643a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ASSERT(*pos == '&');
644a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ++pos;
645a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
646a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (parameterStart == parameterEnd)
647a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            continue;
648a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* nameStart = parameterStart;
649a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        const UChar* equalSign = parameterStart;
650a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        while (equalSign < parameterEnd && *equalSign != '=')
651a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            ++equalSign;
652a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (equalSign == nameStart)
653a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            continue;
654a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        String name(nameStart, equalSign - nameStart);
655a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        String value = equalSign == parameterEnd ? String() : String(equalSign + 1, parameterEnd - equalSign - 1);
656a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        parameters.set(name, value);
657a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
658a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
659a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
6608f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianString KURL::baseAsString() const
6618f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian{
6628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return m_string.left(m_pathAfterLastSlash);
6638f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian}
6648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
665635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#ifdef NDEBUG
666635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
667635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic inline void assertProtocolIsGood(const char*)
668635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
669635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
670635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
671635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#else
672635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
673635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectstatic void assertProtocolIsGood(const char* protocol)
6748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* p = protocol;
6768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (*p) {
6778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(*p > ' ' && *p < 0x7F && !(*p >= 'A' && *p <= 'Z'));
6788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ++p;
6798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
682635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
683635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
6848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool KURL::protocolIs(const char* protocol) const
6858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    assertProtocolIsGood(protocol);
6875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // JavaScript URLs are "valid" and should be executed even if KURL decides they are invalid.
6895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // The free function protocolIsJavaScript() should be used instead.
690643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    ASSERT(!equalIgnoringCase(protocol, String("javascript")));
6915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
6945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
6955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Do the comparison without making a new string object.
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < m_schemeEnd; ++i) {
6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!protocol[i] || toASCIILower(m_string[i]) != protocol[i])
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return !protocol[m_schemeEnd]; // We should have consumed all characters in the argument.
7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::query() const
7048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (m_queryEnd == m_pathEnd)
7068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return String();
7078f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
7088f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return m_string.substring(m_pathEnd + 1, m_queryEnd - (m_pathEnd + 1));
7098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::path() const
7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(m_string.substring(m_portEnd, m_pathEnd - m_portEnd));
7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
716d0825bca7fe65beaee391d30da42e937db621564Steve Blockbool KURL::setProtocol(const String& s)
7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
718d0825bca7fe65beaee391d30da42e937db621564Steve Block    // Firefox and IE remove everything after the first ':'.
719f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t separatorPosition = s.find(':');
720d0825bca7fe65beaee391d30da42e937db621564Steve Block    String newProtocol = s.substring(0, separatorPosition);
721d0825bca7fe65beaee391d30da42e937db621564Steve Block
722d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (!isValidProtocol(newProtocol))
723d0825bca7fe65beaee391d30da42e937db621564Steve Block        return false;
724635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid) {
726d0825bca7fe65beaee391d30da42e937db621564Steve Block        parse(newProtocol + ":" + m_string);
727d0825bca7fe65beaee391d30da42e937db621564Steve Block        return true;
7288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
730d0825bca7fe65beaee391d30da42e937db621564Steve Block    parse(newProtocol + m_string.substring(m_schemeEnd));
731d0825bca7fe65beaee391d30da42e937db621564Steve Block    return true;
7328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setHost(const String& s)
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
739635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
740635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just the host.
741635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
7438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + s + m_string.substring(m_hostEnd));
7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
747643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockvoid KURL::removePort()
748643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
749643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (m_hostEnd == m_portEnd)
750643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return;
751643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    parse(m_string.left(m_hostEnd) + m_string.substring(m_portEnd));
752643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
753643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
7548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setPort(unsigned short i)
7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
759643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    bool colonNeeded = m_portEnd == m_hostEnd;
760643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    int portStart = (colonNeeded ? m_hostEnd : m_hostEnd + 1);
7618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
762643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    parse(m_string.left(portStart) + (colonNeeded ? ":" : "") + String::number(i) + m_string.substring(m_portEnd));
7638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setHostAndPort(const String& hostAndPort)
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
770635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
771635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just host and port.
772635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
7738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool slashSlashNeeded = m_userStart == m_schemeEnd + 1;
7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(hostStart()) + (slashSlashNeeded ? "//" : "") + hostAndPort + m_string.substring(m_portEnd));
7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setUser(const String& user)
7798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
7818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
7828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
783635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
784635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just the user login.
7858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String u;
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int end = m_userEnd;
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!user.isEmpty()) {
7888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        u = user;
7898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userStart == m_schemeEnd + 1)
7908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            u = "//" + u;
7918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Add '@' if we didn't have one before.
7928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (end == m_hostEnd || (end == m_passwordEnd && m_string[end] != '@'))
7938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            u.append('@');
7948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
7958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remove '@' if we now have neither user nor password.
7968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userEnd == m_passwordEnd && end != m_hostEnd && m_string[end] == '@')
7978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end += 1;
7988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_userStart) + u + m_string.substring(end));
8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setPass(const String& password)
8038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
807635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations,
808635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // and to avoid changing more than just the user password.
8098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    String p;
8108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int end = m_passwordEnd;
8118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!password.isEmpty()) {
8128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = ":" + password + "@";
8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userEnd == m_schemeEnd + 1)
8148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p = "//" + p;
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Eat the existing '@' since we are going to add our own.
8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (end != m_hostEnd && m_string[end] == '@')
8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end += 1;
8188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Remove '@' if we now have neither user nor password.
8208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userStart == m_userEnd && end != m_hostEnd && m_string[end] == '@')
8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            end += 1;
8228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_userEnd) + p + m_string.substring(end));
8248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8260bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid KURL::setFragmentIdentifier(const String& s)
8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
830635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
831635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: Non-ASCII characters must be encoded and escaped to match parse() expectations.
8320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    parse(m_string.left(m_queryEnd) + "#" + s);
8338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8350bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochvoid KURL::removeFragmentIdentifier()
8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_queryEnd));
8408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setQuery(const String& query)
8438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
847635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: '#' and non-ASCII characters must be encoded and escaped.
848635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Usually, the query is encoded using document encoding, not UTF-8, but we don't have
849635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // access to the document in this function.
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if ((query.isEmpty() || query[0] != '?') && !query.isNull())
8518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parse(m_string.left(m_pathEnd) + "?" + query + m_string.substring(m_queryEnd));
8528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
8538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        parse(m_string.left(m_pathEnd) + query + m_string.substring(m_queryEnd));
8548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::setPath(const String& s)
8588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
8618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
862635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // FIXME: encodeWithURLEscapeSequences does not correctly escape '#' and '?', so fragment and query parts
863635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // may be inadvertently affected.
8648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(m_string.left(m_portEnd) + encodeWithURLEscapeSequences(s) + m_string.substring(m_pathEnd));
8658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString KURL::prettyURL() const
8688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
8708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return m_string;
8718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar> result;
8738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    append(result, protocol());
8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.append(':');
8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar> authority;
8788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_hostEnd != m_passwordEnd) {
8808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (m_userEnd != m_userStart) {
8818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            append(authority, user());
8828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            authority.append('@');
8838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        append(authority, host());
885643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (hasPort()) {
8868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            authority.append(':');
8878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            append(authority, String::number(port()));
8888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!authority.isEmpty()) {
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(authority);
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (protocolIs("file")) {
8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('/');
8988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    append(result, path());
9018f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
9028f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (m_pathEnd != m_queryEnd) {
9038f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        result.append('?');
9048f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        append(result, query());
9058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
9068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (m_fragmentEnd != m_queryEnd) {
9088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append('#');
9090bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        append(result, fragmentIdentifier());
9108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return String::adopt(result);
9138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString decodeURLEscapeSequences(const String& str)
9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return decodeURLEscapeSequences(str, UTF8Encoding());
9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString decodeURLEscapeSequences(const String& str, const TextEncoding& encoding)
9218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<UChar> result;
9238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CharBuffer buffer;
9258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
926f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned length = str.length();
927f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned decodedPosition = 0;
928f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned searchPosition = 0;
929f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t encodedRunPosition;
930f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    while ((encodedRunPosition = str.find('%', searchPosition)) != notFound) {
9318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find the sequence of %-escape codes.
932f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        unsigned encodedRunEnd = encodedRunPosition;
9338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (length - encodedRunEnd >= 3
9348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && str[encodedRunEnd] == '%'
9358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && isASCIIHexDigit(str[encodedRunEnd + 1])
9368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                && isASCIIHexDigit(str[encodedRunEnd + 2]))
9378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            encodedRunEnd += 3;
9382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        searchPosition = encodedRunEnd;
9398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (encodedRunEnd == encodedRunPosition) {
9408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ++searchPosition;
9418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
9428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Decode the %-escapes into bytes.
9458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned runLength = (encodedRunEnd - encodedRunPosition) / 3;
9468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer.resize(runLength);
9478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        char* p = buffer.data();
9488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const UChar* q = str.characters() + encodedRunPosition;
9498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (unsigned i = 0; i < runLength; ++i) {
9508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = (hexDigitValue(q[1]) << 4) | hexDigitValue(q[2]);
9518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            q += 3;
9528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
9538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Decode the bytes into Unicode characters.
9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        String decoded = (encoding.isValid() ? encoding : UTF8Encoding()).decode(buffer.data(), p - buffer.data());
9568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (decoded.isEmpty())
9578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
9588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Build up the string with what we just skipped and what we just decoded.
9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(str.characters() + decodedPosition, encodedRunPosition - decodedPosition);
9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        result.append(decoded.characters(), decoded.length());
9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        decodedPosition = encodedRunEnd;
9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
9648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    result.append(str.characters() + decodedPosition, length - decodedPosition);
9668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return String::adopt(result);
9688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9702fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// Caution: This function does not bounds check.
9712fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic void appendEscapedChar(char*& buffer, unsigned char c)
9722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
9732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    *buffer++ = '%';
9742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    *buffer++ = hexDigits[c >> 4];
9752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    *buffer++ = hexDigits[c & 0xF];
9762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
9772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void appendEscapingBadChars(char*& buffer, const char* strStart, size_t length)
9798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = buffer;
9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* str = strStart;
9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* strEnd = strStart + length;
9848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (str < strEnd) {
9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = *str++;
9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isBadChar(c)) {
9872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if (c == '%' || c == '?')
9888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *p++ = c;
9892fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            else if (c != 0x09 && c != 0x0a && c != 0x0d)
9902fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                appendEscapedChar(p, c);
9912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        } else
9928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = c;
9932fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
9942fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9952fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    buffer = p;
9962fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
9972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
9982fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic void escapeAndAppendFragment(char*& buffer, const char* strStart, size_t length)
9992fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
10002fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    char* p = buffer;
10012fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10022fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const char* str = strStart;
10032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    const char* strEnd = strStart + length;
10042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    while (str < strEnd) {
10052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        unsigned char c = *str++;
10062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Strip CR, LF and Tab from fragments, per:
10072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // https://bugs.webkit.org/show_bug.cgi?id=8770
10082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (c == 0x09 || c == 0x0a || c == 0x0d)
10092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            continue;
10102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
10112fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Chrome and IE allow non-ascii characters in fragments, however doing
10122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // so would hit an ASSERT in checkEncodedString, so for now we don't.
10132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (c < 0x20 || c >= 127) {
10142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            appendEscapedChar(p, c);
10152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            continue;
10168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        *p++ = c;
10188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer = p;
10218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// copy a path, accounting for "." and ".." segments
10248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic int copyPathRemovingDots(char* dst, const char* src, int srcStart, int srcEnd)
10258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* bufferPathStart = dst;
10278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // empty path is a special case, and need not have a leading slash
10298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (srcStart != srcEnd) {
10308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* baseStringStart = src + srcStart;
10318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* baseStringEnd = src + srcEnd;
10328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* baseStringPos = baseStringStart;
10338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // this code is unprepared for paths that do not begin with a
10358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // slash and we should always have one in the source string
10368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        ASSERT(baseStringPos[0] == '/');
10378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy the leading slash into the destination
10398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *dst = *baseStringPos;
10408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        baseStringPos++;
10418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        dst++;
10428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (baseStringPos < baseStringEnd) {
10448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (baseStringPos[0] == '.' && dst[-1] == '/') {
10458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (baseStringPos[1] == '/' || baseStringPos + 1 == baseStringEnd) {
10468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // skip over "." segment
10478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    baseStringPos += 2;
10488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    continue;
10498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                } else if (baseStringPos[1] == '.' && (baseStringPos[2] == '/' ||
10508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                                       baseStringPos + 2 == baseStringEnd)) {
10518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // skip over ".." segment and rewind the last segment
10528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // the RFC leaves it up to the app to decide what to do with excess
10538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // ".." segments - we choose to drop them since some web content
10548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // relies on this.
10558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    baseStringPos += 3;
10568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (dst > bufferPathStart + 1)
10578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        dst--;
10588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    while (dst > bufferPathStart && dst[-1] != '/')
10598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        dst--;
10608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    continue;
10618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
10628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
10638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *dst = *baseStringPos;
10658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            baseStringPos++;
10668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            dst++;
10678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
10688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *dst = '\0';
10708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return dst - bufferPathStart;
10718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool hasSlashDotOrDotDot(const char* str)
10748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned char* p = reinterpret_cast<const unsigned char*>(str);
10768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!*p)
10778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
10788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned char pc = *p;
10798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (unsigned char c = *++p) {
10808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '.' && (pc == '/' || pc == '.'))
10818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return true;
10828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pc = c;
10838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
10848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return false;
10858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic inline bool matchLetter(char c, char lowercaseLetter)
10888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return (c | 0x20) == lowercaseLetter;
10908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::parse(const String& string)
10938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1094635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    checkEncodedString(string);
1095635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1096635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    CharBuffer buffer(string.length() + 1);
1097635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    copyASCII(string.characters(), string.length(), buffer.data());
1098635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    buffer[string.length()] = '\0';
10998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    parse(buffer.data(), &string);
11008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
11018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11022fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic inline bool equal(const char* a, size_t lenA, const char* b, size_t lenB)
11032fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
11042fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    if (lenA != lenB)
11052fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return false;
11062fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return !strncmp(a, b, lenA);
11072fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
11082fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
11092fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// List of default schemes is taken from google-url:
11102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block// http://code.google.com/p/google-url/source/browse/trunk/src/url_canon_stdurl.cc#120
11112fc2651226baac27029e38c9d6ef883fa32084dbSteve Blockstatic inline bool isDefaultPortForScheme(const char* port, size_t portLength, const char* scheme, size_t schemeLength)
11122fc2651226baac27029e38c9d6ef883fa32084dbSteve Block{
11132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // This switch is theoretically a performance optimization.  It came over when
11142fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    // the code was moved from google-url, but may be removed later.
11152fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    switch (schemeLength) {
11162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 2:
11172fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("ws", 2, scheme, schemeLength) && equal("80", 2, port, portLength);
11182fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 3:
11192fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (equal("ftp", 3, scheme, schemeLength))
11202fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            return equal("21", 2, port, portLength);
11212fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (equal("wss", 3, scheme, schemeLength))
11222fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            return equal("443", 3, port, portLength);
11232fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        break;
11242fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 4:
11252fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("http", 4, scheme, schemeLength) && equal("80", 2, port, portLength);
11262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 5:
11272fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("https", 5, scheme, schemeLength) && equal("443", 3, port, portLength);
11282fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    case 6:
11292fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        return equal("gopher", 6, scheme, schemeLength) && equal("70", 2, port, portLength);
11302fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    }
11312fc2651226baac27029e38c9d6ef883fa32084dbSteve Block    return false;
11322fc2651226baac27029e38c9d6ef883fa32084dbSteve Block}
11332fc2651226baac27029e38c9d6ef883fa32084dbSteve Block
11348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::parse(const char* url, const String* originalString)
11358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
11368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!url || url[0] == '\0') {
11378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // valid URL must be non-empty
11388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = originalString ? *originalString : url;
11398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
11408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!isSchemeFirstChar(url[0])) {
11448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // scheme must start with an alphabetic character
11458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = originalString ? *originalString : url;
11468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
11478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int schemeEnd = 0;
11518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (isSchemeChar(url[schemeEnd]))
11528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        schemeEnd++;
11538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (url[schemeEnd] != ':') {
11558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = originalString ? *originalString : url;
11568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        invalidate();
11578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
11588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
11598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int userStart = schemeEnd + 1;
11618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int userEnd;
11628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int passwordStart;
11638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int passwordEnd;
11648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostStart;
11658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostEnd;
11668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int portStart;
11678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int portEnd;
11688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool hierarchical = url[schemeEnd + 1] == '/';
11708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool isFile = schemeEnd == 4
11728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[0], 'f')
11738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[1], 'i')
11748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[2], 'l')
11758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[3], 'e');
11768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11778f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    m_protocolInHTTPFamily = matchLetter(url[0], 'h')
11788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[1], 't')
11798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[2], 't')
11808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[3], 'p')
11818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && (url[4] == ':' || (matchLetter(url[4], 's') && url[5] == ':'));
11828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (hierarchical && url[schemeEnd + 2] == '/') {
11848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // The part after the scheme is either a net_path or an abs_path whose first path segment is empty.
11858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Attempt to find an authority.
11868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: Authority characters may be scanned twice, and it would be nice to be faster.
11888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        userStart += 2;
11898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        userEnd = userStart;
11908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int colonPos = 0;
11928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (isUserInfoChar(url[userEnd])) {
11938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (url[userEnd] == ':' && colonPos == 0)
11948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                colonPos = userEnd;
11958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userEnd++;
11968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
11978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
11988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (url[userEnd] == '@') {
11998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // actual end of the userinfo, start on the host
12008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (colonPos != 0) {
12018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                passwordEnd = userEnd;
12028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                userEnd = colonPos;
12038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                passwordStart = colonPos + 1;
12048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else
12058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                passwordStart = passwordEnd = userEnd;
12068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostStart = passwordEnd + 1;
12088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else if (url[userEnd] == '[' || isPathSegmentEndChar(url[userEnd])) {
12098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // hit the end of the authority, must have been no user
12108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // or looks like an IPv6 hostname
12118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // either way, try to parse it as a hostname
12128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userEnd = userStart;
12138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            passwordStart = passwordEnd = userEnd;
12148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostStart = userStart;
12158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
12168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // invalid character
12178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_string = originalString ? *originalString : url;
12188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            invalidate();
12198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
12208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostEnd = hostStart;
12238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // IPV6 IP address
12258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (url[hostEnd] == '[') {
12268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostEnd++;
12278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (isIPv6Char(url[hostEnd]))
12288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostEnd++;
12298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (url[hostEnd] == ']')
12308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostEnd++;
12318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            else {
12328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // invalid character
12338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                m_string = originalString ? *originalString : url;
12348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                invalidate();
12358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
12368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
12378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
12388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (isHostnameChar(url[hostEnd]))
12398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostEnd++;
12408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (url[hostEnd] == ':') {
12438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portStart = portEnd = hostEnd + 1;
12448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // possible start of port
12468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portEnd = portStart;
12478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (isASCIIDigit(url[portEnd]))
12488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                portEnd++;
12498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else
12508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portStart = portEnd = hostEnd;
12518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!isPathSegmentEndChar(url[portEnd])) {
12538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // invalid character
12548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            m_string = originalString ? *originalString : url;
12558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            invalidate();
12568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
12578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        if (userStart == portEnd && !m_protocolInHTTPFamily && !isFile) {
12608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // No authority found, which means that this is not a net_path, but rather an abs_path whose first two
12618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // path segments are empty. For file, http and https only, an empty authority is allowed.
12628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userStart -= 2;
12638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            userEnd = userStart;
12648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            passwordStart = userEnd;
12658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            passwordEnd = passwordStart;
12668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostStart = passwordEnd;
12678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostEnd = hostStart;
12688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portStart = hostEnd;
12698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            portEnd = hostEnd;
12708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
12718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
12728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // the part after the scheme must be an opaque_part or an abs_path
12738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        userEnd = userStart;
12748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        passwordStart = passwordEnd = userEnd;
12758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostStart = hostEnd = passwordEnd;
12768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        portStart = portEnd = hostEnd;
12778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
12788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int pathStart = portEnd;
12808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int pathEnd = pathStart;
12818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (url[pathEnd] && url[pathEnd] != '?' && url[pathEnd] != '#')
12828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd++;
12838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int queryStart = pathEnd;
12858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int queryEnd = queryStart;
12868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (url[queryStart] == '?') {
12878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (url[queryEnd] && url[queryEnd] != '#')
12888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            queryEnd++;
12898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
12908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
12918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int fragmentStart = queryEnd;
12928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int fragmentEnd = fragmentStart;
12938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (url[fragmentStart] == '#') {
12948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fragmentStart++;
12958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        fragmentEnd = fragmentStart;
12968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (url[fragmentEnd])
12978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            fragmentEnd++;
12988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
12998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // assemble it all, remembering the real ranges
13018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Vector<char, 4096> buffer(fragmentEnd * 3 + 1);
13038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char *p = buffer.data();
13058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char *strPtr = url;
13068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // copy in the scheme
13088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char *schemeEndPtr = url + schemeEnd;
13098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (strPtr < schemeEndPtr)
13102fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        *p++ = toASCIILower(*strPtr++);
13118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_schemeEnd = p - buffer.data();
13128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool hostIsLocalHost = portEnd - userStart == 9
13148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart], 'l')
13158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+1], 'o')
13168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+2], 'c')
13178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+3], 'a')
13188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+4], 'l')
13198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+5], 'h')
13208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+6], 'o')
13218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+7], 's')
13228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        && matchLetter(url[userStart+8], 't');
13238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // File URLs need a host part unless it is just file:// or file://localhost
13258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool degenFilePath = pathStart == pathEnd && (hostStart == hostEnd || hostIsLocalHost);
13268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool haveNonHostAuthorityPart = userStart != userEnd || passwordStart != passwordEnd || portStart != portEnd;
13288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add ":" after scheme
13308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    *p++ = ':';
13318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // if we have at least one authority part or a file URL - add "//" and authority
13338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isFile ? !degenFilePath : (haveNonHostAuthorityPart || hostStart != hostEnd)) {
13348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '/';
13358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '/';
13368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_userStart = p - buffer.data();
13388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy in the user
13408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        strPtr = url + userStart;
13418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        const char* userEndPtr = url + userEnd;
13428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (strPtr < userEndPtr)
13438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = *strPtr++;
13448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_userEnd = p - buffer.data();
13458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy in the password
13478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (passwordEnd != passwordStart) {
13488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = ':';
13498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            strPtr = url + passwordStart;
13508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const char* passwordEndPtr = url + passwordEnd;
13518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (strPtr < passwordEndPtr)
13528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *p++ = *strPtr++;
13538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
13548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_passwordEnd = p - buffer.data();
13558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // If we had any user info, add "@"
13578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (p - buffer.data() != m_userStart)
13588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = '@';
13598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // copy in the host, except in the case of a file URL with authority="localhost"
13618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!(isFile && hostIsLocalHost && !haveNonHostAuthorityPart)) {
13628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            strPtr = url + hostStart;
13638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const char* hostEndPtr = url + hostEnd;
13648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (strPtr < hostEndPtr)
13658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                *p++ = *strPtr++;
13668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
13678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_hostEnd = p - buffer.data();
13688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        // Copy in the port if the URL has one (and it's not default).
13708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hostEnd != portStart) {
13712fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            const char* portStr = url + portStart;
13722fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            size_t portLength = portEnd - portStart;
13732fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            if (portLength && !isDefaultPortForScheme(portStr, portLength, buffer.data(), m_schemeEnd)) {
13742fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                *p++ = ':';
13752fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                const char* portEndPtr = url + portEnd;
13762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                while (portStr < portEndPtr)
13772fc2651226baac27029e38c9d6ef883fa32084dbSteve Block                    *p++ = *portStr++;
13782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            }
13798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
13808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_portEnd = p - buffer.data();
13818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else
13828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_userStart = m_userEnd = m_passwordEnd = m_hostEnd = m_portEnd = p - buffer.data();
13838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For canonicalization, ensure we have a '/' for no path.
1385643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Do this only for hierarchical URL with protocol http or https.
1386643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (m_protocolInHTTPFamily && hierarchical && pathEnd == pathStart)
13878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '/';
13888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add path, escaping bad characters
13908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!hierarchical || !hasSlashDotOrDotDot(url))
13918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        appendEscapingBadChars(p, url + pathStart, pathEnd - pathStart);
13928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else {
13938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CharBuffer pathBuffer(pathEnd - pathStart + 1);
13948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        size_t length = copyPathRemovingDots(pathBuffer.data(), url, pathStart, pathEnd);
13958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        appendEscapingBadChars(p, pathBuffer.data(), length);
13968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
13978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
13988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathEnd = p - buffer.data();
13998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find the position after the last slash in the path, or
14018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // the position before the path if there are no slashes in it.
14028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int i;
14038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (i = m_pathEnd; i > m_portEnd; --i) {
14048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (buffer[i - 1] == '/')
14058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
14068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_pathAfterLastSlash = i;
14088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add query, escaping bad characters
14108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    appendEscapingBadChars(p, url + queryStart, queryEnd - queryStart);
14118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_queryEnd = p - buffer.data();
14128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // add fragment, escaping bad characters
14148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (fragmentEnd != queryEnd) {
14158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        *p++ = '#';
14162fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        escapeAndAppendFragment(p, url + fragmentStart, fragmentEnd - fragmentStart);
14178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_fragmentEnd = p - buffer.data();
14198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
14218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If we didn't end up actually changing the original string and
14238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // it was already in a String, reuse it to avoid extra allocation.
14248f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (originalString && originalString->length() == static_cast<unsigned>(m_fragmentEnd) && strncmp(buffer.data(), url, m_fragmentEnd) == 0)
14258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = *originalString;
14268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
14278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        m_string = String(buffer.data(), m_fragmentEnd);
14288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    m_isValid = true;
14308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14320bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdochbool equalIgnoringFragmentIdentifier(const KURL& a, const KURL& b)
14338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (a.m_queryEnd != b.m_queryEnd)
14358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
14368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned queryLength = a.m_queryEnd;
14378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (unsigned i = 0; i < queryLength; ++i)
14388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (a.string()[i] != b.string()[i])
14398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
14408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
14418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool protocolHostAndPortAreEqual(const KURL& a, const KURL& b)
14448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (a.m_schemeEnd != b.m_schemeEnd)
14468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
144721939df44de1705786c545cd1bf519d47250322dBen Murdoch
14488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostStartA = a.hostStart();
144921939df44de1705786c545cd1bf519d47250322dBen Murdoch    int hostLengthA = a.hostEnd() - hostStartA;
14508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostStartB = b.hostStart();
145121939df44de1705786c545cd1bf519d47250322dBen Murdoch    int hostLengthB = b.hostEnd() - b.hostStart();
145221939df44de1705786c545cd1bf519d47250322dBen Murdoch    if (hostLengthA != hostLengthB)
14538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
14548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check the scheme
14568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; i < a.m_schemeEnd; ++i)
14578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (a.string()[i] != b.string()[i])
14588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
145921939df44de1705786c545cd1bf519d47250322dBen Murdoch
14608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // And the host
146121939df44de1705786c545cd1bf519d47250322dBen Murdoch    for (int i = 0; i < hostLengthA; ++i)
146221939df44de1705786c545cd1bf519d47250322dBen Murdoch        if (a.string()[hostStartA + i] != b.string()[hostStartB + i])
14638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
146421939df44de1705786c545cd1bf519d47250322dBen Murdoch
14658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (a.port() != b.port())
14668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
14678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
14698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString encodeWithURLEscapeSequences(const String& notEncodedString)
14728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CString asUTF8 = notEncodedString.utf8();
14748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    CharBuffer buffer(asUTF8.length() * 3 + 1);
14768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    char* p = buffer.data();
14778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* str = asUTF8.data();
14798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const char* strEnd = str + asUTF8.length();
14808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (str < strEnd) {
14818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        unsigned char c = *str++;
14822fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        if (isBadChar(c))
14832fc2651226baac27029e38c9d6ef883fa32084dbSteve Block            appendEscapedChar(p, c);
14842fc2651226baac27029e38c9d6ef883fa32084dbSteve Block        else
14858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            *p++ = c;
14868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
14878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(p - buffer.data() <= static_cast<int>(buffer.size()));
14898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return String(buffer.data(), p - buffer.data());
14918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
14928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
14938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Appends the punycoded hostname identified by the given string and length to
14948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// the output buffer. The result will not be null terminated.
14958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void appendEncodedHostname(UCharBuffer& buffer, const UChar* str, unsigned strLen)
14968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
14978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Needs to be big enough to hold an IDN-encoded name.
14988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // For host names bigger than this, we won't do IDN encoding, which is almost certainly OK.
14998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    const unsigned hostnameBufferLength = 2048;
15008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (strLen > hostnameBufferLength || charactersAreAllASCII(str, strLen)) {
15028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer.append(str, strLen);
15038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return;
15048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
15058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#if USE(ICU_UNICODE)
15078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UChar hostnameBuffer[hostnameBufferLength];
15088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UErrorCode error = U_ZERO_ERROR;
15098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int32_t numCharactersConverted = uidna_IDNToASCII(str, strLen, hostnameBuffer,
15108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostnameBufferLength, UIDNA_ALLOW_UNASSIGNED, 0, &error);
15118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (error == U_ZERO_ERROR)
15128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        buffer.append(hostnameBuffer, numCharactersConverted);
15138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#elif USE(QT4_UNICODE)
15148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    QByteArray result = QUrl::toAce(String(str, strLen));
15158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.append(result.constData(), result.length());
1516d0825bca7fe65beaee391d30da42e937db621564Steve Block#elif USE(GLIB_UNICODE)
1517d0825bca7fe65beaee391d30da42e937db621564Steve Block    GOwnPtr<gchar> utf8Hostname;
1518d0825bca7fe65beaee391d30da42e937db621564Steve Block    GOwnPtr<GError> utf8Err;
1519d0825bca7fe65beaee391d30da42e937db621564Steve Block    utf8Hostname.set(g_utf16_to_utf8(str, strLen, 0, 0, &utf8Err.outPtr()));
1520d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (utf8Err)
1521d0825bca7fe65beaee391d30da42e937db621564Steve Block        return;
1522d0825bca7fe65beaee391d30da42e937db621564Steve Block
1523d0825bca7fe65beaee391d30da42e937db621564Steve Block    GOwnPtr<gchar> encodedHostname;
1524d0825bca7fe65beaee391d30da42e937db621564Steve Block    encodedHostname.set(g_hostname_to_ascii(utf8Hostname.get()));
1525d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (!encodedHostname)
1526d0825bca7fe65beaee391d30da42e937db621564Steve Block        return;
1527d0825bca7fe65beaee391d30da42e937db621564Steve Block
1528d0825bca7fe65beaee391d30da42e937db621564Steve Block    buffer.append(encodedHostname.get(), strlen(encodedHostname.get()));
15298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#endif
15308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
15318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void findHostnamesInMailToURL(const UChar* str, int strLen, Vector<pair<int, int> >& nameRanges)
15338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
15348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The 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.
15358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Skip quoted strings so that characters in them don't confuse us.
15368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // When we find a '?' character, we are past the part of the URL that contains host names.
15378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    nameRanges.clear();
15398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int p = 0;
15418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
15428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find start of host name or of quoted string.
15438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int hostnameOrStringStart = findFirstOf(str, strLen, p, "\"@?");
15448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (hostnameOrStringStart == -1)
15458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
15468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar c = str[hostnameOrStringStart];
15478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = hostnameOrStringStart + 1;
15488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '?')
15508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return;
15518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == '@') {
15538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Find end of host name.
15548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int hostnameStart = p;
15558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            int hostnameEnd = findFirstOf(str, strLen, p, ">,?");
15568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            bool done;
15578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (hostnameEnd == -1) {
15588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                hostnameEnd = strLen;
15598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                done = true;
15608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            } else {
15618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                p = hostnameEnd;
15628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                done = false;
15638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
15648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            nameRanges.append(make_pair(hostnameStart, hostnameEnd));
15668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (done)
15688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return;
15698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
15708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Skip quoted string.
15718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            ASSERT(c == '"');
15728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            while (1) {
15738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                int escapedCharacterOrStringEnd = findFirstOf(str, strLen, p, "\"\\");
15748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (escapedCharacterOrStringEnd == -1)
15758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
15768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                c = str[escapedCharacterOrStringEnd];
15788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                p = escapedCharacterOrStringEnd + 1;
15798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // If we are the end of the string, then break from the string loop back to the host name loop.
15818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (c == '"')
15828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    break;
15838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                // Skip escaped character.
15858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                ASSERT(c == '\\');
15868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (p == strLen)
15878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    return;
15888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                ++p;
15908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
15918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
15928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
15938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
15948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
15958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic bool findHostnameInHierarchicalURL(const UChar* str, int strLen, int& startOffset, int& endOffset)
15968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
15978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find the host name in a hierarchical URL.
15988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // It comes after a "://" sequence, with scheme characters preceding, and
15998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // this should be the first colon in the string.
16008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // It ends with the end of the string or a ":" or a path segment ending character.
16018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // If there is a "@" character, the host part is just the part after the "@".
16028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int separator = findFirstOf(str, strLen, 0, ":");
16038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (separator == -1 || separator + 2 >= strLen ||
16048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        str[separator + 1] != '/' || str[separator + 2] != '/')
16058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
16068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Check that all characters before the :// are valid scheme characters.
16088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!isSchemeFirstChar(str[0]))
16098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
16108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 1; i < separator; ++i) {
16118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!isSchemeChar(str[i]))
16128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
16138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Start after the separator.
16168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int authorityStart = separator + 3;
16178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find terminating character.
16198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostnameEnd = strLen;
16208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = authorityStart; i < strLen; ++i) {
16218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        UChar c = str[i];
16228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (c == ':' || (isPathSegmentEndChar(c) && c != 0)) {
16238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            hostnameEnd = i;
16248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
16258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
16268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Find "@" for the start of the host name.
16298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int userInfoTerminator = findFirstOf(str, strLen, authorityStart, "@");
16308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int hostnameStart;
16318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (userInfoTerminator == -1 || userInfoTerminator > hostnameEnd)
16328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostnameStart = authorityStart;
16338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
16348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        hostnameStart = userInfoTerminator + 1;
16358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    startOffset = hostnameStart;
16378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    endOffset = hostnameEnd;
16388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return true;
16398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
16408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// Converts all hostnames found in the given input to punycode, preserving the
16428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// rest of the URL unchanged. The output will NOT be null-terminated.
16438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void encodeHostnames(const String& str, UCharBuffer& output)
16448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
16458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    output.clear();
16468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (protocolIs(str, "mailto")) {
16488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Vector<pair<int, int> > hostnameRanges;
16498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        findHostnamesInMailToURL(str.characters(), str.length(), hostnameRanges);
16508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int n = hostnameRanges.size();
16518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int p = 0;
16528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        for (int i = 0; i < n; ++i) {
16538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            const pair<int, int>& r = hostnameRanges[i];
16548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(&str.characters()[p], r.first - p);
16558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            appendEncodedHostname(output, &str.characters()[r.first], r.second - r.first);
16568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            p = r.second;
16578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
16588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // This will copy either everything after the last hostname, or the
16598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // whole thing if there is no hostname.
16608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        output.append(&str.characters()[p], str.length() - p);
16618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
16628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        int hostStart, hostEnd;
16638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (findHostnameInHierarchicalURL(str.characters(), str.length(), hostStart, hostEnd)) {
16648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(str.characters(), hostStart); // Before hostname.
16658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            appendEncodedHostname(output, &str.characters()[hostStart], hostEnd - hostStart);
16668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(&str.characters()[hostEnd], str.length() - hostEnd); // After hostname.
16678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else {
16688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // No hostname to encode, return the input.
16698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            output.append(str.characters(), str.length());
16708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
16718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
16738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic void encodeRelativeString(const String& rel, const TextEncoding& encoding, CharBuffer& output)
16758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
16768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    UCharBuffer s;
16778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    encodeHostnames(rel, s);
16788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    TextEncoding pathEncoding(UTF8Encoding()); // Path is always encoded as UTF-8; other parts may depend on the scheme.
16808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int pathEnd = -1;
16825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (encoding != pathEncoding && encoding.isValid() && !protocolIs(rel, "mailto") && !protocolIs(rel, "data") && !protocolIsJavaScript(rel)) {
16838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Find the first instance of either # or ?, keep pathEnd at -1 otherwise.
16848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = findFirstOf(s.data(), s.size(), 0, "#?");
16858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
16868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (pathEnd == -1) {
16888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CString decoded = pathEncoding.encode(s.data(), s.size(), URLEncodedEntitiesForUnencodables);
16898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        output.resize(decoded.length());
16908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memcpy(output.data(), decoded.data(), decoded.length());
16918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else {
16928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CString pathDecoded = pathEncoding.encode(s.data(), pathEnd, URLEncodedEntitiesForUnencodables);
16938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Unencodable characters in URLs are represented by converting
16948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // them to XML entities and escaping non-alphanumeric characters.
16958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        CString otherDecoded = encoding.encode(s.data() + pathEnd, s.size() - pathEnd, URLEncodedEntitiesForUnencodables);
16968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
16978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        output.resize(pathDecoded.length() + otherDecoded.length());
16988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memcpy(output.data(), pathDecoded.data(), pathDecoded.length());
16998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        memcpy(output.data() + pathDecoded.length(), otherDecoded.data(), otherDecoded.length());
17008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
17018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    output.append('\0'); // null-terminate the output.
17028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic String substituteBackslashes(const String& string)
17058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1706f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t questionPos = string.find('?');
1707f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t hashPos = string.find('#');
1708f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    unsigned pathEnd;
17098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1710f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (hashPos != notFound && (questionPos == notFound || questionPos > hashPos))
17118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = hashPos;
1712f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    else if (questionPos != notFound)
17138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = questionPos;
17148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    else
17158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pathEnd = string.length();
17168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return string.left(pathEnd).replace('\\','/') + string.substring(pathEnd);
17188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool KURL::isHierarchical() const
17218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!m_isValid)
17238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
17248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(m_string[m_schemeEnd] == ':');
17258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return m_string[m_schemeEnd + 1] == '/';
17268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectvoid KURL::copyToBuffer(CharBuffer& buffer) const
17298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This throws away the high bytes of all the characters in the string!
17318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // That's fine for a valid URL, which is all ASCII, but not for invalid URLs.
17328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    buffer.resize(m_string.length());
17338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    copyASCII(m_string.characters(), m_string.length(), buffer.data());
17348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
17368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool protocolIs(const String& url, const char* protocol)
17378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
17388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Do the comparison without making a new string object.
17398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    assertProtocolIsGood(protocol);
17408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    for (int i = 0; ; ++i) {
17418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!protocol[i])
17428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return url[i] == ':';
17438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (toASCIILower(url[i]) != protocol[i])
17448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return false;
17458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
17468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
17478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1748643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool isValidProtocol(const String& protocol)
1749643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
1750d0825bca7fe65beaee391d30da42e937db621564Steve Block    // RFC3986: ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
1751d0825bca7fe65beaee391d30da42e937db621564Steve Block    if (protocol.isEmpty())
1752d0825bca7fe65beaee391d30da42e937db621564Steve Block        return false;
1753643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!isSchemeFirstChar(protocol[0]))
1754643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return false;
1755643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned protocolLength = protocol.length();
1756643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    for (unsigned i = 1; i < protocolLength; i++) {
1757643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        if (!isSchemeChar(protocol[i]))
1758643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            return false;
1759643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
1760643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return true;
1761643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
1762643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
176381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#ifndef NDEBUG
176481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochvoid KURL::print() const
176581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
176681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    printf("%s\n", m_string.utf8().data());
176781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
176881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#endif
176981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
177081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch#endif // !USE(GOOGLEURL)
177181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
177281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen MurdochString KURL::strippedForUseAsReferrer() const
177381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
177481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    KURL referrer(*this);
177581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    referrer.setUser(String());
177681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    referrer.setPass(String());
177781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    referrer.removeFragmentIdentifier();
177881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return referrer.string();
177981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
178081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
178181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool KURL::isLocalFile() const
178281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
178381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Including feed here might be a bad idea since drag and drop uses this check
178481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // and including feed would allow feeds to potentially let someone's blog
178581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // read the contents of the clipboard on a drag, even without a drop.
178681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    // Likewise with using the FrameLoader::shouldTreatURLAsLocal() function.
178781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return protocolIs("file");
178881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
178981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
179081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochbool protocolIsJavaScript(const String& url)
179181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
179281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return protocolIs(url, "javascript");
179381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
179481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
179581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdochconst KURL& blankURL()
179681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch{
179781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    DEFINE_STATIC_LOCAL(KURL, staticBlankURL, (ParsedURLString, "about:blank"));
179881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch    return staticBlankURL;
179981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch}
180081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch
1801643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool isDefaultPortForProtocol(unsigned short port, const String& protocol)
1802643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
1803643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (protocol.isEmpty())
1804643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return false;
1805643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1806643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    typedef HashMap<String, unsigned, CaseFoldingHash> DefaultPortsMap;
1807643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    DEFINE_STATIC_LOCAL(DefaultPortsMap, defaultPorts, ());
1808643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (defaultPorts.isEmpty()) {
1809643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("http", 80);
1810643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("https", 443);
1811643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("ftp", 21);
1812643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        defaultPorts.set("ftps", 990);
1813643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
1814643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return defaultPorts.get(protocol) == port;
1815643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
1816643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1817643ca7872b450ea4efacab6188849e5aac2ba161Steve Blockbool portAllowed(const KURL& url)
1818643ca7872b450ea4efacab6188849e5aac2ba161Steve Block{
1819643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    unsigned short port = url.port();
1820643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1821643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Since most URLs don't have a port, return early for the "no port" case.
1822643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!port)
1823643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1824643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1825643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // This blocked port list matches the port blocking that Mozilla implements.
1826643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // See http://www.mozilla.org/projects/netlib/PortBanning.html for more information.
1827643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    static const unsigned short blockedPortList[] = {
1828643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        1,    // tcpmux
1829643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        7,    // echo
1830643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        9,    // discard
1831643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        11,   // systat
1832643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        13,   // daytime
1833643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        15,   // netstat
1834643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        17,   // qotd
1835643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        19,   // chargen
1836643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        20,   // FTP-data
1837643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        21,   // FTP-control
1838643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        22,   // SSH
1839643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        23,   // telnet
1840643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        25,   // SMTP
1841643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        37,   // time
1842643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        42,   // name
1843643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        43,   // nicname
1844643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        53,   // domain
1845643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        77,   // priv-rjs
1846643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        79,   // finger
1847643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        87,   // ttylink
1848643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        95,   // supdup
1849643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        101,  // hostriame
1850643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        102,  // iso-tsap
1851643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        103,  // gppitnp
1852643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        104,  // acr-nema
1853643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        109,  // POP2
1854643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        110,  // POP3
1855643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        111,  // sunrpc
1856643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        113,  // auth
1857643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        115,  // SFTP
1858643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        117,  // uucp-path
1859643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        119,  // nntp
1860643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        123,  // NTP
1861643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        135,  // loc-srv / epmap
1862643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        139,  // netbios
1863643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        143,  // IMAP2
1864643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        179,  // BGP
1865643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        389,  // LDAP
1866643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        465,  // SMTP+SSL
1867643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        512,  // print / exec
1868643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        513,  // login
1869643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        514,  // shell
1870643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        515,  // printer
1871643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        526,  // tempo
1872643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        530,  // courier
1873643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        531,  // Chat
1874643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        532,  // netnews
1875643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        540,  // UUCP
1876643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        556,  // remotefs
1877643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        563,  // NNTP+SSL
1878643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        587,  // ESMTP
1879643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        601,  // syslog-conn
1880643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        636,  // LDAP+SSL
1881643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        993,  // IMAP+SSL
1882643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        995,  // POP3+SSL
1883643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        2049, // NFS
1884643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        3659, // apple-sasl / PasswordServer [Apple addition]
1885643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        4045, // lockd
1886643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        6000, // X11
18875e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6665, // Alternate IRC [Apple addition]
18885e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6666, // Alternate IRC [Apple addition]
18895e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6667, // Standard IRC [Apple addition]
18905e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6668, // Alternate IRC [Apple addition]
18915e2bc6953fe6923165b8a5d7679939693a1d58d6Steve Block        6669, // Alternate IRC [Apple addition]
1892dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        invalidPortNumber, // Used to block all invalid port numbers
1893643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    };
18944576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    const unsigned short* const blockedPortListEnd = blockedPortList + WTF_ARRAY_LENGTH(blockedPortList);
1895643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1896643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#ifndef NDEBUG
1897643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // The port list must be sorted for binary_search to work.
1898643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    static bool checkedPortList = false;
1899643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!checkedPortList) {
1900643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        for (const unsigned short* p = blockedPortList; p != blockedPortListEnd - 1; ++p)
1901643ca7872b450ea4efacab6188849e5aac2ba161Steve Block            ASSERT(*p < *(p + 1));
1902643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        checkedPortList = true;
1903643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    }
1904643ca7872b450ea4efacab6188849e5aac2ba161Steve Block#endif
1905643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1906643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // If the port is not in the blocked port list, allow it.
1907643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (!binary_search(blockedPortList, blockedPortListEnd, port))
1908643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1909643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1910643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Allow ports 21 and 22 for FTP URLs, as Mozilla does.
1911643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if ((port == 21 || port == 22) && url.protocolIs("ftp"))
1912643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1913643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1914643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    // Allow any port number in a file URL, since the port number is ignored.
1915643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (url.protocolIs("file"))
1916643ca7872b450ea4efacab6188849e5aac2ba161Steve Block        return true;
1917643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
1918643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    return false;
1919643ca7872b450ea4efacab6188849e5aac2ba161Steve Block}
1920643ca7872b450ea4efacab6188849e5aac2ba161Steve Block
19218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectString mimeTypeFromDataURL(const String& url)
19228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
19238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(protocolIs(url, "data"));
1924f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    size_t index = url.find(';');
1925f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (index == notFound)
19268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        index = url.find(',');
1927f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick    if (index != notFound) {
1928f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick        if (index > 5)
1929f486d19d62f1bc33246748b14b14a9dfa617b57fIain Merrick            return url.substring(5, index - 5);
19308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return "text/plain"; // Data URLs with no MIME type are considered text/plain.
19318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
19328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return "";
19338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
19348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
19358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1936