<commit_before>/*************************************************************************
 *
 *  $RCSfile: ucb.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: sb $ $Date: 2001-11-28 09:42:39 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): Kai Sommerfeld ( kso@sun.com )
 *
 *
 ************************************************************************/

#ifndef _UCB_HXX
#define _UCB_HXX

#ifndef _COM_SUN_STAR_UCB_XCOMMANDPROCESSOR_HPP_
#include <com/sun/star/ucb/XCommandProcessor.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTPROVIDER_HPP_
#include <com/sun/star/ucb/XContentProvider.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTIDENTIFIERFACTORY_HPP_
#include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTPROVIDERMANAGER_HPP_
#include <com/sun/star/ucb/XContentProviderManager.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_
#include <com/sun/star/lang/XInitialization.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _OSL_INTERLOCK_H_ //@@@ see initialize() method
#include <osl/interlck.h>
#endif

#ifndef _UCBHELPER_MACROS_HXX
#include <ucbhelper/macros.hxx>
#endif

#ifndef _UCB_PROVIDERMAP_HXX_
#include "providermap.hxx"
#endif

//=========================================================================

#define UCB_SERVICE_NAME "com.sun.star.ucb.UniversalContentBroker"

//=========================================================================

namespace cppu { class OInterfaceContainerHelper; }

namespace com { namespace sun { namespace star { namespace ucb {
    class XCommandInfo;
    struct GlobalTransferCommandArgument;
} } } }

class UniversalContentBroker :
                public cppu::OWeakObject,
                public com::sun::star::lang::XTypeProvider,
                public com::sun::star::lang::XComponent,
                public com::sun::star::lang::XServiceInfo,
                public com::sun::star::lang::XInitialization,
                public com::sun::star::ucb::XContentProviderManager,
                public com::sun::star::ucb::XContentProvider,
                public com::sun::star::ucb::XContentIdentifierFactory,
                public com::sun::star::ucb::XCommandProcessor
{
public:
    UniversalContentBroker( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& rXSMgr );
    virtual ~UniversalContentBroker();

    // XInterface
    XINTERFACE_DECL()

    // XTypeProvider
    XTYPEPROVIDER_DECL()

    // XServiceInfo
    XSERVICEINFO_DECL()

    // XComponent
    virtual void SAL_CALL
    dispose()
        throw( com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    addEventListener( const com::sun::star::uno::Reference<
                        com::sun::star::lang::XEventListener >& Listener )
        throw( com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    removeEventListener( const com::sun::star::uno::Reference<
                            com::sun::star::lang::XEventListener >& Listener )
        throw( com::sun::star::uno::RuntimeException );

    // XInitialization
    virtual void SAL_CALL
    initialize( const com::sun::star::uno::Sequence<
                        com::sun::star::uno::Any >& aArguments )
        throw( com::sun::star::uno::Exception,
               com::sun::star::uno::RuntimeException );

    // XContentProviderManager
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContentProvider > SAL_CALL
    registerContentProvider( const com::sun::star::uno::Reference<
                                com::sun::star::ucb::XContentProvider >&
                                    Provider,
                             const rtl::OUString& Scheme,
                             sal_Bool ReplaceExisting )
        throw( com::sun::star::ucb::DuplicateProviderException,
               com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    deregisterContentProvider( const com::sun::star::uno::Reference<
                                    com::sun::star::ucb::XContentProvider >&
                                        Provider,
                               const rtl::OUString& Scheme )
        throw( com::sun::star::uno::RuntimeException );
    virtual com::sun::star::uno::Sequence<
        com::sun::star::ucb::ContentProviderInfo > SAL_CALL
    queryContentProviders()
        throw( com::sun::star::uno::RuntimeException );
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContentProvider > SAL_CALL
    queryContentProvider( const rtl::OUString& Identifier )
        throw( com::sun::star::uno::RuntimeException );

    // XContentProvider
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContent > SAL_CALL
    queryContent( const com::sun::star::uno::Reference<
                    com::sun::star::ucb::XContentIdentifier >& Identifier )
        throw( com::sun::star::ucb::IllegalIdentifierException,
               com::sun::star::uno::RuntimeException );
    virtual sal_Int32 SAL_CALL
    compareContentIds( const com::sun::star::uno::Reference<
                        com::sun::star::ucb::XContentIdentifier >& Id1,
                       const com::sun::star::uno::Reference<
                           com::sun::star::ucb::XContentIdentifier >& Id2 )
        throw( com::sun::star::uno::RuntimeException );

    // XContentIdentifierFactory
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContentIdentifier > SAL_CALL
    createContentIdentifier( const rtl::OUString& ContentId )
        throw( com::sun::star::uno::RuntimeException );

    // XCommandProcessor
    virtual sal_Int32 SAL_CALL
    createCommandIdentifier()
        throw( com::sun::star::uno::RuntimeException );
    virtual com::sun::star::uno::Any SAL_CALL
    execute( const com::sun::star::ucb::Command& aCommand,
             sal_Int32 CommandId,
             const com::sun::star::uno::Reference<
                 com::sun::star::ucb::XCommandEnvironment >& Environment )
        throw( com::sun::star::uno::Exception,
               com::sun::star::ucb::CommandAbortedException,
               com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    abort( sal_Int32 CommandId )
        throw( com::sun::star::uno::RuntimeException );

private:
    com::sun::star::uno::Reference< com::sun::star::ucb::XContentProvider >
    queryContentProvider( const rtl::OUString& Identifier,
                          sal_Bool bResolved );

    com::sun::star::uno::Reference< com::sun::star::ucb::XCommandInfo >
    getCommandInfo();

    void
    globalTransfer(
            const com::sun::star::ucb::GlobalTransferCommandArgument & rArg,
            const com::sun::star::uno::Reference<
                 com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw( com::sun::star::uno::Exception );

    com::sun::star::uno::Reference<
        com::sun::star::lang::XMultiServiceFactory > m_xSMgr;
    ProviderMap_Impl m_aProviders;
    osl::Mutex m_aMutex;
    cppu::OInterfaceContainerHelper* m_pDisposeEventListeners;
    oslInterlockedCount m_nInitCount; //@@@ see initialize() method
    sal_Int32 m_nCommandId;
};

#endif /* !_UCB_HXX */
<commit_msg>INTEGRATION: CWS ooo19126 (1.3.268); FILE MERGED 2005/09/05 18:44:54 rt 1.3.268.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: ucb.hxx,v $
 *
 *  $Revision: 1.4 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-09 15:16:06 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _UCB_HXX
#define _UCB_HXX

#ifndef _COM_SUN_STAR_UCB_XCOMMANDPROCESSOR_HPP_
#include <com/sun/star/ucb/XCommandProcessor.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTPROVIDER_HPP_
#include <com/sun/star/ucb/XContentProvider.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTIDENTIFIERFACTORY_HPP_
#include <com/sun/star/ucb/XContentIdentifierFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_UCB_XCONTENTPROVIDERMANAGER_HPP_
#include <com/sun/star/ucb/XContentProviderManager.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XSERVICEINFO_HPP_
#include <com/sun/star/lang/XServiceInfo.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XINITIALIZATION_HPP_
#include <com/sun/star/lang/XInitialization.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XMULTISERVICEFACTORY_HPP_
#include <com/sun/star/lang/XMultiServiceFactory.hpp>
#endif
#ifndef _COM_SUN_STAR_LANG_XTYPEPROVIDER_HPP_
#include <com/sun/star/lang/XTypeProvider.hpp>
#endif

#ifndef _RTL_USTRBUF_HXX_
#include <rtl/ustrbuf.hxx>
#endif
#ifndef _CPPUHELPER_WEAK_HXX_
#include <cppuhelper/weak.hxx>
#endif
#ifndef _OSL_MUTEX_HXX_
#include <osl/mutex.hxx>
#endif

#ifndef _OSL_INTERLOCK_H_ //@@@ see initialize() method
#include <osl/interlck.h>
#endif

#ifndef _UCBHELPER_MACROS_HXX
#include <ucbhelper/macros.hxx>
#endif

#ifndef _UCB_PROVIDERMAP_HXX_
#include "providermap.hxx"
#endif

//=========================================================================

#define UCB_SERVICE_NAME "com.sun.star.ucb.UniversalContentBroker"

//=========================================================================

namespace cppu { class OInterfaceContainerHelper; }

namespace com { namespace sun { namespace star { namespace ucb {
    class XCommandInfo;
    struct GlobalTransferCommandArgument;
} } } }

class UniversalContentBroker :
                public cppu::OWeakObject,
                public com::sun::star::lang::XTypeProvider,
                public com::sun::star::lang::XComponent,
                public com::sun::star::lang::XServiceInfo,
                public com::sun::star::lang::XInitialization,
                public com::sun::star::ucb::XContentProviderManager,
                public com::sun::star::ucb::XContentProvider,
                public com::sun::star::ucb::XContentIdentifierFactory,
                public com::sun::star::ucb::XCommandProcessor
{
public:
    UniversalContentBroker( const com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory >& rXSMgr );
    virtual ~UniversalContentBroker();

    // XInterface
    XINTERFACE_DECL()

    // XTypeProvider
    XTYPEPROVIDER_DECL()

    // XServiceInfo
    XSERVICEINFO_DECL()

    // XComponent
    virtual void SAL_CALL
    dispose()
        throw( com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    addEventListener( const com::sun::star::uno::Reference<
                        com::sun::star::lang::XEventListener >& Listener )
        throw( com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    removeEventListener( const com::sun::star::uno::Reference<
                            com::sun::star::lang::XEventListener >& Listener )
        throw( com::sun::star::uno::RuntimeException );

    // XInitialization
    virtual void SAL_CALL
    initialize( const com::sun::star::uno::Sequence<
                        com::sun::star::uno::Any >& aArguments )
        throw( com::sun::star::uno::Exception,
               com::sun::star::uno::RuntimeException );

    // XContentProviderManager
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContentProvider > SAL_CALL
    registerContentProvider( const com::sun::star::uno::Reference<
                                com::sun::star::ucb::XContentProvider >&
                                    Provider,
                             const rtl::OUString& Scheme,
                             sal_Bool ReplaceExisting )
        throw( com::sun::star::ucb::DuplicateProviderException,
               com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    deregisterContentProvider( const com::sun::star::uno::Reference<
                                    com::sun::star::ucb::XContentProvider >&
                                        Provider,
                               const rtl::OUString& Scheme )
        throw( com::sun::star::uno::RuntimeException );
    virtual com::sun::star::uno::Sequence<
        com::sun::star::ucb::ContentProviderInfo > SAL_CALL
    queryContentProviders()
        throw( com::sun::star::uno::RuntimeException );
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContentProvider > SAL_CALL
    queryContentProvider( const rtl::OUString& Identifier )
        throw( com::sun::star::uno::RuntimeException );

    // XContentProvider
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContent > SAL_CALL
    queryContent( const com::sun::star::uno::Reference<
                    com::sun::star::ucb::XContentIdentifier >& Identifier )
        throw( com::sun::star::ucb::IllegalIdentifierException,
               com::sun::star::uno::RuntimeException );
    virtual sal_Int32 SAL_CALL
    compareContentIds( const com::sun::star::uno::Reference<
                        com::sun::star::ucb::XContentIdentifier >& Id1,
                       const com::sun::star::uno::Reference<
                           com::sun::star::ucb::XContentIdentifier >& Id2 )
        throw( com::sun::star::uno::RuntimeException );

    // XContentIdentifierFactory
    virtual com::sun::star::uno::Reference<
        com::sun::star::ucb::XContentIdentifier > SAL_CALL
    createContentIdentifier( const rtl::OUString& ContentId )
        throw( com::sun::star::uno::RuntimeException );

    // XCommandProcessor
    virtual sal_Int32 SAL_CALL
    createCommandIdentifier()
        throw( com::sun::star::uno::RuntimeException );
    virtual com::sun::star::uno::Any SAL_CALL
    execute( const com::sun::star::ucb::Command& aCommand,
             sal_Int32 CommandId,
             const com::sun::star::uno::Reference<
                 com::sun::star::ucb::XCommandEnvironment >& Environment )
        throw( com::sun::star::uno::Exception,
               com::sun::star::ucb::CommandAbortedException,
               com::sun::star::uno::RuntimeException );
    virtual void SAL_CALL
    abort( sal_Int32 CommandId )
        throw( com::sun::star::uno::RuntimeException );

private:
    com::sun::star::uno::Reference< com::sun::star::ucb::XContentProvider >
    queryContentProvider( const rtl::OUString& Identifier,
                          sal_Bool bResolved );

    com::sun::star::uno::Reference< com::sun::star::ucb::XCommandInfo >
    getCommandInfo();

    void
    globalTransfer(
            const com::sun::star::ucb::GlobalTransferCommandArgument & rArg,
            const com::sun::star::uno::Reference<
                 com::sun::star::ucb::XCommandEnvironment >& xEnv )
        throw( com::sun::star::uno::Exception );

    com::sun::star::uno::Reference<
        com::sun::star::lang::XMultiServiceFactory > m_xSMgr;
    ProviderMap_Impl m_aProviders;
    osl::Mutex m_aMutex;
    cppu::OInterfaceContainerHelper* m_pDisposeEventListeners;
    oslInterlockedCount m_nInitCount; //@@@ see initialize() method
    sal_Int32 m_nCommandId;
};

#endif /* !_UCB_HXX */
<|endoftext|>


<commit_before>// Copyright (c) 2012 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.

#include "chrome/browser/extensions/webstore_standalone_installer.h"

#include "base/values.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/webstore_data_fetcher.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"

using content::WebContents;

namespace extensions {

const char kManifestKey[] = "manifest";
const char kIconUrlKey[] = "icon_url";
const char kLocalizedNameKey[] = "localized_name";
const char kLocalizedDescriptionKey[] = "localized_description";
const char kUsersKey[] = "users";
const char kShowUserCountKey[] = "show_user_count";
const char kAverageRatingKey[] = "average_rating";
const char kRatingCountKey[] = "rating_count";
const char kRedirectUrlKey[] = "redirect_url";

const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
const char kWebstoreRequestError[] =
    "Could not fetch data from the Chrome Web Store";
const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
const char kInvalidManifestError[] = "Invalid manifest";
const char kUserCancelledError[] = "User cancelled install";

WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
    const std::string& webstore_item_id,
    Profile* profile,
    const Callback& callback)
    : id_(webstore_item_id),
      callback_(callback),
      profile_(profile),
      show_user_count_(true),
      average_rating_(0.0),
      rating_count_(0) {
  CHECK(!callback_.is_null());
}

WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}

//
// Private interface implementation.
//

void WebstoreStandaloneInstaller::BeginInstall() {
  AddRef();  // Balanced in CompleteInstall or WebContentsDestroyed.

  if (!Extension::IdIsValid(id_)) {
    CompleteInstall(kInvalidWebstoreItemId);
    return;
  }

  // Use the requesting page as the referrer both since that is more correct
  // (it is the page that caused this request to happen) and so that we can
  // track top sites that trigger inline install requests.
  webstore_data_fetcher_.reset(new WebstoreDataFetcher(
      this,
      profile_->GetRequestContext(),
      GetRequestorURL(),
      id_));
  webstore_data_fetcher_->Start();
}

scoped_ptr<ExtensionInstallPrompt>
WebstoreStandaloneInstaller::CreateInstallUI() {
  return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
}

void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
  CompleteInstall(kWebstoreRequestError);
}

void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
    DictionaryValue* webstore_data) {
  if (!CheckRequestorAlive()) {
    CompleteInstall(std::string());
    return;
  }

  std::string error;

  if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
    CompleteInstall(error);
    return;
  }

  if (!CheckRequestorPermitted(*webstore_data, &error)) {
    CompleteInstall(error);
    return;
  }

  // Manifest, number of users, average rating and rating count are required.
  std::string manifest;
  if (!webstore_data->GetString(kManifestKey, &manifest) ||
      !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
      !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
      !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
    CompleteInstall(kInvalidWebstoreResponseError);
    return;
  }

  // Optional.
  show_user_count_ = true;
  webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);

  if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
      average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
    CompleteInstall(kInvalidWebstoreResponseError);
    return;
  }

  // Localized name and description are optional.
  if ((webstore_data->HasKey(kLocalizedNameKey) &&
      !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
      (webstore_data->HasKey(kLocalizedDescriptionKey) &&
      !webstore_data->GetString(
          kLocalizedDescriptionKey, &localized_description_))) {
    CompleteInstall(kInvalidWebstoreResponseError);
    return;
  }

  // Icon URL is optional.
  GURL icon_url;
  if (webstore_data->HasKey(kIconUrlKey)) {
    std::string icon_url_string;
    if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
      CompleteInstall(kInvalidWebstoreResponseError);
      return;
    }
    icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
        icon_url_string);
    if (!icon_url.is_valid()) {
      CompleteInstall(kInvalidWebstoreResponseError);
      return;
    }
  }

  // Assume ownership of webstore_data.
  webstore_data_.reset(webstore_data);

  scoped_refptr<WebstoreInstallHelper> helper =
      new WebstoreInstallHelper(this,
                                id_,
                                manifest,
                                std::string(),  // We don't have any icon data.
                                icon_url,
                                profile_->GetRequestContext());
  // The helper will call us back via OnWebstoreParseSucces or
  // OnWebstoreParseFailure.
  helper->Start();
}

void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
    const std::string& error) {
  CompleteInstall(error);
}

