<commit_before>#include "window.h"
#include "logging.h"

Window::Window() :
  window_box_(Gtk::ORIENTATION_VERTICAL),
  main_config_(),
  keybindings_(main_config_.keybindings_cfg()),
  terminal_(main_config_.terminal_cfg()),
  notebook_(this,keybindings(),
            main_config_.source_cfg(),
            main_config_.dir_cfg()),
  menu_(keybindings()),
  api_(menu_, notebook_) {
  INFO("Create Window");
  set_title("juCi++");
  set_default_size(600, 400);
  add(window_box_);
  keybindings_.action_group_menu()->add(Gtk::Action::create("FileQuit",
                                                            "Quit juCi++"),
                                        Gtk::AccelKey(keybindings_.config_
                                                      .key_map()["quit"]),
                                        [this]() {
                                          OnWindowHide();
                                        });
  keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFile",
                                                            "Open file"),
                                        Gtk::AccelKey(keybindings_.config_
                                                      .key_map()["open_file"]),
                                        [this]() {
                                          OnOpenFile();
                                        });
  keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFolder",
                                                            "Open folder"),
                                        Gtk::AccelKey(keybindings_.config_
                                                      .key_map()["open_folder"]),
                                        [this]() {
                                          OnFileOpenFolder();
                                        });
  keybindings_.
    action_group_menu()->
    add(Gtk::Action::create("FileSaveAs",
			    "Save as"),
	Gtk::AccelKey(keybindings_.config_
		      .key_map()["save_as"]),
	[this]() {
	  SaveFileAs();
	});

  keybindings_.
    action_group_menu()->
    add(Gtk::Action::create("FileSave",
			    "Save"),
	Gtk::AccelKey(keybindings_.config_
		      .key_map()["save"]),
	[this]() {
	  SaveFile();
	});

  keybindings_.
    action_group_menu()->
    add(Gtk::Action::create("ProjectCompileAndRun",
			    "Compile And Run"),
	Gtk::AccelKey(keybindings_.config_
		      .key_map()["compile_and_run"]),
	[this]() {
	  SaveFile();
	  if (running.try_lock()) {
	    std::thread execute([=]() {
		std::string path = notebook_.CurrentPagePath();
		int pos = path.find_last_of("/\\");
		if(pos != std::string::npos) {
		  path.erase(path.begin()+pos,path.end());
		  terminal_.SetFolderCommand(path);
		}
		terminal_.Compile();
		std::string executable = notebook_.directories().
		  GetCmakeVarValue(path,"add_executable");
		terminal_.Run(executable);
	      });
	    execute.detach();
	    running.unlock();
	  }
	});

    keybindings_.
      action_group_menu()->
      add(Gtk::Action::create("ProjectCompile",
			      "Compile"),
	  Gtk::AccelKey(keybindings_.config_
			.key_map()["compile"]),
	  [this]() {
	    SaveFile();
	    if (running.try_lock()) {
	      std::thread execute([=]() {
		  std::string path =  notebook_.CurrentPagePath();
		  int pos = path.find_last_of("/\\");
		  if(pos != std::string::npos){
		    path.erase(path.begin()+pos,path.end());
		    terminal_.SetFolderCommand(path);
		  }
		  terminal_.Compile();
		});
	      execute.detach();
	      running.unlock();
	    }
	  });
    this->signal_button_release_event().
      connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false);
  terminal_.Terminal().signal_button_release_event().
    connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false);

  add_accel_group(keybindings_.ui_manager_menu()->get_accel_group());
  add_accel_group(keybindings_.ui_manager_hidden()->get_accel_group());
  keybindings_.BuildMenu();

  window_box_.pack_start(menu_.view(), Gtk::PACK_SHRINK);

  window_box_.pack_start(notebook_.entry_view(), Gtk::PACK_SHRINK);
  paned_.set_position(300);
  paned_.pack1(notebook_.view(), true, false);
  paned_.pack2(terminal_.view(), true, true);
  window_box_.pack_end(paned_);
  show_all_children();
  INFO("Window created");
} // Window constructor

void Window::OnWindowHide() {
  hide();
}
void Window::OnFileOpenFolder() {
  Gtk::FileChooserDialog dialog("Please choose a folder",
                                Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
  dialog.set_transient_for(*this);
  //Add response buttons the the dialog:
  dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
  dialog.add_button("Select", Gtk::RESPONSE_OK);

  int result = dialog.run();

  //Handle the response:
  switch(result)
    {
    case(Gtk::RESPONSE_OK):
      {
        std::cout << "Folder selected: " << dialog.get_filename()
                  << std::endl;
        notebook_.directories().open_folder(dialog.get_filename());
        std::cout << dialog.get_filename()<< std::endl;
        break;
      }
    case(Gtk::RESPONSE_CANCEL):
      {
        std::cout << "Cancel clicked." << std::endl;
        break;
      }
    default:
      {
        std::cout << "Unexpected button clicked." << std::endl;
        break;
      }
    }
}

void Window::OnOpenFile() {
  Gtk::FileChooserDialog dialog("Please choose a file",
                                Gtk::FILE_CHOOSER_ACTION_OPEN);
  dialog.set_transient_for(*this);
  dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);

  //Add response buttons the the dialog:
  dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
  dialog.add_button("_Open", Gtk::RESPONSE_OK);

  //Add filters, so that only certain file types can be selected:
  Glib::RefPtr<Gtk::FileFilter> filter_text = Gtk::FileFilter::create();
  filter_text->set_name("Text files");
  filter_text->add_mime_type("text/plain");
  dialog.add_filter(filter_text);

  Glib::RefPtr<Gtk::FileFilter> filter_cpp = Gtk::FileFilter::create();
  filter_cpp->set_name("C/C++ files");
  filter_cpp->add_mime_type("text/x-c");
  filter_cpp->add_mime_type("text/x-c++");
  filter_cpp->add_mime_type("text/x-c-header");
  dialog.add_filter(filter_cpp);

  Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
  filter_any->set_name("Any files");
  filter_any->add_pattern("*");
  dialog.add_filter(filter_any);

  int result = dialog.run();

  switch (result) {
  case(Gtk::RESPONSE_OK): {
    std::cout << "Open clicked." << std::endl;
    std::string path = dialog.get_filename();

    std::cout << "File selected: " << path << std::endl;
    notebook_.OnOpenFile(path);
    break;
  }
  case(Gtk::RESPONSE_CANCEL): {
    std::cout << "Cancel clicked." << std::endl;
    break;
  }
  default: {
    std::cout << "Unexpected button clicked." << std::endl;
    break;
  }
  }
}
bool Window::OnMouseRelease(GdkEventButton *button){
  return notebook_.OnMouseRelease(button);
}

bool Window::SaveFile() {
  if(notebook_.OnSaveFile()) {
    terminal_.PrintMessage("File saved to: " +
			   notebook_.CurrentPagePath()+"\n");
    return true;
  }
  terminal_.PrintMessage("File not saved");
  return false;
}
bool Window::SaveFileAs() {
  if(notebook_.OnSaveFile(notebook_.OnSaveFileAs())){
    terminal_.PrintMessage("File saved to: " +
			   notebook_.CurrentPagePath()+"\n");
    return true;
  }
  terminal_.PrintMessage("File not saved");
  return false;
}
<commit_msg>move lock<commit_after>#include "window.h"
#include "logging.h"

Window::Window() :
  window_box_(Gtk::ORIENTATION_VERTICAL),
  main_config_(),
  keybindings_(main_config_.keybindings_cfg()),
  terminal_(main_config_.terminal_cfg()),
  notebook_(this,keybindings(),
            main_config_.source_cfg(),
            main_config_.dir_cfg()),
  menu_(keybindings()),
  api_(menu_, notebook_) {
  INFO("Create Window");
  set_title("juCi++");
  set_default_size(600, 400);
  add(window_box_);
  keybindings_.action_group_menu()->add(Gtk::Action::create("FileQuit",
                                                            "Quit juCi++"),
                                        Gtk::AccelKey(keybindings_.config_
                                                      .key_map()["quit"]),
                                        [this]() {
                                          OnWindowHide();
                                        });
  keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFile",
                                                            "Open file"),
                                        Gtk::AccelKey(keybindings_.config_
                                                      .key_map()["open_file"]),
                                        [this]() {
                                          OnOpenFile();
                                        });
  keybindings_.action_group_menu()->add(Gtk::Action::create("FileOpenFolder",
                                                            "Open folder"),
                                        Gtk::AccelKey(keybindings_.config_
                                                      .key_map()["open_folder"]),
                                        [this]() {
                                          OnFileOpenFolder();
                                        });
  keybindings_.
    action_group_menu()->
    add(Gtk::Action::create("FileSaveAs",
			    "Save as"),
	Gtk::AccelKey(keybindings_.config_
		      .key_map()["save_as"]),
	[this]() {
	  SaveFileAs();
	});

  keybindings_.
    action_group_menu()->
    add(Gtk::Action::create("FileSave",
			    "Save"),
	Gtk::AccelKey(keybindings_.config_
		      .key_map()["save"]),
	[this]() {
	  SaveFile();
	});

  keybindings_.
    action_group_menu()->
    add(Gtk::Action::create("ProjectCompileAndRun",
			    "Compile And Run"),
	Gtk::AccelKey(keybindings_.config_
		      .key_map()["compile_and_run"]),
	[this]() {
	  SaveFile();
	  if (running.try_lock()) {
	    std::thread execute([=]() {
		std::string path = notebook_.CurrentPagePath();
		int pos = path.find_last_of("/\\");
		if(pos != std::string::npos) {
		  path.erase(path.begin()+pos,path.end());
		  terminal_.SetFolderCommand(path);
		}
		terminal_.Compile();
		std::string executable = notebook_.directories().
		  GetCmakeVarValue(path,"add_executable");
		terminal_.Run(executable);
                running.unlock();
	      });
	    execute.detach();
	  }
	});

    keybindings_.
      action_group_menu()->
      add(Gtk::Action::create("ProjectCompile",
			      "Compile"),
	  Gtk::AccelKey(keybindings_.config_
			.key_map()["compile"]),
	  [this]() {
	    SaveFile();
	    if (running.try_lock()) {
	      std::thread execute([=]() {
		  std::string path =  notebook_.CurrentPagePath();
		  int pos = path.find_last_of("/\\");
		  if(pos != std::string::npos){
		    path.erase(path.begin()+pos,path.end());
		    terminal_.SetFolderCommand(path);
		  }
		  terminal_.Compile();
                  running.unlock();
		});
	      execute.detach();
	    }
	  });
    this->signal_button_release_event().
      connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false);
  terminal_.Terminal().signal_button_release_event().
    connect(sigc::mem_fun(*this,&Window::OnMouseRelease),false);

  add_accel_group(keybindings_.ui_manager_menu()->get_accel_group());
  add_accel_group(keybindings_.ui_manager_hidden()->get_accel_group());
  keybindings_.BuildMenu();

  window_box_.pack_start(menu_.view(), Gtk::PACK_SHRINK);

  window_box_.pack_start(notebook_.entry_view(), Gtk::PACK_SHRINK);
  paned_.set_position(300);
  paned_.pack1(notebook_.view(), true, false);
  paned_.pack2(terminal_.view(), true, true);
  window_box_.pack_end(paned_);
  show_all_children();
  INFO("Window created");
} // Window constructor

