Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/xpcom/io/nsEscape.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
3
/* This Source Code Form is subject to the terms of the Mozilla Public
4
 * License, v. 2.0. If a copy of the MPL was not distributed with this
5
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7
#include "nsEscape.h"
8
9
#include "mozilla/ArrayUtils.h"
10
#include "mozilla/BinarySearch.h"
11
#include "mozilla/CheckedInt.h"
12
#include "mozilla/TextUtils.h"
13
#include "nsTArray.h"
14
#include "nsCRT.h"
15
#include "plstr.h"
16
#include "nsASCIIMask.h"
17
18
static const char hexCharsUpper[] = "0123456789ABCDEF";
19
static const char hexCharsUpperLower[] = "0123456789ABCDEFabcdef";
20
21
static const int netCharType[256] =
22
// clang-format off
23
/*  Bit 0       xalpha      -- the alphas
24
**  Bit 1       xpalpha     -- as xalpha but
25
**                             converts spaces to plus and plus to %2B
26
**  Bit 3 ...   path        -- as xalphas but doesn't escape '/'
27
*/
28
  /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
29
  {  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 0x */
30
     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,   /* 1x */
31
     0,0,0,0,0,0,0,0,0,0,7,4,0,7,7,4,   /* 2x   !"#$%&'()*+,-./  */
32
     7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,   /* 3x  0123456789:;<=>?  */
33
     0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,   /* 4x  @ABCDEFGHIJKLMNO  */
34
     /* bits for '@' changed from 7 to 0 so '@' can be escaped   */
35
     /* in usernames and passwords in publishing.                */
36
     7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,7,   /* 5X  PQRSTUVWXYZ[\]^_  */
37
     0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,   /* 6x  `abcdefghijklmno  */
38
     7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,   /* 7X  pqrstuvwxyz{\}~  DEL */
39
     0,
40
  };
41
42
/* decode % escaped hex codes into character values
43
 */
44
#define UNHEX(C) \
45
773k
    ((C >= '0' && C <= '9') ? C - '0' : \
46
773k
     ((C >= 'A' && C <= 'F') ? C - 'A' + 10 : \
47
518k
     ((C >= 'a' && C <= 'f') ? C - 'a' + 10 : 0)))
48
// clang-format on
49
50
0
#define IS_OK(C) (netCharType[((unsigned int)(C))] & (aFlags))
51
80.9M
#define HEX_ESCAPE '%'
52
53
static const uint32_t ENCODE_MAX_LEN = 6; // %uABCD
54
55
static uint32_t
56
AppendPercentHex(char* aBuffer, unsigned char aChar)
57
4.67M
{
58
4.67M
  uint32_t i = 0;
59
4.67M
  aBuffer[i++] = '%';
60
4.67M
  aBuffer[i++] = hexCharsUpper[aChar >> 4]; // high nibble
61
4.67M
  aBuffer[i++] = hexCharsUpper[aChar & 0xF]; // low nibble
62
4.67M
  return i;
63
4.67M
}
64
65
static uint32_t
66
AppendPercentHex(char16_t* aBuffer, char16_t aChar)
67
0
{
68
0
  uint32_t i = 0;
69
0
  aBuffer[i++] = '%';
70
0
  if (aChar & 0xff00) {
71
0
    aBuffer[i++] = 'u';
72
0
    aBuffer[i++] = hexCharsUpper[aChar >> 12]; // high-byte high nibble
73
0
    aBuffer[i++] = hexCharsUpper[(aChar >> 8) & 0xF]; // high-byte low nibble
74
0
  }
75
0
  aBuffer[i++] = hexCharsUpper[(aChar >> 4) & 0xF]; // low-byte high nibble
76
0
  aBuffer[i++] = hexCharsUpper[aChar & 0xF]; // low-byte low nibble
77
0
  return i;
78
0
}
79
80
//----------------------------------------------------------------------------------------
81
char*
82
nsEscape(const char* aStr, size_t aLength, size_t* aOutputLength,
83
         nsEscapeMask aFlags)
