<commit_before>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2012, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

#include <actionlib/server/simple_action_server.h>
#include <moveit_msgs/MoveGroupAction.h>

#include <tf/transform_listener.h>
#include <planning_interface/planning_interface.h>
#include <planning_request_adapter/planning_request_adapter.h>

#include <planning_scene_monitor/planning_scene_monitor.h>
#include <trajectory_execution_ros/trajectory_execution_monitor_ros.h>
#include <moveit_msgs/DisplayTrajectory.h>
#include <boost/tokenizer.hpp>

#include <trajectory_processing/iterative_smoother.h>

static const std::string ROBOT_DESCRIPTION = "robot_description";      // name of the robot description (a param name, so it can be changed externally)
static const std::string DISPLAY_PATH_PUB_TOPIC = "display_trajectory";

class MoveGroupAction
{
public:

  enum MoveGroupState
    {
      IDLE,
      PLANNING,
      MONITOR
    };

  MoveGroupAction(planning_scene_monitor::PlanningSceneMonitor &psm) :
    nh_("~"), psm_(psm), trajectory_execution_(psm_.getPlanningScene()->getKinematicModel()), state_(IDLE)
  {
    // load the group name
    if (nh_.getParam("group", group_name_))
      ROS_INFO("Starting move_group for group '%s'", group_name_.c_str());
    else
      ROS_FATAL("Group name not specified. Cannot start move_group");

    // load the planning plugin
    try
    {
      planner_plugin_loader_.reset(new pluginlib::ClassLoader<planning_interface::Planner>("planning_interface", "planning_interface::Planner"));
    }
    catch(pluginlib::PluginlibException& ex)
    {
      ROS_FATAL_STREAM("Exception while creating planning plugin loader " << ex.what());
    }

    nh_.getParam("planning_plugin", planning_plugin_name_);
    const std::vector<std::string> &classes = planner_plugin_loader_->getDeclaredClasses();
    if (planning_plugin_name_.empty() && classes.size() == 1)
    {
      planning_plugin_name_ = classes[0];
      ROS_INFO("No 'planning_plugin' parameter specified, but only '%s' planning plugin is available. Using that one.", planning_plugin_name_.c_str());
    }
    if (planning_plugin_name_.empty() && classes.size() > 1)
    {
      planning_plugin_name_ = classes[0];
      ROS_INFO("Multiple planning plugins available. You shuold specify the 'planning_plugin' parameter. Using '%s' for now.", planning_plugin_name_.c_str());
    }
    try
    {
      planner_instance_.reset(planner_plugin_loader_->createUnmanagedInstance(planning_plugin_name_));
      planner_instance_->init(psm_.getPlanningScene()->getKinematicModel());
      ROS_INFO_STREAM("Using planning interface '" << planner_instance_->getDescription() << "'");
    }
    catch(pluginlib::PluginlibException& ex)
    {
      std::stringstream ss;
      for (std::size_t i = 0 ; i < classes.size() ; ++i)
        ss << classes[i] << " ";
      ROS_FATAL_STREAM("Exception while loading planner '" << planning_plugin_name_ << "': " << ex.what() << std::endl
                       << "Available plugins: " << ss.str());
    }

    // load the planner request adapters
    std::string adapters;
    if (nh_.getParam("request_adapters", adapters))
    {
      try
      {
        adapter_plugin_loader_.reset(new pluginlib::ClassLoader<planning_request_adapter::PlanningRequestAdapter>("planning_request_adapter", "planning_request_adapter::PlanningRequestAdapter"));
      }
      catch(pluginlib::PluginlibException& ex)
      {
        ROS_ERROR_STREAM("Exception while creating planning plugin loader " << ex.what());
      }
      boost::char_separator<char> sep(" ");
      boost::tokenizer<boost::char_separator<char> > tok(adapters, sep);
      std::vector<planning_request_adapter::PlanningRequestAdapterConstPtr> ads;
      for(boost::tokenizer<boost::char_separator<char> >::iterator beg = tok.begin() ; beg != tok.end(); ++beg)
      {
        planning_request_adapter::PlanningRequestAdapterConstPtr ad;
        try
        {
          ad.reset(adapter_plugin_loader_->createUnmanagedInstance(*beg));
        }
        catch (pluginlib::PluginlibException& ex)
        {
          ROS_ERROR_STREAM("Exception while planning adapter plugin '" << *beg << "': " << ex.what());
        }
        if (ad)
          ads.push_back(ad);
      }
      if (!ads.empty())
      {
        adapter_chain_.reset(new planning_request_adapter::PlanningRequestAdapterChain());
        for (std::size_t i = 0 ; i < ads.size() ; ++i)
        {
          ROS_INFO_STREAM("Using planning request adapter '" << ads[i]->getDescription() << "'");
          adapter_chain_->addAdapter(ads[i]);
        }
      }
    }

    display_path_publisher_ = root_nh_.advertise<moveit_msgs::DisplayTrajectory>("move_" + group_name_ + "/" + DISPLAY_PATH_PUB_TOPIC, 1, true);

    // start the action server
    action_server_.reset(new actionlib::SimpleActionServer<moveit_msgs::MoveGroupAction>(root_nh_, "move_" + group_name_, false));
    action_server_->registerGoalCallback(boost::bind(&MoveGroupAction::goalCallback, this));
    action_server_->registerPreemptCallback(boost::bind(&MoveGroupAction::preemptCallback, this));
    action_server_->start();
  }

  void goalCallback(void)
  {
    if (service_goal_thread_)
    {
      terminate_service_thread_ = true;
      service_goal_thread_->join();
      service_goal_thread_.reset();
    }
    goal_ = action_server_->acceptNewGoal();
    if (!goal_)
    {
      ROS_ERROR("Something unexpected happened. No goal found in callback for goal...");
      return;
    }

    if (!goal_->request.group_name.empty() && goal_->request.group_name != group_name_)
    {
      moveit_msgs::MoveGroupResult res;
      res.error_code.val = moveit_msgs::MoveItErrorCodes::INVALID_GROUP_NAME;
      action_server_->setAborted(res, "Cannot accept requests for group '" +
                                 goal_->request.group_name  + "' when the move_group action is loaded for group '" +
                                 group_name_ +  "'");
    }
    else
      service_goal_thread_.reset(new boost::thread(boost::bind(&MoveGroupAction::serviceGoalRequest, this)));
  }

  void preemptCallback(void)
  {
    action_server_->setPreempted();
    terminate_service_thread_ = true;
  }

  void serviceGoalRequest(void)
  {
    setState(PLANNING);

    bool solved = false;
    moveit_msgs::GetMotionPlan::Request req;
    req.motion_plan_request = goal_->request;
    if (req.motion_plan_request.group_name.empty())
      req.motion_plan_request.group_name = group_name_;
    moveit_msgs::GetMotionPlan::Response res;
    try
    {
      if (adapter_chain_)
        solved = adapter_chain_->adaptAndPlan(planner_instance_, psm_.getPlanningScene(), req, res);
      else
        solved = planner_instance_->solve(psm_.getPlanningScene(), req, res);
    }
    catch(std::runtime_error &ex)
    {
      ROS_ERROR("Exception caught: '%s'", ex.what());
    }
    catch(...)
    {
      ROS_ERROR("Unknown exception thrown by planner");
    }

    if (solved)
    {
      trajectory_msgs::JointTrajectory trajectory_out;
      smoother_.smooth(res.trajectory.joint_trajectory, trajectory_out, psm_.getGroupJointLimitsMap().at(group_name_));
      res.trajectory.joint_trajectory = trajectory_out;

      setState(MONITOR);
      execution_complete_ = false;

      // display the trajectory
      moveit_msgs::DisplayTrajectory disp;
      disp.model_id = psm_.getPlanningScene()->getKinematicModel()->getName();
      disp.trajectory_start = res.trajectory_start;
      disp.trajectory = res.trajectory;
      display_path_publisher_.publish(disp);

      trajectory_execution::TrajectoryExecutionRequest ter;
      ter.group_name_ = group_name_;
      ter.trajectory_ = res.trajectory.joint_trajectory; // \TODO This should take in a RobotTrajectory
      if (trajectory_execution_.executeTrajectory(ter, boost::bind(&MoveGroupAction::doneWithTrajectoryExecution, this, _1)))
      {
        ros::WallDuration d(0.01);
        while (nh_.ok() && !execution_complete_ && !terminate_service_thread_)
        {
          /// \TODO Check if the remainder of the path is still valid; If not, replan.
          /// We need a callback in the trajectory monitor for this
          d.sleep();
        }
        moveit_msgs::MoveGroupResult res;
        res.error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
        action_server_->setSucceeded(res, "Solution was found and executed.");
      }
      else
      {
        moveit_msgs::MoveGroupResult res;
        //        res.error_code.val = moveit_msgs::MoveItErrorCodes::CONTROL_FAILED;
        action_server_->setAborted(res, "Solution was found but the controller failed to execute it.");
      }
    }
    else
    {
      moveit_msgs::MoveGroupResult res;
      res.error_code.val = moveit_msgs::MoveItErrorCodes::PLANNING_FAILED;
      action_server_->setAborted(res, "No motion plan found. No execution attempted.");
    }

    setState(IDLE);
  }

  bool doneWithTrajectoryExecution(trajectory_execution::TrajectoryExecutionDataVector data)
  {
    execution_complete_ = true;
    return true;
  }

  void setState(MoveGroupState state)
  {
    state_ = state;
    switch (state_)
    {
    case IDLE:
      feedback_.state = "IDLE";
      feedback_.time_to_completion = ros::Duration(0.0);
      break;
    case PLANNING:
      feedback_.state = "PLANNING";
      feedback_.time_to_completion = ros::Duration(0.0);
      break;
    case MONITOR:
      feedback_.state = "MONITOR";
      feedback_.time_to_completion = ros::Duration(0.0);
      break;
    }
    action_server_->publishFeedback(feedback_);
  }

  void status(void)
  {
    ROS_INFO("MoveGroup action for group '%s' running using planning plugin '%s'", group_name_.c_str(), planning_plugin_name_.c_str());
  }

private:

  ros::NodeHandle root_nh_;
  ros::NodeHandle nh_;
  planning_scene_monitor::PlanningSceneMonitor &psm_;

  std::string planning_plugin_name_;
  boost::scoped_ptr<pluginlib::ClassLoader<planning_interface::Planner> > planner_plugin_loader_;
  planning_interface::PlannerPtr planner_instance_;
  std::string group_name_;

  boost::scoped_ptr<pluginlib::ClassLoader<planning_request_adapter::PlanningRequestAdapter> > adapter_plugin_loader_;
  boost::scoped_ptr<planning_request_adapter::PlanningRequestAdapterChain> adapter_chain_;