void Window::OnWindowHide() {
  hide();
}
void Window::OnFileOpenFolder() {
  Gtk::FileChooserDialog dialog("Please choose a folder",
                                Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
  dialog.set_transient_for(*this);
  //Add response buttons the the dialog:
  dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
  dialog.add_button("Select", Gtk::RESPONSE_OK);

  int result = dialog.run();

  //Handle the response:
  switch(result)
    {
    case(Gtk::RESPONSE_OK):
      {
        std::cout << "Folder selected: " << dialog.get_filename()
                  << std::endl;
        notebook_.directories().open_folder(dialog.get_filename());
        std::cout << dialog.get_filename()<< std::endl;
        break;
      }
    case(Gtk::RESPONSE_CANCEL):
      {
        std::cout << "Cancel clicked." << std::endl;
        break;
      }
    default:
      {
        std::cout << "Unexpected button clicked." << std::endl;
        break;
      }
    }
}

void Window::OnOpenFile() {
  Gtk::FileChooserDialog dialog("Please choose a file",
                                Gtk::FILE_CHOOSER_ACTION_OPEN);
  dialog.set_transient_for(*this);
  dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS);

  //Add response buttons the the dialog:
  dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
  dialog.add_button("_Open", Gtk::RESPONSE_OK);

  //Add filters, so that only certain file types can be selected:
  Glib::RefPtr<Gtk::FileFilter> filter_text = Gtk::FileFilter::create();
  filter_text->set_name("Text files");
  filter_text->add_mime_type("text/plain");
  dialog.add_filter(filter_text);

  Glib::RefPtr<Gtk::FileFilter> filter_cpp = Gtk::FileFilter::create();
  filter_cpp->set_name("C/C++ files");
  filter_cpp->add_mime_type("text/x-c");
  filter_cpp->add_mime_type("text/x-c++");
  filter_cpp->add_mime_type("text/x-c-header");
  dialog.add_filter(filter_cpp);

  Glib::RefPtr<Gtk::FileFilter> filter_any = Gtk::FileFilter::create();
  filter_any->set_name("Any files");
  filter_any->add_pattern("*");
  dialog.add_filter(filter_any);

  int result = dialog.run();

  switch (result) {
  case(Gtk::RESPONSE_OK): {
    std::cout << "Open clicked." << std::endl;
    std::string path = dialog.get_filename();

    std::cout << "File selected: " << path << std::endl;
    notebook_.OnOpenFile(path);
    break;
  }
  case(Gtk::RESPONSE_CANCEL): {
    std::cout << "Cancel clicked." << std::endl;
    break;
  }
  default: {
    std::cout << "Unexpected button clicked." << std::endl;
    break;
  }
  }
}
bool Window::OnMouseRelease(GdkEventButton *button){
  return notebook_.OnMouseRelease(button);
}

bool Window::SaveFile() {
  if(notebook_.OnSaveFile()) {
    terminal_.PrintMessage("File saved to: " +
			   notebook_.CurrentPagePath()+"\n");
    return true;
  }
  terminal_.PrintMessage("File not saved");
  return false;
}
bool Window::SaveFileAs() {
  if(notebook_.OnSaveFile(notebook_.OnSaveFileAs())){
    terminal_.PrintMessage("File saved to: " +
			   notebook_.CurrentPagePath()+"\n");
    return true;
  }
  terminal_.PrintMessage("File not saved");
  return false;
}
<|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 "net/base/host_resolver_proc.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include <ws2tcpip.h>
#include <wspiapi.h>  // Needed for Win2k compat.
#elif defined(OS_POSIX)
#include <netdb.h>
#include <sys/socket.h>
#endif
#if defined(OS_LINUX)
#include <resolv.h>
#endif

#include "base/logging.h"
#include "base/time.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"

#if defined(OS_LINUX)
#include "base/singleton.h"
#include "base/thread_local_storage.h"
#endif

namespace net {

HostResolverProc* HostResolverProc::default_proc_ = NULL;

HostResolverProc::HostResolverProc(HostResolverProc* previous) {
  set_previous_proc(previous);

  // Implicitly fall-back to the global default procedure.
  if (!previous)
    set_previous_proc(default_proc_);
}

// static
HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) {
  HostResolverProc* old = default_proc_;
  default_proc_ = proc;
  return old;
}

// static
HostResolverProc* HostResolverProc::GetDefault() {
  return default_proc_;
}

int HostResolverProc::ResolveUsingPrevious(const std::string& host,
                                           AddressFamily address_family,
                                           AddressList* addrlist) {
  if (previous_proc_)
    return previous_proc_->Resolve(host, address_family, addrlist);

  // Final fallback is the system resolver.
  return SystemHostResolverProc(host, address_family, addrlist);
}

#if defined(OS_LINUX)
// On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in
// DNS queries failing either because nameservers are unknown on startup
// or because nameserver info has changed as a result of e.g. connecting to
// a new network. Some distributions patch glibc to stat /etc/resolv.conf
// to try to automatically detect such changes but these patches are not
// universal and even patched systems such as Jaunty appear to need calls
// to res_ninit to reload the nameserver information in different threads.
//
// We adopt the Mozilla solution here which is to call res_ninit when
// lookups fail and to rate limit the reloading to once per second per
// thread.

// Keep a timer per calling thread to rate limit the calling of res_ninit.
class DnsReloadTimer {
 public:
  // Check if the timer for the calling thread has expired. When no
  // timer exists for the calling thread, create one.
  bool Expired() {
    const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
    base::TimeTicks now = base::TimeTicks::Now();
    base::TimeTicks* timer_ptr =
      static_cast<base::TimeTicks*>(tls_index_.Get());

    if (!timer_ptr) {
      timer_ptr = new base::TimeTicks();
      *timer_ptr = base::TimeTicks::Now();
      tls_index_.Set(timer_ptr);
      // Return true to reload dns info on the first call for each thread.
      return true;
    } else if (now - *timer_ptr > kRetryTime) {
      *timer_ptr = now;
      return true;
    } else {
      return false;
    }
  }

  // Free the allocated timer.
  static void SlotReturnFunction(void* data) {
    base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
    delete tls_data;
  }

 private:
  friend struct DefaultSingletonTraits<DnsReloadTimer>;

  DnsReloadTimer() {
    tls_index_.Initialize(SlotReturnFunction);
  }

  ~DnsReloadTimer() {
    tls_index_.Free();
  }

  // We use thread local storage to identify which base::TimeTicks to
  // interact with.
  static ThreadLocalStorage::Slot tls_index_ ;

  DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
};

// A TLS slot to the TimeTicks for the current thread.
// static
ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);

#endif  // defined(OS_LINUX)

int SystemHostResolverProc(const std::string& host,
                           AddressFamily address_family,
                           AddressList* addrlist) {
  // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
  // On Windows it gives the default interface's address, whereas on Linux it
  // gives an error. We will make it fail on all platforms for consistency.
  if (host.empty())
    return ERR_NAME_NOT_RESOLVED;

  struct addrinfo* ai = NULL;
  struct addrinfo hints = {0};

  switch (address_family) {
    case ADDRESS_FAMILY_IPV4:
      hints.ai_family = AF_INET;
      break;
    case ADDRESS_FAMILY_IPV6:
      hints.ai_family = AF_INET6;
      break;
    case ADDRESS_FAMILY_UNSPECIFIED:
      hints.ai_family = AF_UNSPEC;
      break;
    default:
      NOTREACHED();
      hints.ai_family = AF_UNSPEC;
  }

#if defined(OS_WIN)
  // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
  //
  // The following comment in <winsock2.h> is the best documentation I found
  // on AI_ADDRCONFIG for Windows:
  //   Flags used in "hints" argument to getaddrinfo()
  //       - AI_ADDRCONFIG is supported starting with Vista
  //       - default is AI_ADDRCONFIG ON whether the flag is set or not
  //         because the performance penalty in not having ADDRCONFIG in
  //         the multi-protocol stack environment is severe;
  //         this defaulting may be disabled by specifying the AI_ALL flag,
  //         in that case AI_ADDRCONFIG must be EXPLICITLY specified to
  //         enable ADDRCONFIG behavior
  //
  // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful.  If the
  // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
  // to fail with WSANO_DATA (11004) for "localhost", probably because of the
  // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
  //   The IPv4 or IPv6 loopback address is not considered a valid global
  //   address.
  // See http://crbug.com/5234.
  hints.ai_flags = 0;
#else
  hints.ai_flags = AI_ADDRCONFIG;
#endif

  // Restrict result set to only this socket type to avoid duplicates.
  hints.ai_socktype = SOCK_STREAM;

  int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
#if defined(OS_LINUX)
  net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get();
  // If we fail, re-initialise the resolver just in case there have been any
  // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
  if (err && dns_timer->Expired()) {
    res_nclose(&_res);
    if (!res_ninit(&_res))
      err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
  }
#endif

  if (err)
    return ERR_NAME_NOT_RESOLVED;

  addrlist->Adopt(ai);
  return OK;
}

}  // namespace net
<commit_msg>Fix a memory leak in DnsReloadTimer<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 "net/base/host_resolver_proc.h"

#include "build/build_config.h"

#if defined(OS_WIN)
#include <ws2tcpip.h>
#include <wspiapi.h>  // Needed for Win2k compat.
#elif defined(OS_POSIX)
#include <netdb.h>
#include <sys/socket.h>
#endif
#if defined(OS_LINUX)
#include <resolv.h>
#endif

#include "base/logging.h"
#include "base/time.h"
#include "net/base/address_list.h"
#include "net/base/net_errors.h"

#if defined(OS_LINUX)
#include "base/singleton.h"
#include "base/thread_local_storage.h"
#endif

namespace net {

HostResolverProc* HostResolverProc::default_proc_ = NULL;

HostResolverProc::HostResolverProc(HostResolverProc* previous) {
  set_previous_proc(previous);

  // Implicitly fall-back to the global default procedure.
  if (!previous)
    set_previous_proc(default_proc_);
}

// static
HostResolverProc* HostResolverProc::SetDefault(HostResolverProc* proc) {
  HostResolverProc* old = default_proc_;
  default_proc_ = proc;
  return old;
}

// static
HostResolverProc* HostResolverProc::GetDefault() {
  return default_proc_;
}

int HostResolverProc::ResolveUsingPrevious(const std::string& host,
                                           AddressFamily address_family,
                                           AddressList* addrlist) {
  if (previous_proc_)
    return previous_proc_->Resolve(host, address_family, addrlist);

  // Final fallback is the system resolver.
  return SystemHostResolverProc(host, address_family, addrlist);
}

#if defined(OS_LINUX)
// On Linux changes to /etc/resolv.conf can go unnoticed thus resulting in
// DNS queries failing either because nameservers are unknown on startup
// or because nameserver info has changed as a result of e.g. connecting to
// a new network. Some distributions patch glibc to stat /etc/resolv.conf
// to try to automatically detect such changes but these patches are not
// universal and even patched systems such as Jaunty appear to need calls
// to res_ninit to reload the nameserver information in different threads.
//
// We adopt the Mozilla solution here which is to call res_ninit when
// lookups fail and to rate limit the reloading to once per second per
// thread.

// Keep a timer per calling thread to rate limit the calling of res_ninit.
class DnsReloadTimer {
 public:
  // Check if the timer for the calling thread has expired. When no
  // timer exists for the calling thread, create one.
  bool Expired() {
    const base::TimeDelta kRetryTime = base::TimeDelta::FromSeconds(1);
    base::TimeTicks now = base::TimeTicks::Now();
    base::TimeTicks* timer_ptr =
      static_cast<base::TimeTicks*>(tls_index_.Get());

    if (!timer_ptr) {
      timer_ptr = new base::TimeTicks();
      *timer_ptr = base::TimeTicks::Now();
      tls_index_.Set(timer_ptr);
      // Return true to reload dns info on the first call for each thread.
      return true;
    } else if (now - *timer_ptr > kRetryTime) {
      *timer_ptr = now;
      return true;
    } else {
      return false;
    }
  }