84
//----------------------------------------------------------------------------------------
85
0
{
86
0
  if (!aStr) {
87
0
    return nullptr;
88
0
  }
89
0
90
0
  size_t charsToEscape = 0;
91
0
92
0
  const unsigned char* src = (const unsigned char*)aStr;
93
0
  for (size_t i = 0; i < aLength; ++i) {
94
0
    if (!IS_OK(src[i])) {
95
0
      charsToEscape++;
96
0
    }
97
0
  }
98
0
99
0
  // calculate how much memory should be allocated
100
0
  // original length + 2 bytes for each escaped character + terminating '\0'
101
0
  // do the sum in steps to check for overflow
102
0
  size_t dstSize = aLength + 1 + charsToEscape;
103
0
  if (dstSize <= aLength) {
104
0
    return nullptr;
105
0
  }
106
0
  dstSize += charsToEscape;
107
0
  if (dstSize < aLength) {
108
0
    return nullptr;
109
0
  }
110
0
111
0
  // fail if we need more than 4GB
112
0
  if (dstSize > UINT32_MAX) {
113
0
    return nullptr;
114
0
  }
115
0
116
0
  char* result = (char*)moz_xmalloc(dstSize);
117
0
118
0
  unsigned char* dst = (unsigned char*)result;
119
0
  src = (const unsigned char*)aStr;
120
0
  if (aFlags == url_XPAlphas) {
121
0
    for (size_t i = 0; i < aLength; ++i) {
122
0
      unsigned char c = *src++;
123
0
      if (IS_OK(c)) {
124
0
        *dst++ = c;
125
0
      } else if (c == ' ') {
126
0
        *dst++ = '+';  /* convert spaces to pluses */
127
0
      } else {
128
0
        *dst++ = HEX_ESCAPE;
129
0
        *dst++ = hexCharsUpper[c >> 4];  /* high nibble */
130
0
        *dst++ = hexCharsUpper[c & 0x0f];  /* low nibble */
131
0
      }
132
0
    }
133
0
  } else {
134
0
    for (size_t i = 0; i < aLength; ++i) {
135
0
      unsigned char c = *src++;
136
0
      if (IS_OK(c)) {
137
0
        *dst++ = c;
138
0
      } else {
139
0
        *dst++ = HEX_ESCAPE;
140
0
        *dst++ = hexCharsUpper[c >> 4];  /* high nibble */
141
0
        *dst++ = hexCharsUpper[c & 0x0f];  /* low nibble */
142
0
      }
143
0
    }
144
0
  }
145
0
146
0
  *dst = '\0';     /* tack on eos */
147
0
  if (aOutputLength) {
148
0
    *aOutputLength = dst - (unsigned char*)result;
149
0
  }
150
0
151
0
  return result;
152
0
}
153
154
//----------------------------------------------------------------------------------------
155
char*
156
nsUnescape(char* aStr)
157
//----------------------------------------------------------------------------------------
158
0
{
159
0
  nsUnescapeCount(aStr);
160
0
  return aStr;
161
0
}
162
163
//----------------------------------------------------------------------------------------
164
int32_t
165
nsUnescapeCount(char* aStr)
166
//----------------------------------------------------------------------------------------
167
20.0k
{
168
20.0k
  char* src = aStr;
169
20.0k
  char* dst = aStr;
170
20.0k
171
20.0k
  char c1[] = " ";
172
20.0k
  char c2[] = " ";
173
20.0k
  char* const pc1 = c1;
174
20.0k
  char* const pc2 = c2;
175
20.0k
176
20.0k
  if (!*src) {
177
697
    // A null string was passed in.  Nothing to escape.
178
697
    // Returns early as the string might not actually be mutable with
179
697
    // length 0.
180
697
    return 0;
181
697
  }
182
19.3k
183
1.92M
  while (*src) {
184
1.90M
    c1[0] = *(src + 1);
185
1.90M
    if (*(src + 1) == '\0') {
186
19.1k
      c2[0] = '\0';
187
1.88M
    } else {
188
1.88M
      c2[0] = *(src + 2);
189
1.88M
    }
190
1.90M
191
1.90M
    if (*src != HEX_ESCAPE || PL_strpbrk(pc1, hexCharsUpperLower) == 0 ||
192
1.90M
        PL_strpbrk(pc2, hexCharsUpperLower) == 0) {
193
1.70M
      *dst++ = *src++;
194
1.70M
    } else {
195
205k
      src++; /* walk over escape */
196
205k
      if (*src) {
197
205k
        *dst = UNHEX(*src) << 4;
198
205k
        src++;
199
205k
      }
200
205k
      if (*src) {
201
205k
        *dst = (*dst + UNHEX(*src));
202
205k
        src++;
203
205k
      }
204
205k
      dst++;
205
205k
    }
206
1.90M
  }
207
19.3k
208
19.3k
  *dst = 0;
209
19.3k
  return (int)(dst - aStr);
210
19.3k
211
19.3k
} /* NET_UnEscapeCnt */
212
213
void
214
nsAppendEscapedHTML(const nsACString& aSrc, nsACString& aDst)
215
0
{
216
0
  // Preparation: aDst's length will increase by at least aSrc's length. If the
217
0
  // addition overflows, we skip this, which is fine, and we'll likely abort
218
0
  // while (infallibly) appending due to aDst becoming too large.
219
0
  mozilla::CheckedInt<nsACString::size_type> newCapacity = aDst.Length();
220
0
  newCapacity += aSrc.Length();
221
0
  if (newCapacity.isValid()) {
222
0
    aDst.SetCapacity(newCapacity.value());
223
0
  }
224
0
225
0
  for (auto cur = aSrc.BeginReading(); cur != aSrc.EndReading(); cur++) {
226
0
    if (*cur == '<') {
227
0
      aDst.AppendLiteral("&lt;");
228
0
    } else if (*cur == '>') {
229
0
      aDst.AppendLiteral("&gt;");
230
0
    } else if (*cur == '&') {
231
0
      aDst.AppendLiteral("&amp;");
232
0
    } else if (*cur == '"') {
233
0
      aDst.AppendLiteral("&quot;");
234
0
    } else if (*cur == '\'') {
235
0
      aDst.AppendLiteral("&#39;");
236
0
    } else {
237
0
      aDst.Append(*cur);
238
0
    }
239
0
  }
240
0
}
241
242
//----------------------------------------------------------------------------------------
243
//
244
// The following table encodes which characters needs to be escaped for which
245
// parts of an URL.  The bits are the "url components" in the enum EscapeMask,
246
// see nsEscape.h.
247
//
248
// esc_Scheme        =     1
249
// esc_Username      =     2
250
// esc_Password      =     4
251
// esc_Host          =     8
252
// esc_Directory     =    16
253
// esc_FileBaseName  =    32
254
// esc_FileExtension =    64
255
// esc_Param         =   128
256
// esc_Query         =   256
257
// esc_Ref           =   512
258
259
static const uint32_t EscapeChars[256] =
260
// clang-format off
261
//   0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
262
{
263
     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 0x
264
     0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,  // 1x
265
     0,1023,   0, 512,1023,   0,1023, 624,1023,1023,1023,1023,1023,1023, 953, 784,  // 2x   !"#$%&'()*+,-./
266
  1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008,1008,   0,1008,   0, 768,  // 3x  0123456789:;<=>?
267
  1008,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,  // 4x  @ABCDEFGHIJKLMNO
268
  1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1008, 896,1008, 896,1023,  // 5x  PQRSTUVWXYZ[\]^_
269
   384,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,  // 6x  `abcdefghijklmno
270
  1023,1023,1023,1023,1023,1023,1023,1023,1023,1023,1023, 896,1012, 896,1023,   0,  // 7x  pqrstuvwxyz{|}~ DEL
271
     0                                                                              // 80 to FF are zero
272
};
273
// clang-format on
274
275
static uint16_t dontNeedEscape(unsigned char aChar, uint32_t aFlags)
276
31.5M
{
277
31.5M
  return EscapeChars[(uint32_t)aChar] & aFlags;
278
31.5M
}
279
static uint16_t dontNeedEscape(uint16_t aChar, uint32_t aFlags)
280
0
{
281
0
  return aChar < mozilla::ArrayLength(EscapeChars) ?
282
0
    (EscapeChars[(uint32_t)aChar]  & aFlags) : 0;
283
0
}
284
285
//----------------------------------------------------------------------------------------
286
287
/**
288
 * Templated helper for URL escaping a portion of a string.
289
 *
290
 * @param aPart The pointer to the beginning of the portion of the string to
291
 *  escape.
292
 * @param aPartLen The length of the string to escape.
293
 * @param aFlags Flags used to configure escaping. @see EscapeMask
294
 * @param aResult String that has the URL escaped portion appended to. Only
295
 *  altered if the string is URL escaped or |esc_AlwaysCopy| is specified.
296
 * @param aDidAppend Indicates whether or not data was appended to |aResult|.
297
 * @return NS_ERROR_INVALID_ARG, NS_ERROR_OUT_OF_MEMORY on failure.
298
 */