void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
    const std::string& id,
    const SkBitmap& icon,
    base::DictionaryValue* manifest) {
  CHECK_EQ(id_, id);

  if (!CheckRequestorAlive()) {
    CompleteInstall(std::string());
    return;
  }

  manifest_.reset(manifest);
  icon_ = icon;

  install_prompt_ = CreateInstallPrompt();
  if (install_prompt_) {
    ShowInstallUI();
    // Control flow finishes up in InstallUIProceed or InstallUIAbort.
  } else {
    InstallUIProceed();
  }
}

void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
    const std::string& id,
    InstallHelperResultCode result_code,
    const std::string& error_message) {
  CompleteInstall(error_message);
}

void WebstoreStandaloneInstaller::InstallUIProceed() {
  if (!CheckRequestorAlive()) {
    CompleteInstall(std::string());
    return;
  }

  scoped_ptr<WebstoreInstaller::Approval> approval(
      WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
          profile_,
          id_,
          scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy())));
  approval->skip_post_install_ui = !ShouldShowPostInstallUI();
  approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();

  scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
      profile_,
      this,
      &(GetWebContents()->GetController()),
      id_,
      approval.Pass(),
      WebstoreInstaller::FLAG_INLINE_INSTALL);
  installer->Start();
}

void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
  CompleteInstall(kUserCancelledError);
}

void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
    const std::string& id) {
  CHECK_EQ(id_, id);
  CompleteInstall(std::string());
}

void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
    const std::string& id,
    const std::string& error,
    WebstoreInstaller::FailureReason cancelled) {
  CHECK_EQ(id_, id);
  CompleteInstall(error);
}

void WebstoreStandaloneInstaller::AbortInstall() {
  callback_.Reset();
  // Abort any in-progress fetches.
  if (webstore_data_fetcher_) {
    webstore_data_fetcher_.reset();
    Release();  // Matches the AddRef in BeginInstall.
  }
}

void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
  // Clear webstore_data_fetcher_ so that WebContentsDestroyed will no longer
  // call Release in case the WebContents is destroyed before this object.
  scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher(
      webstore_data_fetcher_.Pass());
  if (!callback_.is_null())
    callback_.Run(error.empty(), error);

  Release();  // Matches the AddRef in BeginInstall.
}

void
WebstoreStandaloneInstaller::ShowInstallUI() {
  std::string error;
  localized_extension_for_display_ =
      ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
          manifest_.get(),
          Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
          id_,
          localized_name_,
          localized_description_,
          &error);
  if (!localized_extension_for_display_.get()) {
    CompleteInstall(kInvalidManifestError);
    return;
  }

  install_ui_ = CreateInstallUI();
  install_ui_->ConfirmStandaloneInstall(
      this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
}

}  // namespace extensions
<commit_msg>Add app icon to approval in WebstoreStandaloneInstaller<commit_after>// Copyright (c) 2012 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.

#include "chrome/browser/extensions/webstore_standalone_installer.h"

#include "base/values.h"
#include "chrome/browser/extensions/crx_installer.h"
#include "chrome/browser/extensions/extension_install_prompt.h"
#include "chrome/browser/extensions/extension_install_ui.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/webstore_data_fetcher.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/common/extensions/extension.h"
#include "content/public/browser/web_contents.h"
#include "url/gurl.h"

using content::WebContents;