  // Free the allocated timer.
  static void SlotReturnFunction(void* data) {
    base::TimeTicks* tls_data = static_cast<base::TimeTicks*>(data);
    delete tls_data;
  }

 private:
  friend struct DefaultSingletonTraits<DnsReloadTimer>;

  DnsReloadTimer() {
    tls_index_.Initialize(SlotReturnFunction);
  }

  ~DnsReloadTimer() {
    SlotReturnFunction(tls_index_.Get());
    tls_index_.Free();
  }

  // We use thread local storage to identify which base::TimeTicks to
  // interact with.
  static ThreadLocalStorage::Slot tls_index_ ;

  DISALLOW_COPY_AND_ASSIGN(DnsReloadTimer);
};

// A TLS slot to the TimeTicks for the current thread.
// static
ThreadLocalStorage::Slot DnsReloadTimer::tls_index_(base::LINKER_INITIALIZED);

#endif  // defined(OS_LINUX)

int SystemHostResolverProc(const std::string& host,
                           AddressFamily address_family,
                           AddressList* addrlist) {
  // The result of |getaddrinfo| for empty hosts is inconsistent across systems.
  // On Windows it gives the default interface's address, whereas on Linux it
  // gives an error. We will make it fail on all platforms for consistency.
  if (host.empty())
    return ERR_NAME_NOT_RESOLVED;

  struct addrinfo* ai = NULL;
  struct addrinfo hints = {0};

  switch (address_family) {
    case ADDRESS_FAMILY_IPV4:
      hints.ai_family = AF_INET;
      break;
    case ADDRESS_FAMILY_IPV6:
      hints.ai_family = AF_INET6;
      break;
    case ADDRESS_FAMILY_UNSPECIFIED:
      hints.ai_family = AF_UNSPEC;
      break;
    default:
      NOTREACHED();
      hints.ai_family = AF_UNSPEC;
  }

#if defined(OS_WIN)
  // DO NOT USE AI_ADDRCONFIG ON WINDOWS.
  //
  // The following comment in <winsock2.h> is the best documentation I found
  // on AI_ADDRCONFIG for Windows:
  //   Flags used in "hints" argument to getaddrinfo()
  //       - AI_ADDRCONFIG is supported starting with Vista
  //       - default is AI_ADDRCONFIG ON whether the flag is set or not
  //         because the performance penalty in not having ADDRCONFIG in
  //         the multi-protocol stack environment is severe;
  //         this defaulting may be disabled by specifying the AI_ALL flag,
  //         in that case AI_ADDRCONFIG must be EXPLICITLY specified to
  //         enable ADDRCONFIG behavior
  //
  // Not only is AI_ADDRCONFIG unnecessary, but it can be harmful.  If the
  // computer is not connected to a network, AI_ADDRCONFIG causes getaddrinfo
  // to fail with WSANO_DATA (11004) for "localhost", probably because of the
  // following note on AI_ADDRCONFIG in the MSDN getaddrinfo page:
  //   The IPv4 or IPv6 loopback address is not considered a valid global
  //   address.
  // See http://crbug.com/5234.
  hints.ai_flags = 0;
#else
  hints.ai_flags = AI_ADDRCONFIG;
#endif

  // Restrict result set to only this socket type to avoid duplicates.
  hints.ai_socktype = SOCK_STREAM;

  int err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
#if defined(OS_LINUX)
  net::DnsReloadTimer* dns_timer = Singleton<net::DnsReloadTimer>::get();
  // If we fail, re-initialise the resolver just in case there have been any
  // changes to /etc/resolv.conf and retry. See http://crbug.com/11380 for info.
  if (err && dns_timer->Expired()) {
    res_nclose(&_res);
    if (!res_ninit(&_res))
      err = getaddrinfo(host.c_str(), NULL, &hints, &ai);
  }
#endif

  if (err)
    return ERR_NAME_NOT_RESOLVED;

  addrlist->Adopt(ai);
  return OK;
}

}  // namespace net
<|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 "base/basictypes.h"
#include "base/strings/string_split.h"
#include "base/utf_string_conversions.h"
#include "net/base/mime_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

TEST(MimeUtilTest, ExtensionTest) {
  const struct {
    const base::FilePath::CharType* extension;
    const char* mime_type;
    bool valid;
  } tests[] = {
    { FILE_PATH_LITERAL("png"), "image/png", true },
    { FILE_PATH_LITERAL("css"), "text/css", true },
    { FILE_PATH_LITERAL("pjp"), "image/jpeg", true },
    { FILE_PATH_LITERAL("pjpeg"), "image/jpeg", true },
    { FILE_PATH_LITERAL("not an extension / for sure"), "", false },
  };

  std::string mime_type;
  bool rv;

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    rv = GetMimeTypeFromExtension(tests[i].extension, &mime_type);
    EXPECT_EQ(tests[i].valid, rv);
    if (rv)
      EXPECT_EQ(tests[i].mime_type, mime_type);
  }
}

TEST(MimeUtilTest, FileTest) {
  const struct {
    const base::FilePath::CharType* file_path;
    const char* mime_type;
    bool valid;
  } tests[] = {
    { FILE_PATH_LITERAL("c:\\foo\\bar.css"), "text/css", true },
    { FILE_PATH_LITERAL("c:\\blah"), "", false },
    { FILE_PATH_LITERAL("/usr/local/bin/mplayer"), "", false },
    { FILE_PATH_LITERAL("/home/foo/bar.css"), "text/css", true },
    { FILE_PATH_LITERAL("/blah."), "", false },
    { FILE_PATH_LITERAL("c:\\blah."), "", false },
  };

  std::string mime_type;
  bool rv;

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    rv = GetMimeTypeFromFile(base::FilePath(tests[i].file_path),
                                  &mime_type);
    EXPECT_EQ(tests[i].valid, rv);
    if (rv)
      EXPECT_EQ(tests[i].mime_type, mime_type);
  }
}

TEST(MimeUtilTest, LookupTypes) {
  EXPECT_FALSE(IsUnsupportedTextMimeType("text/banana"));
  EXPECT_TRUE(IsUnsupportedTextMimeType("text/vcard"));

  EXPECT_TRUE(IsSupportedImageMimeType("image/jpeg"));
  EXPECT_FALSE(IsSupportedImageMimeType("image/lolcat"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("text/html"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("text/banana"));
  EXPECT_FALSE(IsSupportedNonImageMimeType("text/vcard"));
  EXPECT_FALSE(IsSupportedNonImageMimeType("application/virus"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-x509-user-cert"));
#if defined(OS_ANDROID)
  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-x509-ca-cert"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-pkcs12"));
#endif

  EXPECT_TRUE(IsSupportedMimeType("image/jpeg"));
  EXPECT_FALSE(IsSupportedMimeType("image/lolcat"));
  EXPECT_TRUE(IsSupportedMimeType("text/html"));
  EXPECT_TRUE(IsSupportedMimeType("text/banana"));
  EXPECT_FALSE(IsSupportedMimeType("text/vcard"));
  EXPECT_FALSE(IsSupportedMimeType("application/virus"));
}

TEST(MimeUtilTest, MatchesMimeType) {
  EXPECT_TRUE(MatchesMimeType("*", "video/x-mpeg"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/x-mpeg"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/*"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg", "video/x-mpeg"));
  EXPECT_TRUE(MatchesMimeType("application/*+xml",
                                   "application/html+xml"));
  EXPECT_TRUE(MatchesMimeType("application/*+xml", "application/+xml"));
  EXPECT_TRUE(MatchesMimeType("aaa*aaa", "aaaaaa"));
  EXPECT_TRUE(MatchesMimeType("*", std::string()));
  EXPECT_FALSE(MatchesMimeType("video/", "video/x-mpeg"));
  EXPECT_FALSE(MatchesMimeType(std::string(), "video/x-mpeg"));
  EXPECT_FALSE(MatchesMimeType(std::string(), std::string()));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg", std::string()));
  EXPECT_FALSE(MatchesMimeType("application/*+xml", "application/xml"));
  EXPECT_FALSE(MatchesMimeType("application/*+xml",
                                    "application/html+xmlz"));
  EXPECT_FALSE(MatchesMimeType("application/*+xml",
                                    "applcation/html+xml"));
  EXPECT_FALSE(MatchesMimeType("aaa*aaa", "aaaaa"));

  EXPECT_TRUE(MatchesMimeType("*", "video/x-mpeg;param=val"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/mpeg"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/mpeg;param=other"));
  EXPECT_TRUE(MatchesMimeType("video/*;param=val", "video/mpeg;param=val"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg", "video/x-mpeg;param=val"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val",
                              "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param2=val2",
                               "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param2=val2",
                               "video/x-mpeg;param2=val"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val",
                              "video/x-mpeg;param=val;param2=val2"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val;param2=val2",
                              "video/x-mpeg;param=val;param2=val2"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param2=val2;param=val",
                              "video/x-mpeg;param=val;param2=val2"));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param3=val3;param=val",
                               "video/x-mpeg;param=val;param2=val2"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val ;param2=val2 ",
                              "video/x-mpeg;param=val;param2=val2"));

  EXPECT_TRUE(MatchesMimeType("*/*;param=val", "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("*/*;param=val", "video/x-mpeg;param=val2"));

  EXPECT_TRUE(MatchesMimeType("*", "*"));
  EXPECT_TRUE(MatchesMimeType("*", "*/*"));
  EXPECT_TRUE(MatchesMimeType("*/*", "*/*"));
  EXPECT_TRUE(MatchesMimeType("*/*", "*"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/*"));
  EXPECT_FALSE(MatchesMimeType("video/*", "*/*"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/*"));
  EXPECT_TRUE(MatchesMimeType("video/*;param=val", "video/*;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/*;param=val2"));

  EXPECT_TRUE(MatchesMimeType("ab*cd", "abxxxcd"));
  EXPECT_TRUE(MatchesMimeType("ab*cd", "abx/xcd"));
  EXPECT_TRUE(MatchesMimeType("ab/*cd", "ab/xxxcd"));
}

// Note: codecs should only be a list of 2 or fewer; hence the restriction of
// results' length to 2.
TEST(MimeUtilTest, ParseCodecString) {
  const struct {
    const char* original;
    size_t expected_size;
    const char* results[2];
  } tests[] = {
    { "\"bogus\"",                  1, { "bogus" }            },
    { "0",                          1, { "0" }                },
    { "avc1.42E01E, mp4a.40.2",     2, { "avc1",   "mp4a" }   },
    { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v",   "mp4a" }   },
    { "mp4v.20.8, samr",            2, { "mp4v",   "samr" }   },
    { "\"theora, vorbis\"",         2, { "theora", "vorbis" } },
    { "",                           0, { }                    },
    { "\"\"",                       0, { }                    },
    { "\"   \"",                    0, { }                    },
    { ",",                          2, { "", "" }             },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    std::vector<std::string> codecs_out;
    ParseCodecString(tests[i].original, &codecs_out, true);
    ASSERT_EQ(tests[i].expected_size, codecs_out.size());
    for (size_t j = 0; j < tests[i].expected_size; ++j)
      EXPECT_EQ(tests[i].results[j], codecs_out[j]);
  }

  // Test without stripping the codec type.
  std::vector<std::string> codecs_out;
  ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false);
  ASSERT_EQ(2u, codecs_out.size());
  EXPECT_EQ("avc1.42E01E", codecs_out[0]);
  EXPECT_EQ("mp4a.40.2", codecs_out[1]);
}

TEST(MimeUtilTest, TestIsMimeType) {
  std::string nonAscii("application/nonutf8");
  EXPECT_TRUE(IsMimeType(nonAscii));
#if defined(OS_WIN)
  nonAscii.append(WideToUTF8(std::wstring(L"\u2603")));
#else
  nonAscii.append("\u2603");  // unicode snowman
#endif
  EXPECT_FALSE(IsMimeType(nonAscii));

  EXPECT_TRUE(IsMimeType("application/mime"));
  EXPECT_TRUE(IsMimeType("audio/mime"));
  EXPECT_TRUE(IsMimeType("example/mime"));
  EXPECT_TRUE(IsMimeType("image/mime"));
  EXPECT_TRUE(IsMimeType("message/mime"));
  EXPECT_TRUE(IsMimeType("model/mime"));
  EXPECT_TRUE(IsMimeType("multipart/mime"));
  EXPECT_TRUE(IsMimeType("text/mime"));
  EXPECT_TRUE(IsMimeType("TEXT/mime"));
  EXPECT_TRUE(IsMimeType("Text/mime"));
  EXPECT_TRUE(IsMimeType("TeXt/mime"));
  EXPECT_TRUE(IsMimeType("video/mime"));
  EXPECT_TRUE(IsMimeType("video/mime;parameter"));
  EXPECT_TRUE(IsMimeType("*/*"));
  EXPECT_TRUE(IsMimeType("*"));

  EXPECT_TRUE(IsMimeType("x-video/mime"));
  EXPECT_TRUE(IsMimeType("X-Video/mime"));
  EXPECT_FALSE(IsMimeType("x-video/"));
  EXPECT_FALSE(IsMimeType("x-/mime"));
  EXPECT_FALSE(IsMimeType("mime/looking"));
  EXPECT_FALSE(IsMimeType("text/"));
}

TEST(MimeUtilTest, TestToIANAMediaType) {
  EXPECT_EQ("", GetIANAMediaType("texting/driving"));
  EXPECT_EQ("", GetIANAMediaType("ham/sandwich"));
  EXPECT_EQ("", GetIANAMediaType(std::string()));
  EXPECT_EQ("", GetIANAMediaType("/application/hamsandwich"));

  EXPECT_EQ("application", GetIANAMediaType("application/poodle-wrestler"));
  EXPECT_EQ("audio", GetIANAMediaType("audio/mpeg"));
  EXPECT_EQ("example", GetIANAMediaType("example/yomomma"));
  EXPECT_EQ("image", GetIANAMediaType("image/png"));
  EXPECT_EQ("message", GetIANAMediaType("message/sipfrag"));
  EXPECT_EQ("model", GetIANAMediaType("model/vrml"));
  EXPECT_EQ("multipart", GetIANAMediaType("multipart/mixed"));
  EXPECT_EQ("text", GetIANAMediaType("text/plain"));
  EXPECT_EQ("video", GetIANAMediaType("video/H261"));
}

TEST(MimeUtilTest, TestGetExtensionsForMimeType) {
  const struct {
    const char* mime_type;
    size_t min_expected_size;
    const char* contained_result;
  } tests[] = {
    { "text/plain", 2, "txt" },
    { "*",          0, NULL  },
    { "message/*",  1, "eml" },
    { "MeSsAge/*",  1, "eml" },
    { "image/bmp",  1, "bmp" },
    { "video/*",    6, "mp4" },
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_IOS)
    { "video/*",    6, "mpg" },
#else
    { "video/*",    6, "mpeg" },
#endif
    { "audio/*",    6, "oga" },
    { "aUDIo/*",    6, "wav" },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    std::vector<base::FilePath::StringType> extensions;
    GetExtensionsForMimeType(tests[i].mime_type, &extensions);
    ASSERT_TRUE(tests[i].min_expected_size <= extensions.size());

    if (!tests[i].contained_result)
      continue;

    bool found = false;
    for (size_t j = 0; !found && j < extensions.size(); ++j) {
#if defined(OS_WIN)
      if (extensions[j] == UTF8ToWide(tests[i].contained_result))
        found = true;
#else
      if (extensions[j] == tests[i].contained_result)
        found = true;
#endif
    }
    ASSERT_TRUE(found) << "Must find at least the contained result within "
                       << tests[i].mime_type;
  }
}

TEST(MimeUtilTest, TestGetCertificateMimeTypeForMimeType) {
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_X509_USER_CERT,
            GetCertificateMimeTypeForMimeType("application/x-x509-user-cert"));
#if defined(OS_ANDROID)
  // Only Android supports CA Certs and PKCS12 archives.
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_X509_CA_CERT,
            GetCertificateMimeTypeForMimeType("application/x-x509-ca-cert"));
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE,
            GetCertificateMimeTypeForMimeType("application/x-pkcs12"));
#else
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN,
            GetCertificateMimeTypeForMimeType("application/x-x509-ca-cert"));
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN,
            GetCertificateMimeTypeForMimeType("application/x-pkcs12"));