  boost::shared_ptr<actionlib::SimpleActionServer<moveit_msgs::MoveGroupAction> > action_server_;
  moveit_msgs::MoveGroupGoalConstPtr goal_;
  moveit_msgs::MoveGroupFeedback feedback_;

  boost::scoped_ptr<boost::thread> service_goal_thread_;

  trajectory_execution_ros::TrajectoryExecutionMonitorRos trajectory_execution_;
  bool terminate_service_thread_;
  bool execution_complete_;
  MoveGroupState state_;
  trajectory_processing::IterativeParabolicSmoother smoother_;

  ros::Publisher display_path_publisher_;
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "move_group", ros::init_options::AnonymousName);

  ros::AsyncSpinner spinner(1);
  spinner.start();

  tf::TransformListener tf;
  planning_scene_monitor::PlanningSceneMonitor psm(ROBOT_DESCRIPTION, &tf);
  if (psm.getPlanningScene()->isConfigured())
  {
    psm.startWorldGeometryMonitor();
    psm.startSceneMonitor();
    psm.startStateMonitor();

    MoveGroupAction mga(psm);
    mga.status();
    ros::waitForShutdown();
  }
  else
    ROS_ERROR("Planning scene not configured");

  return 0;
}
<commit_msg>use planning scene diffs<commit_after>/*********************************************************************
* Software License Agreement (BSD License)
*
*  Copyright (c) 2012, Willow Garage, Inc.
*  All rights reserved.
*
*  Redistribution and use in source and binary forms, with or without
*  modification, are permitted provided that the following conditions
*  are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*   * Redistributions in binary form must reproduce the above
*     copyright notice, this list of conditions and the following
*     disclaimer in the documentation and/or other materials provided
*     with the distribution.
*   * Neither the name of the Willow Garage nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
*  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
*  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
*  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
*  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
*  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
*  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
*  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
*  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
*  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
*  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
*  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
*  POSSIBILITY OF SUCH DAMAGE.
*********************************************************************/

#include <actionlib/server/simple_action_server.h>
#include <moveit_msgs/MoveGroupAction.h>

#include <tf/transform_listener.h>
#include <planning_interface/planning_interface.h>
#include <planning_request_adapter/planning_request_adapter.h>

#include <planning_scene_monitor/planning_scene_monitor.h>
#include <trajectory_execution_ros/trajectory_execution_monitor_ros.h>
#include <moveit_msgs/DisplayTrajectory.h>
#include <boost/tokenizer.hpp>

#include <trajectory_processing/iterative_smoother.h>

static const std::string ROBOT_DESCRIPTION = "robot_description";      // name of the robot description (a param name, so it can be changed externally)
static const std::string DISPLAY_PATH_PUB_TOPIC = "display_trajectory";

class MoveGroupAction
{
public:

  enum MoveGroupState
    {
      IDLE,
      PLANNING,
      MONITOR
    };

  MoveGroupAction(planning_scene_monitor::PlanningSceneMonitor &psm) :
    nh_("~"), psm_(psm), trajectory_execution_(psm_.getPlanningScene()->getKinematicModel()), state_(IDLE)
  {
    // load the group name
    if (nh_.getParam("group", group_name_))
      ROS_INFO("Starting move_group for group '%s'", group_name_.c_str());
    else
      ROS_FATAL("Group name not specified. Cannot start move_group");

    // load the planning plugin
    try
    {
      planner_plugin_loader_.reset(new pluginlib::ClassLoader<planning_interface::Planner>("planning_interface", "planning_interface::Planner"));
    }
    catch(pluginlib::PluginlibException& ex)
    {
      ROS_FATAL_STREAM("Exception while creating planning plugin loader " << ex.what());
    }

    nh_.getParam("planning_plugin", planning_plugin_name_);
    const std::vector<std::string> &classes = planner_plugin_loader_->getDeclaredClasses();
    if (planning_plugin_name_.empty() && classes.size() == 1)
    {
      planning_plugin_name_ = classes[0];
      ROS_INFO("No 'planning_plugin' parameter specified, but only '%s' planning plugin is available. Using that one.", planning_plugin_name_.c_str());
    }
    if (planning_plugin_name_.empty() && classes.size() > 1)
    {
      planning_plugin_name_ = classes[0];
      ROS_INFO("Multiple planning plugins available. You shuold specify the 'planning_plugin' parameter. Using '%s' for now.", planning_plugin_name_.c_str());
    }
    try
    {
      planner_instance_.reset(planner_plugin_loader_->createUnmanagedInstance(planning_plugin_name_));
      planner_instance_->init(psm_.getPlanningScene()->getKinematicModel());
      ROS_INFO_STREAM("Using planning interface '" << planner_instance_->getDescription() << "'");
    }
    catch(pluginlib::PluginlibException& ex)
    {
      std::stringstream ss;
      for (std::size_t i = 0 ; i < classes.size() ; ++i)
        ss << classes[i] << " ";
      ROS_FATAL_STREAM("Exception while loading planner '" << planning_plugin_name_ << "': " << ex.what() << std::endl
                       << "Available plugins: " << ss.str());
    }

    // load the planner request adapters
    std::string adapters;
    if (nh_.getParam("request_adapters", adapters))
    {
      try
      {
        adapter_plugin_loader_.reset(new pluginlib::ClassLoader<planning_request_adapter::PlanningRequestAdapter>("planning_request_adapter", "planning_request_adapter::PlanningRequestAdapter"));
      }
      catch(pluginlib::PluginlibException& ex)
      {
        ROS_ERROR_STREAM("Exception while creating planning plugin loader " << ex.what());
      }
      boost::char_separator<char> sep(" ");
      boost::tokenizer<boost::char_separator<char> > tok(adapters, sep);
      std::vector<planning_request_adapter::PlanningRequestAdapterConstPtr> ads;
      for(boost::tokenizer<boost::char_separator<char> >::iterator beg = tok.begin() ; beg != tok.end(); ++beg)
      {
        planning_request_adapter::PlanningRequestAdapterConstPtr ad;
        try
        {
          ad.reset(adapter_plugin_loader_->createUnmanagedInstance(*beg));
        }
        catch (pluginlib::PluginlibException& ex)
        {
          ROS_ERROR_STREAM("Exception while planning adapter plugin '" << *beg << "': " << ex.what());
        }
        if (ad)
          ads.push_back(ad);
      }
      if (!ads.empty())
      {
        adapter_chain_.reset(new planning_request_adapter::PlanningRequestAdapterChain());
        for (std::size_t i = 0 ; i < ads.size() ; ++i)
        {
          ROS_INFO_STREAM("Using planning request adapter '" << ads[i]->getDescription() << "'");
          adapter_chain_->addAdapter(ads[i]);
        }
      }
    }

    display_path_publisher_ = root_nh_.advertise<moveit_msgs::DisplayTrajectory>("move_" + group_name_ + "/" + DISPLAY_PATH_PUB_TOPIC, 1, true);

    // start the action server
    action_server_.reset(new actionlib::SimpleActionServer<moveit_msgs::MoveGroupAction>(root_nh_, "move_" + group_name_, false));
    action_server_->registerGoalCallback(boost::bind(&MoveGroupAction::goalCallback, this));
    action_server_->registerPreemptCallback(boost::bind(&MoveGroupAction::preemptCallback, this));
    action_server_->start();
  }

  void goalCallback(void)
  {
    if (service_goal_thread_)
    {
      terminate_service_thread_ = true;
      service_goal_thread_->join();
      service_goal_thread_.reset();
    }
    goal_ = action_server_->acceptNewGoal();
    if (!goal_)
    {
      ROS_ERROR("Something unexpected happened. No goal found in callback for goal...");
      return;
    }

    if (!goal_->request.group_name.empty() && goal_->request.group_name != group_name_)
    {
      moveit_msgs::MoveGroupResult res;
      res.error_code.val = moveit_msgs::MoveItErrorCodes::INVALID_GROUP_NAME;
      action_server_->setAborted(res, "Cannot accept requests for group '" +
                                 goal_->request.group_name  + "' when the move_group action is loaded for group '" +
                                 group_name_ +  "'");
    }
    else
      service_goal_thread_.reset(new boost::thread(boost::bind(&MoveGroupAction::serviceGoalRequest, this)));
  }

  void preemptCallback(void)
  {
    action_server_->setPreempted();
    terminate_service_thread_ = true;
  }

  void serviceGoalRequest(void)
  {
    setState(PLANNING);

    bool solved = false;
    moveit_msgs::GetMotionPlan::Request req;
    req.motion_plan_request = goal_->request;
    if (req.motion_plan_request.group_name.empty())
      req.motion_plan_request.group_name = group_name_;
    moveit_msgs::GetMotionPlan::Response res;

    planning_scene::PlanningScenePtr diff(new planning_scene::PlanningScene(psm_.getPlanningScene()));
    diff->setPlanningSceneDiffMsg(goal_->planning_scene_diff);

    const planning_scene::PlanningScenePtr &the_scene = diff;

    try
    {
      if (adapter_chain_)
        solved = adapter_chain_->adaptAndPlan(planner_instance_, the_scene, req, res);
      else
        solved = planner_instance_->solve(the_scene, req, res);
    }
    catch(std::runtime_error &ex)
    {
      ROS_ERROR("Exception caught: '%s'", ex.what());
    }
    catch(...)
    {
      ROS_ERROR("Unknown exception thrown by planner");
    }

    if (solved)
    {
      trajectory_msgs::JointTrajectory trajectory_out;
      smoother_.smooth(res.trajectory.joint_trajectory, trajectory_out, psm_.getGroupJointLimitsMap().at(group_name_));
      res.trajectory.joint_trajectory = trajectory_out;

      setState(MONITOR);
      execution_complete_ = false;

      // display the trajectory
      moveit_msgs::DisplayTrajectory disp;
      disp.model_id = psm_.getPlanningScene()->getKinematicModel()->getName();
      disp.trajectory_start = res.trajectory_start;
      disp.trajectory = res.trajectory;
      display_path_publisher_.publish(disp);

      trajectory_execution::TrajectoryExecutionRequest ter;
      ter.group_name_ = group_name_;
      ter.trajectory_ = res.trajectory.joint_trajectory; // \TODO This should take in a RobotTrajectory
      if (trajectory_execution_.executeTrajectory(ter, boost::bind(&MoveGroupAction::doneWithTrajectoryExecution, this, _1)))
      {
        ros::WallDuration d(0.01);
        while (nh_.ok() && !execution_complete_ && !terminate_service_thread_)
        {
          /// \TODO Check if the remainder of the path is still valid; If not, replan.
          /// We need a callback in the trajectory monitor for this
          d.sleep();
        }
        moveit_msgs::MoveGroupResult res;
        res.error_code.val = moveit_msgs::MoveItErrorCodes::SUCCESS;
        action_server_->setSucceeded(res, "Solution was found and executed.");
      }
      else
      {
        moveit_msgs::MoveGroupResult res;
        //        res.error_code.val = moveit_msgs::MoveItErrorCodes::CONTROL_FAILED;
        action_server_->setAborted(res, "Solution was found but the controller failed to execute it.");
      }
    }
    else
    {
      moveit_msgs::MoveGroupResult res;
      res.error_code.val = moveit_msgs::MoveItErrorCodes::PLANNING_FAILED;
      action_server_->setAborted(res, "No motion plan found. No execution attempted.");
    }

    setState(IDLE);
  }

