blob: afb704073b0ca1a6dc43ab71bbcc58ccfc3afed1 [file] [log] [blame]
/*
* 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 "ExternalWrapper.h"
#include "nsIHttpProtocolHandler.h"
#include "nsISupports.h"
#include "nsNetCID.h"
#include "nsCOMPtr.h"
#include "nsMemory.h"
#include "nsServiceManagerUtils.h"
#include "nsIPromptService.h"
#ifndef NS_IMPL_ISUPPORTS2_CI
#include "nsIClassInfoImpl.h" // 1.9 only
#endif
#include "LoadModuleMessage.h"
#include "ServerMethods.h"
#include "BrowserChannel.h"
#include "AllowedConnections.h"
NS_IMPL_ISUPPORTS2_CI(ExternalWrapper, IOOPHM, nsISecurityCheckedComponent)
ExternalWrapper::ExternalWrapper() {
Debug::log(Debug::Spam) << "ExternalWrapper::ExternalWrapper()"
<< Debug::flush;
preferences = new Preferences();
windowWatcher = do_GetService(NS_WINDOWWATCHER_CONTRACTID);
if (!windowWatcher) {
Debug::log(Debug::Warning) << "Can't get WindowWatcher service"
<< Debug::flush;
return;
}
}
ExternalWrapper::~ExternalWrapper() {
Debug::log(Debug::Spam) << "ExternalWrapper::~ExternalWrapper" << Debug::flush;
}
// define the CID for nsIHttpProtocolHandler
static NS_DEFINE_CID(kHttpHandlerCID, NS_HTTPPROTOCOLHANDLER_CID);
static nsresult getUserAgent(std::string& userAgent) {
nsresult res;
nsCOMPtr<nsIHttpProtocolHandler> http = do_GetService(kHttpHandlerCID, &res);
if (NS_FAILED(res)) {
return res;
}
nsCString userAgentStr;
res = http->GetUserAgent(userAgentStr);
if (NS_FAILED(res)) {
return res;
}
userAgent.assign(userAgentStr.get());
return NS_OK;
}
std::string ExternalWrapper::computeTabIdentity() {
std::string returnVal;
if (!windowWatcher) {
return returnVal;
}
nsCOMPtr<nsIDOMWindow> topWindow(domWindow);
if (topWindow->GetTop(getter_AddRefs(topWindow)) != NS_OK) {
Debug::log(Debug::Warning) << "Unable to get top window" << Debug::flush;
return returnVal;
}
nsCOMPtr<nsIWebBrowserChrome> chrome;
if (windowWatcher->GetChromeForWindow(topWindow.get(),
getter_AddRefs(chrome)) != NS_OK) {
Debug::log(Debug::Warning) << "Unable to get browser chrome for window"
<< Debug::flush;
return returnVal;
}
Debug::log(Debug::Debugging) << "computeTabIdentity: browserChrome = "
<< (void*) chrome.get() << Debug::flush;
// TODO(jat): find a way to get the tab from the chrome window
return returnVal;
}
NS_IMETHODIMP ExternalWrapper::Init(nsIDOMWindow* domWindow,
PRBool *_retval) {
Debug::log(Debug::Spam) << "Init" << Debug::flush;
this->domWindow = domWindow;
*_retval = true;
return NS_OK;
}
bool ExternalWrapper::askUserToAllow(const std::string& url) {
nsCOMPtr<nsIPromptService> promptService = do_GetService(
"@mozilla.org/embedcomp/prompt-service;1");
if (!promptService) {
return false;
}
NS_ConvertASCIItoUTF16 title("Allow GWT Development Mode Connection");
NS_ConvertASCIItoUTF16 text("This web server is requesting a GWT "
"development mode connection -- do you want to allow it?");
NS_ConvertASCIItoUTF16 checkMsg("Remember this decision for this server "
"(change in GWT plugin preferences)");
PRBool remember = false;
PRBool include = true;
if (promptService->ConfirmCheck(domWindow.get(), title.get(), text.get(),
checkMsg.get(), &remember, &include) != NS_OK) {
return false;
}
if (remember) {
preferences->addNewRule(AllowedConnections::getHostFromUrl(url), !include);
}
return include;
}
NS_IMETHODIMP ExternalWrapper::Connect(const nsACString& url,
const nsACString& sessionKey, const nsACString& aAddr,
const nsACString& aModuleName, const nsACString& hostedHtmlVersion,
PRBool *_retval) {
Debug::log(Debug::Spam) << "Connect(url=" << url << ", sessionKey="
<< sessionKey << ", address=" << aAddr << ", module=" << aModuleName
<< ", hostedHtmlVersion=" << hostedHtmlVersion << Debug::flush;
// TODO: string utilities?
nsCString urlAutoStr(url);
nsCString sessionKeyAutoStr(sessionKey);
nsCString addrAutoStr(aAddr);
nsCString moduleAutoStr(aModuleName);
nsCString hostedHtmlVersionAutoStr(hostedHtmlVersion);
std::string hostedUrl(addrAutoStr.get());
std::string urlStr(urlAutoStr.get());
bool allowed = false;
if (!AllowedConnections::matchesRule(urlStr, &allowed)) {
// If we didn't match an existing rule, prompt the user
allowed = askUserToAllow(urlStr);
}
if (!allowed) {
*_retval = false;
return NS_OK;
}
size_t index = hostedUrl.find(':');
if (index == std::string::npos) {
*_retval = false;
return NS_OK;
}
std::string hostPart = hostedUrl.substr(0, index);
std::string portPart = hostedUrl.substr(index + 1);
HostChannel* channel = new HostChannel();
Debug::log(Debug::Debugging) << "Connecting..." << Debug::flush;
if (!channel->connectToHost(hostPart.c_str(),
atoi(portPart.c_str()))) {
*_retval = false;
return NS_OK;
}
Debug::log(Debug::Debugging) << "...Connected" << Debug::flush;
sessionHandler.reset(new FFSessionHandler(channel/*, ctx*/));
std::string hostedHtmlVersionStr(hostedHtmlVersionAutoStr.get());
if (!channel->init(sessionHandler.get(), BROWSERCHANNEL_PROTOCOL_VERSION,
BROWSERCHANNEL_PROTOCOL_VERSION,
hostedHtmlVersionStr)) {
*_retval = false;
return NS_OK;
}
std::string moduleName(moduleAutoStr.get());
std::string userAgent;
// get the user agent
nsresult res = getUserAgent(userAgent);
if (NS_FAILED(res)) {
return res;
}
std::string tabKeyStr = computeTabIdentity();
std::string sessionKeyStr(sessionKeyAutoStr.get());
LoadModuleMessage::send(*channel, urlStr, tabKeyStr, sessionKeyStr,
moduleName, userAgent, sessionHandler.get());
// TODO: return session object?
*_retval = true;
return NS_OK;
}
// nsISecurityCheckedComponent
static char* cloneAllAccess() {
static const char allAccess[] = "allAccess";
return static_cast<char*>(nsMemory::Clone(allAccess, sizeof(allAccess)));
}
static bool strEquals(const PRUnichar* utf16, const char* ascii) {
nsCString utf8;
NS_UTF16ToCString(nsDependentString(utf16), NS_CSTRING_ENCODING_UTF8, utf8);
return strcmp(ascii, utf8.get()) == 0;
}
NS_IMETHODIMP ExternalWrapper::CanCreateWrapper(const nsIID * iid, char **_retval) {
Debug::log(Debug::Spam) << "ExternalWrapper::CanCreateWrapper" << Debug::flush;
*_retval = cloneAllAccess();
return NS_OK;
}
NS_IMETHODIMP ExternalWrapper::CanCallMethod(const nsIID * iid, const PRUnichar *methodName, char **_retval) {
Debug::log(Debug::Spam) << "ExternalWrapper::CanCallMethod" << Debug::flush;
if (strEquals(methodName, "connect") || strEquals(methodName, "init")) {
*_retval = cloneAllAccess();
} else {
*_retval = nsnull;
}
return NS_OK;
}
NS_IMETHODIMP ExternalWrapper::CanGetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval) {
Debug::log(Debug::Spam) << "ExternalWrapper::CanGetProperty" << Debug::flush;
*_retval = nsnull;
return NS_OK;
}
NS_IMETHODIMP ExternalWrapper::CanSetProperty(const nsIID * iid, const PRUnichar *propertyName, char **_retval) {
Debug::log(Debug::Spam) << "ExternalWrapper::CanSetProperty" << Debug::flush;
*_retval = nsnull;
return NS_OK;
}