299
template<class T>
300
static nsresult
301
T_EscapeURL(const typename T::char_type* aPart, size_t aPartLen,
302
            uint32_t aFlags, const ASCIIMaskArray* aFilterMask,
303
            T& aResult, bool& aDidAppend)
304
7.64M
{
305
7.64M
  typedef nsCharTraits<typename T::char_type> traits;
306
7.64M
  typedef typename traits::unsigned_char_type unsigned_char_type;
307
7.64M
  static_assert(sizeof(*aPart) == 1 || sizeof(*aPart) == 2,
308
7.64M
                "unexpected char type");
309
7.64M
310
7.64M
  if (!aPart) {
311
0
    MOZ_ASSERT_UNREACHABLE("null pointer");
312
0
    return NS_ERROR_INVALID_ARG;
313
0
  }
314
7.64M
315
7.64M
  bool forced = !!(aFlags & esc_Forced);
316
7.64M
  bool ignoreNonAscii = !!(aFlags & esc_OnlyASCII);
317
7.64M
  bool ignoreAscii = !!(aFlags & esc_OnlyNonASCII);
318
7.64M
  bool writing = !!(aFlags & esc_AlwaysCopy);
319
7.64M
  bool colon = !!(aFlags & esc_Colon);
320
7.64M
  bool spaces = !!(aFlags & esc_Spaces);
321
7.64M
322
7.64M
  auto src = reinterpret_cast<const unsigned_char_type*>(aPart);
323
7.64M
324
7.64M
  typename T::char_type tempBuffer[100];
325
7.64M
  unsigned int tempBufferPos = 0;
326
7.64M
327
7.64M
  bool previousIsNonASCII = false;
328
39.1M
  for (size_t i = 0; i < aPartLen; ++i) {
329
31.5M
    unsigned_char_type c = *src++;
330
31.5M
331
31.5M
    // If there is a filter, we wish to skip any characters which match it.
332
31.5M
    // This is needed so we don't perform an extra pass just to extract the
333
31.5M
    // filtered characters.
334
31.5M
    if (aFilterMask && mozilla::ASCIIMask::IsMasked(*aFilterMask, c)) {
335
0
      if (!writing) {
336
0
        if (!aResult.Append(aPart, i, mozilla::fallible)) {
337
0
          return NS_ERROR_OUT_OF_MEMORY;
338
0
        }
339
0
        writing = true;
340
0
      }
341
0
      continue;
342
31.5M
    }
343
31.5M
344
31.5M
    // if the char has not to be escaped or whatever follows % is
345
31.5M
    // a valid escaped string, just copy the char.
346
31.5M
    //
347
31.5M
    // Also the % will not be escaped until forced
348
31.5M
    // See bugzilla bug 61269 for details why we changed this
349
31.5M
    //
350
31.5M
    // And, we will not escape non-ascii characters if requested.
351
31.5M
    // On special request we will also escape the colon even when
352
31.5M
    // not covered by the matrix.
353
31.5M
    // ignoreAscii is not honored for control characters (C0 and DEL)
354
31.5M
    //
355
31.5M
    // And, we should escape the '|' character when it occurs after any
356
31.5M
    // non-ASCII character as it may be aPart of a multi-byte character.
357
31.5M
    //
358
31.5M
    // 0x20..0x7e are the valid ASCII characters.
359
31.5M
    if ((dontNeedEscape(c, aFlags) || (c == HEX_ESCAPE && !forced)
360
31.5M
         || (c > 0x7f && ignoreNonAscii)
361
31.5M
         || (c >= 0x20 && c < 0x7f && ignoreAscii))
362
31.5M
        && !(c == ':' && colon)
363
31.5M
        && !(c == ' ' && spaces)
364
31.5M
        && !(previousIsNonASCII && c == '|' && !ignoreNonAscii)) {
365
26.8M
      if (writing) {
366
3.40M
        tempBuffer[tempBufferPos++] = c;
367
3.40M
      }
368
26.8M
    } else { /* do the escape magic */
369
4.67M
      if (!writing) {
370
514k
        if (!aResult.Append(aPart, i, mozilla::fallible)) {
371
0
          return NS_ERROR_OUT_OF_MEMORY;
372
0
        }
373
514k
        writing = true;
374
514k
      }
375
4.67M
      uint32_t len = ::AppendPercentHex(tempBuffer + tempBufferPos, c);
376
4.67M
      tempBufferPos += len;
377
4.67M
      MOZ_ASSERT(len <= ENCODE_MAX_LEN, "potential buffer overflow");
378
4.67M
    }
379
31.5M
380
31.5M
    // Flush the temp buffer if it doesnt't have room for another encoded char.
381
31.5M
    if (tempBufferPos >= mozilla::ArrayLength(tempBuffer) - ENCODE_MAX_LEN) {
382
130k
      NS_ASSERTION(writing, "should be writing");
383
130k
      if (!aResult.Append(tempBuffer, tempBufferPos, mozilla::fallible)) {
384
0
        return NS_ERROR_OUT_OF_MEMORY;
385
0
      }
386
130k
      tempBufferPos = 0;
387
130k
    }
388
31.5M
389
31.5M
    previousIsNonASCII = (c > 0x7f);
390
31.5M
  }
391
7.64M
  if (writing) {
392
514k
    if (!aResult.Append(tempBuffer, tempBufferPos, mozilla::fallible)) {
393
0
      return NS_ERROR_OUT_OF_MEMORY;
394
0
    }
395
7.64M
  }
396
7.64M
  aDidAppend = writing;
397
7.64M
  return NS_OK;
398
7.64M
}
Unified_cpp_xpcom_io0.cpp:nsresult T_EscapeURL<nsTSubstring<char> >(nsTSubstring<char>::char_type const*, unsigned long, unsigned int, std::__1::array<bool, 128ul> const*, nsTSubstring<char>&, bool&)
Line
Count
Source
304
7.64M
{
305
7.64M
  typedef nsCharTraits<typename T::char_type> traits;
306
7.64M
  typedef typename traits::unsigned_char_type unsigned_char_type;
307
7.64M
  static_assert(sizeof(*aPart) == 1 || sizeof(*aPart) == 2,
308
7.64M
                "unexpected char type");
309
7.64M
310
7.64M
  if (!aPart) {
311
0
    MOZ_ASSERT_UNREACHABLE("null pointer");
312
0
    return NS_ERROR_INVALID_ARG;
313
0
  }
314
7.64M
315
7.64M
  bool forced = !!(aFlags & esc_Forced);
316
7.64M
  bool ignoreNonAscii = !!(aFlags & esc_OnlyASCII);
317
7.64M
  bool ignoreAscii = !!(aFlags & esc_OnlyNonASCII);
318
7.64M
  bool writing = !!(aFlags & esc_AlwaysCopy);
319
7.64M
  bool colon = !!(aFlags & esc_Colon);
320
7.64M
  bool spaces = !!(aFlags & esc_Spaces);
321
7.64M
322
7.64M
  auto src = reinterpret_cast<const unsigned_char_type*>(aPart);
323
7.64M
324
7.64M
  typename T::char_type tempBuffer[100];
325
7.64M
  unsigned int tempBufferPos = 0;
326
7.64M
327
7.64M
  bool previousIsNonASCII = false;
328
39.1M
  for (size_t i = 0; i < aPartLen; ++i) {
329
31.5M
    unsigned_char_type c = *src++;
330
31.5M
331
31.5M
    // If there is a filter, we wish to skip any characters which match it.
332
31.5M
    // This is needed so we don't perform an extra pass just to extract the
333
31.5M
    // filtered characters.
334
31.5M
    if (aFilterMask && mozilla::ASCIIMask::IsMasked(*aFilterMask, c)) {
335
0
      if (!writing) {
336
0
        if (!aResult.Append(aPart, i, mozilla::fallible)) {
337
0
          return NS_ERROR_OUT_OF_MEMORY;
338
0
        }
339
0
        writing = true;
340
0
      }
341
0
      continue;
342
31.5M
    }
343
31.5M
344
31.5M
    // if the char has not to be escaped or whatever follows % is
345
31.5M
    // a valid escaped string, just copy the char.
346
31.5M
    //
347
31.5M
    // Also the % will not be escaped until forced
348
31.5M
    // See bugzilla bug 61269 for details why we changed this
349
31.5M
    //
350
31.5M
    // And, we will not escape non-ascii characters if requested.
351
31.5M
    // On special request we will also escape the colon even when
352
31.5M
    // not covered by the matrix.
353
31.5M
    // ignoreAscii is not honored for control characters (C0 and DEL)
354
31.5M
    //
355
31.5M
    // And, we should escape the '|' character when it occurs after any
356
31.5M
    // non-ASCII character as it may be aPart of a multi-byte character.
357
31.5M
    //
358
31.5M
    // 0x20..0x7e are the valid ASCII characters.
359
31.5M
    if ((dontNeedEscape(c, aFlags) || (c == HEX_ESCAPE && !forced)
360
31.5M
         || (c > 0x7f && ignoreNonAscii)
361
31.5M
         || (c >= 0x20 && c < 0x7f && ignoreAscii))
362
31.5M
        && !(c == ':' && colon)
363
31.5M
        && !(c == ' ' && spaces)
364
31.5M
        && !(previousIsNonASCII && c == '|' && !ignoreNonAscii)) {
365
26.8M
      if (writing) {
366
3.40M
        tempBuffer[tempBufferPos++] = c;
367
3.40M
      }
368
26.8M
    } else { /* do the escape magic */
369
4.67M
      if (!writing) {
370
514k
        if (!aResult.Append(aPart, i, mozilla::fallible)) {
371
0
          return NS_ERROR_OUT_OF_MEMORY;
372
0
        }
373
514k
        writing = true;
374
514k
      }
375
4.67M
      uint32_t len = ::AppendPercentHex(tempBuffer + tempBufferPos, c);
376
4.67M
      tempBufferPos += len;
377
4.67M
      MOZ_ASSERT(len <= ENCODE_MAX_LEN, "potential buffer overflow");
378
4.67M
    }
379
31.5M
380
31.5M
    // Flush the temp buffer if it doesnt't have room for another encoded char.
381
31.5M
    if (tempBufferPos >= mozilla::ArrayLength(tempBuffer) - ENCODE_MAX_LEN) {
382
130k
      NS_ASSERTION(writing, "should be writing");
383
130k
      if (!aResult.Append(tempBuffer, tempBufferPos, mozilla::fallible)) {
384
0
        return NS_ERROR_OUT_OF_MEMORY;
385
0
      }
386
130k
      tempBufferPos = 0;
387
130k
    }
388
31.5M
389
31.5M
    previousIsNonASCII = (c > 0x7f);
390
31.5M
  }
391
7.64M
  if (writing) {
392
514k
    if (!aResult.Append(tempBuffer, tempBufferPos, mozilla::fallible)) {
393
0
      return NS_ERROR_OUT_OF_MEMORY;
394
0
    }
395
7.64M
  }
396
7.64M
  aDidAppend = writing;
397
7.64M
  return NS_OK;
398
7.64M
}
Unexecuted instantiation: Unified_cpp_xpcom_io0.cpp:nsresult T_EscapeURL<nsTSubstring<char16_t> >(nsTSubstring<char16_t>::char_type const*, unsigned long, unsigned int, std::__1::array<bool, 128ul> const*, nsTSubstring<char16_t>&, bool&)
399
400
bool
401
NS_EscapeURL(const char* aPart, int32_t aPartLen, uint32_t aFlags,
402
             nsACString& aResult)
