url_to_filename_encoder.h revision 868fa2fe829687343ffae624259930155e16dbd8
15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2010 The Chromium Authors. All rights reserved. 25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file. 45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL filename encoder goals: 65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1. Allow URLs with arbitrary path-segment length, generating filenames 85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with a maximum of 128 characters. 95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2. Provide a somewhat human readable filenames, for easy debugging flow. 105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3. Provide reverse-mapping from filenames back to URLs. 115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 4. Be able to distinguish http://x from http://x/ from http://x/index.html. 125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Those can all be different URLs. 135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 5. Be able to represent http://a/b/c and http://a/b/c/d, a pattern seen 145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// with Facebook Connect. 155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We need an escape-character for representing characters that are legal 175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in URL paths, but not in filenames, such as '?'. 185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We can pick any legal character as an escape, as long as we escape it too. 205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// But as we have a goal of having filenames that humans can correlate with 215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URLs, we should pick one that doesn't show up frequently in URLs. Candidates 225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// are ~`!@#$%^&()-=_+{}[],. but we would prefer to avoid characters that are 235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// shell escapes or that various build tools use. 245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// .#&%-=_+ occur frequently in URLs. 265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// <>:"/\|?* are illegal in Windows 275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// See http://msdn.microsoft.com/en-us/library/aa365247(VS.85).aspx 285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ~`!$^&(){}[]'; are special to Unix shells 295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// In addition, build tools do not like ^@#% 305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Josh took a quick look at the frequency of some special characters in 325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Sadeesh's slurped directory from Fall 09 and found the following occurances: 335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ^ 3 build tool doesn't like ^ in testdata filenames 355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// @ 10 build tool doesn't like @ in testdata filenames 365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// . 1676 too frequent in URLs 375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// , 76 THE WINNER 385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// # 0 build tool doesn't like it 395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// & 487 Prefer to avoid shell escapes 405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// % 374 g4 doesn't like it 415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// = 579 very frequent in URLs -- leave unmodified 425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// - 464 very frequent in URLs -- leave unmodified 435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// _ 798 very frequent in URLs -- leave unmodified 445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// The escaping algorithm is: 475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 1) Escape all unfriendly symbols as ,XX where XX is the hex code. 485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 2) Add a ',' at the end (We do not allow ',' at end of any directory name, 495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// so this assures that e.g. /a and /a/b can coexist in the filesystem). 505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3) Go through the path segment by segment (where a segment is one directory 515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// or leaf in the path) and 525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3a) If the segment is empty, escape the second slash. i.e. if it was 535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// www.foo.com//a then we escape the second / like www.foo.com/,2Fa, 545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3a) If it is "." or ".." prepend with ',' (so that we have a non- 555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// empty and non-reserved filename). 565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 3b) If it is over 128 characters, break it up into smaller segments by 575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// inserting ,-/ (Windows limits paths to 128 chars, other OSes also 585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// have limits that would restrict us) 595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// 605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// For example: 615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// URL File 625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// / /, 635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /index.html /index.html, 645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /. /., 655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /a/b /a/b, 665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /a/b/ /a/b/, 675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /a/b/c /a/b/c, Note: no prefix problem 685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /u?foo=bar /u,3Ffoo=bar, 695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// // /,2F, 705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /./ /,./, 715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /../ /,../, 725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /, /,2C, 735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /,./ /,2C./, 745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// /very...longname/ /very...long,-/name If very...long is about 126 long. 755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// NOTE: we avoid using some classes here (like FilePath and GURL) because we 775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// share this code with other projects externally. 785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef NET_TOOLS_DUMP_CACHE_URL_TO_FILENAME_ENCODER_H_ 805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define NET_TOOLS_DUMP_CACHE_URL_TO_FILENAME_ENCODER_H_ 815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string> 835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 84868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h" 855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "net/tools/dump_cache/url_utilities.h" 865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace net { 885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Helper class for converting a URL into a filename. 905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class UrlToFilenameEncoder { 915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public: 925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Given a |url| and a |base_path|, returns a filename which represents this 935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |url|. |url| may include URL escaping such as %21 for ! 945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |legacy_escape| indicates that this function should use the old-style 955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // of encoding. 965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // TODO(mbelshe): delete the legacy_escape code. 975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string Encode(const std::string& url, std::string base_path, 985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) bool legacy_escape) { 995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string filename; 1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (!legacy_escape) { 1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_no_scheme = UrlUtilities::GetUrlHostPath(url); 1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) EncodeSegment(base_path, url_no_scheme, '/', &filename); 1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WIN32 1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReplaceAll(&filename, "/", "\\"); 1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } else { 1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string clean_url(url); 1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (clean_url.length() && clean_url[clean_url.length()-1] == '/') 1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) clean_url.append("index.html"); 1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string host = UrlUtilities::GetUrlHost(clean_url); 1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename.append(base_path); 1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename.append(host); 1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef WIN32 1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename.append("\\"); 1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#else 1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename.append("/"); 1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string url_filename = UrlUtilities::GetUrlPath(clean_url); 1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Strip the leading '/'. 1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) if (url_filename[0] == '/') 1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_filename = url_filename.substr(1); 1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace '/' with '\'. 1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ConvertToSlashes(&url_filename); 1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Strip double back-slashes ("\\\\"). 1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) StripDoubleSlashes(&url_filename); 1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Save path as filesystem-safe characters. 1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) url_filename = LegacyEscape(url_filename); 1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) filename.append(url_filename); 1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef WIN32 1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Last step - convert to native slashes. 1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string slash("/"); 1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string backslash("\\"); 1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReplaceAll(&filename, backslash, slash); 1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif 1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) return filename; 1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Rewrite HTML in a form that the SPDY in-memory server 1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // can read. 1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |filename_prefix| is prepended without escaping. 1495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |escaped_ending| is the URL to be encoded into a filename. It may have URL 1505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // escaped characters (like %21 for !). 1515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |dir_separator| is "/" on Unix, "\" on Windows. 1525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |encoded_filename| is the resultant filename. 1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void EncodeSegment( 1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& filename_prefix, 1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& escaped_ending, 1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char dir_separator, 1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* encoded_filename); 1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Decodes a filename that was encoded with EncodeSegment, 1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // yielding back the original URL. 1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static bool Decode(const std::string& encoded_filename, 1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) char dir_separator, 1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string* decoded_url); 1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kEscapeChar; 1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const char kTruncationChar; 1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static const size_t kMaximumSubdirectoryLength; 1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) friend class UrlToFilenameEncoderTest; 1705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private: 1725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Appends a segment of the path, special-casing "." and "..", and 1735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ensuring that the segment does not exceed the path length. If it does, 1745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it chops the end off the segment, writes the segment with a separator of 1755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // ",-/", and then rewrites segment to contain just the truncated piece so 1765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // it can be used in the next iteration. 1775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // |segment| is a read/write parameter containing segment to write 1785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Note: this should not be called with empty segment. 1795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void AppendSegment(std::string* segment, std::string* dest); 1805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Allow reading of old slurped files. 1825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static std::string LegacyEscape(const std::string& path); 1835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace all instances of |from| within |str| as |to|. 1855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ReplaceAll(std::string* str, const std::string& from, 1865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string& to) { 1875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) std::string::size_type pos(0); 1885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) while ((pos = str->find(from, pos)) != std::string::npos) { 1895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) str->replace(pos, from.size(), to); 1905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) pos += from.size(); 1915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 1935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 1945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace all instances of "/" with "\" in |path|. 1955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void ConvertToSlashes(std::string* path) { 1965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string slash("/"); 1975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string backslash("\\"); 1985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReplaceAll(path, slash, backslash); 1995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) // Replace all instances of "\\" with "%5C%5C" in |path|. 2025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) static void StripDoubleSlashes(std::string* path) { 2035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string doubleslash("\\\\"); 2045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) const std::string escaped_doubleslash("%5C%5C"); 2055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) ReplaceAll(path, doubleslash, escaped_doubleslash); 2065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) } 2075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}; 2085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)} // namespace net 2105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) 2115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif // NET_TOOLS_DUMP_CACHE_URL_TO_FILENAME_ENCODER_H_ 212