#endif
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN,
            GetCertificateMimeTypeForMimeType("text/plain"));
}

}  // namespace net
<commit_msg>Adding unit test for two new functions in mime_util.h/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 "base/basictypes.h"
#include "base/strings/string_split.h"
#include "base/utf_string_conversions.h"
#include "net/base/mime_util.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace net {

TEST(MimeUtilTest, ExtensionTest) {
  const struct {
    const base::FilePath::CharType* extension;
    const char* mime_type;
    bool valid;
  } tests[] = {
    { FILE_PATH_LITERAL("png"), "image/png", true },
    { FILE_PATH_LITERAL("css"), "text/css", true },
    { FILE_PATH_LITERAL("pjp"), "image/jpeg", true },
    { FILE_PATH_LITERAL("pjpeg"), "image/jpeg", true },
    { FILE_PATH_LITERAL("not an extension / for sure"), "", false },
  };

  std::string mime_type;
  bool rv;

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    rv = GetMimeTypeFromExtension(tests[i].extension, &mime_type);
    EXPECT_EQ(tests[i].valid, rv);
    if (rv)
      EXPECT_EQ(tests[i].mime_type, mime_type);
  }
}

TEST(MimeUtilTest, FileTest) {
  const struct {
    const base::FilePath::CharType* file_path;
    const char* mime_type;
    bool valid;
  } tests[] = {
    { FILE_PATH_LITERAL("c:\\foo\\bar.css"), "text/css", true },
    { FILE_PATH_LITERAL("c:\\blah"), "", false },
    { FILE_PATH_LITERAL("/usr/local/bin/mplayer"), "", false },
    { FILE_PATH_LITERAL("/home/foo/bar.css"), "text/css", true },
    { FILE_PATH_LITERAL("/blah."), "", false },
    { FILE_PATH_LITERAL("c:\\blah."), "", false },
  };

  std::string mime_type;
  bool rv;

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    rv = GetMimeTypeFromFile(base::FilePath(tests[i].file_path),
                                  &mime_type);
    EXPECT_EQ(tests[i].valid, rv);
    if (rv)
      EXPECT_EQ(tests[i].mime_type, mime_type);
  }
}