403
1.88M
{
404
1.88M
  if (aPartLen < 0) {
405
349
    aPartLen = strlen(aPart);
406
349
  }
407
1.88M
408
1.88M
  bool result = false;
409
1.88M
  nsresult rv = T_EscapeURL(aPart, aPartLen, aFlags, nullptr, aResult, result);
410
1.88M
  if (NS_FAILED(rv)) {
411
0
    ::NS_ABORT_OOM(aResult.Length() * sizeof(nsACString::char_type));
412
0
  }
413
1.88M
414
1.88M
  return result;
415
1.88M
}
416
417
nsresult
418
NS_EscapeURL(const nsACString& aStr, uint32_t aFlags, nsACString& aResult,
419
             const mozilla::fallible_t&)
420
3.84M
{
421
3.84M
  bool appended = false;
422
3.84M
  nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, nullptr, aResult, appended);
423
3.84M
  if (NS_FAILED(rv)) {
424
0
    aResult.Truncate();
425
0
    return rv;
426
0
  }
427
3.84M
428
3.84M
  if (!appended) {
429
3.84M
    aResult = aStr;
430
3.84M
  }
431
3.84M
432
3.84M
  return rv;
433
3.84M
}
434
435
nsresult
436
NS_EscapeAndFilterURL(const nsACString& aStr, uint32_t aFlags,
437
                      const ASCIIMaskArray* aFilterMask,
438
                      nsACString& aResult, const mozilla::fallible_t&)