namespace extensions {

const char kManifestKey[] = "manifest";
const char kIconUrlKey[] = "icon_url";
const char kLocalizedNameKey[] = "localized_name";
const char kLocalizedDescriptionKey[] = "localized_description";
const char kUsersKey[] = "users";
const char kShowUserCountKey[] = "show_user_count";
const char kAverageRatingKey[] = "average_rating";
const char kRatingCountKey[] = "rating_count";
const char kRedirectUrlKey[] = "redirect_url";

const char kInvalidWebstoreItemId[] = "Invalid Chrome Web Store item ID";
const char kWebstoreRequestError[] =
    "Could not fetch data from the Chrome Web Store";
const char kInvalidWebstoreResponseError[] = "Invalid Chrome Web Store reponse";
const char kInvalidManifestError[] = "Invalid manifest";
const char kUserCancelledError[] = "User cancelled install";

WebstoreStandaloneInstaller::WebstoreStandaloneInstaller(
    const std::string& webstore_item_id,
    Profile* profile,
    const Callback& callback)
    : id_(webstore_item_id),
      callback_(callback),
      profile_(profile),
      show_user_count_(true),
      average_rating_(0.0),
      rating_count_(0) {
  CHECK(!callback_.is_null());
}

WebstoreStandaloneInstaller::~WebstoreStandaloneInstaller() {}

//
// Private interface implementation.
//

void WebstoreStandaloneInstaller::BeginInstall() {
  AddRef();  // Balanced in CompleteInstall or WebContentsDestroyed.

  if (!Extension::IdIsValid(id_)) {
    CompleteInstall(kInvalidWebstoreItemId);
    return;
  }

  // Use the requesting page as the referrer both since that is more correct
  // (it is the page that caused this request to happen) and so that we can
  // track top sites that trigger inline install requests.
  webstore_data_fetcher_.reset(new WebstoreDataFetcher(
      this,
      profile_->GetRequestContext(),
      GetRequestorURL(),
      id_));
  webstore_data_fetcher_->Start();
}

scoped_ptr<ExtensionInstallPrompt>
WebstoreStandaloneInstaller::CreateInstallUI() {
  return make_scoped_ptr(new ExtensionInstallPrompt(GetWebContents()));
}

void WebstoreStandaloneInstaller::OnWebstoreRequestFailure() {
  CompleteInstall(kWebstoreRequestError);
}

void WebstoreStandaloneInstaller::OnWebstoreResponseParseSuccess(
    DictionaryValue* webstore_data) {
  if (!CheckRequestorAlive()) {
    CompleteInstall(std::string());
    return;
  }

  std::string error;

  if (!CheckInlineInstallPermitted(*webstore_data, &error)) {
    CompleteInstall(error);
    return;
  }

  if (!CheckRequestorPermitted(*webstore_data, &error)) {
    CompleteInstall(error);
    return;
  }

  // Manifest, number of users, average rating and rating count are required.
  std::string manifest;
  if (!webstore_data->GetString(kManifestKey, &manifest) ||
      !webstore_data->GetString(kUsersKey, &localized_user_count_) ||
      !webstore_data->GetDouble(kAverageRatingKey, &average_rating_) ||
      !webstore_data->GetInteger(kRatingCountKey, &rating_count_)) {
    CompleteInstall(kInvalidWebstoreResponseError);
    return;
  }

  // Optional.
  show_user_count_ = true;
  webstore_data->GetBoolean(kShowUserCountKey, &show_user_count_);

  if (average_rating_ < ExtensionInstallPrompt::kMinExtensionRating ||
      average_rating_ > ExtensionInstallPrompt::kMaxExtensionRating) {
    CompleteInstall(kInvalidWebstoreResponseError);
    return;
  }

  // Localized name and description are optional.
  if ((webstore_data->HasKey(kLocalizedNameKey) &&
      !webstore_data->GetString(kLocalizedNameKey, &localized_name_)) ||
      (webstore_data->HasKey(kLocalizedDescriptionKey) &&
      !webstore_data->GetString(
          kLocalizedDescriptionKey, &localized_description_))) {
    CompleteInstall(kInvalidWebstoreResponseError);
    return;
  }

  // Icon URL is optional.
  GURL icon_url;
  if (webstore_data->HasKey(kIconUrlKey)) {
    std::string icon_url_string;
    if (!webstore_data->GetString(kIconUrlKey, &icon_url_string)) {
      CompleteInstall(kInvalidWebstoreResponseError);
      return;
    }
    icon_url = GURL(extension_urls::GetWebstoreLaunchURL()).Resolve(
        icon_url_string);
    if (!icon_url.is_valid()) {
      CompleteInstall(kInvalidWebstoreResponseError);
      return;
    }
  }

  // Assume ownership of webstore_data.
  webstore_data_.reset(webstore_data);

  scoped_refptr<WebstoreInstallHelper> helper =
      new WebstoreInstallHelper(this,
                                id_,
                                manifest,
                                std::string(),  // We don't have any icon data.
                                icon_url,
                                profile_->GetRequestContext());
  // The helper will call us back via OnWebstoreParseSucces or
  // OnWebstoreParseFailure.
  helper->Start();
}

void WebstoreStandaloneInstaller::OnWebstoreResponseParseFailure(
    const std::string& error) {
  CompleteInstall(error);
}

void WebstoreStandaloneInstaller::OnWebstoreParseSuccess(
    const std::string& id,
    const SkBitmap& icon,
    base::DictionaryValue* manifest) {
  CHECK_EQ(id_, id);

  if (!CheckRequestorAlive()) {
    CompleteInstall(std::string());
    return;
  }

  manifest_.reset(manifest);
  icon_ = icon;

  install_prompt_ = CreateInstallPrompt();
  if (install_prompt_) {
    ShowInstallUI();
    // Control flow finishes up in InstallUIProceed or InstallUIAbort.
  } else {
    InstallUIProceed();
  }
}

void WebstoreStandaloneInstaller::OnWebstoreParseFailure(
    const std::string& id,
    InstallHelperResultCode result_code,
    const std::string& error_message) {
  CompleteInstall(error_message);
}

void WebstoreStandaloneInstaller::InstallUIProceed() {
  if (!CheckRequestorAlive()) {
    CompleteInstall(std::string());
    return;
  }

  scoped_ptr<WebstoreInstaller::Approval> approval(
      WebstoreInstaller::Approval::CreateWithNoInstallPrompt(
          profile_,
          id_,
          scoped_ptr<base::DictionaryValue>(manifest_.get()->DeepCopy())));
  approval->skip_post_install_ui = !ShouldShowPostInstallUI();
  approval->use_app_installed_bubble = ShouldShowAppInstalledBubble();
  approval->installing_icon = gfx::ImageSkia::CreateFrom1xBitmap(icon_);

  scoped_refptr<WebstoreInstaller> installer = new WebstoreInstaller(
      profile_,
      this,
      &(GetWebContents()->GetController()),
      id_,
      approval.Pass(),
      WebstoreInstaller::FLAG_INLINE_INSTALL);
  installer->Start();
}

void WebstoreStandaloneInstaller::InstallUIAbort(bool user_initiated) {
  CompleteInstall(kUserCancelledError);
}

void WebstoreStandaloneInstaller::OnExtensionInstallSuccess(
    const std::string& id) {
  CHECK_EQ(id_, id);
  CompleteInstall(std::string());
}

void WebstoreStandaloneInstaller::OnExtensionInstallFailure(
    const std::string& id,
    const std::string& error,
    WebstoreInstaller::FailureReason cancelled) {
  CHECK_EQ(id_, id);
  CompleteInstall(error);
}

void WebstoreStandaloneInstaller::AbortInstall() {
  callback_.Reset();
  // Abort any in-progress fetches.
  if (webstore_data_fetcher_) {
    webstore_data_fetcher_.reset();
    Release();  // Matches the AddRef in BeginInstall.
  }
}

void WebstoreStandaloneInstaller::CompleteInstall(const std::string& error) {
  // Clear webstore_data_fetcher_ so that WebContentsDestroyed will no longer
  // call Release in case the WebContents is destroyed before this object.
  scoped_ptr<WebstoreDataFetcher> webstore_data_fetcher(
      webstore_data_fetcher_.Pass());
  if (!callback_.is_null())
    callback_.Run(error.empty(), error);

  Release();  // Matches the AddRef in BeginInstall.
}

void
WebstoreStandaloneInstaller::ShowInstallUI() {
  std::string error;
  localized_extension_for_display_ =
      ExtensionInstallPrompt::GetLocalizedExtensionForDisplay(
          manifest_.get(),
          Extension::REQUIRE_KEY | Extension::FROM_WEBSTORE,
          id_,
          localized_name_,
          localized_description_,
          &error);
  if (!localized_extension_for_display_.get()) {
    CompleteInstall(kInvalidManifestError);
    return;
  }

  install_ui_ = CreateInstallUI();
  install_ui_->ConfirmStandaloneInstall(
      this, localized_extension_for_display_.get(), &icon_, *install_prompt_);
}

}  // namespace extensions
<|endoftext|>


<commit_before>// Copyright (c) 2010 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.

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/ref_counted.h"
#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/in_process_webkit/indexed_db_context.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/testing_profile.h"
#include "chrome/test/thread_test_helper.h"
#include "chrome/test/ui_test_utils.h"

// This browser test is aimed towards exercising the IndexedDB bindings and
// the actual implementation that lives in the browser side (in_process_webkit).
class IndexedDBBrowserTest : public InProcessBrowserTest {
 public:
  IndexedDBBrowserTest() {
    EnableDOMAutomation();
  }

  GURL testUrl(const FilePath& file_path) {
    const FilePath kTestDir(FILE_PATH_LITERAL("indexeddb"));
    return ui_test_utils::GetTestUrl(kTestDir, file_path);
  }

  void SimpleTest(const GURL& test_url) {
    // The test page will perform tests on IndexedDB, then navigate to either
    // a #pass or #fail ref.
    LOG(INFO) << "Navigating to URL and blocking.";
    ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
        browser(), test_url, 2);
    LOG(INFO) << "Navigation done.";
    std::string result = browser()->GetSelectedTabContents()->GetURL().ref();
    if (result != "pass") {
      std::string js_result;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
          browser()->GetSelectedTabContents()->render_view_host(), L"",
          L"window.domAutomationController.send(getLog())", &js_result));
      FAIL() << "Failed: " << js_result;
    }
  }
};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_IndexTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("index_test.html"))));
}