TEST(MimeUtilTest, LookupTypes) {
  EXPECT_FALSE(IsUnsupportedTextMimeType("text/banana"));
  EXPECT_TRUE(IsUnsupportedTextMimeType("text/vcard"));

  EXPECT_TRUE(IsSupportedImageMimeType("image/jpeg"));
  EXPECT_FALSE(IsSupportedImageMimeType("image/lolcat"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("text/html"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("text/banana"));
  EXPECT_FALSE(IsSupportedNonImageMimeType("text/vcard"));
  EXPECT_FALSE(IsSupportedNonImageMimeType("application/virus"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-x509-user-cert"));
#if defined(OS_ANDROID)
  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-x509-ca-cert"));
  EXPECT_TRUE(IsSupportedNonImageMimeType("application/x-pkcs12"));
#endif

  EXPECT_TRUE(IsSupportedMimeType("image/jpeg"));
  EXPECT_FALSE(IsSupportedMimeType("image/lolcat"));
  EXPECT_TRUE(IsSupportedMimeType("text/html"));
  EXPECT_TRUE(IsSupportedMimeType("text/banana"));
  EXPECT_FALSE(IsSupportedMimeType("text/vcard"));
  EXPECT_FALSE(IsSupportedMimeType("application/virus"));
}

TEST(MimeUtilTest, MatchesMimeType) {
  EXPECT_TRUE(MatchesMimeType("*", "video/x-mpeg"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/x-mpeg"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/*"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg", "video/x-mpeg"));
  EXPECT_TRUE(MatchesMimeType("application/*+xml",
                                   "application/html+xml"));
  EXPECT_TRUE(MatchesMimeType("application/*+xml", "application/+xml"));
  EXPECT_TRUE(MatchesMimeType("aaa*aaa", "aaaaaa"));
  EXPECT_TRUE(MatchesMimeType("*", std::string()));
  EXPECT_FALSE(MatchesMimeType("video/", "video/x-mpeg"));
  EXPECT_FALSE(MatchesMimeType(std::string(), "video/x-mpeg"));
  EXPECT_FALSE(MatchesMimeType(std::string(), std::string()));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg", std::string()));
  EXPECT_FALSE(MatchesMimeType("application/*+xml", "application/xml"));
  EXPECT_FALSE(MatchesMimeType("application/*+xml",
                                    "application/html+xmlz"));
  EXPECT_FALSE(MatchesMimeType("application/*+xml",
                                    "applcation/html+xml"));
  EXPECT_FALSE(MatchesMimeType("aaa*aaa", "aaaaa"));

  EXPECT_TRUE(MatchesMimeType("*", "video/x-mpeg;param=val"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/mpeg"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/mpeg;param=other"));
  EXPECT_TRUE(MatchesMimeType("video/*;param=val", "video/mpeg;param=val"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg", "video/x-mpeg;param=val"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val",
                              "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param2=val2",
                               "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param2=val2",
                               "video/x-mpeg;param2=val"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val",
                              "video/x-mpeg;param=val;param2=val2"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val;param2=val2",
                              "video/x-mpeg;param=val;param2=val2"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param2=val2;param=val",
                              "video/x-mpeg;param=val;param2=val2"));
  EXPECT_FALSE(MatchesMimeType("video/x-mpeg;param3=val3;param=val",
                               "video/x-mpeg;param=val;param2=val2"));
  EXPECT_TRUE(MatchesMimeType("video/x-mpeg;param=val ;param2=val2 ",
                              "video/x-mpeg;param=val;param2=val2"));

  EXPECT_TRUE(MatchesMimeType("*/*;param=val", "video/x-mpeg;param=val"));
  EXPECT_FALSE(MatchesMimeType("*/*;param=val", "video/x-mpeg;param=val2"));

  EXPECT_TRUE(MatchesMimeType("*", "*"));
  EXPECT_TRUE(MatchesMimeType("*", "*/*"));
  EXPECT_TRUE(MatchesMimeType("*/*", "*/*"));
  EXPECT_TRUE(MatchesMimeType("*/*", "*"));
  EXPECT_TRUE(MatchesMimeType("video/*", "video/*"));
  EXPECT_FALSE(MatchesMimeType("video/*", "*/*"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/*"));
  EXPECT_TRUE(MatchesMimeType("video/*;param=val", "video/*;param=val"));
  EXPECT_FALSE(MatchesMimeType("video/*;param=val", "video/*;param=val2"));

  EXPECT_TRUE(MatchesMimeType("ab*cd", "abxxxcd"));
  EXPECT_TRUE(MatchesMimeType("ab*cd", "abx/xcd"));
  EXPECT_TRUE(MatchesMimeType("ab/*cd", "ab/xxxcd"));
}

// Note: codecs should only be a list of 2 or fewer; hence the restriction of
// results' length to 2.
TEST(MimeUtilTest, ParseCodecString) {
  const struct {
    const char* original;
    size_t expected_size;
    const char* results[2];
  } tests[] = {
    { "\"bogus\"",                  1, { "bogus" }            },
    { "0",                          1, { "0" }                },
    { "avc1.42E01E, mp4a.40.2",     2, { "avc1",   "mp4a" }   },
    { "\"mp4v.20.240, mp4a.40.2\"", 2, { "mp4v",   "mp4a" }   },
    { "mp4v.20.8, samr",            2, { "mp4v",   "samr" }   },
    { "\"theora, vorbis\"",         2, { "theora", "vorbis" } },
    { "",                           0, { }                    },
    { "\"\"",                       0, { }                    },
    { "\"   \"",                    0, { }                    },
    { ",",                          2, { "", "" }             },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    std::vector<std::string> codecs_out;
    ParseCodecString(tests[i].original, &codecs_out, true);
    ASSERT_EQ(tests[i].expected_size, codecs_out.size());
    for (size_t j = 0; j < tests[i].expected_size; ++j)
      EXPECT_EQ(tests[i].results[j], codecs_out[j]);
  }

  // Test without stripping the codec type.
  std::vector<std::string> codecs_out;
  ParseCodecString("avc1.42E01E, mp4a.40.2", &codecs_out, false);
  ASSERT_EQ(2u, codecs_out.size());
  EXPECT_EQ("avc1.42E01E", codecs_out[0]);
  EXPECT_EQ("mp4a.40.2", codecs_out[1]);
}

TEST(MimeUtilTest, TestIsMimeType) {
  std::string nonAscii("application/nonutf8");
  EXPECT_TRUE(IsMimeType(nonAscii));
#if defined(OS_WIN)
  nonAscii.append(WideToUTF8(std::wstring(L"\u2603")));
#else
  nonAscii.append("\u2603");  // unicode snowman
#endif
  EXPECT_FALSE(IsMimeType(nonAscii));

  EXPECT_TRUE(IsMimeType("application/mime"));
  EXPECT_TRUE(IsMimeType("audio/mime"));
  EXPECT_TRUE(IsMimeType("example/mime"));
  EXPECT_TRUE(IsMimeType("image/mime"));
  EXPECT_TRUE(IsMimeType("message/mime"));
  EXPECT_TRUE(IsMimeType("model/mime"));
  EXPECT_TRUE(IsMimeType("multipart/mime"));
  EXPECT_TRUE(IsMimeType("text/mime"));
  EXPECT_TRUE(IsMimeType("TEXT/mime"));
  EXPECT_TRUE(IsMimeType("Text/mime"));
  EXPECT_TRUE(IsMimeType("TeXt/mime"));
  EXPECT_TRUE(IsMimeType("video/mime"));
  EXPECT_TRUE(IsMimeType("video/mime;parameter"));
  EXPECT_TRUE(IsMimeType("*/*"));
  EXPECT_TRUE(IsMimeType("*"));

  EXPECT_TRUE(IsMimeType("x-video/mime"));
  EXPECT_TRUE(IsMimeType("X-Video/mime"));
  EXPECT_FALSE(IsMimeType("x-video/"));
  EXPECT_FALSE(IsMimeType("x-/mime"));
  EXPECT_FALSE(IsMimeType("mime/looking"));
  EXPECT_FALSE(IsMimeType("text/"));
}

TEST(MimeUtilTest, TestToIANAMediaType) {
  EXPECT_EQ("", GetIANAMediaType("texting/driving"));
  EXPECT_EQ("", GetIANAMediaType("ham/sandwich"));
  EXPECT_EQ("", GetIANAMediaType(std::string()));
  EXPECT_EQ("", GetIANAMediaType("/application/hamsandwich"));

  EXPECT_EQ("application", GetIANAMediaType("application/poodle-wrestler"));
  EXPECT_EQ("audio", GetIANAMediaType("audio/mpeg"));
  EXPECT_EQ("example", GetIANAMediaType("example/yomomma"));
  EXPECT_EQ("image", GetIANAMediaType("image/png"));
  EXPECT_EQ("message", GetIANAMediaType("message/sipfrag"));
  EXPECT_EQ("model", GetIANAMediaType("model/vrml"));
  EXPECT_EQ("multipart", GetIANAMediaType("multipart/mixed"));
  EXPECT_EQ("text", GetIANAMediaType("text/plain"));
  EXPECT_EQ("video", GetIANAMediaType("video/H261"));
}

TEST(MimeUtilTest, TestGetExtensionsForMimeType) {
  const struct {
    const char* mime_type;
    size_t min_expected_size;
    const char* contained_result;
  } tests[] = {
    { "text/plain", 2, "txt" },
    { "*",          0, NULL  },
    { "message/*",  1, "eml" },
    { "MeSsAge/*",  1, "eml" },
    { "image/bmp",  1, "bmp" },
    { "video/*",    6, "mp4" },
#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_IOS)
    { "video/*",    6, "mpg" },
#else
    { "video/*",    6, "mpeg" },
#endif
    { "audio/*",    6, "oga" },
    { "aUDIo/*",    6, "wav" },
  };

  for (size_t i = 0; i < ARRAYSIZE_UNSAFE(tests); ++i) {
    std::vector<base::FilePath::StringType> extensions;
    GetExtensionsForMimeType(tests[i].mime_type, &extensions);
    ASSERT_TRUE(tests[i].min_expected_size <= extensions.size());

    if (!tests[i].contained_result)
      continue;

    bool found = false;
    for (size_t j = 0; !found && j < extensions.size(); ++j) {
#if defined(OS_WIN)
      if (extensions[j] == UTF8ToWide(tests[i].contained_result))
        found = true;
#else
      if (extensions[j] == tests[i].contained_result)
        found = true;
#endif
    }
    ASSERT_TRUE(found) << "Must find at least the contained result within "
                       << tests[i].mime_type;
  }
}

TEST(MimeUtilTest, TestGetCertificateMimeTypeForMimeType) {
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_X509_USER_CERT,
            GetCertificateMimeTypeForMimeType("application/x-x509-user-cert"));
#if defined(OS_ANDROID)
  // Only Android supports CA Certs and PKCS12 archives.
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_X509_CA_CERT,
            GetCertificateMimeTypeForMimeType("application/x-x509-ca-cert"));
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_PKCS12_ARCHIVE,
            GetCertificateMimeTypeForMimeType("application/x-pkcs12"));
#else
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN,
            GetCertificateMimeTypeForMimeType("application/x-x509-ca-cert"));
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN,
            GetCertificateMimeTypeForMimeType("application/x-pkcs12"));
#endif
  EXPECT_EQ(CERTIFICATE_MIME_TYPE_UNKNOWN,
            GetCertificateMimeTypeForMimeType("text/plain"));
}

TEST(MimeUtilTest, TestAddMultipartValueForUpload) {
  const char* ref_output = "--boundary\r\nContent-Disposition: form-data;"
                           " name=\"value name\"\r\nContent-Type: content type"
                           "\r\n\r\nvalue\r\n"
                           "--boundary\r\nContent-Disposition: form-data;"
                           " name=\"value name\"\r\n\r\nvalue\r\n"
                           "--boundary--\r\n";
  std::string post_data;
  AddMultipartValueForUpload("value name", "value", "boundary",
                             "content type", &post_data);
  AddMultipartValueForUpload("value name", "value", "boundary",
                             "", &post_data);
  AddMultipartFinalDelimiterForUpload("boundary", &post_data);
  EXPECT_STREQ(ref_output, post_data.c_str());
}

}  // namespace net
<|endoftext|>


<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_network_layer.h"

#include "base/field_trial.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
#include "net/socket/client_socket_factory.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_network_transaction.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"

namespace net {

//-----------------------------------------------------------------------------

// static
HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
    HostResolver* host_resolver,
    ProxyService* proxy_service,
    SSLConfigService* ssl_config_service,
    HttpAuthHandlerFactory* http_auth_handler_factory,
    HttpNetworkDelegate* network_delegate,
    NetLog* net_log) {
  DCHECK(proxy_service);

  return new HttpNetworkLayer(ClientSocketFactory::GetDefaultFactory(),
                              host_resolver, proxy_service, ssl_config_service,
                              http_auth_handler_factory,
                              network_delegate,
                              net_log);
}

// static
HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
    HttpNetworkSession* session) {
  DCHECK(session);

  return new HttpNetworkLayer(session);
}

//-----------------------------------------------------------------------------
bool HttpNetworkLayer::force_spdy_ = false;

HttpNetworkLayer::HttpNetworkLayer(
    ClientSocketFactory* socket_factory,
    HostResolver* host_resolver,
    ProxyService* proxy_service,
    SSLConfigService* ssl_config_service,
    HttpAuthHandlerFactory* http_auth_handler_factory,
    HttpNetworkDelegate* network_delegate,
    NetLog* net_log)
    : socket_factory_(socket_factory),
      host_resolver_(host_resolver),
      proxy_service_(proxy_service),
      ssl_config_service_(ssl_config_service),
      session_(NULL),
      spdy_session_pool_(NULL),
      http_auth_handler_factory_(http_auth_handler_factory),
      network_delegate_(network_delegate),
      net_log_(net_log),
      suspended_(false) {
  DCHECK(proxy_service_);
  DCHECK(ssl_config_service_.get());
}

HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session)
    : socket_factory_(ClientSocketFactory::GetDefaultFactory()),
      ssl_config_service_(NULL),
      session_(session),
      spdy_session_pool_(session->spdy_session_pool()),
      http_auth_handler_factory_(NULL),
      network_delegate_(NULL),
      net_log_(NULL),
      suspended_(false) {
  DCHECK(session_.get());
}

HttpNetworkLayer::~HttpNetworkLayer() {
}

int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
  if (suspended_)
    return ERR_NETWORK_IO_SUSPENDED;

  if (force_spdy_)
    trans->reset(new SpdyNetworkTransaction(GetSession()));
  else
    trans->reset(new HttpNetworkTransaction(GetSession()));
  return OK;
}

HttpCache* HttpNetworkLayer::GetCache() {
  return NULL;
}

void HttpNetworkLayer::Suspend(bool suspend) {
  suspended_ = suspend;

  if (suspend && session_)
    session_->tcp_socket_pool()->CloseIdleSockets();
}

HttpNetworkSession* HttpNetworkLayer::GetSession() {
  if (!session_) {
    DCHECK(proxy_service_);
    SpdySessionPool* spdy_pool = new SpdySessionPool();
    session_ = new HttpNetworkSession(host_resolver_, proxy_service_,
        socket_factory_, ssl_config_service_, spdy_pool,
        http_auth_handler_factory_, network_delegate_, net_log_);
    // These were just temps for lazy-initializing HttpNetworkSession.
    host_resolver_ = NULL;
    proxy_service_ = NULL;
    socket_factory_ = NULL;
    http_auth_handler_factory_ = NULL;
    net_log_ = NULL;
    network_delegate_ = NULL;
  }
  return session_;
}