  bool doneWithTrajectoryExecution(trajectory_execution::TrajectoryExecutionDataVector data)
  {
    execution_complete_ = true;
    return true;
  }

  void setState(MoveGroupState state)
  {
    state_ = state;
    switch (state_)
    {
    case IDLE:
      feedback_.state = "IDLE";
      feedback_.time_to_completion = ros::Duration(0.0);
      break;
    case PLANNING:
      feedback_.state = "PLANNING";
      feedback_.time_to_completion = ros::Duration(0.0);
      break;
    case MONITOR:
      feedback_.state = "MONITOR";
      feedback_.time_to_completion = ros::Duration(0.0);
      break;
    }
    action_server_->publishFeedback(feedback_);
  }

  void status(void)
  {
    ROS_INFO("MoveGroup action for group '%s' running using planning plugin '%s'", group_name_.c_str(), planning_plugin_name_.c_str());
  }

private:

  ros::NodeHandle root_nh_;
  ros::NodeHandle nh_;
  planning_scene_monitor::PlanningSceneMonitor &psm_;

  std::string planning_plugin_name_;
  boost::scoped_ptr<pluginlib::ClassLoader<planning_interface::Planner> > planner_plugin_loader_;
  planning_interface::PlannerPtr planner_instance_;
  std::string group_name_;

  boost::scoped_ptr<pluginlib::ClassLoader<planning_request_adapter::PlanningRequestAdapter> > adapter_plugin_loader_;
  boost::scoped_ptr<planning_request_adapter::PlanningRequestAdapterChain> adapter_chain_;

  boost::shared_ptr<actionlib::SimpleActionServer<moveit_msgs::MoveGroupAction> > action_server_;
  moveit_msgs::MoveGroupGoalConstPtr goal_;
  moveit_msgs::MoveGroupFeedback feedback_;

  boost::scoped_ptr<boost::thread> service_goal_thread_;

  trajectory_execution_ros::TrajectoryExecutionMonitorRos trajectory_execution_;
  bool terminate_service_thread_;
  bool execution_complete_;
  MoveGroupState state_;
  trajectory_processing::IterativeParabolicSmoother smoother_;

  ros::Publisher display_path_publisher_;
};

int main(int argc, char **argv)
{
  ros::init(argc, argv, "move_group", ros::init_options::AnonymousName);

  ros::AsyncSpinner spinner(1);
  spinner.start();

  tf::TransformListener tf;
  planning_scene_monitor::PlanningSceneMonitor psm(ROBOT_DESCRIPTION, &tf);
  if (psm.getPlanningScene()->isConfigured())
  {
    psm.startWorldGeometryMonitor();
    psm.startSceneMonitor();
    psm.startStateMonitor();

    MoveGroupAction mga(psm);
    mga.status();
    ros::waitForShutdown();
  }
  else
    ROS_ERROR("Planning scene not configured");

  return 0;
}
<|endoftext|>


<commit_before>/*
 * opencog/cogserver/server/ServerSocket.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * Copyright (C) 2010 Linas Vepstas <linasvepstas@gmail.com>
 * All Rights Reserved
 *
 * Written by Welter Luigi <welter@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <mutex>

#include <opencog/cogserver/server/ServerSocket.h>
#include <opencog/util/Logger.h>

using namespace opencog;

ServerSocket::ServerSocket(void) :
    _socket(nullptr)
{
}

ServerSocket::~ServerSocket()
{
   logger().debug("ServerSocket::~ServerSocket()");
}

void ServerSocket::Send(const std::string& cmd)
{
    boost::system::error_code error;
    boost::asio::write(*_socket, boost::asio::buffer(cmd),
                       boost::asio::transfer_all(), error);

    // The most likely cause of an error is that the remote side has
    // closed the socket, and we just don't know it yet.  We should
    // maybe not log those errors?
    if (error)
        logger().warn("ServerSocket::Send(): %s", error.message().c_str());
}

// As far as I can tell, boost::asio is not actually thread-safe,
// in particular, when closing and estroying sockets.  This strikes
// me as incredibly stupid -- a first-class reason to not use boost.
// But whatever.  Hack around this for now.
static std::mutex _asio_crash;

void ServerSocket::SetCloseAndDelete()
{
    std::lock_guard<std::mutex> lock(_asio_crash);
    logger().debug("ServerSocket::SetCloseAndDelete()");
    try
    {
        _socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
        _socket->close();
    }
    catch (const boost::system::system_error& e)
    {
        if (e.code() != boost::asio::error::not_connected)
        {
            logger().error("ServerSocket::handle_connection(): Error closing socket: %s", e.what());
        }
    }
}

typedef boost::asio::buffers_iterator<
    boost::asio::streambuf::const_buffers_type> bitter;

// Some random RFC 854 characters
#define IAC 0xff  // Telnet Interpret As Command
#define IP 0xf4   // Telnet IP Interrupt Process
#define AO 0xf5   // Telnet AO Abort Output
#define EL 0xf8   // Telnet EL Erase Line
#define WILL 0xfb // Telnet WILL
#define DO 0xfd   // Telnet DO
#define TIMING_MARK 0x6 // Telnet RFC 860 timing mark
#define TRANSMIT_BINARY 0x0 // Telnet RFC 856 8-bit-clean
#define CHARSET 0x2A // Telnet RFC 2066

// Goal: if the user types in a ctrl-C or a ctrl-D, we want to
// react immediately to this. A ctrl-D is just the ascii char 0x4
// while the ctrl-C is wrapped in a telnet "interpret as command"
// IAC byte secquence.  Basically, we want to forward all IAC
// sequences immediately, as well as the ctrl-D.
//
// Currently not implemented, but could be: support for the arrow
// keys, which generate the sequence 0x1b 0x5c A B C or D.
//
std::pair<bitter, bool>
match_eol_or_escape(bitter begin, bitter end)
{
    bool telnet_mode = false;
    bitter i = begin;
    while (i != end)
    {
        unsigned char c = *i++;
        if (IAC == c) telnet_mode = true;
        if (('\n' == c) ||
            (0x04 == c) || // ASCII EOT End of Transmission (ctrl-D)
            (telnet_mode && (c <= 0xf0)))
        {
            return std::make_pair(i, true);
        }
    }
    return std::make_pair(i, false);
}

void ServerSocket::set_socket(boost::asio::ip::tcp::socket* sock)
{
    _socket = sock;
}

void ServerSocket::handle_connection(void)
{
    logger().debug("ServerSocket::handle_connection()");
    OnConnection();
    boost::asio::streambuf b;
    while (true)
    {
        try
        {
            boost::asio::read_until(*_socket, b, match_eol_or_escape);
            std::istream is(&b);
            std::string line;
            std::getline(is, line);
            if (!line.empty() && line[line.length()-1] == '\r') {
                line.erase(line.end()-1);
            }
            OnLine(line);
        }
        catch (const boost::system::system_error& e)
        {
            if (e.code() == boost::asio::error::eof) {
                break;
            } else if (e.code() == boost::asio::error::connection_reset) {
                break;
            } else if (e.code() == boost::asio::error::not_connected) {
                break;
            } else {
                logger().error("ServerSocket::handle_connection(): Error reading data. Message: %s", e.what());
            }
        }
    }

    std::lock_guard<std::mutex> lock(_asio_crash);
    try
    {
        _socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
        _socket->close();
    }
    catch (const boost::system::system_error& e)
    {
        if (e.code() != boost::asio::error::not_connected)
        {
            logger().error("ServerSocket::handle_connection(): Error closing socket: %s", e.what());
        }
    }

    delete _socket;
    _socket = nullptr;

    delete this;
}
<commit_msg>Wrap boost::asio::write in a conditional<commit_after>/*
 * opencog/cogserver/server/ServerSocket.cc
 *
 * Copyright (C) 2002-2007 Novamente LLC
 * Copyright (C) 2010 Linas Vepstas <linasvepstas@gmail.com>
 * All Rights Reserved
 *
 * Written by Welter Luigi <welter@vettalabs.com>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License v3 as
 * published by the Free Software Foundation and including the exceptions
 * at http://opencog.org/wiki/Licenses
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program; if not, write to:
 * Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */

#include <mutex>

#include <opencog/cogserver/server/ServerSocket.h>
#include <opencog/util/Logger.h>

using namespace opencog;

ServerSocket::ServerSocket(void) :
    _socket(nullptr)
{
}

ServerSocket::~ServerSocket()
{
   logger().debug("ServerSocket::~ServerSocket()");
}

void ServerSocket::Send(const std::string& cmd)
{
    if (_socket)
    {
        boost::system::error_code error;
        boost::asio::write(*_socket, boost::asio::buffer(cmd),
                           boost::asio::transfer_all(), error);

        // The most likely cause of an error is that the remote side has
        // closed the socket, and we just don't know it yet.  We should
        // maybe not log those errors?
        if (error)
            logger().warn("ServerSocket::Send(): %s", error.message().c_str());
    }
    else
        logger().warn("ServerSocket::Send(): cannot send '%s' "
                      "because _socket is nullptr", cmd.c_str());
}

// As far as I can tell, boost::asio is not actually thread-safe,
// in particular, when closing and estroying sockets.  This strikes
// me as incredibly stupid -- a first-class reason to not use boost.
// But whatever.  Hack around this for now.
static std::mutex _asio_crash;

void ServerSocket::SetCloseAndDelete()
{
    std::lock_guard<std::mutex> lock(_asio_crash);
    logger().debug("ServerSocket::SetCloseAndDelete()");
    try
    {
        _socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
        _socket->close();
    }
    catch (const boost::system::system_error& e)
    {
        if (e.code() != boost::asio::error::not_connected)
        {
            logger().error("ServerSocket::handle_connection(): Error closing socket: %s", e.what());
        }
    }
}

typedef boost::asio::buffers_iterator<
    boost::asio::streambuf::const_buffers_type> bitter;