// Flaky on windows, see http://crbug.com/67422 and http://crbug.com/69293.
#if defined(OS_WIN)
#define MAYBE_KeyPathTest FLAKY_KeyPathTest
#else
#define MAYBE_KeyPathTest KeyPathTest
#endif

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, MAYBE_KeyPathTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_path_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_get_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_ObjectStoreTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("object_store_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("database_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_TransactionTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_DoesntHangTest) {
  SimpleTest(testUrl(FilePath(
      FILE_PATH_LITERAL("transaction_run_forever.html"))));
  ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

// In proc browser test is needed here because ClearLocalState indirectly calls
// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
  // Create test files.
  ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
  FilePath indexeddb_dir = temp_dir.path().Append(
      IndexedDBContext::kIndexedDBDirectory);
  ASSERT_TRUE(file_util::CreateDirectory(indexeddb_dir));

  FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_foo_0"));
  file_name_1.append(IndexedDBContext::kIndexedDBExtension);
  FilePath::StringType file_name_2(FILE_PATH_LITERAL("chrome-extension_foo_0"));
  file_name_2.append(IndexedDBContext::kIndexedDBExtension);
  FilePath temp_file_path_1 = indexeddb_dir.Append(file_name_1);
  FilePath temp_file_path_2 = indexeddb_dir.Append(file_name_2);

  ASSERT_EQ(1, file_util::WriteFile(temp_file_path_1, ".", 1));
  ASSERT_EQ(1, file_util::WriteFile(temp_file_path_2, "o", 1));

  // Create the scope which will ensure we run the destructor of the webkit
  // context which should trigger the clean up.
  {
    TestingProfile profile;
    WebKitContext *webkit_context = profile.GetWebKitContext();
    webkit_context->indexed_db_context()->set_data_path(indexeddb_dir);
    webkit_context->set_clear_local_state_on_exit(true);
  }
  // Make sure we wait until the destructor has run.
  scoped_refptr<ThreadTestHelper> helper(
      new ThreadTestHelper(BrowserThread::WEBKIT));
  ASSERT_TRUE(helper->Run());

  // Because we specified https for scheme to be skipped the second file
  // should survive and the first go into vanity.
  ASSERT_FALSE(file_util::PathExists(temp_file_path_1));
  ASSERT_TRUE(file_util::PathExists(temp_file_path_2));
}
<commit_msg>Disable IndexedDBBrowserTest.KeyPathTest per WebKit revision 76531.<commit_after>// Copyright (c) 2010 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.

#include "base/command_line.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/ref_counted.h"
#include "base/scoped_temp_dir.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/in_process_webkit/indexed_db_context.h"
#include "chrome/browser/in_process_webkit/webkit_context.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/test/in_process_browser_test.h"
#include "chrome/test/testing_profile.h"
#include "chrome/test/thread_test_helper.h"
#include "chrome/test/ui_test_utils.h"

// This browser test is aimed towards exercising the IndexedDB bindings and
// the actual implementation that lives in the browser side (in_process_webkit).
class IndexedDBBrowserTest : public InProcessBrowserTest {
 public:
  IndexedDBBrowserTest() {
    EnableDOMAutomation();
  }

  GURL testUrl(const FilePath& file_path) {
    const FilePath kTestDir(FILE_PATH_LITERAL("indexeddb"));
    return ui_test_utils::GetTestUrl(kTestDir, file_path);
  }

  void SimpleTest(const GURL& test_url) {
    // The test page will perform tests on IndexedDB, then navigate to either
    // a #pass or #fail ref.
    LOG(INFO) << "Navigating to URL and blocking.";
    ui_test_utils::NavigateToURLBlockUntilNavigationsComplete(
        browser(), test_url, 2);
    LOG(INFO) << "Navigation done.";
    std::string result = browser()->GetSelectedTabContents()->GetURL().ref();
    if (result != "pass") {
      std::string js_result;
      ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractString(
          browser()->GetSelectedTabContents()->render_view_host(), L"",
          L"window.domAutomationController.send(getLog())", &js_result));
      FAIL() << "Failed: " << js_result;
    }
  }
};

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, CursorTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("cursor_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_IndexTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("index_test.html"))));
}

// Flaky on windows, see http://crbug.com/67422 and http://crbug.com/69293.
//#if defined(OS_WIN)
//#define MAYBE_KeyPathTest FLAKY_KeyPathTest
//#else
//#define MAYBE_KeyPathTest KeyPathTest
//#endif

// Disabled per http://trac.webkit.org/changeset/76531. See http://crbug.com/70665.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DISABLED_KeyPathTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("key_path_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, TransactionGetTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_get_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_ObjectStoreTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("object_store_test.html"))));
}

IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, DatabaseTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("database_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_TransactionTest) {
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

// Flaky. See http://crbug.com/70643.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, FLAKY_DoesntHangTest) {
  SimpleTest(testUrl(FilePath(
      FILE_PATH_LITERAL("transaction_run_forever.html"))));
  ui_test_utils::CrashTab(browser()->GetSelectedTabContents());
  SimpleTest(testUrl(FilePath(FILE_PATH_LITERAL("transaction_test.html"))));
}

// In proc browser test is needed here because ClearLocalState indirectly calls
// WebKit's isMainThread through WebSecurityOrigin->SecurityOrigin.
IN_PROC_BROWSER_TEST_F(IndexedDBBrowserTest, ClearLocalState) {
  // Create test files.
  ScopedTempDir temp_dir;
  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
  FilePath indexeddb_dir = temp_dir.path().Append(
      IndexedDBContext::kIndexedDBDirectory);
  ASSERT_TRUE(file_util::CreateDirectory(indexeddb_dir));

  FilePath::StringType file_name_1(FILE_PATH_LITERAL("http_foo_0"));
  file_name_1.append(IndexedDBContext::kIndexedDBExtension);
  FilePath::StringType file_name_2(FILE_PATH_LITERAL("chrome-extension_foo_0"));
  file_name_2.append(IndexedDBContext::kIndexedDBExtension);
  FilePath temp_file_path_1 = indexeddb_dir.Append(file_name_1);
  FilePath temp_file_path_2 = indexeddb_dir.Append(file_name_2);

  ASSERT_EQ(1, file_util::WriteFile(temp_file_path_1, ".", 1));
  ASSERT_EQ(1, file_util::WriteFile(temp_file_path_2, "o", 1));

  // Create the scope which will ensure we run the destructor of the webkit
  // context which should trigger the clean up.
  {
    TestingProfile profile;
    WebKitContext *webkit_context = profile.GetWebKitContext();
    webkit_context->indexed_db_context()->set_data_path(indexeddb_dir);
    webkit_context->set_clear_local_state_on_exit(true);
  }
  // Make sure we wait until the destructor has run.
  scoped_refptr<ThreadTestHelper> helper(
      new ThreadTestHelper(BrowserThread::WEBKIT));
  ASSERT_TRUE(helper->Run());

  // Because we specified https for scheme to be skipped the second file
  // should survive and the first go into vanity.
  ASSERT_FALSE(file_util::PathExists(temp_file_path_1));
  ASSERT_TRUE(file_util::PathExists(temp_file_path_2));
}
<|endoftext|>


<commit_before>// Copyright (c) 2010 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.

#include "chrome/browser/policy/configuration_policy_provider_win.h"

#include <userenv.h>

#include <algorithm>

#include "base/logging.h"
#include "base/object_watcher.h"
#include "base/scoped_ptr.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/win/registry.h"
#include "chrome/common/policy_constants.h"

using base::win::RegKey;

namespace policy {

namespace {

bool ReadRegistryStringValue(RegKey* key, const string16& name,
                             string16* result) {
  DWORD value_size = 0;
  DWORD key_type = 0;
  scoped_array<uint8> buffer;

  if (!key->ReadValue(name.c_str(), 0, &value_size, &key_type))
    return false;
  if (key_type != REG_SZ)
    return false;

  // According to the Microsoft documentation, the string
  // buffer may not be explicitly 0-terminated. Allocate a
  // slightly larger buffer and pre-fill to zeros to guarantee
  // the 0-termination.
  buffer.reset(new uint8[value_size + 2]);
  memset(buffer.get(), 0, value_size + 2);
  key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL);
  result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
  return true;
}

}  // namespace