// static
void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
  static const char kDisableSSL[] = "no-ssl";
  static const char kDisableCompression[] = "no-compress";

  // We want an A/B experiment between SPDY enabled and SPDY disabled,
  // but only for pages where SPDY *could have been* negotiated.  To do
  // this, we use NPN, but prevent it from negotiating SPDY.  If the
  // server negotiates HTTP, rather than SPDY, today that will only happen
  // on servers that installed NPN (and could have done SPDY).  But this is
  // a bit of a hack, as this correlation between NPN and SPDY is not
  // really guaranteed.
  static const char kEnableNPN[] = "npn";
  static const char kEnableNpnHttpOnly[] = "npn-http";

  // Except for the first element, the order is irrelevant.  First element
  // specifies the fallback in case nothing matches
  // (SSLClientSocket::kNextProtoNoOverlap).  Otherwise, the SSL library
  // will choose the first overlapping protocol in the server's list, since
  // it presumedly has a better understanding of which protocol we should
  // use, therefore the rest of the ordering here is not important.
  static const char kNpnProtosFull[] =
      "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy";
  // No spdy specified.
  static const char kNpnProtosHttpOnly[] = "\x08http/1.1\x07http1.1";

  std::vector<std::string> spdy_options;
  SplitString(mode, ',', &spdy_options);

  // Force spdy mode (use SpdyNetworkTransaction for all http requests).
  force_spdy_ = true;

  for (std::vector<std::string>::iterator it = spdy_options.begin();
       it != spdy_options.end(); ++it) {
    const std::string& option = *it;
    if (option == kDisableSSL) {
      SpdySession::SetSSLMode(false);  // Disable SSL
    } else if (option == kDisableCompression) {
      spdy::SpdyFramer::set_enable_compression_default(false);
    } else if (option == kEnableNPN) {
      HttpNetworkTransaction::SetUseAlternateProtocols(true);
      HttpNetworkTransaction::SetNextProtos(kNpnProtosFull);
      force_spdy_ = false;
    } else if (option == kEnableNpnHttpOnly) {
      HttpNetworkTransaction::SetUseAlternateProtocols(true);
      HttpNetworkTransaction::SetNextProtos(kNpnProtosHttpOnly);
      force_spdy_ = false;
    } else if (option.empty() && it == spdy_options.begin()) {
      continue;
    } else {
      LOG(DFATAL) << "Unrecognized spdy option: " << option;
    }
  }
}

}  // namespace net
<commit_msg>Add back a flag to disable Alternate-Protocol processing. Specifically, provide a no-alt-protocols option to the --use-spdy flag.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "net/http/http_network_layer.h"

#include "base/field_trial.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "net/http/http_network_session.h"
#include "net/http/http_network_transaction.h"
#include "net/socket/client_socket_factory.h"
#include "net/spdy/spdy_framer.h"
#include "net/spdy/spdy_network_transaction.h"
#include "net/spdy/spdy_session.h"
#include "net/spdy/spdy_session_pool.h"

namespace net {

//-----------------------------------------------------------------------------

// static
HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
    HostResolver* host_resolver,
    ProxyService* proxy_service,
    SSLConfigService* ssl_config_service,
    HttpAuthHandlerFactory* http_auth_handler_factory,
    HttpNetworkDelegate* network_delegate,
    NetLog* net_log) {
  DCHECK(proxy_service);

  return new HttpNetworkLayer(ClientSocketFactory::GetDefaultFactory(),
                              host_resolver, proxy_service, ssl_config_service,
                              http_auth_handler_factory,
                              network_delegate,
                              net_log);
}

// static
HttpTransactionFactory* HttpNetworkLayer::CreateFactory(
    HttpNetworkSession* session) {
  DCHECK(session);

  return new HttpNetworkLayer(session);
}

//-----------------------------------------------------------------------------
bool HttpNetworkLayer::force_spdy_ = false;

HttpNetworkLayer::HttpNetworkLayer(
    ClientSocketFactory* socket_factory,
    HostResolver* host_resolver,
    ProxyService* proxy_service,
    SSLConfigService* ssl_config_service,
    HttpAuthHandlerFactory* http_auth_handler_factory,
    HttpNetworkDelegate* network_delegate,
    NetLog* net_log)
    : socket_factory_(socket_factory),
      host_resolver_(host_resolver),
      proxy_service_(proxy_service),
      ssl_config_service_(ssl_config_service),
      session_(NULL),
      spdy_session_pool_(NULL),
      http_auth_handler_factory_(http_auth_handler_factory),
      network_delegate_(network_delegate),
      net_log_(net_log),
      suspended_(false) {
  DCHECK(proxy_service_);
  DCHECK(ssl_config_service_.get());
}

HttpNetworkLayer::HttpNetworkLayer(HttpNetworkSession* session)
    : socket_factory_(ClientSocketFactory::GetDefaultFactory()),
      ssl_config_service_(NULL),
      session_(session),
      spdy_session_pool_(session->spdy_session_pool()),
      http_auth_handler_factory_(NULL),
      network_delegate_(NULL),
      net_log_(NULL),
      suspended_(false) {
  DCHECK(session_.get());
}

HttpNetworkLayer::~HttpNetworkLayer() {
}

int HttpNetworkLayer::CreateTransaction(scoped_ptr<HttpTransaction>* trans) {
  if (suspended_)
    return ERR_NETWORK_IO_SUSPENDED;

  if (force_spdy_)
    trans->reset(new SpdyNetworkTransaction(GetSession()));
  else
    trans->reset(new HttpNetworkTransaction(GetSession()));
  return OK;
}

HttpCache* HttpNetworkLayer::GetCache() {
  return NULL;
}

void HttpNetworkLayer::Suspend(bool suspend) {
  suspended_ = suspend;

  if (suspend && session_)
    session_->tcp_socket_pool()->CloseIdleSockets();
}

HttpNetworkSession* HttpNetworkLayer::GetSession() {
  if (!session_) {
    DCHECK(proxy_service_);
    SpdySessionPool* spdy_pool = new SpdySessionPool();
    session_ = new HttpNetworkSession(host_resolver_, proxy_service_,
        socket_factory_, ssl_config_service_, spdy_pool,
        http_auth_handler_factory_, network_delegate_, net_log_);
    // These were just temps for lazy-initializing HttpNetworkSession.
    host_resolver_ = NULL;
    proxy_service_ = NULL;
    socket_factory_ = NULL;
    http_auth_handler_factory_ = NULL;
    net_log_ = NULL;
    network_delegate_ = NULL;
  }
  return session_;
}

// static
void HttpNetworkLayer::EnableSpdy(const std::string& mode) {
  static const char kDisableSSL[] = "no-ssl";
  static const char kDisableCompression[] = "no-compress";
  static const char kDisableAltProtocols[] = "no-alt-protocols";

  // We want an A/B experiment between SPDY enabled and SPDY disabled,
  // but only for pages where SPDY *could have been* negotiated.  To do
  // this, we use NPN, but prevent it from negotiating SPDY.  If the
  // server negotiates HTTP, rather than SPDY, today that will only happen
  // on servers that installed NPN (and could have done SPDY).  But this is
  // a bit of a hack, as this correlation between NPN and SPDY is not
  // really guaranteed.
  static const char kEnableNPN[] = "npn";
  static const char kEnableNpnHttpOnly[] = "npn-http";

  // Except for the first element, the order is irrelevant.  First element
  // specifies the fallback in case nothing matches
  // (SSLClientSocket::kNextProtoNoOverlap).  Otherwise, the SSL library
  // will choose the first overlapping protocol in the server's list, since
  // it presumedly has a better understanding of which protocol we should
  // use, therefore the rest of the ordering here is not important.
  static const char kNpnProtosFull[] =
      "\x08http/1.1\x07http1.1\x06spdy/1\x04spdy";
  // No spdy specified.
  static const char kNpnProtosHttpOnly[] = "\x08http/1.1\x07http1.1";

  std::vector<std::string> spdy_options;
  SplitString(mode, ',', &spdy_options);

  // Force spdy mode (use SpdyNetworkTransaction for all http requests).
  force_spdy_ = true;

  bool use_alt_protocols = true;

  for (std::vector<std::string>::iterator it = spdy_options.begin();
       it != spdy_options.end(); ++it) {
    const std::string& option = *it;
    if (option == kDisableSSL) {
      SpdySession::SetSSLMode(false);  // Disable SSL
    } else if (option == kDisableCompression) {
      spdy::SpdyFramer::set_enable_compression_default(false);
    } else if (option == kEnableNPN) {
      HttpNetworkTransaction::SetUseAlternateProtocols(use_alt_protocols);
      HttpNetworkTransaction::SetNextProtos(kNpnProtosFull);
      force_spdy_ = false;
    } else if (option == kEnableNpnHttpOnly) {
      HttpNetworkTransaction::SetUseAlternateProtocols(use_alt_protocols);
      HttpNetworkTransaction::SetNextProtos(kNpnProtosHttpOnly);
      force_spdy_ = false;
    } else if (option == kDisableAltProtocols) {
      use_alt_protocols = false;
      HttpNetworkTransaction::SetUseAlternateProtocols(false);
    } else if (option.empty() && it == spdy_options.begin()) {
      continue;
    } else {
      LOG(DFATAL) << "Unrecognized spdy option: " << option;
    }
  }
}

}  // namespace net
<|endoftext|>


<commit_before>// Copyright (c) 2019 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.

#ifndef TOKDEF
# define TOKDEF(k, s)
#endif

#ifndef TOKEN
# define TOKEN(k, s) TOKDEF(TK_##k, s)
#endif

#ifndef PUNCTUATOR
# define PUNCTUATOR(k, s) TOKEN(k, s)
#endif

#ifndef KEYWORD
# define KEYWORD(k, s) TOKDEF(KW_##k, s)
#endif

PUNCTUATOR(LPAREN, "(")
PUNCTUATOR(RPAREN, ")")
PUNCTUATOR(LBRACKET, "[")
PUNCTUATOR(RBRACKET, "]")
PUNCTUATOR(LBRACE, "{")
PUNCTUATOR(RBRACE, "}")
PUNCTUATOR(COLON, ":")
PUNCTUATOR(DOT, ".")
PUNCTUATOR(COMMA, ",")
PUNCTUATOR(STAR, "*")
PUNCTUATOR(SLASH, "/")
PUNCTUATOR(PERCENT, "%")
PUNCTUATOR(PLUS, "+")
PUNCTUATOR(MINUS, "-")
PUNCTUATOR(PIPE, "|")
PUNCTUATOR(AMP, "&")
PUNCTUATOR(BANG, "!")
PUNCTUATOR(EQ, "=")
PUNCTUATOR(LT, "<")
PUNCTUATOR(GT, ">")
PUNCTUATOR(LTEQ, "<=")
PUNCTUATOR(GTEQ, ">=")
PUNCTUATOR(EQEQ, "==")
PUNCTUATOR(BANGEQ, "!=")

KEYWORD(CLASS, "class")
KEYWORD(META, "meta")
KEYWORD(VAR, "var")

TOKEN(EMBED, "embed")
TOKEN(IDENTIFIER, "identifier")
TOKEN(NUMERIC, "numeric")
TOKEN(STRING, "string")

TOKEN(NL, "new-line")

TOKEN(ERROR, "error")
TOKEN(EOF, "eof")

#undef KEYWORD
#undef PUNCTUATOR
#undef TOKEN
#undef TOKDEF
<commit_msg>:construction: chore(kinds): updated the kinds definitions<commit_after>// Copyright (c) 2019 ASMlover. 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 ofconditions 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 materialsprovided with the
//    distribution.
//
// 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 HOLDER 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.

#ifndef TOKDEF
# define TOKDEF(k, s)
#endif

#ifndef TOKEN
# define TOKEN(k, s) TOKDEF(TK_##k, s)
#endif

#ifndef PUNCTUATOR
# define PUNCTUATOR(k, s) TOKEN(k, s)
#endif

#ifndef KEYWORD
# define KEYWORD(k, s) TOKDEF(KW_##k, s)
#endif

PUNCTUATOR(LPAREN, "(")
PUNCTUATOR(RPAREN, ")")
PUNCTUATOR(LBRACKET, "[")
PUNCTUATOR(RBRACKET, "]")
PUNCTUATOR(LBRACE, "{")
PUNCTUATOR(RBRACE, "}")
PUNCTUATOR(COLON, ":")
PUNCTUATOR(DOT, ".")
PUNCTUATOR(COMMA, ",")
PUNCTUATOR(STAR, "*")
PUNCTUATOR(SLASH, "/")
PUNCTUATOR(PERCENT, "%")
PUNCTUATOR(PLUS, "+")
PUNCTUATOR(MINUS, "-")
PUNCTUATOR(PIPE, "|")
PUNCTUATOR(AMP, "&")
PUNCTUATOR(BANG, "!")
PUNCTUATOR(EQ, "=")
PUNCTUATOR(LT, "<")
PUNCTUATOR(GT, ">")
PUNCTUATOR(LTEQ, "<=")
PUNCTUATOR(GTEQ, ">=")
PUNCTUATOR(EQEQ, "==")
PUNCTUATOR(BANGEQ, "!=")

