Home | History | Annotate | Download | only in flip_server
      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