1bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// Copyright 2016 the V8 project authors. All rights reserved.
2bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// Use of this source code is governed by a BSD-style license that can be
3bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch// found in the LICENSE file.
4bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
5bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/uri.h"
6bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
7bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/char-predicates-inl.h"
8bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/handles.h"
9bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/isolate-inl.h"
10bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch#include "src/list.h"
1113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch#include "src/string-search.h"
12bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
13bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochnamespace v8 {
14bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochnamespace internal {
15bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
1613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochnamespace {  // anonymous namespace for DecodeURI helper functions
1713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochbool IsReservedPredicate(uc16 c) {
1813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  switch (c) {
1913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '#':
2013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '$':
2113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '&':
2213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '+':
2313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case ',':
2413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '/':
2513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case ':':
2613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case ';':
2713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '=':
2813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '?':
2913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '@':
3013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      return true;
3113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    default:
3213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      return false;
3313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
3413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
3513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
3613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochbool IsReplacementCharacter(const uint8_t* octets, int length) {
3713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // The replacement character is at codepoint U+FFFD in the Unicode Specials
3813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // table. Its UTF-8 encoding is 0xEF 0xBF 0xBD.
3913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (length != 3 || octets[0] != 0xef || octets[1] != 0xbf ||
4013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      octets[2] != 0xbd) {
4113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return false;
4213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
4313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return true;
4413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
4513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
4613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochbool DecodeOctets(const uint8_t* octets, int length, List<uc16>* buffer) {
4713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  size_t cursor = 0;
4813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  uc32 value = unibrow::Utf8::ValueOf(octets, length, &cursor);
4913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (value == unibrow::Utf8::kBadChar &&
5013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      !IsReplacementCharacter(octets, length)) {
5113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return false;
5213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
5313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
54c8c1d9e03f4babd16833b0f8ccf6aab5fa6e8c7aBen Murdoch  if (value <= static_cast<uc32>(unibrow::Utf16::kMaxNonSurrogateCharCode)) {
5513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add(value);
5613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  } else {
5713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add(unibrow::Utf16::LeadSurrogate(value));
5813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add(unibrow::Utf16::TrailSurrogate(value));
5913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
6013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return true;
6113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
6213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
6313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochint TwoDigitHex(uc16 character1, uc16 character2) {
6413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (character1 > 'f') return -1;
6513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int high = HexValue(character1);
6613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (high == -1) return -1;
6713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (character2 > 'f') return -1;
6813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int low = HexValue(character2);
6913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (low == -1) return -1;
7013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return (high << 4) + low;
7113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
7213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
7313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <typename T>
7413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochvoid AddToBuffer(uc16 decoded, String::FlatContent* uri_content, int index,
7513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                 bool is_uri, List<T>* buffer) {
7613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (is_uri && IsReservedPredicate(decoded)) {
7713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add('%');
7813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    uc16 first = uri_content->Get(index + 1);
7913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    uc16 second = uri_content->Get(index + 2);
8013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DCHECK_GT(std::numeric_limits<T>::max(), first);
8113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DCHECK_GT(std::numeric_limits<T>::max(), second);
8213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
8313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add(first);
8413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add(second);
8513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  } else {
8613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    buffer->Add(decoded);
8713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
8813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
8913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
9013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochbool IntoTwoByte(int index, bool is_uri, int uri_length,
9113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                 String::FlatContent* uri_content, List<uc16>* buffer) {
9213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  for (int k = index; k < uri_length; k++) {
9313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    uc16 code = uri_content->Get(k);
9413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    if (code == '%') {
95f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      int two_digits;
9613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (k + 2 >= uri_length ||
97f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          (two_digits = TwoDigitHex(uri_content->Get(k + 1),
98f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                    uri_content->Get(k + 2))) < 0) {
9913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        return false;
10013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
10113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      k += 2;
102f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      uc16 decoded = static_cast<uc16>(two_digits);
10313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (decoded > unibrow::Utf8::kMaxOneByteChar) {
10413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        uint8_t octets[unibrow::Utf8::kMaxEncodedSize];
10513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        octets[0] = decoded;
10613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
10713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        int number_of_continuation_bytes = 0;
10813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        while ((decoded << ++number_of_continuation_bytes) & 0x80) {
10913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          if (number_of_continuation_bytes > 3 || k + 3 >= uri_length) {
11013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch            return false;
11113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          }
11213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          if (uri_content->Get(++k) != '%' ||
113f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch              (two_digits = TwoDigitHex(uri_content->Get(k + 1),
114f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                        uri_content->Get(k + 2))) < 0) {
11513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch            return false;
11613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          }
11713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          k += 2;
118f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          uc16 continuation_byte = static_cast<uc16>(two_digits);
11913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          octets[number_of_continuation_bytes] = continuation_byte;
12013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        }
12113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
12213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        if (!DecodeOctets(octets, number_of_continuation_bytes, buffer)) {
12313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          return false;
12413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        }
12513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      } else {
12613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        AddToBuffer(decoded, uri_content, k - 2, is_uri, buffer);
12713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
12813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    } else {
12913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      buffer->Add(code);
13013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
13113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
13213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return true;
13313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
13413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
13513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochbool IntoOneAndTwoByte(Handle<String> uri, bool is_uri,
13613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                       List<uint8_t>* one_byte_buffer,
13713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                       List<uc16>* two_byte_buffer) {
13813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  DisallowHeapAllocation no_gc;
13913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  String::FlatContent uri_content = uri->GetFlatContent();
14013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
14113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int uri_length = uri->length();
14213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  for (int k = 0; k < uri_length; k++) {
14313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    uc16 code = uri_content.Get(k);
14413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    if (code == '%') {
145f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      int two_digits;
14613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (k + 2 >= uri_length ||
147f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch          (two_digits = TwoDigitHex(uri_content.Get(k + 1),
148f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch                                    uri_content.Get(k + 2))) < 0) {
14913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        return false;
15013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
15113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
152f91f0611dbaf29ca0f1d4aecb357ce243a19d2faBen Murdoch      uc16 decoded = static_cast<uc16>(two_digits);
15313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (decoded > unibrow::Utf8::kMaxOneByteChar) {
15413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        return IntoTwoByte(k, is_uri, uri_length, &uri_content,
15513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                           two_byte_buffer);
15613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
15713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
15813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      AddToBuffer(decoded, &uri_content, k, is_uri, one_byte_buffer);
15913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      k += 2;
16013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    } else {
16113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (code > unibrow::Utf8::kMaxOneByteChar) {
16213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        return IntoTwoByte(k, is_uri, uri_length, &uri_content,
16313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                           two_byte_buffer);
16413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
16513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      one_byte_buffer->Add(code);
16613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
16713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
16813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return true;
16913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
17013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
17113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}  // anonymous namespace
17213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
17313e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybeHandle<String> Uri::Decode(Isolate* isolate, Handle<String> uri,
17413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                bool is_uri) {
17513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  uri = String::Flatten(uri);
17613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  List<uint8_t> one_byte_buffer;
17713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  List<uc16> two_byte_buffer;
17813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
17913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (!IntoOneAndTwoByte(uri, is_uri, &one_byte_buffer, &two_byte_buffer)) {
18013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    THROW_NEW_ERROR(isolate, NewURIError(), String);
18113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
18213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
18313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (two_byte_buffer.is_empty()) {
18413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return isolate->factory()->NewStringFromOneByte(
18513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        one_byte_buffer.ToConstVector());
18613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
18713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
18813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Handle<SeqTwoByteString> result;
18913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  ASSIGN_RETURN_ON_EXCEPTION(
19013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      isolate, result, isolate->factory()->NewRawTwoByteString(
19113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                           one_byte_buffer.length() + two_byte_buffer.length()),
19213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      String);
19313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
19413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  CopyChars(result->GetChars(), one_byte_buffer.ToConstVector().start(),
19513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch            one_byte_buffer.length());
19613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  CopyChars(result->GetChars() + one_byte_buffer.length(),
19713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch            two_byte_buffer.ToConstVector().start(), two_byte_buffer.length());
19813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
19913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return result;
20013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
20113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
202bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochnamespace {  // anonymous namespace for EncodeURI helper functions
203bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochbool IsUnescapePredicateInUriComponent(uc16 c) {
204bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  if (IsAlphaNumeric(c)) {
205bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    return true;
206bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
207bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
208bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  switch (c) {
209bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '!':
210bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '\'':
211bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '(':
212bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case ')':
213bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '*':
214bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '-':
215bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '.':
216bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '_':
217bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '~':
218bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      return true;
219bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    default:
220bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      return false;
221bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
222bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
223bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
224bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochbool IsUriSeparator(uc16 c) {
225bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  switch (c) {
226bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '#':
227bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case ':':
228bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case ';':
229bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '/':
230bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '?':
231bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '$':
232bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '&':
233bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '+':
234bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case ',':
235bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '@':
236bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    case '=':
237bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      return true;
238bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    default:
239bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      return false;
240bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
241bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
242bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
24313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochvoid AddEncodedOctetToBuffer(uint8_t octet, List<uint8_t>* buffer) {
244bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  buffer->Add('%');
245bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  buffer->Add(HexCharOfValue(octet >> 4));
246bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  buffer->Add(HexCharOfValue(octet & 0x0F));
247bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
248bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
249bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid EncodeSingle(uc16 c, List<uint8_t>* buffer) {
25013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  char s[4] = {};
25113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int number_of_bytes;
25213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  number_of_bytes =
25313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      unibrow::Utf8::Encode(s, c, unibrow::Utf16::kNoPreviousCharacter, false);
25413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  for (int k = 0; k < number_of_bytes; k++) {
25513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    AddEncodedOctetToBuffer(s[k], buffer);
256bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
257bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
258bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
259bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdochvoid EncodePair(uc16 cc1, uc16 cc2, List<uint8_t>* buffer) {
26013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  char s[4] = {};
26113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int number_of_bytes =
26213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      unibrow::Utf8::Encode(s, unibrow::Utf16::CombineSurrogatePair(cc1, cc2),
26313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                            unibrow::Utf16::kNoPreviousCharacter, false);
26413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  for (int k = 0; k < number_of_bytes; k++) {
26513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    AddEncodedOctetToBuffer(s[k], buffer);
26613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
267bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
268bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
269bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}  // anonymous namespace
270bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
27113e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybeHandle<String> Uri::Encode(Isolate* isolate, Handle<String> uri,
27213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                bool is_uri) {
273bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  uri = String::Flatten(uri);
274bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  int uri_length = uri->length();
275bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  List<uint8_t> buffer(uri_length);
276bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
277bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  {
278bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    DisallowHeapAllocation no_gc;
279bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    String::FlatContent uri_content = uri->GetFlatContent();
280bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
281bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    for (int k = 0; k < uri_length; k++) {
282bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      uc16 cc1 = uri_content.Get(k);
283bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      if (unibrow::Utf16::IsLeadSurrogate(cc1)) {
284bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        k++;
285bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        if (k < uri_length) {
286bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch          uc16 cc2 = uri->Get(k);
287bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch          if (unibrow::Utf16::IsTrailSurrogate(cc2)) {
288bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch            EncodePair(cc1, cc2, &buffer);
289bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch            continue;
290bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch          }
291bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        }
292bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      } else if (!unibrow::Utf16::IsTrailSurrogate(cc1)) {
293bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        if (IsUnescapePredicateInUriComponent(cc1) ||
294bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch            (is_uri && IsUriSeparator(cc1))) {
295bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch          buffer.Add(cc1);
296bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        } else {
297bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch          EncodeSingle(cc1, &buffer);
298bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        }
299bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch        continue;
300bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      }
301bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
302bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch      AllowHeapAllocation allocate_error_and_return;
30313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      THROW_NEW_ERROR(isolate, NewURIError(), String);
30413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
30513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
30613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
30713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return isolate->factory()->NewStringFromOneByte(buffer.ToConstVector());
30813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
30913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
31013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochnamespace {  // Anonymous namespace for Escape and Unescape
31113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
31213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <typename Char>
31313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochint UnescapeChar(Vector<const Char> vector, int i, int length, int* step) {
31413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  uint16_t character = vector[i];
31513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int32_t hi = 0;
31613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int32_t lo = 0;
31713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (character == '%' && i <= length - 6 && vector[i + 1] == 'u' &&
31813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      (hi = TwoDigitHex(vector[i + 2], vector[i + 3])) > -1 &&
31913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      (lo = TwoDigitHex(vector[i + 4], vector[i + 5])) > -1) {
32013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    *step = 6;
32113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return (hi << 8) + lo;
32213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  } else if (character == '%' && i <= length - 3 &&
32313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch             (lo = TwoDigitHex(vector[i + 1], vector[i + 2])) > -1) {
32413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    *step = 3;
32513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return lo;
32613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  } else {
32713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    *step = 1;
32813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return character;
32913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
33013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
33113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
33213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <typename Char>
33313e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybeHandle<String> UnescapeSlow(Isolate* isolate, Handle<String> string,
33413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                 int start_index) {
33513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  bool one_byte = true;
33613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int length = string->length();
33713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
33813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int unescaped_length = 0;
33913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
34013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DisallowHeapAllocation no_allocation;
34113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Vector<const Char> vector = string->GetCharVector<Char>();
34213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    for (int i = start_index; i < length; unescaped_length++) {
34313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      int step;
34413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (UnescapeChar(vector, i, length, &step) >
34513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch          String::kMaxOneByteCharCode) {
34613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        one_byte = false;
34713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
34813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      i += step;
349bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch    }
350bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  }
351bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
35213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  DCHECK(start_index < length);
35313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Handle<String> first_part =
35413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      isolate->factory()->NewProperSubString(string, 0, start_index);
35513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
35613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int dest_position = 0;
35713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Handle<String> second_part;
35813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  DCHECK(unescaped_length <= String::kMaxLength);
35913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (one_byte) {
36013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Handle<SeqOneByteString> dest = isolate->factory()
36113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                        ->NewRawOneByteString(unescaped_length)
36213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                        .ToHandleChecked();
36313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DisallowHeapAllocation no_allocation;
36413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Vector<const Char> vector = string->GetCharVector<Char>();
36513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    for (int i = start_index; i < length; dest_position++) {
36613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      int step;
36713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      dest->SeqOneByteStringSet(dest_position,
36813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                UnescapeChar(vector, i, length, &step));
36913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      i += step;
37013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
37113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    second_part = dest;
37213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  } else {
37313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Handle<SeqTwoByteString> dest = isolate->factory()
37413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                        ->NewRawTwoByteString(unescaped_length)
37513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                        .ToHandleChecked();
37613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DisallowHeapAllocation no_allocation;
37713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Vector<const Char> vector = string->GetCharVector<Char>();
37813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    for (int i = start_index; i < length; dest_position++) {
37913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      int step;
38013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      dest->SeqTwoByteStringSet(dest_position,
38113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                UnescapeChar(vector, i, length, &step));
38213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      i += step;
38313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
38413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    second_part = dest;
38513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
38613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return isolate->factory()->NewConsString(first_part, second_part);
38713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
38813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
38913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochbool IsNotEscaped(uint16_t c) {
39013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (IsAlphaNumeric(c)) {
39113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    return true;
39213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
39313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  //  @*_+-./
39413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  switch (c) {
39513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '@':
39613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '*':
39713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '_':
39813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '+':
39913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '-':
40013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '.':
40113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    case '/':
40213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      return true;
40313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    default:
40413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      return false;
40513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
40613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
40713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
40813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <typename Char>
40913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochstatic MaybeHandle<String> UnescapePrivate(Isolate* isolate,
41013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                           Handle<String> source) {
41113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int index;
41213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
41313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DisallowHeapAllocation no_allocation;
41413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    StringSearch<uint8_t, Char> search(isolate, STATIC_CHAR_VECTOR("%"));
41513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    index = search.Search(source->GetCharVector<Char>(), 0);
41613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    if (index < 0) return source;
41713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
41813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return UnescapeSlow<Char>(isolate, source, index);
41913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
42013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
42113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochtemplate <typename Char>
42213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdochstatic MaybeHandle<String> EscapePrivate(Isolate* isolate,
42313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                         Handle<String> string) {
42413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  DCHECK(string->IsFlat());
42513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int escaped_length = 0;
42613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int length = string->length();
42713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
42813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
42913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DisallowHeapAllocation no_allocation;
43013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Vector<const Char> vector = string->GetCharVector<Char>();
43113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    for (int i = 0; i < length; i++) {
43213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      uint16_t c = vector[i];
43313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (c >= 256) {
43413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        escaped_length += 6;
43513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      } else if (IsNotEscaped(c)) {
43613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        escaped_length++;
43713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      } else {
43813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        escaped_length += 3;
43913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
44013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
44113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      // We don't allow strings that are longer than a maximal length.
44213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      DCHECK(String::kMaxLength < 0x7fffffff - 6);     // Cannot overflow.
44313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (escaped_length > String::kMaxLength) break;  // Provoke exception.
44413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
44513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
44613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
44713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  // No length change implies no change.  Return original string if no change.
44813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  if (escaped_length == length) return string;
44913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
45013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Handle<SeqOneByteString> dest;
45113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  ASSIGN_RETURN_ON_EXCEPTION(
45213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      isolate, dest, isolate->factory()->NewRawOneByteString(escaped_length),
45313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      String);
45413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  int dest_position = 0;
45513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
45613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  {
45713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    DisallowHeapAllocation no_allocation;
45813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    Vector<const Char> vector = string->GetCharVector<Char>();
45913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    for (int i = 0; i < length; i++) {
46013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      uint16_t c = vector[i];
46113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      if (c >= 256) {
46213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position, '%');
46313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 1, 'u');
46413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 2, HexCharOfValue(c >> 12));
46513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 3,
46613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                  HexCharOfValue((c >> 8) & 0xf));
46713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 4,
46813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch                                  HexCharOfValue((c >> 4) & 0xf));
46913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 5, HexCharOfValue(c & 0xf));
47013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest_position += 6;
47113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      } else if (IsNotEscaped(c)) {
47213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position, c);
47313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest_position++;
47413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      } else {
47513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position, '%');
47613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 1, HexCharOfValue(c >> 4));
47713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest->SeqOneByteStringSet(dest_position + 2, HexCharOfValue(c & 0xf));
47813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch        dest_position += 3;
47913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch      }
48013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch    }
48113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  }
48213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
48313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return dest;
48413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
48513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
48613e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}  // Anonymous namespace
48713e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
48813e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybeHandle<String> Uri::Escape(Isolate* isolate, Handle<String> string) {
48913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  Handle<String> result;
49013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  string = String::Flatten(string);
49113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return string->IsOneByteRepresentationUnderneath()
49213e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch             ? EscapePrivate<uint8_t>(isolate, string)
49313e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch             : EscapePrivate<uc16>(isolate, string);
49413e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch}
49513e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch
49613e2dadd00298019ed862f2b2fc5068bba730bcfBen MurdochMaybeHandle<String> Uri::Unescape(Isolate* isolate, Handle<String> string) {
497bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch  Handle<String> result;
49813e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  string = String::Flatten(string);
49913e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch  return string->IsOneByteRepresentationUnderneath()
50013e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch             ? UnescapePrivate<uint8_t>(isolate, string)
50113e2dadd00298019ed862f2b2fc5068bba730bcfBen Murdoch             : UnescapePrivate<uc16>(isolate, string);
502bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}
503bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch
504bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}  // namespace internal
505bcf72ee8e3b26f1d0726869c7ddb3921c68b09a8Ben Murdoch}  // namespace v8
506