// Some random RFC 854 characters
#define IAC 0xff  // Telnet Interpret As Command
#define IP 0xf4   // Telnet IP Interrupt Process
#define AO 0xf5   // Telnet AO Abort Output
#define EL 0xf8   // Telnet EL Erase Line
#define WILL 0xfb // Telnet WILL
#define DO 0xfd   // Telnet DO
#define TIMING_MARK 0x6 // Telnet RFC 860 timing mark
#define TRANSMIT_BINARY 0x0 // Telnet RFC 856 8-bit-clean
#define CHARSET 0x2A // Telnet RFC 2066

// Goal: if the user types in a ctrl-C or a ctrl-D, we want to
// react immediately to this. A ctrl-D is just the ascii char 0x4
// while the ctrl-C is wrapped in a telnet "interpret as command"
// IAC byte secquence.  Basically, we want to forward all IAC
// sequences immediately, as well as the ctrl-D.
//
// Currently not implemented, but could be: support for the arrow
// keys, which generate the sequence 0x1b 0x5c A B C or D.
//
std::pair<bitter, bool>
match_eol_or_escape(bitter begin, bitter end)
{
    bool telnet_mode = false;
    bitter i = begin;
    while (i != end)
    {
        unsigned char c = *i++;
        if (IAC == c) telnet_mode = true;
        if (('\n' == c) ||
            (0x04 == c) || // ASCII EOT End of Transmission (ctrl-D)
            (telnet_mode && (c <= 0xf0)))
        {
            return std::make_pair(i, true);
        }
    }
    return std::make_pair(i, false);
}

void ServerSocket::set_socket(boost::asio::ip::tcp::socket* sock)
{
    _socket = sock;
}

void ServerSocket::handle_connection(void)
{
    logger().debug("ServerSocket::handle_connection()");
    OnConnection();
    boost::asio::streambuf b;
    while (true)
    {
        try
        {
            boost::asio::read_until(*_socket, b, match_eol_or_escape);
            std::istream is(&b);
            std::string line;
            std::getline(is, line);
            if (!line.empty() && line[line.length()-1] == '\r') {
                line.erase(line.end()-1);
            }
            OnLine(line);
        }
        catch (const boost::system::system_error& e)
        {
            if (e.code() == boost::asio::error::eof) {
                break;
            } else if (e.code() == boost::asio::error::connection_reset) {
                break;
            } else if (e.code() == boost::asio::error::not_connected) {
                break;
            } else {
                logger().error("ServerSocket::handle_connection(): Error reading data. Message: %s", e.what());
            }
        }
    }

    std::lock_guard<std::mutex> lock(_asio_crash);
    try
    {
        _socket->shutdown(boost::asio::ip::tcp::socket::shutdown_both);
        _socket->close();
    }
    catch (const boost::system::system_error& e)
    {
        if (e.code() != boost::asio::error::not_connected)
        {
            logger().error("ServerSocket::handle_connection(): Error closing socket: %s", e.what());
        }
    }

    delete _socket;
    _socket = nullptr;

    delete this;
}
<|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/chromeos/drive/drive_scheduler.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/chromeos/drive/drive_test_util.h"
#include "chrome/browser/google_apis/dummy_drive_service.h"
#include "chrome/browser/google_apis/gdata_wapi_parser.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::_;

namespace drive {

namespace {

class FakeDriveService : public google_apis::DummyDriveService {
  virtual void GetResourceList(
      const GURL& feed_url,
      int64 start_changestamp,
      const std::string& search_query,
      bool shared_with_me,
      const std::string& directory_resource_id,
      const google_apis::GetResourceListCallback& callback) OVERRIDE {
    // TODO: Make this more flexible.
    if (feed_url == GURL("http://example.com/gdata/root_feed.json")) {
      // Make some sample data.
      scoped_ptr<base::Value> feed_data = google_apis::test_util::LoadJSONFile(
          "gdata/root_feed.json");
      scoped_ptr<google_apis::ResourceList> resource_list =
          google_apis::ResourceList::ExtractAndParse(*feed_data);
      base::MessageLoopProxy::current()->PostTask(FROM_HERE,
          base::Bind(callback,
                     google_apis::HTTP_SUCCESS,
                     base::Passed(&resource_list)));
    } else {
      scoped_ptr<google_apis::ResourceList> resource_list;
      base::MessageLoopProxy::current()->PostTask(FROM_HERE,
          base::Bind(callback,
                     google_apis::GDATA_PARSE_ERROR,
                     base::Passed(&resource_list)));
    }
  }

  virtual void GetAccountMetadata(
      const google_apis::GetAccountMetadataCallback& callback) OVERRIDE {
    // Make some sample data.
    scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
        "gdata/account_metadata.json");
    scoped_ptr<google_apis::AccountMetadataFeed> account_metadata
        = google_apis::AccountMetadataFeed::CreateFrom(*data);

    base::MessageLoopProxy::current()->PostTask(FROM_HERE,
        base::Bind(callback,
                   google_apis::HTTP_SUCCESS,
                   base::Passed(&account_metadata)));
  }

  virtual void GetApplicationInfo(
      const google_apis::GetDataCallback& callback) OVERRIDE {
    scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
        "gdata/account_metadata.json");

    base::MessageLoopProxy::current()->PostTask(FROM_HERE,
        base::Bind(callback,
                   google_apis::HTTP_SUCCESS,
                   base::Passed(&data)));
  }

  virtual void DeleteResource(
      const GURL& edit_url,
      const google_apis::EntryActionCallback& callback) {
    if (edit_url == GURL("/feeds/default/private/full/some_file"))
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

  virtual void GetResourceEntry(
      const std::string& resource_id,
      const google_apis::GetResourceEntryCallback& callback) {
    if (resource_id == "file:2_file_resource_id") {
      scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
          "gdata/file_entry.json");

      // Parsing ResourceEntry is cheap enough to do on UI thread.
      scoped_ptr<google_apis::ResourceEntry> entry =
          google_apis::ResourceEntry::ExtractAndParse(*data);
      if (!entry) {
        callback.Run(google_apis::GDATA_PARSE_ERROR,
                     scoped_ptr<google_apis::ResourceEntry>());
        return;
      }

      callback.Run(google_apis::HTTP_SUCCESS, entry.Pass());
    } else {
      callback.Run(google_apis::HTTP_NOT_FOUND,
                   scoped_ptr<google_apis::ResourceEntry>());
    }
  }

  virtual void CopyHostedDocument(
      const std::string& resource_id,
      const FilePath::StringType& new_name,
      const google_apis::GetResourceEntryCallback& callback) {
    if (resource_id == "file:2_file_resource_id") {
      scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
          "gdata/file_entry.json");

      // Parsing ResourceEntry is cheap enough to do on UI thread.
      scoped_ptr<google_apis::ResourceEntry> entry =
          google_apis::ResourceEntry::ExtractAndParse(*data);
      if (!entry) {
        callback.Run(google_apis::GDATA_PARSE_ERROR,
                     scoped_ptr<google_apis::ResourceEntry>());
        return;
      }

      callback.Run(google_apis::HTTP_SUCCESS, entry.Pass());
    } else {
      callback.Run(google_apis::HTTP_NOT_FOUND,
                   scoped_ptr<google_apis::ResourceEntry>());
    }
  }

  virtual void AddNewDirectory(
      const GURL& parent_content_url,
      const FilePath::StringType& directory_name,
      const google_apis::GetResourceEntryCallback& callback) {
    scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
        "gdata/directory_entry.json");

    // Parsing ResourceEntry is cheap enough to do on UI thread.
    scoped_ptr<google_apis::ResourceEntry> entry =
        google_apis::ResourceEntry::ExtractAndParse(*data);
    if (!entry) {
      callback.Run(google_apis::GDATA_PARSE_ERROR,
                   scoped_ptr<google_apis::ResourceEntry>());
      return;
    }

    callback.Run(google_apis::HTTP_SUCCESS, entry.Pass());
  }

  virtual void RenameResource(
      const GURL& edit_url,
      const FilePath::StringType& new_name,
      const google_apis::EntryActionCallback& callback) {
    if (edit_url == GURL("/feeds/default/private/full/some_file"))
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

  virtual void AddResourceToDirectory(
      const GURL& parent_content_url,
      const GURL& edit_url,
      const google_apis::EntryActionCallback& callback) {
    if (parent_content_url ==
        GURL("/feeds/default/private/full/some_directory") &&
        edit_url == GURL("/feeds/default/private/full/some_file"))
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

  virtual void RemoveResourceFromDirectory(
      const GURL& parent_content_url,
      const std::string& resource_id,
      const google_apis::EntryActionCallback& callback) {
    if (parent_content_url ==
        GURL("/feeds/default/private/full/some_directory") &&
        resource_id == "file:2_file_resource_id")
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

};

class MockNetworkChangeNotifier : public net::NetworkChangeNotifier {
 public:
  MOCK_CONST_METHOD0(GetCurrentConnectionType,
                     net::NetworkChangeNotifier::ConnectionType());
};

}  // namespace

class DriveSchedulerTest : public testing::Test {
 public:
  DriveSchedulerTest()
      : ui_thread_(content::BrowserThread::UI, &message_loop_),
        profile_(new TestingProfile) {
  }

  virtual void SetUp() OVERRIDE {
    mock_network_change_notifier_.reset(new MockNetworkChangeNotifier);

    fake_drive_service_.reset(new FakeDriveService());
    scheduler_.reset(new DriveScheduler(profile_.get(),
                                        fake_drive_service_.get()));

    scheduler_->Initialize();
    scheduler_->SetDisableThrottling(true);
  }

  virtual void TearDown() OVERRIDE {
    // The scheduler should be deleted before NetworkLibrary, as it
    // registers itself as observer of NetworkLibrary.
    scheduler_.reset();
    google_apis::test_util::RunBlockingPoolTask();
    fake_drive_service_.reset();
    mock_network_change_notifier_.reset();
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to a network with
  // the specified connection type.
  void ChangeConnectionType(net::NetworkChangeNotifier::ConnectionType type) {
    EXPECT_CALL(*mock_network_change_notifier_, GetCurrentConnectionType())
        .WillRepeatedly(Return(type));
    // Notify the sync client that the network is changed. This is done via
    // NetworkChangeNotifier in production, but here, we simulate the behavior
    // by directly calling OnConnectionTypeChanged().
    scheduler_->OnConnectionTypeChanged(type);
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to wifi network.
  void ConnectToWifi() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to cellular network.
  void ConnectToCellular() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_2G);
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to wimax network.
  void ConnectToWimax() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_4G);
  }

  // Sets up MockNetworkChangeNotifier as if it's disconnected.
  void ConnectToNone() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE);
  }

 protected:
  MessageLoopForUI message_loop_;
  content::TestBrowserThread ui_thread_;
  scoped_ptr<TestingProfile> profile_;
  scoped_ptr<DriveScheduler> scheduler_;
  scoped_ptr<MockNetworkChangeNotifier> mock_network_change_notifier_;
  scoped_ptr<FakeDriveService> fake_drive_service_;
};