// Period at which to run the reload task in case the group policy change
// watchers fail.
const int kReloadIntervalMinutes = 15;

ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    GroupPolicyChangeWatcher(
        base::WeakPtr<ConfigurationPolicyProviderWin> provider,
        int reload_interval_minutes)
        : provider_(provider),
          user_policy_changed_event_(false, false),
          machine_policy_changed_event_(false, false),
          user_policy_watcher_failed_(false),
          machine_policy_watcher_failed_(false),
          reload_interval_minutes_(reload_interval_minutes),
          reload_task_(NULL) {
  if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
    PLOG(WARNING) << "Failed to register user group policy notification";
    user_policy_watcher_failed_ = true;
  }
  if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
    PLOG(WARNING) << "Failed to register machine group policy notification.";
    machine_policy_watcher_failed_ = true;
  }
}

ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    ~GroupPolicyChangeWatcher() {
  if (MessageLoop::current())
    MessageLoop::current()->RemoveDestructionObserver(this);
  DCHECK(!reload_task_);
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Start() {
  MessageLoop::current()->AddDestructionObserver(this);
  SetupWatches();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Stop() {
  user_policy_watcher_.StopWatching();
  machine_policy_watcher_.StopWatching();
  if (reload_task_) {
    reload_task_->Cancel();
    reload_task_ = NULL;
  }
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::SetupWatches() {
  if (reload_task_) {
    reload_task_->Cancel();
    reload_task_ = NULL;
  }

  if (!user_policy_watcher_failed_) {
    if (!user_policy_watcher_.GetWatchedObject() &&
        !user_policy_watcher_.StartWatching(
            user_policy_changed_event_.handle(), this)) {
      LOG(WARNING) << "Failed to start watch for user policy change event";
      user_policy_watcher_failed_ = true;
    }
  }
  if (!machine_policy_watcher_failed_) {
    if (!machine_policy_watcher_.GetWatchedObject() &&
        !machine_policy_watcher_.StartWatching(
            machine_policy_changed_event_.handle(), this)) {
      LOG(WARNING) << "Failed to start watch for machine policy change event";
      machine_policy_watcher_failed_ = true;
    }
  }

  if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) {
    reload_task_ =
        NewRunnableMethod(this, &GroupPolicyChangeWatcher::ReloadFromTask);
    int64 delay =
        base::TimeDelta::FromMinutes(reload_interval_minutes_).InMilliseconds();
    MessageLoop::current()->PostDelayedTask(FROM_HERE, reload_task_, delay);
  }
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Reload() {
  if (provider_.get())
    provider_->NotifyStoreOfPolicyChange();
  SetupWatches();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    ReloadFromTask() {
  // Make sure to not call Cancel() on the task, since it might hold the last
  // reference that keeps this object alive.
  reload_task_ = NULL;
  Reload();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    OnObjectSignaled(HANDLE object) {
  DCHECK(object == user_policy_changed_event_.handle() ||
         object == machine_policy_changed_event_.handle())
      << "unexpected object signaled policy reload, obj = "
      << std::showbase << std::hex << object;
  Reload();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    WillDestroyCurrentMessageLoop() {
  reload_task_ = NULL;
  MessageLoop::current()->RemoveDestructionObserver(this);
}

ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin(
    const PolicyDefinitionList* policy_list)
    : ConfigurationPolicyProvider(policy_list) {
  watcher_ = new GroupPolicyChangeWatcher(this->AsWeakPtr(),
                                          kReloadIntervalMinutes);
  watcher_->Start();
}

ConfigurationPolicyProviderWin::~ConfigurationPolicyProviderWin() {
  watcher_->Stop();
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyString(
    const string16& name, string16* result) const {
  string16 path = string16(kRegistrySubKey);
  RegKey policy_key;
  // First try the global policy.
  if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
    if (ReadRegistryStringValue(&policy_key, name, result))
      return true;
    policy_key.Close();
  }
  // Fall back on user-specific policy.
  if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
    return false;
  return ReadRegistryStringValue(&policy_key, name, result);
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyStringList(
    const string16& key, ListValue* result) const {
  string16 path = string16(kRegistrySubKey);
  path += ASCIIToUTF16("\\") + key;
  RegKey policy_key;
  if (!policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
    policy_key.Close();
    // Fall back on user-specific policy.
    if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
      return false;
  }
  string16 policy_string;
  int index = 0;
  while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index),
                                 &policy_string)) {
    result->Append(Value::CreateStringValue(policy_string));
  }
  return true;
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean(
    const string16& value_name, bool* result) const {
  DWORD value;
  RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
  if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value != 0;
    return true;
  }

  RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
  if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value != 0;
    return true;
  }
  return false;
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger(
    const string16& value_name, uint32* result) const {
  DWORD value;
  RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
  if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value;
    return true;
  }

  RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
  if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value;
    return true;
  }
  return false;
}

bool ConfigurationPolicyProviderWin::Provide(
    ConfigurationPolicyStoreInterface* store) {
  // This function calls GetRegistryPolicy* which hit up the registry. Those
  // are I/O functions not allowed to be called on the main thread.
  // http://crbug.com/66453
//  base::ThreadRestrictions::ScopedAllowIO allow_io;
  const PolicyDefinitionList* policy_list(policy_definition_list());
  for (const PolicyDefinitionList::Entry* current = policy_list->begin;
       current != policy_list->end; ++current) {
    std::wstring name = UTF8ToWide(current->name);
    switch (current->value_type) {
      case Value::TYPE_STRING: {
        std::wstring string_value;
        if (GetRegistryPolicyString(name.c_str(), &string_value)) {
          store->Apply(current->policy_type,
                       Value::CreateStringValue(string_value));
        }
        break;
      }
      case Value::TYPE_LIST: {
        scoped_ptr<ListValue> list_value(new ListValue);
        if (GetRegistryPolicyStringList(name.c_str(), list_value.get()))
          store->Apply(current->policy_type, list_value.release());
        break;
      }
      case Value::TYPE_BOOLEAN: {
        bool bool_value;
        if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) {
          store->Apply(current->policy_type,
                       Value::CreateBooleanValue(bool_value));
        }
        break;
      }
      case Value::TYPE_INTEGER: {
        uint32 int_value;
        if (GetRegistryPolicyInteger(name.c_str(), &int_value)) {
          store->Apply(current->policy_type,
                       Value::CreateIntegerValue(int_value));
        }
        break;
      }
      default:
        NOTREACHED();
        return false;
    }
  }

  return true;
}

}  // namespace policy
<commit_msg>Really apply the temp fix for hitting I/O on the main thread. Already approved.<commit_after>// Copyright (c) 2010 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.

#include "chrome/browser/policy/configuration_policy_provider_win.h"

#include <userenv.h>

#include <algorithm>

#include "base/logging.h"
#include "base/object_watcher.h"
#include "base/scoped_ptr.h"
#include "base/string_number_conversions.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "base/sys_string_conversions.h"
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "base/values.h"
#include "base/win/registry.h"
#include "chrome/common/policy_constants.h"

using base::win::RegKey;