439
1.92M
{
440
1.92M
  bool appended = false;
441
1.92M
  nsresult rv = T_EscapeURL(aStr.Data(), aStr.Length(), aFlags, aFilterMask, aResult, appended);
442
1.92M
  if (NS_FAILED(rv)) {
443
0
    aResult.Truncate();
444
0
    return rv;
445
0
  }
446
1.92M
447
1.92M
  if (!appended) {
448
1.79M
    if (!aResult.Assign(aStr, fallible)) {
449
0
      return NS_ERROR_OUT_OF_MEMORY;
450
0
    }
451
1.92M
  }
452
1.92M
453
1.92M
  return rv;
454
1.92M
}
455
456
const nsAString&
457
NS_EscapeURL(const nsAString& aStr, uint32_t aFlags, nsAString& aResult)
458
0
{
459
0
  bool result = false;
460
0
  nsresult rv = T_EscapeURL<nsAString>(aStr.Data(), aStr.Length(), aFlags, nullptr, aResult, result);
461
0
462
0
  if (NS_FAILED(rv)) {
463
0
    ::NS_ABORT_OOM(aResult.Length() * sizeof(nsAString::char_type));
464
0
  }
465
0
466
0
  if (result) {
467
0
    return aResult;
468
0
  }
469
0
  return aStr;
470
0
}
471
472
// Starting at aStr[aStart] find the first index in aStr that matches any
473
// character in aForbidden. Return false if not found.
474
static bool
475
FindFirstMatchFrom(const nsString& aStr, size_t aStart,
476
                   const nsTArray<char16_t>& aForbidden, size_t* aIndex)