TEST_F(DriveSchedulerTest, GetApplicationInfo) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<base::Value> value;

  scheduler_->GetApplicationInfo(
      base::Bind(&google_apis::test_util::CopyResultsFromGetDataCallback,
                 &error,
                 &value));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(value);
}

TEST_F(DriveSchedulerTest, GetAccountMetadata) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::AccountMetadataFeed> account_metadata;

  scheduler_->GetAccountMetadata(
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetAccountMetadataCallback,
          &error,
          &account_metadata));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(account_metadata);
}

TEST_F(DriveSchedulerTest, GetResourceList) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceList> resource_list;

  scheduler_->GetResourceList(
      GURL("http://example.com/gdata/root_feed.json"),
      0,
      std::string(),
      true,
      std::string(),
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceListCallback,
          &error,
          &resource_list));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(resource_list);
}

TEST_F(DriveSchedulerTest, GetResourceEntry) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceEntry> entry;

  scheduler_->GetResourceEntry(
      "file:2_file_resource_id",  // resource ID
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceEntryCallback,
          &error,
          &entry));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(entry);
}

TEST_F(DriveSchedulerTest, DeleteResource) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->DeleteResource(
      GURL("/feeds/default/private/full/some_file"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, CopyHostedDocument) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceEntry> entry;

  scheduler_->CopyHostedDocument(
      "file:2_file_resource_id",  // resource ID
      FILE_PATH_LITERAL("New Document"),  // new name
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceEntryCallback,
          &error,
          &entry));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(entry);
}

TEST_F(DriveSchedulerTest, RenameResource) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->RenameResource(
      GURL("/feeds/default/private/full/some_file"),
      FILE_PATH_LITERAL("New Name"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, AddResourceToDirectory) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->AddResourceToDirectory(
      GURL("/feeds/default/private/full/some_directory"),
      GURL("/feeds/default/private/full/some_file"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, RemoveResourceFromDirectory) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->RemoveResourceFromDirectory(
      GURL("/feeds/default/private/full/some_directory"),
      "file:2_file_resource_id",  // resource ID
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, AddNewDirectory) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceEntry> entry;

  scheduler_->AddNewDirectory(
      GURL("/feeds/default/private/full/folder%3Aroot"),
      FILE_PATH_LITERAL("New Directory"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceEntryCallback,
          &error,
          &entry));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(entry);
}

}  // namespace drive
<commit_msg>drive: Stop loading account_metadata.json from drive_scheduler_unittest.cc<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/chromeos/drive/drive_scheduler.h"

#include "base/bind.h"
#include "base/file_util.h"
#include "base/json/json_reader.h"
#include "base/threading/sequenced_worker_pool.h"
#include "chrome/browser/chromeos/drive/drive_test_util.h"
#include "chrome/browser/google_apis/dummy_drive_service.h"
#include "chrome/browser/google_apis/gdata_wapi_parser.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

using ::testing::AnyNumber;
using ::testing::DoAll;
using ::testing::Eq;
using ::testing::Return;
using ::testing::StrictMock;
using ::testing::_;

namespace drive {

namespace {

class FakeDriveService : public google_apis::DummyDriveService {
  virtual void GetResourceList(
      const GURL& feed_url,
      int64 start_changestamp,
      const std::string& search_query,
      bool shared_with_me,
      const std::string& directory_resource_id,
      const google_apis::GetResourceListCallback& callback) OVERRIDE {
    // TODO: Make this more flexible.
    if (feed_url == GURL("http://example.com/gdata/root_feed.json")) {
      // Make some sample data.
      scoped_ptr<base::Value> feed_data = google_apis::test_util::LoadJSONFile(
          "gdata/root_feed.json");
      scoped_ptr<google_apis::ResourceList> resource_list =
          google_apis::ResourceList::ExtractAndParse(*feed_data);
      base::MessageLoopProxy::current()->PostTask(FROM_HERE,
          base::Bind(callback,
                     google_apis::HTTP_SUCCESS,
                     base::Passed(&resource_list)));
    } else {
      scoped_ptr<google_apis::ResourceList> resource_list;
      base::MessageLoopProxy::current()->PostTask(FROM_HERE,
          base::Bind(callback,
                     google_apis::GDATA_PARSE_ERROR,
                     base::Passed(&resource_list)));
    }
  }

  virtual void GetAccountMetadata(
      const google_apis::GetAccountMetadataCallback& callback) OVERRIDE {
    // The contents don't matter here, so just return empty metadata.
    scoped_ptr<google_apis::AccountMetadataFeed> account_metadata(
        new google_apis::AccountMetadataFeed);

    base::MessageLoopProxy::current()->PostTask(FROM_HERE,
        base::Bind(callback,
                   google_apis::HTTP_SUCCESS,
                   base::Passed(&account_metadata)));
  }

  virtual void GetApplicationInfo(
      const google_apis::GetDataCallback& callback) OVERRIDE {
    // The contents don't matter here, so just return an empty dictionary.
    scoped_ptr<base::Value> data(new base::DictionaryValue);

    base::MessageLoopProxy::current()->PostTask(FROM_HERE,
        base::Bind(callback,
                   google_apis::HTTP_SUCCESS,
                   base::Passed(&data)));
  }

  virtual void DeleteResource(
      const GURL& edit_url,
      const google_apis::EntryActionCallback& callback) {
    if (edit_url == GURL("/feeds/default/private/full/some_file"))
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

  virtual void GetResourceEntry(
      const std::string& resource_id,
      const google_apis::GetResourceEntryCallback& callback) {
    if (resource_id == "file:2_file_resource_id") {
      scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
          "gdata/file_entry.json");

      // Parsing ResourceEntry is cheap enough to do on UI thread.
      scoped_ptr<google_apis::ResourceEntry> entry =
          google_apis::ResourceEntry::ExtractAndParse(*data);
      if (!entry) {
        callback.Run(google_apis::GDATA_PARSE_ERROR,
                     scoped_ptr<google_apis::ResourceEntry>());
        return;
      }

      callback.Run(google_apis::HTTP_SUCCESS, entry.Pass());
    } else {
      callback.Run(google_apis::HTTP_NOT_FOUND,
                   scoped_ptr<google_apis::ResourceEntry>());
    }
  }

  virtual void CopyHostedDocument(
      const std::string& resource_id,
      const FilePath::StringType& new_name,
      const google_apis::GetResourceEntryCallback& callback) {
    if (resource_id == "file:2_file_resource_id") {
      scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
          "gdata/file_entry.json");

      // Parsing ResourceEntry is cheap enough to do on UI thread.
      scoped_ptr<google_apis::ResourceEntry> entry =
          google_apis::ResourceEntry::ExtractAndParse(*data);
      if (!entry) {
        callback.Run(google_apis::GDATA_PARSE_ERROR,
                     scoped_ptr<google_apis::ResourceEntry>());
        return;
      }

      callback.Run(google_apis::HTTP_SUCCESS, entry.Pass());
    } else {
      callback.Run(google_apis::HTTP_NOT_FOUND,
                   scoped_ptr<google_apis::ResourceEntry>());
    }
  }

  virtual void AddNewDirectory(
      const GURL& parent_content_url,
      const FilePath::StringType& directory_name,
      const google_apis::GetResourceEntryCallback& callback) {
    scoped_ptr<Value> data = google_apis::test_util::LoadJSONFile(
        "gdata/directory_entry.json");

    // Parsing ResourceEntry is cheap enough to do on UI thread.
    scoped_ptr<google_apis::ResourceEntry> entry =
        google_apis::ResourceEntry::ExtractAndParse(*data);
    if (!entry) {
      callback.Run(google_apis::GDATA_PARSE_ERROR,
                   scoped_ptr<google_apis::ResourceEntry>());
      return;
    }

    callback.Run(google_apis::HTTP_SUCCESS, entry.Pass());
  }

  virtual void RenameResource(
      const GURL& edit_url,
      const FilePath::StringType& new_name,
      const google_apis::EntryActionCallback& callback) {
    if (edit_url == GURL("/feeds/default/private/full/some_file"))
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

  virtual void AddResourceToDirectory(
      const GURL& parent_content_url,
      const GURL& edit_url,
      const google_apis::EntryActionCallback& callback) {
    if (parent_content_url ==
        GURL("/feeds/default/private/full/some_directory") &&
        edit_url == GURL("/feeds/default/private/full/some_file"))
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

  virtual void RemoveResourceFromDirectory(
      const GURL& parent_content_url,
      const std::string& resource_id,
      const google_apis::EntryActionCallback& callback) {
    if (parent_content_url ==
        GURL("/feeds/default/private/full/some_directory") &&
        resource_id == "file:2_file_resource_id")
      callback.Run(google_apis::HTTP_SUCCESS);
    else
      callback.Run(google_apis::HTTP_NOT_FOUND);
  }

};

class MockNetworkChangeNotifier : public net::NetworkChangeNotifier {
 public:
  MOCK_CONST_METHOD0(GetCurrentConnectionType,
                     net::NetworkChangeNotifier::ConnectionType());
};

}  // namespace

class DriveSchedulerTest : public testing::Test {
 public:
  DriveSchedulerTest()
      : ui_thread_(content::BrowserThread::UI, &message_loop_),
        profile_(new TestingProfile) {
  }

  virtual void SetUp() OVERRIDE {
    mock_network_change_notifier_.reset(new MockNetworkChangeNotifier);

    fake_drive_service_.reset(new FakeDriveService());
    scheduler_.reset(new DriveScheduler(profile_.get(),
                                        fake_drive_service_.get()));

    scheduler_->Initialize();
    scheduler_->SetDisableThrottling(true);
  }

  virtual void TearDown() OVERRIDE {
    // The scheduler should be deleted before NetworkLibrary, as it
    // registers itself as observer of NetworkLibrary.
    scheduler_.reset();
    google_apis::test_util::RunBlockingPoolTask();
    fake_drive_service_.reset();
    mock_network_change_notifier_.reset();
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to a network with
  // the specified connection type.
  void ChangeConnectionType(net::NetworkChangeNotifier::ConnectionType type) {
    EXPECT_CALL(*mock_network_change_notifier_, GetCurrentConnectionType())
        .WillRepeatedly(Return(type));
    // Notify the sync client that the network is changed. This is done via
    // NetworkChangeNotifier in production, but here, we simulate the behavior
    // by directly calling OnConnectionTypeChanged().
    scheduler_->OnConnectionTypeChanged(type);
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to wifi network.
  void ConnectToWifi() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_WIFI);
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to cellular network.
  void ConnectToCellular() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_2G);
  }