KEYWORD(CLASS, "class")
KEYWORD(META, "meta")
KEYWORD(VAR, "var")

TOKEN(IDENTIFIER, "identifier")
TOKEN(NUMERIC, "numeric")
TOKEN(STRING, "string")

TOKEN(NL, "new-line")

TOKEN(ERROR, "error")
TOKEN(EOF, "eof")

#undef KEYWORD
#undef PUNCTUATOR
#undef TOKEN
#undef TOKDEF
<|endoftext|>


<commit_before>#include <config.h>
#include <assert.h>
#include <boost/assert.hpp>
#include <dune/common/exceptions.hh>
#include <dune/common/timer.hh>
#include <dune/multiscale/common/righthandside_assembler.hh>
#include <dune/multiscale/msfem/elliptic_msfem_matrix_assembler.hh>
#include <dune/multiscale/msfem/msfem_grid_specifier.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/common/parameter/configcontainer.hh>
#include <dune/stuff/common/profiler.hh>
#include <dune/stuff/discretefunction/projection/heterogenous.hh>
#include <sstream>

#include "dune/multiscale/common/dirichletconstraints.hh"
#include "dune/multiscale/common/traits.hh"
#include "dune/multiscale/msfem/msfem_traits.hh"
#include "msfem_solver.hh"

namespace Dune {
namespace Multiscale {
namespace MsFEM {

Elliptic_MsFEM_Solver::Elliptic_MsFEM_Solver(const DiscreteFunctionSpace& discreteFunctionSpace)
  : discreteFunctionSpace_(discreteFunctionSpace) {}

void Elliptic_MsFEM_Solver::subgrid_to_hostrid_projection(const SubgridDiscreteFunctionType& sub_func,
                                                          DiscreteFunctionType& host_func) const {
  host_func.clear();
  Stuff::HeterogenousProjection<>::project(sub_func, host_func);
} // subgrid_to_hostrid_projection

void Elliptic_MsFEM_Solver::identify_fine_scale_part(MacroMicroGridSpecifier& specifier,
                                                     MsFEMTraits::LocalGridListType& subgrid_list,
                                                     const DiscreteFunctionType& coarse_msfem_solution,
                                                     DiscreteFunctionType& fine_scale_part) const {
  fine_scale_part.clear();
  DiscreteFunctionSpace& coarse_space = specifier.coarseSpace();

  DSC_LOG_INFO << "Indentifying fine scale part of the MsFEM solution... ";
  // traverse coarse space
  for (auto& coarseCell : coarse_space) {
    LocalSolutionManager localSolManager(coarseCell, subgrid_list, specifier);
    localSolManager.loadLocalSolutions();
    auto& localSolutions = localSolManager.getLocalSolutions();

    auto coarseSolutionLF = coarse_msfem_solution.localFunction(coarseCell);

    if ((DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 3) || specifier.simplexCoarseGrid()) {
      BOOST_ASSERT_MSG(localSolutions.size() == Dune::GridSelector::dimgrid,
                       "We should have dim local solutions per coarse element on triangular meshes!");

      JacobianRangeType grad_coarse_msfem_on_entity;
      // We only need the gradient of the coarse scale part on the element, which is a constant.
      coarseSolutionLF.jacobian(coarseCell.geometry().center(), grad_coarse_msfem_on_entity);

      // get the coarse gradient on T, multiply it with the local correctors and sum it up.
      for (int spaceDimension = 0; spaceDimension < Dune::GridSelector::dimgrid; ++spaceDimension) {
        *localSolutions[spaceDimension] *= grad_coarse_msfem_on_entity[0][spaceDimension];
        if (spaceDimension > 0)
          *localSolutions[0] += *localSolutions[spaceDimension];
      }
    } else {
      //! @warning At this point, we assume to have the same types of elements in the coarse and fine grid!
      BOOST_ASSERT_MSG(
          static_cast<long long>(localSolutions.size() - localSolManager.numBoundaryCorrectors()) ==
              static_cast<long long>(coarseSolutionLF.numDofs()),
          "The current implementation relies on having thesame types of elements on coarse and fine level!");
      for (int dof = 0; dof < coarseSolutionLF.numDofs(); ++dof) {
        *localSolutions[dof] *= coarseSolutionLF[dof];
        if (dof > 0)
          *localSolutions[0] += *localSolutions[dof];
      }

      // add dirichlet corrector
      DiscreteFunctionType boundaryCorrector("Boundary Corrector", discreteFunctionSpace_);
      DMM::MsFEMTraits::LocalGridDiscreteFunctionType& ff = *localSolutions[coarseSolutionLF.numDofs() + 1];
      subgrid_to_hostrid_projection(ff, boundaryCorrector);
      fine_scale_part += boundaryCorrector;

      // substract neumann corrector
      subgrid_to_hostrid_projection(*localSolutions[coarseSolutionLF.numDofs()], boundaryCorrector);
      fine_scale_part -= boundaryCorrector;
    }

    // oversampling strategy 3: just sum up the local correctors:
    if ((DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 3)) {
      DiscreteFunctionType correction_on_U_T("correction_on_U_T", discreteFunctionSpace_);
      subgrid_to_hostrid_projection(*localSolutions[0], correction_on_U_T);
      fine_scale_part += correction_on_U_T;
    }

    // oversampling strategy 1 or 2: restrict the local correctors to the element T, sum them up and apply a conforming
    // projection:
    if ((DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 1) || (DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 2)) {

//      DUNE_THROW(NotImplemented, "pretty sure this is bs. there's no sum of local correctors. restriction also no longer works");
//      for (auto& local_entity : localSolManager.getLocalDiscreteFunctionSpace()) {
//        if (subgrid_list.covers(coarseCell, local_entity)) {
//          const auto sub_loc_value = localSolutions[0]->localFunction(local_entity);

//          assert(localSolutions.size() == coarseSolutionLF.numDofs() + localSolManager.numBoundaryCorrectors());
//          auto host_loc_value = fine_scale_part.localFunction(local_entity);

//          const auto number_of_nodes_entity = local_entity.count<LocalGrid::dimension>();

//          for (auto i : DSC::valueRange(number_of_nodes_entity)) {
//            const auto node = local_entity.subEntity<LocalGrid::dimension>(i);
//            const auto global_index_node = gridPart.indexSet().index(*node);

//            // devide the value by the number of fine elements sharing the node (will be
//            // added numEntitiesSharingNode times)
//            const auto numEntitiesSharingNode = nodeToEntityMap[global_index_node].size();
//            host_loc_value[i] += (sub_loc_value[i] / numEntitiesSharingNode);
//          }
//        }
//      }
    }
  }
  DSC_LOG_INFO << " done." << std::endl;
}

void Elliptic_MsFEM_Solver::solve_dirichlet_zero(
    const CommonTraits::DiffusionType& diffusion_op, const CommonTraits::FirstSourceType& f,
    // number of layers per coarse grid entity T:  U(T) is created by enrichting T with
    // n(T)-layers.
    MacroMicroGridSpecifier& specifier, MsFEMTraits::LocalGridListType& subgrid_list,
    DiscreteFunctionType& coarse_scale_part, DiscreteFunctionType& fine_scale_part,
    DiscreteFunctionType& solution) const {
  DSC::Profiler::ScopedTiming st("msfem.Elliptic_MsFEM_Solver.solve_dirichlet_zero");

  DiscreteFunctionSpace& coarse_space = specifier.coarseSpace();

  DiscreteFunctionType coarse_msfem_solution("Coarse Part MsFEM Solution", coarse_space);
  coarse_msfem_solution.clear();

  //! define the right hand side assembler tool
  // (for linear and non-linear elliptic and parabolic problems, for sources f and/or G )
  typedef RightHandSideAssembler RhsAssembler;

  // Assemble and solve the local problems. Timing is done in assembleAndSolveAll-method
  MsFEMLocalProblemSolver localProblemSolver(specifier, subgrid_list, diffusion_op);
  localProblemSolver.assembleAndSolveAll();

  //! define the discrete (elliptic) operator that describes our problem
  // discrete elliptic MsFEM operator (corresponds with MsFEM Matrix)
  // ( effect of the discretized differential operator on a certain discrete function )
  const DiscreteEllipticMsFEMOperator elliptic_msfem_op(specifier, coarse_space, subgrid_list, diffusion_op);

  //! (stiffness) matrix
  MsLinearOperatorTypeType msfem_matrix("MsFEM stiffness matrix", coarse_space, coarse_space);

  //! right hand side vector
  // right hand side for the finite element method:
  DiscreteFunctionType msfem_rhs("MsFEM right hand side", coarse_space);
  msfem_rhs.clear();

  // to assemble the computational time
  DSC_PROFILER.startTiming("msfem.assembleMatrix");
  // assemble the MsFEM stiffness matrix
  elliptic_msfem_op.assemble_matrix(msfem_matrix);
  DSC_LOG_INFO << "Time to assemble MsFEM stiffness matrix: " << DSC_PROFILER.stopTiming("msfem.assembleMatrix")
               << "ms" << std::endl;

  // assemble right hand side
  DSC_PROFILER.startTiming("msfem.assembleRHS");
  if (DSC_CONFIG_GET("msfem.petrov_galerkin", 1))
    DSC_LOG_ERROR << "MsFEM does not work with Petrov-Galerkin at the moment!\n";

  RhsAssembler::assemble_for_MsFEM_symmetric(f, specifier, subgrid_list, msfem_rhs);

  msfem_rhs.communicate();
  DSC_LOG_INFO << "Time to assemble and communicate MsFEM rhs: " << DSC_PROFILER.stopTiming("msfem.assembleRHS")
               << "ms" << std::endl;

  BOOST_ASSERT_MSG(msfem_rhs.dofsValid(), "Coarse scale RHS DOFs need to be valid!");

  DSC_PROFILER.startTiming("msfem.solveCoarse");
  const InverseOperatorType msfem_biCGStab(msfem_matrix, 1e-8, 1e-8,
                                           DSC_CONFIG_GET("msfem.solver.iterations", msfem_rhs.size()),
                                           DSC_CONFIG_GET("msfem.solver.verbose", false), "bcgs",
                                           DSC_CONFIG_GET("msfem.solver.preconditioner_type", std::string("sor")));
  msfem_biCGStab(msfem_rhs, coarse_msfem_solution);
  DSC_LOG_INFO << "Time to solve coarse MsFEM problem: " << DSC_PROFILER.stopTiming("msfem.solveCoarse")
               << "ms." << std::endl;

  if (!coarse_msfem_solution.dofsValid())
    DUNE_THROW(InvalidStateException, "Degrees of freedom of coarse solution are not valid!");

  // get the dirichlet values
  solution.clear();
  Dune::Multiscale::copyDirichletValues(coarse_space, solution);

  //! identify fine scale part of MsFEM solution (including the projection!)
  identify_fine_scale_part(specifier, subgrid_list, coarse_msfem_solution, fine_scale_part);
  {
    DSC::Profiler::ScopedTiming commFSTimer("msfem.Elliptic_MsFEM_Solver.solve_dirichlet_zero.comm_fine_scale_part");
    fine_scale_part.communicate();
  }

  BOOST_ASSERT_MSG(coarse_scale_part.dofsValid(), "Coarse scale part DOFs need to be valid!");
  BOOST_ASSERT_MSG(fine_scale_part.dofsValid(), "Fine scale part DOFs need to be valid!");

  DS::HeterogenousProjection<>::project(coarse_msfem_solution, coarse_scale_part);
  // add coarse and fine scale part to solution
  solution += coarse_scale_part;
  solution += fine_scale_part;

  // seperate the msfem output from other output
  std::cout << std::endl << std::endl;

} // solve_dirichlet_zero

} // namespace MsFEM {
} // namespace Multiscale {
} // namespace Dune {
<commit_msg>3x speedup for Elliptic_MsFEM_Solver::identify_fine_scale_part<commit_after>#include <config.h>
#include <assert.h>
#include <boost/assert.hpp>
#include <dune/common/exceptions.hh>
#include <dune/common/timer.hh>
#include <dune/multiscale/common/righthandside_assembler.hh>
#include <dune/multiscale/msfem/elliptic_msfem_matrix_assembler.hh>
#include <dune/multiscale/msfem/msfem_grid_specifier.hh>
#include <dune/stuff/common/logging.hh>
#include <dune/stuff/common/parameter/configcontainer.hh>
#include <dune/stuff/common/profiler.hh>
#include <dune/stuff/discretefunction/projection/heterogenous.hh>
#include <sstream>

