mirror of
https://github.com/Xahau/xahaud.git
synced 2025-12-06 17:27:52 +00:00
* Removed MultiSocket. Code that previously used the MultiSocket now uses a combination of boost::asio coroutines and CRTP. * Sitefiles headers rolled up and directory flattened. * Disabled Sitefiles use of deprecated HTTPClient. * Validators headers tidied up. * Disabled Validators use of deprecated HTTPClient.
309 lines
9.0 KiB
C++
309 lines
9.0 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of rippled: https://github.com/ripple/rippled
|
|
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#ifndef RIPPLE_SITEFILES_LOGIC_H_INCLUDED
|
|
#define RIPPLE_SITEFILES_LOGIC_H_INCLUDED
|
|
|
|
#include <beast/http/URL.h>
|
|
#include <beast/module/asio/http/HTTPResponse.h> // DEPRECATED
|
|
#include <boost/regex.hpp>
|
|
#include <map>
|
|
#include <memory>
|
|
#include <set>
|
|
|
|
namespace ripple {
|
|
namespace SiteFiles {
|
|
|
|
/*
|
|
Config file format:
|
|
|
|
Syntactically a series of lines, where line has this format:
|
|
[ <vertical whitespace> ] <anything> ( <vertical-whitespace> OR <end-of-file> )
|
|
|
|
Semantically a series of of zero or more sections, where each section
|
|
has a name and optional data. Specifically, the format:
|
|
( <start-of-file> OR <header> ) <data>
|
|
|
|
Data appearing before the first header goes into the section whose
|
|
name is the empty string "".
|
|
|
|
All lines are valid, errors are not possible. Each line matches one of
|
|
the Comment, Header, or Data format:
|
|
|
|
Comment:
|
|
[ <horizontal whitespace> ] [ '#' <anything> ]
|
|
|
|
Comment lines are ignored; The file is treated as if
|
|
the comment lines do not exist.
|
|
|
|
Header:
|
|
[ <horizontal whitespace> ] '[' <anything> ']' [ <anything> ]
|
|
|
|
Data:
|
|
Anything not matching a comment or header.
|
|
|
|
Lines in a data block are added to the section with the last name parsed,
|
|
or the empty string if no header line has been seen yet.
|
|
*/
|
|
class Logic
|
|
{
|
|
public:
|
|
typedef std::set <Listener*> Listeners;
|
|
typedef std::map <beast::URL, SiteFile> SiteFiles;
|
|
|
|
struct State
|
|
{
|
|
State()
|
|
{
|
|
}
|
|
|
|
Listeners listeners;
|
|
SiteFiles files;
|
|
};
|
|
|
|
typedef beast::SharedData <State> SharedState;
|
|
|
|
SharedState m_state;
|
|
beast::Journal m_journal;
|
|
|
|
explicit Logic (beast::Journal journal)
|
|
: m_journal (journal)
|
|
{
|
|
}
|
|
|
|
~Logic ()
|
|
{
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Logic
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void addListener (Listener& listener)
|
|
{
|
|
SharedState::Access state (m_state);
|
|
|
|
// Notify the listener for each site file already added
|
|
for (SiteFiles::const_iterator iter (state->files.begin());
|
|
iter != state->files.end(); ++iter)
|
|
{
|
|
listener.onSiteFileFetch (to_string (iter->first), iter->second);
|
|
}
|
|
|
|
state->listeners.insert (&listener);
|
|
}
|
|
|
|
void removeListener (Listener& listener)
|
|
{
|
|
SharedState::Access state (m_state);
|
|
state->listeners.erase (&listener);
|
|
}
|
|
|
|
void addURL (std::string const& urlstr)
|
|
{
|
|
// VFALCO This is commented out because the HTTPClient
|
|
// implementation is now obsolete. A new HTTP client
|
|
// that uses the latest best practices (asio coroutines,
|
|
// beast::http::message and beast::http::parser) should
|
|
// be used.
|
|
//
|
|
// NOTE SiteFiles is currently an unused module.
|
|
//
|
|
#if 0
|
|
auto url = beast::parse_URL (urlstr);
|
|
|
|
if (!url.first)
|
|
{
|
|
m_journal.error <<
|
|
"Error parsing '" << urlstr << "'";
|
|
return;
|
|
}
|
|
|
|
auto const result (m_client->get (url.second));
|
|
|
|
boost::system::error_code const error (result.first);
|
|
|
|
if (error)
|
|
{
|
|
m_journal.error <<
|
|
"HTTP GET '" << url.second <<
|
|
"' failed: " << error.message();
|
|
return;
|
|
}
|
|
|
|
beast::HTTPResponse const& response (*result.second);
|
|
|
|
processResponse (url.second, response);
|
|
#endif
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
// Implementation
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
void processResponse (beast::URL const& url, beast::HTTPResponse const& response)
|
|
{
|
|
SharedState::Access state (m_state);
|
|
|
|
std::pair <SiteFiles::iterator, bool> result (
|
|
state->files.emplace (url, 0));
|
|
|
|
if (! result.second)
|
|
{
|
|
m_journal.error <<
|
|
"Duplicate URL '" << url << "' ignored";
|
|
return;
|
|
}
|
|
|
|
SiteFile& siteFile (result.first->second);
|
|
parse (siteFile, response);
|
|
|
|
for (Listeners::iterator iter (state->listeners.begin());
|
|
iter != state->listeners.end(); ++iter)
|
|
{
|
|
Listener* const listener (*iter);
|
|
listener->onSiteFileFetch (to_string (url), siteFile);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
static boost::regex const& reHeader ()
|
|
{
|
|
static boost::regex re (
|
|
"(?:\\v*)" // Line break (optional)
|
|
"(?:\\h*)" // Horizontal whitespace (optional)
|
|
"(?:\\[)" // Open bracket
|
|
"([^\\]]*)" // [1] Everything between the brackets
|
|
"(?:\\])" // Close bracket
|
|
"(?:\\V*)" // Rest of the line
|
|
, boost::regex::perl |
|
|
boost::regex_constants::match_not_null
|
|
);
|
|
|
|
return re;
|
|
}
|
|
|
|
static boost::regex const& reComment ()
|
|
{
|
|
static boost::regex re (
|
|
"(?:\\v)*" // Line break (optional)
|
|
"(?:\\h*)" // Horizontal whitespace (optional)
|
|
"(?:#\\V*)*" // Comment
|
|
"(?:\\v*)" // Line break (optional)
|
|
, boost::regex::perl
|
|
| boost::regex_constants::match_not_null
|
|
);
|
|
|
|
return re;
|
|
}
|
|
|
|
static boost::regex const& reData ()
|
|
{
|
|
static boost::regex re (
|
|
"(?:\\v|\\h)*" // Whitespace
|
|
"(\\V*)" // [1] Rest of the line
|
|
, boost::regex::perl
|
|
| boost::regex_constants::match_not_null
|
|
);
|
|
|
|
return re;
|
|
}
|
|
#else
|
|
|
|
// regex debugger:
|
|
//
|
|
// https://www.debuggex.com/r/jwZFkNrqsouaTPHf
|
|
//
|
|
// (Thanks to J Lynn)
|
|
//
|
|
static boost::regex const& reHeader ()
|
|
{
|
|
static boost::regex re (
|
|
"(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments
|
|
"(?:\\v*)" // Line break (optional)
|
|
"(?:\\h*)" // Horizontal whitespace (optional)
|
|
"(?:\\[)" // Open bracket
|
|
"([^\\]]*)" // [1] Everything between the brackets
|
|
"(?:\\])" // Close bracket
|
|
"(?:\\V*)" // Rest of the line
|
|
"(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments
|
|
, boost::regex::perl
|
|
);
|
|
|
|
return re;
|
|
}
|
|
|
|
static boost::regex const& reData ()
|
|
{
|
|
static boost::regex re (
|
|
"(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments
|
|
"(\\V*)" // [1] Rest of the line
|
|
"(?:\\h*(?:#\\V*)?\\v)*" // Zero or more comments
|
|
, boost::regex::perl
|
|
);
|
|
|
|
return re;
|
|
}
|
|
#endif
|
|
template <typename BidirectionalIterator>
|
|
void parse (
|
|
SiteFile& siteFile,
|
|
BidirectionalIterator start,
|
|
BidirectionalIterator end)
|
|
{
|
|
Section* section (&siteFile.insert (""));
|
|
|
|
boost::match_results <BidirectionalIterator> m;
|
|
for (;start != end;)
|
|
{
|
|
if (boost::regex_search (start, end, m, reHeader(),
|
|
boost::regex_constants::match_continuous))
|
|
{
|
|
std::string const& s (m[1]);
|
|
section = &siteFile.insert (s);
|
|
}
|
|
else
|
|
{
|
|
boost::regex_search (start, end, m, reData(),
|
|
boost::regex_constants::match_continuous);
|
|
|
|
std::string const& s (m[1]);
|
|
section->push_back (s);
|
|
}
|
|
|
|
start = m[0].second;
|
|
}
|
|
}
|
|
|
|
void parse (SiteFile& siteFile, beast::HTTPResponse const& response)
|
|
{
|
|
std::string const s (response.body().to_string());
|
|
parse (siteFile, s.begin(), s.end());
|
|
}
|
|
};
|
|
|
|
}
|
|
}
|
|
|
|
#endif
|