  // Sets up MockNetworkChangeNotifier as if it's connected to wimax network.
  void ConnectToWimax() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_4G);
  }

  // Sets up MockNetworkChangeNotifier as if it's disconnected.
  void ConnectToNone() {
    ChangeConnectionType(net::NetworkChangeNotifier::CONNECTION_NONE);
  }

 protected:
  MessageLoopForUI message_loop_;
  content::TestBrowserThread ui_thread_;
  scoped_ptr<TestingProfile> profile_;
  scoped_ptr<DriveScheduler> scheduler_;
  scoped_ptr<MockNetworkChangeNotifier> mock_network_change_notifier_;
  scoped_ptr<FakeDriveService> fake_drive_service_;
};

TEST_F(DriveSchedulerTest, GetApplicationInfo) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<base::Value> value;

  scheduler_->GetApplicationInfo(
      base::Bind(&google_apis::test_util::CopyResultsFromGetDataCallback,
                 &error,
                 &value));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(value);
}

TEST_F(DriveSchedulerTest, GetAccountMetadata) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::AccountMetadataFeed> account_metadata;

  scheduler_->GetAccountMetadata(
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetAccountMetadataCallback,
          &error,
          &account_metadata));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(account_metadata);
}

TEST_F(DriveSchedulerTest, GetResourceList) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceList> resource_list;

  scheduler_->GetResourceList(
      GURL("http://example.com/gdata/root_feed.json"),
      0,
      std::string(),
      true,
      std::string(),
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceListCallback,
          &error,
          &resource_list));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(resource_list);
}

TEST_F(DriveSchedulerTest, GetResourceEntry) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceEntry> entry;

  scheduler_->GetResourceEntry(
      "file:2_file_resource_id",  // resource ID
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceEntryCallback,
          &error,
          &entry));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(entry);
}

TEST_F(DriveSchedulerTest, DeleteResource) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->DeleteResource(
      GURL("/feeds/default/private/full/some_file"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, CopyHostedDocument) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceEntry> entry;

  scheduler_->CopyHostedDocument(
      "file:2_file_resource_id",  // resource ID
      FILE_PATH_LITERAL("New Document"),  // new name
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceEntryCallback,
          &error,
          &entry));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(entry);
}

TEST_F(DriveSchedulerTest, RenameResource) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->RenameResource(
      GURL("/feeds/default/private/full/some_file"),
      FILE_PATH_LITERAL("New Name"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, AddResourceToDirectory) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->AddResourceToDirectory(
      GURL("/feeds/default/private/full/some_directory"),
      GURL("/feeds/default/private/full/some_file"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, RemoveResourceFromDirectory) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;

  scheduler_->RemoveResourceFromDirectory(
      GURL("/feeds/default/private/full/some_directory"),
      "file:2_file_resource_id",  // resource ID
      base::Bind(
          &google_apis::test_util::CopyResultsFromEntryActionCallback,
          &error));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
}

TEST_F(DriveSchedulerTest, AddNewDirectory) {
  ConnectToWifi();

  google_apis::GDataErrorCode error = google_apis::GDATA_OTHER_ERROR;
  scoped_ptr<google_apis::ResourceEntry> entry;

  scheduler_->AddNewDirectory(
      GURL("/feeds/default/private/full/folder%3Aroot"),
      FILE_PATH_LITERAL("New Directory"),
      base::Bind(
          &google_apis::test_util::CopyResultsFromGetResourceEntryCallback,
          &error,
          &entry));
  google_apis::test_util::RunBlockingPoolTask();

  ASSERT_EQ(google_apis::HTTP_SUCCESS, error);
  ASSERT_TRUE(entry);
}

}  // namespace drive
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 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/ssl/ssl_policy.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ssl/ssl_cert_error_handler.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/browser/ssl/ssl_mixed_content_handler.h"
#include "chrome/browser/ssl/ssl_request_info.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "net/base/cert_status_flags.h"
#include "net/base/ssl_info.h"
#include "webkit/glue/resource_type.h"

using WebKit::WebConsoleMessage;

class SSLPolicy::ShowMixedContentTask : public Task {
 public:
  ShowMixedContentTask(SSLPolicy* policy, SSLMixedContentHandler* handler);
  virtual ~ShowMixedContentTask();

  virtual void Run();

 private:
  SSLPolicy* policy_;
  scoped_refptr<SSLMixedContentHandler> handler_;

  DISALLOW_COPY_AND_ASSIGN(ShowMixedContentTask);
};

SSLPolicy::ShowMixedContentTask::ShowMixedContentTask(SSLPolicy* policy,
                                           SSLMixedContentHandler* handler)
    : policy_(policy),
      handler_(handler) {
}

SSLPolicy::ShowMixedContentTask::~ShowMixedContentTask() {
}

void SSLPolicy::ShowMixedContentTask::Run() {
  policy_->AllowMixedContentForOrigin(handler_->frame_origin());
  policy_->AllowMixedContentForOrigin(handler_->main_frame_origin());
  policy_->backend()->Reload();
}

SSLPolicy::SSLPolicy(SSLPolicyBackend* backend)
    : backend_(backend) {
  DCHECK(backend_);
}

void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
  // First we check if we know the policy for this error.
  net::X509Certificate::Policy::Judgment judgment =
      backend_->QueryPolicy(handler->ssl_info().cert,
                            handler->request_url().host());

  if (judgment == net::X509Certificate::Policy::ALLOWED) {
    handler->ContinueRequest();
    return;
  }

  // The judgment is either DENIED or UNKNOWN.
  // For now we handle the DENIED as the UNKNOWN, which means a blocking
  // page is shown to the user every time he comes back to the page.

  switch(handler->cert_error()) {
    case net::ERR_CERT_COMMON_NAME_INVALID:
    case net::ERR_CERT_DATE_INVALID:
    case net::ERR_CERT_AUTHORITY_INVALID:
      OnOverridableCertError(handler);
      break;
    case net::ERR_CERT_NO_REVOCATION_MECHANISM:
      // Ignore this error.
      handler->ContinueRequest();
      break;
    case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
      // We ignore this error and display an infobar.
      handler->ContinueRequest();
      backend_->ShowMessage(l10n_util::GetString(
          IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_INFO_BAR));
      break;
    case net::ERR_CERT_CONTAINS_ERRORS:
    case net::ERR_CERT_REVOKED:
    case net::ERR_CERT_INVALID:
      OnFatalCertError(handler);
      break;
    default:
      NOTREACHED();
      handler->CancelRequest();
      break;
  }
}

void SSLPolicy::OnMixedContent(SSLMixedContentHandler* handler) {
  // Get the user's mixed content preference.
  PrefService* prefs = handler->GetTabContents()->profile()->GetPrefs();
  FilterPolicy::Type filter_policy =
      FilterPolicy::FromInt(prefs->GetInteger(prefs::kMixedContentFiltering));

  // If the user has added an exception, doctor the |filter_policy|.
  std::string host = GURL(handler->main_frame_origin()).host();
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS) &&
      backend_->IsForceTLSEnabledForHost(host)) {
    // We're supposed to block all mixed content for this host.
    filter_policy = FilterPolicy::FILTER_ALL;
  } else if (backend_->DidAllowMixedContentForHost(host) ||
             backend_->DidMarkHostAsBroken(host, handler->pid())) {
    // Let the mixed content through.
    filter_policy = FilterPolicy::DONT_FILTER;
  } else if (filter_policy != FilterPolicy::DONT_FILTER) {
    backend_->ShowMessageWithLink(
        l10n_util::GetString(IDS_SSL_INFO_BAR_FILTERED_CONTENT),
        l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT),
        new ShowMixedContentTask(this, handler));
  }

  handler->StartRequest(filter_policy);
  AddMixedContentWarningToConsole(handler);
}

void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
  if (net::IsCertStatusError(info->ssl_cert_status()))
    UpdateStateForUnsafeContent(info);

  if (IsMixedContent(info->url(),
                     info->resource_type(),
                     info->filter_policy(),
                     info->frame_origin()))
    UpdateStateForMixedContent(info);
}

void SSLPolicy::UpdateEntry(NavigationEntry* entry) {
  DCHECK(entry);

  InitializeEntryIfNeeded(entry);

  if (!entry->url().SchemeIsSecure())
    return;

  // An HTTPS response may not have a certificate for some reason.  When that
  // happens, use the unauthenticated (HTTP) rather than the authentication
  // broken security style so that we can detect this error condition.
  if (!entry->ssl().cert_id()) {
    entry->ssl().set_security_style(SECURITY_STYLE_UNAUTHENTICATED);
    return;
  }

  if (net::IsCertStatusError(entry->ssl().cert_status())) {
    entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN);
    return;
  }

  if (backend_->DidMarkHostAsBroken(entry->url().host(),
                                   entry->site_instance()->GetProcess()->pid()))
    entry->ssl().set_has_mixed_content();
}