#include "dune/multiscale/common/dirichletconstraints.hh"
#include "dune/multiscale/common/traits.hh"
#include "dune/multiscale/msfem/msfem_traits.hh"
#include "msfem_solver.hh"

namespace Dune {
namespace Multiscale {
namespace MsFEM {

Elliptic_MsFEM_Solver::Elliptic_MsFEM_Solver(const DiscreteFunctionSpace& discreteFunctionSpace)
  : discreteFunctionSpace_(discreteFunctionSpace) {}

void Elliptic_MsFEM_Solver::subgrid_to_hostrid_projection(const SubgridDiscreteFunctionType& sub_func,
                                                          DiscreteFunctionType& host_func) const {
  host_func.clear();
  Stuff::HeterogenousProjection<>::project(sub_func, host_func);
} // subgrid_to_hostrid_projection

void Elliptic_MsFEM_Solver::identify_fine_scale_part(MacroMicroGridSpecifier& specifier,
                                                     MsFEMTraits::LocalGridListType& subgrid_list,
                                                     const DiscreteFunctionType& coarse_msfem_solution,
                                                     DiscreteFunctionType& fine_scale_part) const {
  fine_scale_part.clear();
  DiscreteFunctionSpace& coarse_space = specifier.coarseSpace();

  DSC_LOG_INFO << "Indentifying fine scale part of the MsFEM solution... ";
  DiscreteFunctionType fine_correction("Boundary Corrector", discreteFunctionSpace_);

  // traverse coarse space
  for (auto& coarseCell : coarse_space) {
    LocalSolutionManager localSolManager(coarseCell, subgrid_list, specifier);
    localSolManager.loadLocalSolutions();
    auto& localSolutions = localSolManager.getLocalSolutions();

    auto coarseSolutionLF = coarse_msfem_solution.localFunction(coarseCell);
    DMM::MsFEMTraits::LocalGridDiscreteFunctionType local_correction("", localSolManager.space());
    local_correction.clear();

    if ((DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 3) || specifier.simplexCoarseGrid()) {
      BOOST_ASSERT_MSG(localSolutions.size() == Dune::GridSelector::dimgrid,
                       "We should have dim local solutions per coarse element on triangular meshes!");

      JacobianRangeType grad_coarse_msfem_on_entity;
      // We only need the gradient of the coarse scale part on the element, which is a constant.
      coarseSolutionLF.jacobian(coarseCell.geometry().center(), grad_coarse_msfem_on_entity);

      // get the coarse gradient on T, multiply it with the local correctors and sum it up.
      for (int spaceDimension = 0; spaceDimension < Dune::GridSelector::dimgrid; ++spaceDimension) {
        *localSolutions[spaceDimension] *= grad_coarse_msfem_on_entity[0][spaceDimension];
        if (spaceDimension > 0)
          *localSolutions[0] += *localSolutions[spaceDimension];
      }
    } else {
      //! @warning At this point, we assume to have the same types of elements in the coarse and fine grid!
      BOOST_ASSERT_MSG(
          static_cast<long long>(localSolutions.size() - localSolManager.numBoundaryCorrectors()) ==
              static_cast<long long>(coarseSolutionLF.numDofs()),
          "The current implementation relies on having thesame types of elements on coarse and fine level!");
      for (int dof = 0; dof < coarseSolutionLF.numDofs(); ++dof) {
        *localSolutions[dof] *= coarseSolutionLF[dof];
        if (dof > 0)
          *localSolutions[0] += *localSolutions[dof];
      }

      // add dirichlet corrector
      local_correction += *localSolutions[coarseSolutionLF.numDofs() + 1];
      // substract neumann corrector
      local_correction -= *localSolutions[coarseSolutionLF.numDofs() + 1];
    }

    // oversampling strategy 3: just sum up the local correctors:
    if ((DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 3)) {
      local_correction += *localSolutions[0];
    }

    // oversampling strategy 1 or 2: restrict the local correctors to the element T, sum them up and apply a conforming
    // projection:
    if ((DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 1) || (DSC_CONFIG_GET("msfem.oversampling_strategy", 1) == 2)) {

//      DUNE_THROW(NotImplemented, "pretty sure this is bs. there's no sum of local correctors. restriction also no longer works");
//      for (auto& local_entity : localSolManager.space()) {
//        if (subgrid_list.covers(coarseCell, local_entity)) {
//          const auto sub_loc_value = localSolutions[0]->localFunction(local_entity);

//          assert(localSolutions.size() == coarseSolutionLF.numDofs() + localSolManager.numBoundaryCorrectors());
//          auto host_loc_value = fine_scale_part.localFunction(local_entity);

//          const auto number_of_nodes_entity = local_entity.count<LocalGrid::dimension>();

//          for (auto i : DSC::valueRange(number_of_nodes_entity)) {
//            const auto node = local_entity.subEntity<LocalGrid::dimension>(i);
//            const auto global_index_node = gridPart.indexSet().index(*node);

//            // devide the value by the number of fine elements sharing the node (will be
//            // added numEntitiesSharingNode times)
//            const auto numEntitiesSharingNode = nodeToEntityMap[global_index_node].size();
//            host_loc_value[i] += (sub_loc_value[i] / numEntitiesSharingNode);
//          }
//        }
//      }
    }

    Stuff::HeterogenousProjection<>::project(local_correction, fine_correction);
    fine_scale_part += fine_correction;
  }
  DSC_LOG_INFO << " done." << std::endl;
}

void Elliptic_MsFEM_Solver::solve_dirichlet_zero(
    const CommonTraits::DiffusionType& diffusion_op, const CommonTraits::FirstSourceType& f,
    // number of layers per coarse grid entity T:  U(T) is created by enrichting T with
    // n(T)-layers.
    MacroMicroGridSpecifier& specifier, MsFEMTraits::LocalGridListType& subgrid_list,
    DiscreteFunctionType& coarse_scale_part, DiscreteFunctionType& fine_scale_part,
    DiscreteFunctionType& solution) const {
  DSC::Profiler::ScopedTiming st("msfem.Elliptic_MsFEM_Solver.solve_dirichlet_zero");

  DiscreteFunctionSpace& coarse_space = specifier.coarseSpace();

  DiscreteFunctionType coarse_msfem_solution("Coarse Part MsFEM Solution", coarse_space);
  coarse_msfem_solution.clear();

  //! define the right hand side assembler tool
  // (for linear and non-linear elliptic and parabolic problems, for sources f and/or G )
  typedef RightHandSideAssembler RhsAssembler;

  // Assemble and solve the local problems. Timing is done in assembleAndSolveAll-method
  MsFEMLocalProblemSolver localProblemSolver(specifier, subgrid_list, diffusion_op);
  localProblemSolver.assembleAndSolveAll();

  //! define the discrete (elliptic) operator that describes our problem
  // discrete elliptic MsFEM operator (corresponds with MsFEM Matrix)
  // ( effect of the discretized differential operator on a certain discrete function )
  const DiscreteEllipticMsFEMOperator elliptic_msfem_op(specifier, coarse_space, subgrid_list, diffusion_op);

  //! (stiffness) matrix
  MsLinearOperatorTypeType msfem_matrix("MsFEM stiffness matrix", coarse_space, coarse_space);

  //! right hand side vector
  // right hand side for the finite element method:
  DiscreteFunctionType msfem_rhs("MsFEM right hand side", coarse_space);
  msfem_rhs.clear();

  // to assemble the computational time
  DSC_PROFILER.startTiming("msfem.assembleMatrix");
  // assemble the MsFEM stiffness matrix
  elliptic_msfem_op.assemble_matrix(msfem_matrix);
  DSC_LOG_INFO << "Time to assemble MsFEM stiffness matrix: " << DSC_PROFILER.stopTiming("msfem.assembleMatrix")
               << "ms" << std::endl;

  // assemble right hand side
  DSC_PROFILER.startTiming("msfem.assembleRHS");
  if (DSC_CONFIG_GET("msfem.petrov_galerkin", 1))
    DSC_LOG_ERROR << "MsFEM does not work with Petrov-Galerkin at the moment!\n";

  RhsAssembler::assemble_for_MsFEM_symmetric(f, specifier, subgrid_list, msfem_rhs);

  msfem_rhs.communicate();
  DSC_LOG_INFO << "Time to assemble and communicate MsFEM rhs: " << DSC_PROFILER.stopTiming("msfem.assembleRHS")
               << "ms" << std::endl;

  BOOST_ASSERT_MSG(msfem_rhs.dofsValid(), "Coarse scale RHS DOFs need to be valid!");

  DSC_PROFILER.startTiming("msfem.solveCoarse");
  const InverseOperatorType msfem_biCGStab(msfem_matrix, 1e-8, 1e-8,
                                           DSC_CONFIG_GET("msfem.solver.iterations", msfem_rhs.size()),
                                           DSC_CONFIG_GET("msfem.solver.verbose", false), "bcgs",
                                           DSC_CONFIG_GET("msfem.solver.preconditioner_type", std::string("sor")));
  msfem_biCGStab(msfem_rhs, coarse_msfem_solution);
  DSC_LOG_INFO << "Time to solve coarse MsFEM problem: " << DSC_PROFILER.stopTiming("msfem.solveCoarse")
               << "ms." << std::endl;

  if (!coarse_msfem_solution.dofsValid())
    DUNE_THROW(InvalidStateException, "Degrees of freedom of coarse solution are not valid!");

  // get the dirichlet values
  solution.clear();
  Dune::Multiscale::copyDirichletValues(coarse_space, solution);

  //! identify fine scale part of MsFEM solution (including the projection!)
  identify_fine_scale_part(specifier, subgrid_list, coarse_msfem_solution, fine_scale_part);
  {
    DSC::Profiler::ScopedTiming commFSTimer("msfem.Elliptic_MsFEM_Solver.solve_dirichlet_zero.comm_fine_scale_part");
    fine_scale_part.communicate();
  }

  BOOST_ASSERT_MSG(coarse_scale_part.dofsValid(), "Coarse scale part DOFs need to be valid!");
  BOOST_ASSERT_MSG(fine_scale_part.dofsValid(), "Fine scale part DOFs need to be valid!");

  DS::HeterogenousProjection<>::project(coarse_msfem_solution, coarse_scale_part);
  // add coarse and fine scale part to solution
  solution += coarse_scale_part;
  solution += fine_scale_part;

  // seperate the msfem output from other output
  std::cout << std::endl << std::endl;

} // solve_dirichlet_zero

} // namespace MsFEM {
} // namespace Multiscale {
} // namespace Dune {
<|endoftext|>