477
0
{
478
0
  const size_t len = aForbidden.Length();
479
0
  for (size_t j = aStart, l = aStr.Length(); j < l; ++j) {
480
0
    size_t unused;
481
0
    if (mozilla::BinarySearch(aForbidden, 0, len, aStr[j], &unused)) {
482
0
      *aIndex = j;
483
0
      return true;
484
0
    }
485
0
  }
486
0
  return false;
487
0
}
488
489
const nsAString&
490
NS_EscapeURL(const nsString& aStr, const nsTArray<char16_t>& aForbidden,
491
             nsAString& aResult)
492
0
{
493
0
  bool didEscape = false;
494
0
  for (size_t i = 0, strLen = aStr.Length(); i < strLen; ) {
495
0
    size_t j;
496
0
    if (MOZ_UNLIKELY(FindFirstMatchFrom(aStr, i, aForbidden, &j))) {
497
0
      if (i == 0) {
498
0
        didEscape = true;
499
0
        aResult.Truncate();
500
0
        aResult.SetCapacity(aStr.Length());
501
0
      }
502
0
      if (j != i) {
503
0
        // The substring from 'i' up to 'j' that needs no escaping.
504
0
        aResult.Append(nsDependentSubstring(aStr, i, j - i));
505
0
      }
506
0
      char16_t buffer[ENCODE_MAX_LEN];
507
0
      uint32_t bufferLen = ::AppendPercentHex(buffer, aStr[j]);
508
0
      MOZ_ASSERT(bufferLen <= ENCODE_MAX_LEN, "buffer overflow");
509
0
      aResult.Append(buffer, bufferLen);
510
0
      i = j + 1;
511
0
    } else {
512
0
      if (MOZ_UNLIKELY(didEscape)) {
513
0
        // The tail of the string that needs no escaping.
514
0
        aResult.Append(nsDependentSubstring(aStr, i, strLen - i));
515
0
      }
516
0
      break;
517
0
    }
518
0
  }
519
0
  if (MOZ_UNLIKELY(didEscape)) {
520
0
    return aResult;
521
0
  }
522
0
  return aStr;
523
0
}
524
525
bool
526
NS_UnescapeURL(const char* aStr, int32_t aLen, uint32_t aFlags,
527
               nsACString& aResult)