// static
bool SSLPolicy::IsMixedContent(const GURL& url,
                               ResourceType::Type resource_type,
                               FilterPolicy::Type filter_policy,
                               const std::string& frame_origin) {
  ////////////////////////////////////////////////////////////////////////////
  // WARNING: This function is called from both the IO and UI threads.  Do  //
  //          not touch any non-thread-safe objects!  You have been warned. //
  ////////////////////////////////////////////////////////////////////////////

  // We can't possibly have mixed content when loading the main frame.
  if (resource_type == ResourceType::MAIN_FRAME)
    return false;

  // If we've filtered the resource, then it's no longer dangerous.
  if (filter_policy != FilterPolicy::DONT_FILTER)
    return false;

  // If the frame doing the loading is already insecure, then we must have
  // already dealt with whatever mixed content might be going on.
  if (!GURL(frame_origin).SchemeIsSecure())
    return false;

  // We aren't worried about mixed content if we're loading an HTTPS URL.
  if (url.SchemeIsSecure())
    return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// SSLBlockingPage::Delegate methods

SSLErrorInfo SSLPolicy::GetSSLErrorInfo(SSLCertErrorHandler* handler) {
  return SSLErrorInfo::CreateError(
      SSLErrorInfo::NetErrorToErrorType(handler->cert_error()),
      handler->ssl_info().cert, handler->request_url());
}

void SSLPolicy::OnDenyCertificate(SSLCertErrorHandler* handler) {
  // Default behavior for rejecting a certificate.
  //
  // While DenyCertForHost() executes synchronously on this thread,
  // CancelRequest() gets posted to a different thread. Calling
  // DenyCertForHost() first ensures deterministic ordering.
  backend_->DenyCertForHost(handler->ssl_info().cert,
                            handler->request_url().host());
  handler->CancelRequest();
}

void SSLPolicy::OnAllowCertificate(SSLCertErrorHandler* handler) {
  // Default behavior for accepting a certificate.
  // Note that we should not call SetMaxSecurityStyle here, because the active
  // NavigationEntry has just been deleted (in HideInterstitialPage) and the
  // new NavigationEntry will not be set until DidNavigate.  This is ok,
  // because the new NavigationEntry will have its max security style set
  // within DidNavigate.
  //
  // While AllowCertForHost() executes synchronously on this thread,
  // ContinueRequest() gets posted to a different thread. Calling
  // AllowCertForHost() first ensures deterministic ordering.
  backend_->AllowCertForHost(handler->ssl_info().cert,
                             handler->request_url().host());
  handler->ContinueRequest();
}

////////////////////////////////////////////////////////////////////////////////
// Certificate Error Routines

void SSLPolicy::OnOverridableCertError(SSLCertErrorHandler* handler) {
  if (handler->resource_type() != ResourceType::MAIN_FRAME) {
    // A sub-resource has a certificate error.  The user doesn't really
    // have a context for making the right decision, so block the
    // request hard, without an info bar to allow showing the insecure
    // content.
    handler->DenyRequest();
    return;
  }
  // We need to ask the user to approve this certificate.
  SSLBlockingPage* blocking_page = new SSLBlockingPage(handler, this);
  blocking_page->Show();
}

void SSLPolicy::OnFatalCertError(SSLCertErrorHandler* handler) {
  if (handler->resource_type() != ResourceType::MAIN_FRAME) {
    handler->DenyRequest();
    return;
  }
  handler->CancelRequest();
  ShowErrorPage(handler);
  // No need to degrade our security indicators because we didn't continue.
}

void SSLPolicy::ShowErrorPage(SSLCertErrorHandler* handler) {
  SSLErrorInfo error_info = GetSSLErrorInfo(handler);

  // Let's build the html error page.
  DictionaryValue strings;
  strings.SetString(L"title", l10n_util::GetString(IDS_SSL_ERROR_PAGE_TITLE));
  strings.SetString(L"headLine", error_info.title());
  strings.SetString(L"description", error_info.details());
  strings.SetString(L"moreInfoTitle",
                    l10n_util::GetString(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
  SSLBlockingPage::SetExtraInfo(&strings, error_info.extra_information());

  strings.SetString(L"back", l10n_util::GetString(IDS_SSL_ERROR_PAGE_BACK));

  strings.SetString(L"textdirection",
      (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
      L"rtl" : L"ltr");

  static const StringPiece html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_SSL_ERROR_HTML));

  std::string html_text(jstemplate_builder::GetTemplateHtml(html, &strings,
                                                            "template_root"));

  TabContents* tab  = handler->GetTabContents();
  int cert_id = CertStore::GetSharedInstance()->StoreCert(
      handler->ssl_info().cert, tab->render_view_host()->process()->pid());
  std::string security_info =
      SSLManager::SerializeSecurityInfo(cert_id,
                                        handler->ssl_info().cert_status,
                                        handler->ssl_info().security_bits);
  tab->render_view_host()->LoadAlternateHTMLString(html_text,
                                                   true,
                                                   handler->request_url(),
                                                   security_info);
  tab->controller().GetActiveEntry()->set_page_type(
      NavigationEntry::ERROR_PAGE);
}

void SSLPolicy::AddMixedContentWarningToConsole(
    SSLMixedContentHandler* handler) {
  const std::wstring& text = l10n_util::GetStringF(
      IDS_MIXED_CONTENT_LOG_MESSAGE,
      UTF8ToWide(handler->frame_origin()),
      UTF8ToWide(handler->request_url().spec()));
  backend_->AddMessageToConsole(
      WideToUTF16Hack(text), WebConsoleMessage::LevelWarning);
}

void SSLPolicy::InitializeEntryIfNeeded(NavigationEntry* entry) {
  if (entry->ssl().security_style() != SECURITY_STYLE_UNKNOWN)
    return;

  entry->ssl().set_security_style(entry->url().SchemeIsSecure() ?
      SECURITY_STYLE_AUTHENTICATED : SECURITY_STYLE_UNAUTHENTICATED);
}

void SSLPolicy::MarkOriginAsBroken(const std::string& origin, int pid) {
  GURL parsed_origin(origin);
  if (!parsed_origin.SchemeIsSecure())
    return;

  backend_->MarkHostAsBroken(parsed_origin.host(), pid);
}

void SSLPolicy::AllowMixedContentForOrigin(const std::string& origin) {
  GURL parsed_origin(origin);
  if (!parsed_origin.SchemeIsSecure())
    return;

  backend_->AllowMixedContentForHost(parsed_origin.host());
}

void SSLPolicy::UpdateStateForMixedContent(SSLRequestInfo* info) {
  if (info->resource_type() != ResourceType::MAIN_FRAME ||
      info->resource_type() != ResourceType::SUB_FRAME) {
    // The frame's origin now contains mixed content and therefore is broken.
    MarkOriginAsBroken(info->frame_origin(), info->pid());
  }

  if (info->resource_type() != ResourceType::MAIN_FRAME) {
    // The main frame now contains a frame with mixed content.  Therefore, we
    // mark the main frame's origin as broken too.
    MarkOriginAsBroken(info->main_frame_origin(), info->pid());
  }
}

void SSLPolicy::UpdateStateForUnsafeContent(SSLRequestInfo* info) {
  // This request as a broken cert, which means its host is broken.
  backend_->MarkHostAsBroken(info->url().host(), info->pid());
  UpdateStateForMixedContent(info);
}
<commit_msg>Fix crash when updating a navigation entry without a site_instance.<commit_after>// Copyright (c) 2006-2008 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/ssl/ssl_policy.h"

#include "app/l10n_util.h"
#include "app/resource_bundle.h"
#include "base/base_switches.h"
#include "base/command_line.h"
#include "base/singleton.h"
#include "base/string_piece.h"
#include "base/string_util.h"
#include "chrome/browser/cert_store.h"
#include "chrome/browser/renderer_host/render_view_host.h"
#include "chrome/browser/ssl/ssl_cert_error_handler.h"
#include "chrome/browser/ssl/ssl_error_info.h"
#include "chrome/browser/ssl/ssl_mixed_content_handler.h"
#include "chrome/browser/ssl/ssl_request_info.h"
#include "chrome/browser/tab_contents/navigation_entry.h"
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/jstemplate_builder.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "chrome/common/pref_service.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/time_format.h"
#include "chrome/common/url_constants.h"
#include "grit/browser_resources.h"
#include "grit/generated_resources.h"
#include "net/base/cert_status_flags.h"
#include "net/base/ssl_info.h"
#include "webkit/glue/resource_type.h"

using WebKit::WebConsoleMessage;

class SSLPolicy::ShowMixedContentTask : public Task {
 public:
  ShowMixedContentTask(SSLPolicy* policy, SSLMixedContentHandler* handler);
  virtual ~ShowMixedContentTask();

  virtual void Run();

 private:
  SSLPolicy* policy_;
  scoped_refptr<SSLMixedContentHandler> handler_;

  DISALLOW_COPY_AND_ASSIGN(ShowMixedContentTask);
};

SSLPolicy::ShowMixedContentTask::ShowMixedContentTask(SSLPolicy* policy,
                                           SSLMixedContentHandler* handler)
    : policy_(policy),
      handler_(handler) {
}

SSLPolicy::ShowMixedContentTask::~ShowMixedContentTask() {
}

void SSLPolicy::ShowMixedContentTask::Run() {
  policy_->AllowMixedContentForOrigin(handler_->frame_origin());
  policy_->AllowMixedContentForOrigin(handler_->main_frame_origin());
  policy_->backend()->Reload();
}

SSLPolicy::SSLPolicy(SSLPolicyBackend* backend)
    : backend_(backend) {
  DCHECK(backend_);
}

void SSLPolicy::OnCertError(SSLCertErrorHandler* handler) {
  // First we check if we know the policy for this error.
  net::X509Certificate::Policy::Judgment judgment =
      backend_->QueryPolicy(handler->ssl_info().cert,
                            handler->request_url().host());

  if (judgment == net::X509Certificate::Policy::ALLOWED) {
    handler->ContinueRequest();
    return;
  }

  // The judgment is either DENIED or UNKNOWN.
  // For now we handle the DENIED as the UNKNOWN, which means a blocking
  // page is shown to the user every time he comes back to the page.

  switch(handler->cert_error()) {
    case net::ERR_CERT_COMMON_NAME_INVALID:
    case net::ERR_CERT_DATE_INVALID:
    case net::ERR_CERT_AUTHORITY_INVALID:
      OnOverridableCertError(handler);
      break;
    case net::ERR_CERT_NO_REVOCATION_MECHANISM:
      // Ignore this error.
      handler->ContinueRequest();
      break;
    case net::ERR_CERT_UNABLE_TO_CHECK_REVOCATION:
      // We ignore this error and display an infobar.
      handler->ContinueRequest();
      backend_->ShowMessage(l10n_util::GetString(
          IDS_CERT_ERROR_UNABLE_TO_CHECK_REVOCATION_INFO_BAR));
      break;
    case net::ERR_CERT_CONTAINS_ERRORS:
    case net::ERR_CERT_REVOKED:
    case net::ERR_CERT_INVALID:
      OnFatalCertError(handler);
      break;
    default:
      NOTREACHED();
      handler->CancelRequest();
      break;
  }
}

void SSLPolicy::OnMixedContent(SSLMixedContentHandler* handler) {
  // Get the user's mixed content preference.
  PrefService* prefs = handler->GetTabContents()->profile()->GetPrefs();
  FilterPolicy::Type filter_policy =
      FilterPolicy::FromInt(prefs->GetInteger(prefs::kMixedContentFiltering));

  // If the user has added an exception, doctor the |filter_policy|.
  std::string host = GURL(handler->main_frame_origin()).host();
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kForceHTTPS) &&
      backend_->IsForceTLSEnabledForHost(host)) {
    // We're supposed to block all mixed content for this host.
    filter_policy = FilterPolicy::FILTER_ALL;
  } else if (backend_->DidAllowMixedContentForHost(host) ||
             backend_->DidMarkHostAsBroken(host, handler->pid())) {
    // Let the mixed content through.
    filter_policy = FilterPolicy::DONT_FILTER;
  } else if (filter_policy != FilterPolicy::DONT_FILTER) {
    backend_->ShowMessageWithLink(
        l10n_util::GetString(IDS_SSL_INFO_BAR_FILTERED_CONTENT),
        l10n_util::GetString(IDS_SSL_INFO_BAR_SHOW_CONTENT),
        new ShowMixedContentTask(this, handler));
  }

  handler->StartRequest(filter_policy);
  AddMixedContentWarningToConsole(handler);
}

