// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__
#define NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__
#include <string>
#include "net/tools/flip_server/url_utilities.h"
namespace net {
// Helper class for converting a URL into a filename.
class UrlToFilenameEncoder {
public:
// Given a |url| and a |base_path|, returns a string which represents this
// |url|.
static std::string Encode(const std::string& url, std::string base_path) {
std::string clean_url(url);
if (clean_url.length() && clean_url[clean_url.length()-1] == '/')
clean_url.append("index.html");
std::string host = UrlUtilities::GetUrlHost(clean_url);
std::string filename(base_path);
filename = filename.append(host + "/");
std::string url_filename = UrlUtilities::GetUrlPath(clean_url);
// Strip the leading '/'
if (url_filename[0] == '/')
url_filename = url_filename.substr(1);
// replace '/' with '\'
ConvertToSlashes(url_filename);
// strip double slashes ("\\")
StripDoubleSlashes(url_filename);
// Save path as filesystem-safe characters
url_filename = Escape(url_filename);
filename = filename.append(url_filename);
#ifndef WIN32
// Last step - convert to native slashes!
const std::string slash("/");
const std::string backslash("\\");
ReplaceAll(filename, backslash, slash);
#endif
return filename;
}
private:
static const unsigned int kMaximumSubdirectoryLength = 128;
// Escape the given input |path| and chop any individual components
// of the path which are greater than kMaximumSubdirectoryLength characters
// into two chunks.
static std::string Escape(const std::string& path) {
std::string output;
// Note: We also chop paths into medium sized 'chunks'.
// This is due to the incompetence of the windows
// filesystem, which still hasn't figured out how
// to deal with long filenames.
unsigned int last_slash = 0;
for (size_t index = 0; index < path.length(); index++) {
char ch = path[index];
if (ch == 0x5C)
last_slash = index;
if ((ch == 0x2D) || // hyphen
(ch == 0x5C) || (ch == 0x5F) || // backslash, underscore
((0x30 <= ch) && (ch <= 0x39)) || // Digits [0-9]
((0x41 <= ch) && (ch <= 0x5A)) || // Uppercase [A-Z]
((0x61 <= ch) && (ch <= 0x7A))) { // Lowercase [a-z]
output.append(&path[index],1);
} else {
char encoded[3];
encoded[0] = 'x';
encoded[1] = ch / 16;
encoded[1] += (encoded[1] >= 10) ? 'A' - 10 : '0';
encoded[2] = ch % 16;
encoded[2] += (encoded[2] >= 10) ? 'A' - 10 : '0';
output.append(encoded, 3);
}
if (index - last_slash > kMaximumSubdirectoryLength) {
#ifdef WIN32
char slash = '\\';
#else
char slash = '/';
#endif
output.append(&slash, 1);
last_slash = index;
}
}
return output;
}
// Replace all instances of |from| within |str| as |to|.
static void ReplaceAll(std::string& str, const std::string& from,
const std::string& to) {
std::string::size_type pos(0);
while ((pos = str.find(from, pos)) != std::string::npos) {
str.replace(pos, from.size(), to);
pos += from.size();
}
}
// Replace all instances of "/" with "\" in |path|.
static void ConvertToSlashes(std::string& path) {
const std::string slash("/");
const std::string backslash("\\");
ReplaceAll(path, slash, backslash);
}
// Replace all instances of "\\" with "%5C%5C" in |path|.
static void StripDoubleSlashes(std::string& path) {
const std::string doubleslash("\\\\");
const std::string escaped_doubleslash("%5C%5C");
ReplaceAll(path, doubleslash, escaped_doubleslash);
}
};
} // namespace net
#endif // NET_TOOLS_FLIP_SERVER_URL_TO_FILE_ENCODER_H__