1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__ 6 #define NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__ 7 8 #include <string> 9 #include "net/tools/flip_server/url_utilities.h" 10 11 namespace net { 12 13 // Helper class for converting a URL into a filename. 14 class UrlToFilenameEncoder { 15 public: 16 // Given a |url| and a |base_path|, returns a string which represents this 17 // |url|. 18 static std::string Encode(const std::string& url, std::string base_path) { 19 std::string clean_url(url); 20 if (clean_url.length() && clean_url[clean_url.length()-1] == '/') 21 clean_url.append("index.html"); 22 23 std::string host = UrlUtilities::GetUrlHost(clean_url); 24 std::string filename(base_path); 25 filename = filename.append(host + "/"); 26 27 std::string url_filename = UrlUtilities::GetUrlPath(clean_url); 28 // Strip the leading '/' 29 if (url_filename[0] == '/') 30 url_filename = url_filename.substr(1); 31 32 // replace '/' with '\' 33 ConvertToSlashes(url_filename); 34 35 // strip double slashes ("\\") 36 StripDoubleSlashes(url_filename); 37 38 // Save path as filesystem-safe characters 39 url_filename = Escape(url_filename); 40 filename = filename.append(url_filename); 41 42 #ifndef WIN32 43 // Last step - convert to native slashes! 44 const std::string slash("/"); 45 const std::string backslash("\\"); 46 ReplaceAll(filename, backslash, slash); 47 #endif 48 49 return filename; 50 } 51 52 private: 53 static const unsigned int kMaximumSubdirectoryLength = 128; 54 55 56 // Escape the given input |path| and chop any individual components 57 // of the path which are greater than kMaximumSubdirectoryLength characters 58 // into two chunks. 59 static std::string Escape(const std::string& path) { 60 std::string output; 61 62 // Note: We also chop paths into medium sized 'chunks'. 63 // This is due to the incompetence of the windows 64 // filesystem, which still hasn't figured out how 65 // to deal with long filenames. 66 unsigned int last_slash = 0; 67 for (size_t index = 0; index < path.length(); index++) { 68 char ch = path[index]; 69 if (ch == 0x5C) 70 last_slash = index; 71 if ((ch == 0x2D) || // hyphen 72 (ch == 0x5C) || (ch == 0x5F) || // backslash, underscore 73 ((0x30 <= ch) && (ch <= 0x39)) || // Digits [0-9] 74 ((0x41 <= ch) && (ch <= 0x5A)) || // Uppercase [A-Z] 75 ((0x61 <= ch) && (ch <= 0x7A))) { // Lowercase [a-z] 76 output.append(&path[index],1); 77 } else { 78 char encoded[3]; 79 encoded[0] = 'x'; 80 encoded[1] = ch / 16; 81 encoded[1] += (encoded[1] >= 10) ? 'A' - 10 : '0'; 82 encoded[2] = ch % 16; 83 encoded[2] += (encoded[2] >= 10) ? 'A' - 10 : '0'; 84 output.append(encoded, 3); 85 } 86 if (index - last_slash > kMaximumSubdirectoryLength) { 87 #ifdef WIN32 88 char slash = '\\'; 89 #else 90 char slash = '/'; 91 #endif 92 output.append(&slash, 1); 93 last_slash = index; 94 } 95 } 96 return output; 97 } 98 99 // Replace all instances of |from| within |str| as |to|. 100 static void ReplaceAll(std::string& str, const std::string& from, 101 const std::string& to) { 102 std::string::size_type pos(0); 103 while ((pos = str.find(from, pos)) != std::string::npos) { 104 str.replace(pos, from.size(), to); 105 pos += from.size(); 106 } 107 } 108 109 // Replace all instances of "/" with "\" in |path|. 110 static void ConvertToSlashes(std::string& path) { 111 const std::string slash("/"); 112 const std::string backslash("\\"); 113 ReplaceAll(path, slash, backslash); 114 } 115 116 // Replace all instances of "\\" with "%5C%5C" in |path|. 117 static void StripDoubleSlashes(std::string& path) { 118 const std::string doubleslash("\\\\"); 119 const std::string escaped_doubleslash("%5C%5C"); 120 ReplaceAll(path, doubleslash, escaped_doubleslash); 121 } 122 }; 123 124 } // namespace net 125 126 #endif // NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__ 127 128