namespace policy {

namespace {

bool ReadRegistryStringValue(RegKey* key, const string16& name,
                             string16* result) {
  DWORD value_size = 0;
  DWORD key_type = 0;
  scoped_array<uint8> buffer;

  if (!key->ReadValue(name.c_str(), 0, &value_size, &key_type))
    return false;
  if (key_type != REG_SZ)
    return false;

  // According to the Microsoft documentation, the string
  // buffer may not be explicitly 0-terminated. Allocate a
  // slightly larger buffer and pre-fill to zeros to guarantee
  // the 0-termination.
  buffer.reset(new uint8[value_size + 2]);
  memset(buffer.get(), 0, value_size + 2);
  key->ReadValue(name.c_str(), buffer.get(), &value_size, NULL);
  result->assign(reinterpret_cast<const wchar_t*>(buffer.get()));
  return true;
}

}  // namespace

// Period at which to run the reload task in case the group policy change
// watchers fail.
const int kReloadIntervalMinutes = 15;

ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    GroupPolicyChangeWatcher(
        base::WeakPtr<ConfigurationPolicyProviderWin> provider,
        int reload_interval_minutes)
        : provider_(provider),
          user_policy_changed_event_(false, false),
          machine_policy_changed_event_(false, false),
          user_policy_watcher_failed_(false),
          machine_policy_watcher_failed_(false),
          reload_interval_minutes_(reload_interval_minutes),
          reload_task_(NULL) {
  if (!RegisterGPNotification(user_policy_changed_event_.handle(), false)) {
    PLOG(WARNING) << "Failed to register user group policy notification";
    user_policy_watcher_failed_ = true;
  }
  if (!RegisterGPNotification(machine_policy_changed_event_.handle(), true)) {
    PLOG(WARNING) << "Failed to register machine group policy notification.";
    machine_policy_watcher_failed_ = true;
  }
}

ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    ~GroupPolicyChangeWatcher() {
  if (MessageLoop::current())
    MessageLoop::current()->RemoveDestructionObserver(this);
  DCHECK(!reload_task_);
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Start() {
  MessageLoop::current()->AddDestructionObserver(this);
  SetupWatches();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Stop() {
  user_policy_watcher_.StopWatching();
  machine_policy_watcher_.StopWatching();
  if (reload_task_) {
    reload_task_->Cancel();
    reload_task_ = NULL;
  }
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::SetupWatches() {
  if (reload_task_) {
    reload_task_->Cancel();
    reload_task_ = NULL;
  }

  if (!user_policy_watcher_failed_) {
    if (!user_policy_watcher_.GetWatchedObject() &&
        !user_policy_watcher_.StartWatching(
            user_policy_changed_event_.handle(), this)) {
      LOG(WARNING) << "Failed to start watch for user policy change event";
      user_policy_watcher_failed_ = true;
    }
  }
  if (!machine_policy_watcher_failed_) {
    if (!machine_policy_watcher_.GetWatchedObject() &&
        !machine_policy_watcher_.StartWatching(
            machine_policy_changed_event_.handle(), this)) {
      LOG(WARNING) << "Failed to start watch for machine policy change event";
      machine_policy_watcher_failed_ = true;
    }
  }

  if (user_policy_watcher_failed_ || machine_policy_watcher_failed_) {
    reload_task_ =
        NewRunnableMethod(this, &GroupPolicyChangeWatcher::ReloadFromTask);
    int64 delay =
        base::TimeDelta::FromMinutes(reload_interval_minutes_).InMilliseconds();
    MessageLoop::current()->PostDelayedTask(FROM_HERE, reload_task_, delay);
  }
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::Reload() {
  if (provider_.get())
    provider_->NotifyStoreOfPolicyChange();
  SetupWatches();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    ReloadFromTask() {
  // Make sure to not call Cancel() on the task, since it might hold the last
  // reference that keeps this object alive.
  reload_task_ = NULL;
  Reload();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    OnObjectSignaled(HANDLE object) {
  DCHECK(object == user_policy_changed_event_.handle() ||
         object == machine_policy_changed_event_.handle())
      << "unexpected object signaled policy reload, obj = "
      << std::showbase << std::hex << object;
  Reload();
}

void ConfigurationPolicyProviderWin::GroupPolicyChangeWatcher::
    WillDestroyCurrentMessageLoop() {
  reload_task_ = NULL;
  MessageLoop::current()->RemoveDestructionObserver(this);
}

ConfigurationPolicyProviderWin::ConfigurationPolicyProviderWin(
    const PolicyDefinitionList* policy_list)
    : ConfigurationPolicyProvider(policy_list) {
  watcher_ = new GroupPolicyChangeWatcher(this->AsWeakPtr(),
                                          kReloadIntervalMinutes);
  watcher_->Start();
}

ConfigurationPolicyProviderWin::~ConfigurationPolicyProviderWin() {
  watcher_->Stop();
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyString(
    const string16& name, string16* result) const {
  string16 path = string16(kRegistrySubKey);
  RegKey policy_key;
  // First try the global policy.
  if (policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
    if (ReadRegistryStringValue(&policy_key, name, result))
      return true;
    policy_key.Close();
  }
  // Fall back on user-specific policy.
  if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
    return false;
  return ReadRegistryStringValue(&policy_key, name, result);
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyStringList(
    const string16& key, ListValue* result) const {
  string16 path = string16(kRegistrySubKey);
  path += ASCIIToUTF16("\\") + key;
  RegKey policy_key;
  if (!policy_key.Open(HKEY_LOCAL_MACHINE, path.c_str(), KEY_READ)) {
    policy_key.Close();
    // Fall back on user-specific policy.
    if (!policy_key.Open(HKEY_CURRENT_USER, path.c_str(), KEY_READ))
      return false;
  }
  string16 policy_string;
  int index = 0;
  while (ReadRegistryStringValue(&policy_key, base::IntToString16(++index),
                                 &policy_string)) {
    result->Append(Value::CreateStringValue(policy_string));
  }
  return true;
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyBoolean(
    const string16& value_name, bool* result) const {
  DWORD value;
  RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
  if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value != 0;
    return true;
  }

  RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
  if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value != 0;
    return true;
  }
  return false;
}

bool ConfigurationPolicyProviderWin::GetRegistryPolicyInteger(
    const string16& value_name, uint32* result) const {
  DWORD value;
  RegKey hkcu_policy_key(HKEY_LOCAL_MACHINE, kRegistrySubKey, KEY_READ);
  if (hkcu_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value;
    return true;
  }

  RegKey hklm_policy_key(HKEY_CURRENT_USER, kRegistrySubKey, KEY_READ);
  if (hklm_policy_key.ReadValueDW(value_name.c_str(), &value)) {
    *result = value;
    return true;
  }
  return false;
}

bool ConfigurationPolicyProviderWin::Provide(
    ConfigurationPolicyStoreInterface* store) {
  // This function calls GetRegistryPolicy* which hit up the registry. Those
  // are I/O functions not allowed to be called on the main thread.
  // http://crbug.com/66453
  base::ThreadRestrictions::ScopedAllowIO allow_io;
  const PolicyDefinitionList* policy_list(policy_definition_list());
  for (const PolicyDefinitionList::Entry* current = policy_list->begin;
       current != policy_list->end; ++current) {
    std::wstring name = UTF8ToWide(current->name);
    switch (current->value_type) {
      case Value::TYPE_STRING: {
        std::wstring string_value;
        if (GetRegistryPolicyString(name.c_str(), &string_value)) {
          store->Apply(current->policy_type,
                       Value::CreateStringValue(string_value));
        }
        break;
      }
      case Value::TYPE_LIST: {
        scoped_ptr<ListValue> list_value(new ListValue);
        if (GetRegistryPolicyStringList(name.c_str(), list_value.get()))
          store->Apply(current->policy_type, list_value.release());
        break;
      }
      case Value::TYPE_BOOLEAN: {
        bool bool_value;
        if (GetRegistryPolicyBoolean(name.c_str(), &bool_value)) {
          store->Apply(current->policy_type,
                       Value::CreateBooleanValue(bool_value));
        }
        break;
      }
      case Value::TYPE_INTEGER: {
        uint32 int_value;
        if (GetRegistryPolicyInteger(name.c_str(), &int_value)) {
          store->Apply(current->policy_type,
                       Value::CreateIntegerValue(int_value));
        }
        break;
      }
      default:
        NOTREACHED();
        return false;
    }
  }

  return true;
}

}  // namespace policy
<|endoftext|>


<commit_before>/* <src/Pipe.cpp>
 *
 * This file is part of the x0 web server project and is released under GPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2013 Christian Parpart <trapni@gmail.com>
 */

#include <x0/io/Pipe.h>
#include <x0/Socket.h>

#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

namespace x0 {

/* creates a pipe
 *
 * \param flags an OR'ed value of O_NONBLOCK and O_CLOEXEC
 */
Pipe::Pipe(int flags) :
	size_(0)
{
	if (::pipe2(pipe_, flags) < 0) {
		pipe_[0] = -errno;
		pipe_[1] = -1;
	}
}

void Pipe::clear()
{
	char buf[4096];
	ssize_t rv;

	do rv = ::read(readFd(), buf, sizeof(buf));
	while (rv > 0);

	size_ = 0;
}

ssize_t Pipe::write(const void* buf, size_t size)
{
	ssize_t rv = ::write(writeFd(), buf, size);

	if (rv > 0)
		size_ += rv;

	return rv;
}

ssize_t Pipe::write(Socket* socket, size_t size)
{
	return socket->write(this, size);
}

ssize_t Pipe::write(Pipe* pipe, size_t size)
{
	ssize_t rv = splice(pipe->readFd(), NULL, writeFd(), NULL, pipe->size_, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);

	if (rv > 0) {
		pipe->size_ -= rv;
		size_ += rv;
	}

	return rv;
}

ssize_t Pipe::write(int fd, off_t* fd_off, size_t size)
{
	ssize_t rv = splice(fd, fd_off, writeFd(), NULL, size, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);

	if (rv > 0)
		size_ += rv;

	return rv;
}

ssize_t Pipe::read(void* buf, size_t size)
{
	ssize_t rv = ::read(readFd(), buf, size);

	if (rv > 0)
		size_ -= rv;

	return rv;
}

ssize_t Pipe::read(Socket* socket, size_t size)
{
	return socket->read(this, size);
}

ssize_t Pipe::read(Pipe* pipe, size_t size)
{
	return pipe->write(this, size);
}

ssize_t Pipe::read(int fd, off_t* fd_off, size_t size)
{
	ssize_t rv = splice(readFd(), fd_off, fd, NULL, size, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);

	if (rv > 0)
		size_ -= rv;

	return rv;
}

} // namespace x0
<commit_msg>do not compile Pipe on osx<commit_after>/* <src/Pipe.cpp>
 *
 * This file is part of the x0 web server project and is released under GPL-3.
 * http://www.xzero.io/
 *
 * (c) 2009-2013 Christian Parpart <trapni@gmail.com>
 */

#include <x0/io/Pipe.h>
#include <x0/Socket.h>

#include <errno.h>
#include <unistd.h>
#include <fcntl.h>

#ifndef __APPLE__
namespace x0 {

/* creates a pipe
 *
 * \param flags an OR'ed value of O_NONBLOCK and O_CLOEXEC
 */
Pipe::Pipe(int flags) :
	size_(0)
{
	if (::pipe2(pipe_, flags) < 0) {
		pipe_[0] = -errno;
		pipe_[1] = -1;
	}
}

void Pipe::clear()
{
	char buf[4096];
	ssize_t rv;

	do rv = ::read(readFd(), buf, sizeof(buf));
	while (rv > 0);

	size_ = 0;
}

ssize_t Pipe::write(const void* buf, size_t size)
{
	ssize_t rv = ::write(writeFd(), buf, size);

	if (rv > 0)
		size_ += rv;

	return rv;
}

ssize_t Pipe::write(Socket* socket, size_t size)
{
	return socket->write(this, size);
}

ssize_t Pipe::write(Pipe* pipe, size_t size)
{
	ssize_t rv = splice(pipe->readFd(), NULL, writeFd(), NULL, pipe->size_, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);

	if (rv > 0) {
		pipe->size_ -= rv;
		size_ += rv;
	}

	return rv;
}

ssize_t Pipe::write(int fd, off_t* fd_off, size_t size)
{
	ssize_t rv = splice(fd, fd_off, writeFd(), NULL, size, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);

	if (rv > 0)
		size_ += rv;

	return rv;
}

ssize_t Pipe::read(void* buf, size_t size)
{
	ssize_t rv = ::read(readFd(), buf, size);

	if (rv > 0)
		size_ -= rv;

	return rv;
}

ssize_t Pipe::read(Socket* socket, size_t size)
{
	return socket->read(this, size);
}

ssize_t Pipe::read(Pipe* pipe, size_t size)
{
	return pipe->write(this, size);
}

ssize_t Pipe::read(int fd, off_t* fd_off, size_t size)
{
	ssize_t rv = splice(readFd(), fd_off, fd, NULL, size, SPLICE_F_MOVE | SPLICE_F_NONBLOCK);

	if (rv > 0)
		size_ -= rv;

	return rv;
}

} // namespace x0
#endif
<|endoftext|>


<commit_before>//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//

#include "swift/AST/Builtins.h"
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"

#define DEBUG_TYPE "copy-propagation"

using namespace swift;

//===----------------------------------------------------------------------===//
//                       MARK: ShrinkBorrowScope
//===----------------------------------------------------------------------===//

class ShrinkBorrowScope {
  // The instruction that begins this borrow scope.
  BeginBorrowInst *introducer;

  InstructionDeleter &deleter;

  SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts;

  /// Instructions which are users of the simple (i.e. not reborrowed) extended
  /// i.e. copied lifetime of the introducer.
  SmallPtrSet<SILInstruction *, 16> users;

  /// Deinit barriers that obstruct hoisting end_borrow instructions.
  llvm::SmallVector<std::pair<SILBasicBlock *, SILInstruction *>>
      barrierInstructions;

  /// Blocks above which the borrow scope cannot be hoisted.
  ///
  /// Consequently, these blocks must begin with end_borrow %borrow.
  ///
  /// Note: These blocks aren't barrier blocks.  Rather the borrow scope is
  ///       barred from being hoisted out of them.  That could happen because
  ///       one of its predecessors is a barrier block (i.e. has a successor
  ///       which is live) or because one of its predecessors has a terminator
  ///       which is itself a deinit barrier.
  SmallPtrSet<SILBasicBlock *, 8> barredBlocks;

  llvm::SmallDenseMap<ApplySite, size_t> transitiveUsesPerApplySite;

  // The list of blocks to look for new points at which to insert end_borrows
  // in.  A block must not be processed if all of its successors have not yet
  // been.  For that reason, it is necessary to allow the same block to be
  // visited multiple times, at most once for each successor.
  SmallVector<SILBasicBlock *, 8> worklist;
  // The instructions from which the shrinking starts, the scope ending
  // instructions, keyed off the block in which they appear.
  llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *> startingInstructions;
  // The end _borrow instructions for this borrow scope that existed before
  // ShrinkBorrowScope ran and which were not modified.
  llvm::SmallPtrSet<SILInstruction *, 8> reusedEndBorrowInsts;

  // Whether ShrinkBorrowScope made any changes to the function.
  //
  // It could have made one of the following sorts of changes:
  // - deleted an end_borrow
  // - created an end_borrow
  // - rewrote the operand of an instruction
  //   - ApplySite
  //   - begin_borrow
  //   - copy_value
  bool madeChange;

public:
  ShrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter,
                    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts)
      : introducer(bbi), deleter(deleter),
        modifiedCopyValueInsts(modifiedCopyValueInsts), madeChange(false) {}

  bool run();

  bool populateUsers();
  bool initializeWorklist();
  void findBarriers();
  bool rewrite();
  bool createEndBorrow(SILInstruction *insertionPoint);

  bool isBarrierApply(SILInstruction *instruction) {
    // For now, treat every apply (that doesn't use the borrowed value) as a
    // barrier.
    return isa<ApplySite>(instruction);
  }

  bool mayAccessPointer(SILInstruction *instruction) {
    if (!instruction->mayReadOrWriteMemory())
      return false;
    bool fail = false;
    visitAccessedAddress(instruction, [&fail](Operand *operand) {
      auto accessStorage = AccessStorage::compute(operand->get());
      if (accessStorage.getKind() != AccessRepresentation::Kind::Unidentified)
        fail = true;
    });
    return fail;
  }

  bool mayLoadWeakOrUnowned(SILInstruction *instruction) {
    // TODO: It is possible to do better here by looking at the address that is
    //       being loaded.
    return isa<LoadWeakInst>(instruction) || isa<LoadUnownedInst>(instruction);
  }

  bool isDeinitBarrier(SILInstruction *instruction) {
    return isBarrierApply(instruction) || instruction->maySynchronize() ||
           mayAccessPointer(instruction) || mayLoadWeakOrUnowned(instruction);
  }

  bool canReplaceValueWithBorrowedValue(SILValue value) {
    while (true) {
      auto *instruction = value.getDefiningInstruction();
      if (!instruction)
        return false;
      if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        value = cvi->getOperand();
        continue;
      } else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi == introducer) {
          return true;
        }
      }
      return false;
    }
  }

  size_t usesInApply(ApplySite apply) {
    if (auto count = transitiveUsesPerApplySite.lookup(apply))
      return count;
    return 0;
  }

  bool canHoistOverInstruction(SILInstruction *instruction) {
    return tryHoistOverInstruction(instruction, /*rewrite=*/false);
  }

  bool tryHoistOverInstruction(SILInstruction *instruction, bool rewrite = true) {
    if (users.contains(instruction)) {
      if (auto apply = ApplySite::isa(instruction)) {
        SmallVector<int, 2> rewritableArgumentIndices;
        auto count = apply.getNumArguments();
        for (unsigned index = 0; index < count; ++index) {
          auto argument = apply.getArgument(index);
          if (canReplaceValueWithBorrowedValue(argument)) {
            rewritableArgumentIndices.push_back(index);
          }
        }
        if (rewritableArgumentIndices.size() != usesInApply(apply)) {
          return false;
        }
        if (rewrite) {
          // We can rewrite all the arguments which are transitive uses of the
          // borrow.
          for (auto index : rewritableArgumentIndices) {
            auto argument = apply.getArgument(index);
            auto borrowee = introducer->getOperand();
            if (auto *cvi = dyn_cast<CopyValueInst>(argument)) {
              cvi->setOperand(borrowee);
              modifiedCopyValueInsts.push_back(cvi);
              madeChange = true;
            } else {
              apply.setArgument(index, borrowee);
              madeChange = true;
            }
          }
        }
        return true;
      } else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi->isLexical() &&
            canReplaceValueWithBorrowedValue(bbi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            bbi->setOperand(borrowee);
            madeChange = true;
          }
          return true;
        }
      } else if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        if (canReplaceValueWithBorrowedValue(cvi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            cvi->setOperand(borrowee);
            madeChange = true;
            modifiedCopyValueInsts.push_back(cvi);
          }
          return true;
        }
      }
      return false;
    }
    return !isDeinitBarrier(instruction);
  }
};