528
1.08M
{
529
1.08M
  bool didAppend = false;
530
1.08M
  nsresult rv = NS_UnescapeURL(aStr, aLen, aFlags, aResult, didAppend,
531
1.08M
                               mozilla::fallible);
532
1.08M
  if (rv == NS_ERROR_OUT_OF_MEMORY) {
533
0
    ::NS_ABORT_OOM(aLen * sizeof(nsACString::char_type));
534
0
  }
535
1.08M
536
1.08M
  return didAppend;
537
1.08M
}
538
539
nsresult
540
NS_UnescapeURL(const char* aStr, int32_t aLen, uint32_t aFlags,
541
               nsACString& aResult, bool& aDidAppend,
542
               const mozilla::fallible_t&)
543
1.08M
{
544
1.08M
  if (!aStr) {
545
0
    MOZ_ASSERT_UNREACHABLE("null pointer");
546
0
    return NS_ERROR_INVALID_ARG;
547
0
  }
548
1.08M
549
1.08M
  MOZ_ASSERT(aResult.IsEmpty(),
550
1.08M
             "Passing a non-empty string as an out parameter!");
551
1.08M
552
1.08M
  uint32_t len;
553
1.08M
  if (aLen < 0) {
554
0
    size_t stringLength = strlen(aStr);
555
0
    if (stringLength >= UINT32_MAX) {
556
0
      return NS_ERROR_OUT_OF_MEMORY;
557
0
    }
558
0
    len = stringLength;
559
1.08M
  } else {
560
1.08M
    len = aLen;
561
1.08M
  }
562
1.08M
563
1.08M
  bool ignoreNonAscii = !!(aFlags & esc_OnlyASCII);
564
1.08M
  bool ignoreAscii = !!(aFlags & esc_OnlyNonASCII);
565
1.08M
  bool writing = !!(aFlags & esc_AlwaysCopy);
566
1.08M
  bool skipControl = !!(aFlags & esc_SkipControl);
567
1.08M
  bool skipInvalidHostChar = !!(aFlags & esc_Host);
568
1.08M
569
1.08M
  unsigned char* destPtr;
570
1.08M
  uint32_t destPos;
571
1.08M
572
1.08M
  if (writing) {
573
1.08M
    if (!aResult.SetLength(len, mozilla::fallible)) {
574
0
      return NS_ERROR_OUT_OF_MEMORY;
575
0
    }
576
1.08M
    destPos = 0;
577
1.08M
    destPtr = reinterpret_cast<unsigned char*>(aResult.BeginWriting());
578
1.08M
  }
579
1.08M
580
1.08M
  const char* last = aStr;
581
1.08M
  const char* end = aStr + len;
582
1.08M
583
15.2M
  for (const char* p = aStr; p < end; ++p) {
584
14.1M
    if (*p == HEX_ESCAPE && p + 2 < end) {
585
181k
      unsigned char c1 = *((unsigned char*)p + 1);
586
181k
      unsigned char c2 = *((unsigned char*)p + 2);
587
181k
      unsigned char u = (UNHEX(c1) << 4) + UNHEX(c2);
588
181k
      if (mozilla::IsAsciiHexDigit(c1) && mozilla::IsAsciiHexDigit(c2) &&
589
181k
          (!skipInvalidHostChar || dontNeedEscape(u, aFlags) || c1 >= '8') &&
590
181k
          ((c1 < '8' && !ignoreAscii) || (c1 >= '8' && !ignoreNonAscii)) &&
591
181k
          !(skipControl &&
592
55.5k
            (c1 < '2' || (c1 == '7' && (c2 == 'f' || c2 == 'F'))))) {
593
55.5k
        if (MOZ_UNLIKELY(!writing)) {
594
0
          writing = true;
595
0
          if (!aResult.SetLength(len, mozilla::fallible)) {
596
0
            return NS_ERROR_OUT_OF_MEMORY;
597
0
          }
598
0
          destPos = 0;
599
0
          destPtr = reinterpret_cast<unsigned char*>(aResult.BeginWriting());
600
0
        }
601
55.5k
        if (p > last) {
602
48.5k
          auto toCopy = p - last;
603
48.5k
          memcpy(destPtr + destPos, last, toCopy);
604
48.5k
          destPos += toCopy;
605
48.5k
          MOZ_ASSERT(destPos <= len);
606
48.5k
          last = p;
607
48.5k
        }
608
55.5k
        destPtr[destPos] = u;
609
55.5k
        destPos += 1;
610
55.5k
        MOZ_ASSERT(destPos <= len);
611
55.5k
        p += 2;
612
55.5k
        last += 3;
613
55.5k
      }
614
181k
    }
615
14.1M
  }
616
1.08M
  if (writing && last < end) {
617
1.08M
    auto toCopy = end - last;
618
1.08M
    memcpy(destPtr + destPos, last, toCopy);
619
1.08M
    destPos += toCopy;
620
1.08M
    MOZ_ASSERT(destPos <= len);
621
1.08M
  }
622
1.08M
623
1.08M
  if (writing) {
624
1.08M
    aResult.Truncate(destPos);
625
1.08M
  }
626
1.08M
627
1.08M
  aDidAppend = writing;
628
1.08M
  return NS_OK;
629
1.08M
}