void SSLPolicy::OnRequestStarted(SSLRequestInfo* info) {
  if (net::IsCertStatusError(info->ssl_cert_status()))
    UpdateStateForUnsafeContent(info);

  if (IsMixedContent(info->url(),
                     info->resource_type(),
                     info->filter_policy(),
                     info->frame_origin()))
    UpdateStateForMixedContent(info);
}

void SSLPolicy::UpdateEntry(NavigationEntry* entry) {
  DCHECK(entry);

  InitializeEntryIfNeeded(entry);

  if (!entry->url().SchemeIsSecure())
    return;

  // An HTTPS response may not have a certificate for some reason.  When that
  // happens, use the unauthenticated (HTTP) rather than the authentication
  // broken security style so that we can detect this error condition.
  if (!entry->ssl().cert_id()) {
    entry->ssl().set_security_style(SECURITY_STYLE_UNAUTHENTICATED);
    return;
  }

  if (net::IsCertStatusError(entry->ssl().cert_status())) {
    entry->ssl().set_security_style(SECURITY_STYLE_AUTHENTICATION_BROKEN);
    return;
  }

  SiteInstance* site_instance = entry->site_instance();
  // Note that |site_instance| can be NULL here because NavigationEntries don't
  // necessarily have site instances.  Without a process, the entry can't
  // possibly have mixed content.  See bug http://crbug.com/12423.
  if (site_instance &&
      backend_->DidMarkHostAsBroken(entry->url().host(),
                                    site_instance->GetProcess()->pid()))
    entry->ssl().set_has_mixed_content();
}

// static
bool SSLPolicy::IsMixedContent(const GURL& url,
                               ResourceType::Type resource_type,
                               FilterPolicy::Type filter_policy,
                               const std::string& frame_origin) {
  ////////////////////////////////////////////////////////////////////////////
  // WARNING: This function is called from both the IO and UI threads.  Do  //
  //          not touch any non-thread-safe objects!  You have been warned. //
  ////////////////////////////////////////////////////////////////////////////

  // We can't possibly have mixed content when loading the main frame.
  if (resource_type == ResourceType::MAIN_FRAME)
    return false;

  // If we've filtered the resource, then it's no longer dangerous.
  if (filter_policy != FilterPolicy::DONT_FILTER)
    return false;

  // If the frame doing the loading is already insecure, then we must have
  // already dealt with whatever mixed content might be going on.
  if (!GURL(frame_origin).SchemeIsSecure())
    return false;

  // We aren't worried about mixed content if we're loading an HTTPS URL.
  if (url.SchemeIsSecure())
    return false;

  return true;
}

////////////////////////////////////////////////////////////////////////////////
// SSLBlockingPage::Delegate methods

SSLErrorInfo SSLPolicy::GetSSLErrorInfo(SSLCertErrorHandler* handler) {
  return SSLErrorInfo::CreateError(
      SSLErrorInfo::NetErrorToErrorType(handler->cert_error()),
      handler->ssl_info().cert, handler->request_url());
}

void SSLPolicy::OnDenyCertificate(SSLCertErrorHandler* handler) {
  // Default behavior for rejecting a certificate.
  //
  // While DenyCertForHost() executes synchronously on this thread,
  // CancelRequest() gets posted to a different thread. Calling
  // DenyCertForHost() first ensures deterministic ordering.
  backend_->DenyCertForHost(handler->ssl_info().cert,
                            handler->request_url().host());
  handler->CancelRequest();
}

void SSLPolicy::OnAllowCertificate(SSLCertErrorHandler* handler) {
  // Default behavior for accepting a certificate.
  // Note that we should not call SetMaxSecurityStyle here, because the active
  // NavigationEntry has just been deleted (in HideInterstitialPage) and the
  // new NavigationEntry will not be set until DidNavigate.  This is ok,
  // because the new NavigationEntry will have its max security style set
  // within DidNavigate.
  //
  // While AllowCertForHost() executes synchronously on this thread,
  // ContinueRequest() gets posted to a different thread. Calling
  // AllowCertForHost() first ensures deterministic ordering.
  backend_->AllowCertForHost(handler->ssl_info().cert,
                             handler->request_url().host());
  handler->ContinueRequest();
}

////////////////////////////////////////////////////////////////////////////////
// Certificate Error Routines

void SSLPolicy::OnOverridableCertError(SSLCertErrorHandler* handler) {
  if (handler->resource_type() != ResourceType::MAIN_FRAME) {
    // A sub-resource has a certificate error.  The user doesn't really
    // have a context for making the right decision, so block the
    // request hard, without an info bar to allow showing the insecure
    // content.
    handler->DenyRequest();
    return;
  }
  // We need to ask the user to approve this certificate.
  SSLBlockingPage* blocking_page = new SSLBlockingPage(handler, this);
  blocking_page->Show();
}

void SSLPolicy::OnFatalCertError(SSLCertErrorHandler* handler) {
  if (handler->resource_type() != ResourceType::MAIN_FRAME) {
    handler->DenyRequest();
    return;
  }
  handler->CancelRequest();
  ShowErrorPage(handler);
  // No need to degrade our security indicators because we didn't continue.
}

void SSLPolicy::ShowErrorPage(SSLCertErrorHandler* handler) {
  SSLErrorInfo error_info = GetSSLErrorInfo(handler);

  // Let's build the html error page.
  DictionaryValue strings;
  strings.SetString(L"title", l10n_util::GetString(IDS_SSL_ERROR_PAGE_TITLE));
  strings.SetString(L"headLine", error_info.title());
  strings.SetString(L"description", error_info.details());
  strings.SetString(L"moreInfoTitle",
                    l10n_util::GetString(IDS_CERT_ERROR_EXTRA_INFO_TITLE));
  SSLBlockingPage::SetExtraInfo(&strings, error_info.extra_information());

  strings.SetString(L"back", l10n_util::GetString(IDS_SSL_ERROR_PAGE_BACK));

  strings.SetString(L"textdirection",
      (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT) ?
      L"rtl" : L"ltr");

  static const StringPiece html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_SSL_ERROR_HTML));

  std::string html_text(jstemplate_builder::GetTemplateHtml(html, &strings,
                                                            "template_root"));

  TabContents* tab  = handler->GetTabContents();
  int cert_id = CertStore::GetSharedInstance()->StoreCert(
      handler->ssl_info().cert, tab->render_view_host()->process()->pid());
  std::string security_info =
      SSLManager::SerializeSecurityInfo(cert_id,
                                        handler->ssl_info().cert_status,
                                        handler->ssl_info().security_bits);
  tab->render_view_host()->LoadAlternateHTMLString(html_text,
                                                   true,
                                                   handler->request_url(),
                                                   security_info);
  tab->controller().GetActiveEntry()->set_page_type(
      NavigationEntry::ERROR_PAGE);
}

void SSLPolicy::AddMixedContentWarningToConsole(
    SSLMixedContentHandler* handler) {
  const std::wstring& text = l10n_util::GetStringF(
      IDS_MIXED_CONTENT_LOG_MESSAGE,
      UTF8ToWide(handler->frame_origin()),
      UTF8ToWide(handler->request_url().spec()));
  backend_->AddMessageToConsole(
      WideToUTF16Hack(text), WebConsoleMessage::LevelWarning);
}

void SSLPolicy::InitializeEntryIfNeeded(NavigationEntry* entry) {
  if (entry->ssl().security_style() != SECURITY_STYLE_UNKNOWN)
    return;

  entry->ssl().set_security_style(entry->url().SchemeIsSecure() ?
      SECURITY_STYLE_AUTHENTICATED : SECURITY_STYLE_UNAUTHENTICATED);
}

void SSLPolicy::MarkOriginAsBroken(const std::string& origin, int pid) {
  GURL parsed_origin(origin);
  if (!parsed_origin.SchemeIsSecure())
    return;

  backend_->MarkHostAsBroken(parsed_origin.host(), pid);
}

void SSLPolicy::AllowMixedContentForOrigin(const std::string& origin) {
  GURL parsed_origin(origin);
  if (!parsed_origin.SchemeIsSecure())
    return;

  backend_->AllowMixedContentForHost(parsed_origin.host());
}

void SSLPolicy::UpdateStateForMixedContent(SSLRequestInfo* info) {
  if (info->resource_type() != ResourceType::MAIN_FRAME ||
      info->resource_type() != ResourceType::SUB_FRAME) {
    // The frame's origin now contains mixed content and therefore is broken.
    MarkOriginAsBroken(info->frame_origin(), info->pid());
  }

  if (info->resource_type() != ResourceType::MAIN_FRAME) {
    // The main frame now contains a frame with mixed content.  Therefore, we
    // mark the main frame's origin as broken too.
    MarkOriginAsBroken(info->main_frame_origin(), info->pid());
  }
}

void SSLPolicy::UpdateStateForUnsafeContent(SSLRequestInfo* info) {
  // This request as a broken cert, which means its host is broken.
  backend_->MarkHostAsBroken(info->url().host(), info->pid());
  UpdateStateForMixedContent(info);
}
<|endoftext|>


<commit_before>// Copyright (c) 2011 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/ui/window_snapshot/window_snapshot.h"

#include "base/logging.h"
#include "ui/gfx/rect.h"

namespace browser {

bool GrabWindowSnapshot(gfx::NativeWindow window_handle,
                             std::vector<unsigned char>* png_representation,
                             const gfx::Rect& snapshot_bounds) {
  // TODO(saintlou): Stub for Aura.
  NOTIMPLEMENTED();
  return false;
}

}  // namespace browser
<commit_msg>Implementation of window_snapshot_aura<commit_after>// Copyright (c) 2011 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/ui/window_snapshot/window_snapshot.h"

#include "base/logging.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/aura/window.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/compositor/compositor.h"
#include "ui/gfx/rect.h"

namespace browser {

bool GrabWindowSnapshot(gfx::NativeWindow window,
                        std::vector<unsigned char>* png_representation,
                        const gfx::Rect& snapshot_bounds) {
  ui::Compositor* compositor = window->layer()->GetCompositor();

  gfx::Rect desktop_snapshot_bounds = gfx::Rect(
      snapshot_bounds.origin().Add(window->bounds().origin()),
      snapshot_bounds.size());

  DCHECK_LE(desktop_snapshot_bounds.right() , compositor->size().width());
  DCHECK_LE(desktop_snapshot_bounds.bottom(), compositor->size().height());

  SkBitmap bitmap;
  if (!compositor->ReadPixels(&bitmap, desktop_snapshot_bounds))
    return false;

  unsigned char* pixels = reinterpret_cast<unsigned char*>(bitmap.getPixels());

  gfx::PNGCodec::Encode(pixels, gfx::PNGCodec::FORMAT_BGRA,
                        snapshot_bounds.size(),
                        bitmap.rowBytes(), true,
                        std::vector<gfx::PNGCodec::Comment>(),
                        png_representation);
  return true;
}

}  // namespace browser
<|endoftext|>