//===----------------------------------------------------------------------===//
//                        MARK: Rewrite borrow scopes
//===----------------------------------------------------------------------===//

bool ShrinkBorrowScope::run() {
  if (!BorrowedValue(introducer).isLocalScope())
    return false;
  if (!populateUsers())
    return false;
  if (!initializeWorklist())
    return false;

  findBarriers();

  madeChange |= rewrite();

  return madeChange;
}

bool ShrinkBorrowScope::populateUsers() {
  SmallVector<Operand *, 16> uses;
  if (!findExtendedUsesOfSimpleBorrowedValue(BorrowedValue(introducer),
                                             &uses)) {
    // If the value produced by begin_borrow escapes, don't shrink the borrow
    // scope.
    return false;
  }
  for (auto *use : uses) {
    auto *user = use->getUser();
    users.insert(user);
    if (auto apply = ApplySite::isa(user)) {
      ++transitiveUsesPerApplySite[apply];
    }
  }
  return true;
}

bool ShrinkBorrowScope::initializeWorklist() {
  llvm::SmallVector<SILInstruction *, 16> scopeEndingInsts;
  BorrowedValue(introducer).getLocalScopeEndingInstructions(scopeEndingInsts);

  // Form a map of the scopeEndingInsts, keyed off the block they occur in.  If
  // a scope ending instruction is not an end_borrow, bail out.
  for (auto *instruction : scopeEndingInsts) {
    if (!isa<EndBorrowInst>(instruction))
      return false;
    auto *block = instruction->getParent();
    worklist.push_back(block);
    startingInstructions[block] = instruction;
  }

  return true;
}

void ShrinkBorrowScope::findBarriers() {
  // Walk the cfg backwards from the blocks containing scope ending
  // instructions, visiting only the initial blocks (which contained those
  // instructions) and those blocks all of whose successors have already been
  // visited.
  //
  // TODO: Handle loops.

  // Blocks to the top of which the borrow scope has been shrunk.
  SmallPtrSet<SILBasicBlock *, 8> deadBlocks;
  auto hasOnlyDeadSuccessors =
      [&deadBlocks](SILBasicBlock *block) -> bool {
    return llvm::all_of(block->getSuccessorBlocks(), [=](auto *successor) {
      return deadBlocks.contains(successor);
    });
  };

  while (!worklist.empty()) {
    auto *block = worklist.pop_back_val();
    auto *startingInstruction = startingInstructions.lookup(block);
    if (!startingInstruction && !hasOnlyDeadSuccessors(block)) {
      continue;
    }
    for (auto *successor : block->getSuccessorBlocks()) {
      barredBlocks.erase(successor);
    }

    // We either have processed all successors of block or else it is a block
    // which contained one of the original scope-ending instructions.  Scan the
    // block backwards, looking for the first deinit barrier.  If we've visited
    // all successors, start scanning from the terminator.  If the block
    // contained an original scope-ending instruction, start scanning from it.
    SILInstruction *instruction =
        startingInstruction ? startingInstruction : block->getTerminator();
    if (!startingInstruction) {
      // That there's no starting instruction means that this this block did not
      // contain an original introducer.  It was added to the worklist later.
      // At that time, it was checked that this block (along with all that
      // successor's other predecessors) had a terminator over which the borrow
      // scope could be shrunk.  Shrink it now.
#ifndef NDEBUG
      bool hoisted =
#endif
      tryHoistOverInstruction(block->getTerminator());
#ifndef NDEBUG
      assert(hoisted);
#endif
    }
    SILInstruction *barrier = nullptr;
    while ((instruction = instruction->getPreviousInstruction())) {
      if (instruction == introducer) {
        barrier = instruction;
        break;
      }
      if (!tryHoistOverInstruction(instruction)) {
        barrier = instruction;
        break;
      }
    }

    if (barrier) {
      barrierInstructions.push_back({block, barrier});
    } else {
      deadBlocks.insert(block);
      barredBlocks.insert(block);
      // If any of block's predecessor has a terminator over which the scope
      // can't be shrunk, the scope is barred from shrinking out of this block.
      if (llvm::all_of(block->getPredecessorBlocks(), [&](auto *block) {
            return canHoistOverInstruction(block->getTerminator());
            })) {
        // Otherwise, add all predecessors to the worklist and attempt to shrink
        // the borrow scope through them.
        for (auto *predecessor : block->getPredecessorBlocks()) {
          worklist.push_back(predecessor);
        }
      }
    }
  }
}

