| /* | 
 |  * Copyright 2008 Google Inc. | 
 |  * | 
 |  * Licensed under the Apache License, Version 2.0 (the "License"); you may not | 
 |  * use this file except in compliance with the License. You may obtain a copy of | 
 |  * the License at | 
 |  * | 
 |  * http://www.apache.org/licenses/LICENSE-2.0 | 
 |  * | 
 |  * Unless required by applicable law or agreed to in writing, software | 
 |  * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
 |  * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
 |  * License for the specific language governing permissions and limitations under | 
 |  * the License. | 
 |  */ | 
 |  | 
 | #include "Debug.h" | 
 | #include <string> | 
 | #include <cstring> | 
 | #include <vector> | 
 |  | 
 | #include "AllowedConnections.h" | 
 |  | 
 |  | 
 | // TODO(jat): do we need to protect against parallel access to static state? | 
 | //    current browsers only use one thread, but Chrome is multithreaded, though | 
 | //    it isn't clear if plugins see parallel execution.  For now, we will | 
 | //    assume the caller takes responsibility for making sure there are no | 
 | //    concurrent calls into AllowedConnections. | 
 | std::vector<AllowedConnections::Rule> AllowedConnections::rules; | 
 |  | 
 | /** | 
 |  * Get the host portion of the URL, not including the port. | 
 |  * | 
 |  * @return the host portion of the URL, or the unmodified URL if it does not appear | 
 |  *     to be valid | 
 |  */ | 
 | std::string AllowedConnections::getHostFromUrl(const std::string& url) { | 
 |   int protoEnd = url.find("://"); | 
 |   if (protoEnd == std::string::npos) { | 
 |     Debug::log(Debug::Debugging) << "getHostFromUrl(" << url | 
 |         << ") - no :// in URL" << Debug::flush; | 
 |     return url; | 
 |   } | 
 |   protoEnd += 3; // skip over "://" | 
 |   int hostEnd = url.find('/', protoEnd); | 
 |   if (hostEnd == std::string::npos) { | 
 |     hostEnd = url.length(); | 
 |   } | 
 |   int colon = url.find(':', protoEnd); | 
 |   if (colon == std::string::npos || colon > hostEnd) { | 
 |     colon = hostEnd; | 
 |   } | 
 |   std::string host = url.substr(protoEnd, colon - protoEnd); | 
 |   return host; | 
 | } | 
 |  | 
 | bool AllowedConnections::matchesRule(const std::string& url, | 
 |     bool* allowed) { | 
 |   std::string host = getHostFromUrl(url); | 
 |   // always allow localhost, localhost.* or 127.0.0.1 for the host | 
 |   // TODO(jat): try and get IP addresses of local interfaces? | 
 |   if (host == "localhost" || host.find("localhost.") == 0 | 
 |       || host == "127.0.0.1") { | 
 |     *allowed = true; | 
 |     return true; | 
 |   } | 
 |   Debug::log(Debug::Spam) << "Checking host " << host << Debug::flush; | 
 |   for (std::vector<AllowedConnections::Rule>::const_iterator it = rules.begin(); | 
 |        it != rules.end(); ++it) { | 
 |     Debug::log(Debug::Spam) << "  comparing to " << it->getPattern() | 
 |         << Debug::flush; | 
 |     // TODO(jat): add support for regexes | 
 |     if (host == it->getPattern()) { | 
 |       *allowed = !it->isExcluded(); | 
 |       return true; | 
 |     } | 
 |   } | 
 |   Debug::log(Debug::Info) | 
 |       << "GWT Development Mode connection requested by unknown web server " | 
 |       << host << Debug::flush; | 
 |   return false; | 
 | } | 
 |  | 
 | void AllowedConnections::addRule(const std::string& pattern, | 
 |     bool exclude) { | 
 |   Debug::log(Debug::Spam) << "AllowedConnections::addRule(pattern=" << pattern | 
 |       << ", excl=" << exclude << ")" << Debug::flush; | 
 |   rules.push_back(AllowedConnections::Rule(pattern, exclude)); | 
 | } | 
 |  | 
 | void AllowedConnections::clearRules() { | 
 |   rules.clear(); | 
 | } | 
 |  | 
 | void AllowedConnections::initFromAccessList(const std::string& accessList) { | 
 |   clearRules(); | 
 |   int n = accessList.length(); | 
 |   for (int i = 0; i < n; ) { | 
 |     bool exclude = false; | 
 |     if (accessList[i] == '!') { | 
 |       exclude = true; | 
 |       ++i; | 
 |     } | 
 |     int comma = i - 1; // for pre-increment below | 
 |     while (++comma < n && accessList[comma] != ','); // empty | 
 |     addRule(accessList.substr(i, comma - i), exclude); | 
 |     i = comma + 1; | 
 |   } | 
 | } |