bool ShrinkBorrowScope::rewrite() {
  bool createdBorrow = false;

  // Insert the new end_borrow instructions that occur after deinit barriers.
  for (auto pair : barrierInstructions) {
    auto *insertionPoint = pair.second->getNextInstruction();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  // Insert the new end_borrow instructions that occur at the beginning of
  // blocks which we couldn't hoist out of.
  for (auto *block : barredBlocks) {
    auto *insertionPoint = &*block->begin();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  if (createdBorrow) {
    // Remove all the original end_borrow instructions.
    for (auto pair : startingInstructions) {
      if (reusedEndBorrowInsts.contains(pair.second)) {
        continue;
      }
      deleter.forceDelete(pair.getSecond());
    }
  }

  return createdBorrow;
}

bool ShrinkBorrowScope::createEndBorrow(SILInstruction *insertionPoint) {
  if (auto *ebi = dyn_cast<EndBorrowInst>(insertionPoint)) {
    llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *>::iterator location;
    if ((location = llvm::find_if(startingInstructions, [&](auto pair) -> bool {
           return pair.second == insertionPoint;
         })) != startingInstructions.end()) {
      reusedEndBorrowInsts.insert(location->second);
      return false;
    }
  }
  auto builder = SILBuilderWithScope(insertionPoint);
  builder.createEndBorrow(
      RegularLocation::getAutoGeneratedLocation(insertionPoint->getLoc()),
      introducer);
  return true;
}

bool swift::shrinkBorrowScope(
    BeginBorrowInst *bbi, InstructionDeleter &deleter,
    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts) {
  ShrinkBorrowScope borrowShrinker(bbi, deleter, modifiedCopyValueInsts);
  return borrowShrinker.run();
}
<commit_msg>[NFC] [ShrinkBorrowScope] Moved check.<commit_after>//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2021 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//

#include "swift/AST/Builtins.h"
#include "swift/SIL/MemAccessUtils.h"
#include "swift/SIL/OwnershipUtils.h"
#include "swift/SIL/SILBasicBlock.h"
#include "swift/SILOptimizer/Utils/CanonicalizeBorrowScope.h"
#include "swift/SILOptimizer/Utils/InstOptUtils.h"
#include "swift/SILOptimizer/Utils/InstructionDeleter.h"

#define DEBUG_TYPE "copy-propagation"

using namespace swift;

//===----------------------------------------------------------------------===//
//                       MARK: ShrinkBorrowScope
//===----------------------------------------------------------------------===//

class ShrinkBorrowScope {
  // The instruction that begins this borrow scope.
  BeginBorrowInst *introducer;

  InstructionDeleter &deleter;

  SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts;

  /// Instructions which are users of the simple (i.e. not reborrowed) extended
  /// i.e. copied lifetime of the introducer.
  SmallPtrSet<SILInstruction *, 16> users;

  /// Deinit barriers that obstruct hoisting end_borrow instructions.
  llvm::SmallVector<std::pair<SILBasicBlock *, SILInstruction *>>
      barrierInstructions;

  /// Blocks above which the borrow scope cannot be hoisted.
  ///
  /// Consequently, these blocks must begin with end_borrow %borrow.
  ///
  /// Note: These blocks aren't barrier blocks.  Rather the borrow scope is
  ///       barred from being hoisted out of them.  That could happen because
  ///       one of its predecessors is a barrier block (i.e. has a successor
  ///       which is live) or because one of its predecessors has a terminator
  ///       which is itself a deinit barrier.
  SmallPtrSet<SILBasicBlock *, 8> barredBlocks;

  llvm::SmallDenseMap<ApplySite, size_t> transitiveUsesPerApplySite;

  // The list of blocks to look for new points at which to insert end_borrows
  // in.  A block must not be processed if all of its successors have not yet
  // been.  For that reason, it is necessary to allow the same block to be
  // visited multiple times, at most once for each successor.
  SmallVector<SILBasicBlock *, 8> worklist;
  // The instructions from which the shrinking starts, the scope ending
  // instructions, keyed off the block in which they appear.
  llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *> startingInstructions;
  // The end _borrow instructions for this borrow scope that existed before
  // ShrinkBorrowScope ran and which were not modified.
  llvm::SmallPtrSet<SILInstruction *, 8> reusedEndBorrowInsts;

  // Whether ShrinkBorrowScope made any changes to the function.
  //
  // It could have made one of the following sorts of changes:
  // - deleted an end_borrow
  // - created an end_borrow
  // - rewrote the operand of an instruction
  //   - ApplySite
  //   - begin_borrow
  //   - copy_value
  bool madeChange;

public:
  ShrinkBorrowScope(BeginBorrowInst *bbi, InstructionDeleter &deleter,
                    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts)
      : introducer(bbi), deleter(deleter),
        modifiedCopyValueInsts(modifiedCopyValueInsts), madeChange(false) {}

  bool run();

  bool populateUsers();
  bool initializeWorklist();
  void findBarriers();
  bool rewrite();
  bool createEndBorrow(SILInstruction *insertionPoint);

  bool isBarrierApply(SILInstruction *instruction) {
    // For now, treat every apply (that doesn't use the borrowed value) as a
    // barrier.
    return isa<ApplySite>(instruction);
  }

  bool mayAccessPointer(SILInstruction *instruction) {
    if (!instruction->mayReadOrWriteMemory())
      return false;
    bool fail = false;
    visitAccessedAddress(instruction, [&fail](Operand *operand) {
      auto accessStorage = AccessStorage::compute(operand->get());
      if (accessStorage.getKind() != AccessRepresentation::Kind::Unidentified)
        fail = true;
    });
    return fail;
  }

  bool mayLoadWeakOrUnowned(SILInstruction *instruction) {
    // TODO: It is possible to do better here by looking at the address that is
    //       being loaded.
    return isa<LoadWeakInst>(instruction) || isa<LoadUnownedInst>(instruction);
  }

  bool isDeinitBarrier(SILInstruction *instruction) {
    return isBarrierApply(instruction) || instruction->maySynchronize() ||
           mayAccessPointer(instruction) || mayLoadWeakOrUnowned(instruction);
  }

  bool canReplaceValueWithBorrowedValue(SILValue value) {
    while (true) {
      auto *instruction = value.getDefiningInstruction();
      if (!instruction)
        return false;
      if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        value = cvi->getOperand();
        continue;
      } else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi == introducer) {
          return true;
        }
      }
      return false;
    }
  }

  size_t usesInApply(ApplySite apply) {
    if (auto count = transitiveUsesPerApplySite.lookup(apply))
      return count;
    return 0;
  }

  bool canHoistOverInstruction(SILInstruction *instruction) {
    return tryHoistOverInstruction(instruction, /*rewrite=*/false);
  }

  bool tryHoistOverInstruction(SILInstruction *instruction, bool rewrite = true) {
    if (instruction == introducer) {
      return false;
    }
    if (users.contains(instruction)) {
      if (auto apply = ApplySite::isa(instruction)) {
        SmallVector<int, 2> rewritableArgumentIndices;
        auto count = apply.getNumArguments();
        for (unsigned index = 0; index < count; ++index) {
          auto argument = apply.getArgument(index);
          if (canReplaceValueWithBorrowedValue(argument)) {
            rewritableArgumentIndices.push_back(index);
          }
        }
        if (rewritableArgumentIndices.size() != usesInApply(apply)) {
          return false;
        }
        if (rewrite) {
          // We can rewrite all the arguments which are transitive uses of the
          // borrow.
          for (auto index : rewritableArgumentIndices) {
            auto argument = apply.getArgument(index);
            auto borrowee = introducer->getOperand();
            if (auto *cvi = dyn_cast<CopyValueInst>(argument)) {
              cvi->setOperand(borrowee);
              modifiedCopyValueInsts.push_back(cvi);
              madeChange = true;
            } else {
              apply.setArgument(index, borrowee);
              madeChange = true;
            }
          }
        }
        return true;
      } else if (auto *bbi = dyn_cast<BeginBorrowInst>(instruction)) {
        if (bbi->isLexical() &&
            canReplaceValueWithBorrowedValue(bbi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            bbi->setOperand(borrowee);
            madeChange = true;
          }
          return true;
        }
      } else if (auto *cvi = dyn_cast<CopyValueInst>(instruction)) {
        if (canReplaceValueWithBorrowedValue(cvi->getOperand())) {
          if (rewrite) {
            auto borrowee = introducer->getOperand();
            cvi->setOperand(borrowee);
            madeChange = true;
            modifiedCopyValueInsts.push_back(cvi);
          }
          return true;
        }
      }
      return false;
    }
    return !isDeinitBarrier(instruction);
  }
};

//===----------------------------------------------------------------------===//
//                        MARK: Rewrite borrow scopes
//===----------------------------------------------------------------------===//

bool ShrinkBorrowScope::run() {
  if (!BorrowedValue(introducer).isLocalScope())
    return false;
  if (!populateUsers())
    return false;
  if (!initializeWorklist())
    return false;

  findBarriers();

  madeChange |= rewrite();

  return madeChange;
}

bool ShrinkBorrowScope::populateUsers() {
  SmallVector<Operand *, 16> uses;
  if (!findExtendedUsesOfSimpleBorrowedValue(BorrowedValue(introducer),
                                             &uses)) {
    // If the value produced by begin_borrow escapes, don't shrink the borrow
    // scope.
    return false;
  }
  for (auto *use : uses) {
    auto *user = use->getUser();
    users.insert(user);
    if (auto apply = ApplySite::isa(user)) {
      ++transitiveUsesPerApplySite[apply];
    }
  }
  return true;
}

bool ShrinkBorrowScope::initializeWorklist() {
  llvm::SmallVector<SILInstruction *, 16> scopeEndingInsts;
  BorrowedValue(introducer).getLocalScopeEndingInstructions(scopeEndingInsts);

  // Form a map of the scopeEndingInsts, keyed off the block they occur in.  If
  // a scope ending instruction is not an end_borrow, bail out.
  for (auto *instruction : scopeEndingInsts) {
    if (!isa<EndBorrowInst>(instruction))
      return false;
    auto *block = instruction->getParent();
    worklist.push_back(block);
    startingInstructions[block] = instruction;
  }

  return true;
}

void ShrinkBorrowScope::findBarriers() {
  // Walk the cfg backwards from the blocks containing scope ending
  // instructions, visiting only the initial blocks (which contained those
  // instructions) and those blocks all of whose successors have already been
  // visited.
  //
  // TODO: Handle loops.

  // Blocks to the top of which the borrow scope has been shrunk.
  SmallPtrSet<SILBasicBlock *, 8> deadBlocks;
  auto hasOnlyDeadSuccessors =
      [&deadBlocks](SILBasicBlock *block) -> bool {
    return llvm::all_of(block->getSuccessorBlocks(), [=](auto *successor) {
      return deadBlocks.contains(successor);
    });
  };

  while (!worklist.empty()) {
    auto *block = worklist.pop_back_val();
    auto *startingInstruction = startingInstructions.lookup(block);
    if (!startingInstruction && !hasOnlyDeadSuccessors(block)) {
      continue;
    }
    for (auto *successor : block->getSuccessorBlocks()) {
      barredBlocks.erase(successor);
    }

    // We either have processed all successors of block or else it is a block
    // which contained one of the original scope-ending instructions.  Scan the
    // block backwards, looking for the first deinit barrier.  If we've visited
    // all successors, start scanning from the terminator.  If the block
    // contained an original scope-ending instruction, start scanning from it.
    SILInstruction *instruction =
        startingInstruction ? startingInstruction : block->getTerminator();
    if (!startingInstruction) {
      // That there's no starting instruction means that this this block did not
      // contain an original introducer.  It was added to the worklist later.
      // At that time, it was checked that this block (along with all that
      // successor's other predecessors) had a terminator over which the borrow
      // scope could be shrunk.  Shrink it now.
#ifndef NDEBUG
      bool hoisted =
#endif
      tryHoistOverInstruction(block->getTerminator());
#ifndef NDEBUG
      assert(hoisted);
#endif
    }
    SILInstruction *barrier = nullptr;
    while ((instruction = instruction->getPreviousInstruction())) {
      if (!tryHoistOverInstruction(instruction)) {
        barrier = instruction;
        break;
      }
    }

    if (barrier) {
      barrierInstructions.push_back({block, barrier});
    } else {
      deadBlocks.insert(block);
      barredBlocks.insert(block);
      // If any of block's predecessor has a terminator over which the scope
      // can't be shrunk, the scope is barred from shrinking out of this block.
      if (llvm::all_of(block->getPredecessorBlocks(), [&](auto *block) {
            return canHoistOverInstruction(block->getTerminator());
            })) {
        // Otherwise, add all predecessors to the worklist and attempt to shrink
        // the borrow scope through them.
        for (auto *predecessor : block->getPredecessorBlocks()) {
          worklist.push_back(predecessor);
        }
      }
    }
  }
}

bool ShrinkBorrowScope::rewrite() {
  bool createdBorrow = false;

  // Insert the new end_borrow instructions that occur after deinit barriers.
  for (auto pair : barrierInstructions) {
    auto *insertionPoint = pair.second->getNextInstruction();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  // Insert the new end_borrow instructions that occur at the beginning of
  // blocks which we couldn't hoist out of.
  for (auto *block : barredBlocks) {
    auto *insertionPoint = &*block->begin();
    createdBorrow |= createEndBorrow(insertionPoint);
  }

  if (createdBorrow) {
    // Remove all the original end_borrow instructions.
    for (auto pair : startingInstructions) {
      if (reusedEndBorrowInsts.contains(pair.second)) {
        continue;
      }
      deleter.forceDelete(pair.getSecond());
    }
  }

  return createdBorrow;
}

bool ShrinkBorrowScope::createEndBorrow(SILInstruction *insertionPoint) {
  if (auto *ebi = dyn_cast<EndBorrowInst>(insertionPoint)) {
    llvm::SmallDenseMap<SILBasicBlock *, SILInstruction *>::iterator location;
    if ((location = llvm::find_if(startingInstructions, [&](auto pair) -> bool {
           return pair.second == insertionPoint;
         })) != startingInstructions.end()) {
      reusedEndBorrowInsts.insert(location->second);
      return false;
    }
  }
  auto builder = SILBuilderWithScope(insertionPoint);
  builder.createEndBorrow(
      RegularLocation::getAutoGeneratedLocation(insertionPoint->getLoc()),
      introducer);
  return true;
}

bool swift::shrinkBorrowScope(
    BeginBorrowInst *bbi, InstructionDeleter &deleter,
    SmallVectorImpl<CopyValueInst *> &modifiedCopyValueInsts) {
  ShrinkBorrowScope borrowShrinker(bbi, deleter, modifiedCopyValueInsts);
  return borrowShrinker.run();
}
<|endoftext|>