mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Rearrange sources (#4997)
This commit is contained in:
committed by
John Freeman
parent
2e902dee53
commit
e416ee72ca
159
src/libxrpl/server/JSONRPCUtil.cpp
Normal file
159
src/libxrpl/server/JSONRPCUtil.cpp
Normal file
@@ -0,0 +1,159 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
#include <ripple/protocol/BuildInfo.h>
|
||||
#include <ripple/protocol/SystemParameters.h>
|
||||
#include <ripple/protocol/jss.h>
|
||||
#include <ripple/server/impl/JSONRPCUtil.h>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::string
|
||||
getHTTPHeaderTimestamp()
|
||||
{
|
||||
// CHECKME This is probably called often enough that optimizing it makes
|
||||
// sense. There's no point in doing all this work if this function
|
||||
// gets called multiple times a second.
|
||||
char buffer[96];
|
||||
time_t now;
|
||||
time(&now);
|
||||
struct tm now_gmt
|
||||
{
|
||||
};
|
||||
#ifndef _MSC_VER
|
||||
gmtime_r(&now, &now_gmt);
|
||||
#else
|
||||
gmtime_s(&now_gmt, &now);
|
||||
#endif
|
||||
strftime(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"Date: %a, %d %b %Y %H:%M:%S +0000\r\n",
|
||||
&now_gmt);
|
||||
return std::string(buffer);
|
||||
}
|
||||
|
||||
void
|
||||
HTTPReply(
|
||||
int nStatus,
|
||||
std::string const& content,
|
||||
Json::Output const& output,
|
||||
beast::Journal j)
|
||||
{
|
||||
JLOG(j.trace()) << "HTTP Reply " << nStatus << " " << content;
|
||||
|
||||
if (content.empty() && nStatus == 401)
|
||||
{
|
||||
output("HTTP/1.0 401 Authorization Required\r\n");
|
||||
output(getHTTPHeaderTimestamp());
|
||||
|
||||
// CHECKME this returns a different version than the replies below. Is
|
||||
// this by design or an accident or should it be using
|
||||
// BuildInfo::getFullVersionString () as well?
|
||||
output("Server: " + systemName() + "-json-rpc/v1");
|
||||
output("\r\n");
|
||||
|
||||
// Be careful in modifying this! If you change the contents you MUST
|
||||
// update the Content-Length header as well to indicate the correct
|
||||
// size of the data.
|
||||
output(
|
||||
"WWW-Authenticate: Basic realm=\"jsonrpc\"\r\n"
|
||||
"Content-Type: text/html\r\n"
|
||||
"Content-Length: 296\r\n"
|
||||
"\r\n"
|
||||
"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 "
|
||||
"Transitional//EN\"\r\n"
|
||||
"\"http://www.w3.org/TR/1999/REC-html401-19991224/loose.dtd"
|
||||
"\">\r\n"
|
||||
"<HTML>\r\n"
|
||||
"<HEAD>\r\n"
|
||||
"<TITLE>Error</TITLE>\r\n"
|
||||
"<META HTTP-EQUIV='Content-Type' "
|
||||
"CONTENT='text/html; charset=ISO-8859-1'>\r\n"
|
||||
"</HEAD>\r\n"
|
||||
"<BODY><H1>401 Unauthorized.</H1></BODY>\r\n");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (nStatus)
|
||||
{
|
||||
case 200:
|
||||
output("HTTP/1.1 200 OK\r\n");
|
||||
break;
|
||||
case 202:
|
||||
output("HTTP/1.1 202 Accepted\r\n");
|
||||
break;
|
||||
case 400:
|
||||
output("HTTP/1.1 400 Bad Request\r\n");
|
||||
break;
|
||||
case 401:
|
||||
output("HTTP/1.1 401 Authorization Required\r\n");
|
||||
break;
|
||||
case 403:
|
||||
output("HTTP/1.1 403 Forbidden\r\n");
|
||||
break;
|
||||
case 404:
|
||||
output("HTTP/1.1 404 Not Found\r\n");
|
||||
break;
|
||||
case 405:
|
||||
output("HTTP/1.1 405 Method Not Allowed\r\n");
|
||||
break;
|
||||
case 429:
|
||||
output("HTTP/1.1 429 Too Many Requests\r\n");
|
||||
break;
|
||||
case 500:
|
||||
output("HTTP/1.1 500 Internal Server Error\r\n");
|
||||
break;
|
||||
case 501:
|
||||
output("HTTP/1.1 501 Not Implemented\r\n");
|
||||
break;
|
||||
case 503:
|
||||
output("HTTP/1.1 503 Server is overloaded\r\n");
|
||||
break;
|
||||
}
|
||||
|
||||
output(getHTTPHeaderTimestamp());
|
||||
|
||||
output(
|
||||
"Connection: Keep-Alive\r\n"
|
||||
"Content-Length: ");
|
||||
|
||||
// VFALCO TODO Determine if/when this header should be added
|
||||
// if (context.app.config().RPC_ALLOW_REMOTE)
|
||||
// output ("Access-Control-Allow-Origin: *\r\n");
|
||||
|
||||
output(std::to_string(content.size() + 2));
|
||||
output(
|
||||
"\r\n"
|
||||
"Content-Type: application/json; charset=UTF-8\r\n");
|
||||
|
||||
output("Server: " + systemName() + "-json-rpc/");
|
||||
output(BuildInfo::getFullVersionString());
|
||||
output(
|
||||
"\r\n"
|
||||
"\r\n");
|
||||
output(content);
|
||||
output("\r\n");
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
326
src/libxrpl/server/Port.cpp
Normal file
326
src/libxrpl/server/Port.cpp
Normal file
@@ -0,0 +1,326 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/safe_cast.h>
|
||||
#include <ripple/beast/core/LexicalCast.h>
|
||||
#include <ripple/beast/rfc2616.h>
|
||||
#include <ripple/server/Port.h>
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/algorithm/string/trim.hpp>
|
||||
#include <sstream>
|
||||
|
||||
namespace ripple {
|
||||
|
||||
bool
|
||||
Port::secure() const
|
||||
{
|
||||
return protocol.count("peer") > 0 || protocol.count("https") > 0 ||
|
||||
protocol.count("wss") > 0 || protocol.count("wss2") > 0;
|
||||
}
|
||||
|
||||
std::string
|
||||
Port::protocols() const
|
||||
{
|
||||
std::string s;
|
||||
for (auto iter = protocol.cbegin(); iter != protocol.cend(); ++iter)
|
||||
s += (iter != protocol.cbegin() ? "," : "") + *iter;
|
||||
return s;
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<<(std::ostream& os, Port const& p)
|
||||
{
|
||||
os << "'" << p.name << "' (ip=" << p.ip << ":" << p.port << ", ";
|
||||
|
||||
if (p.admin_nets_v4.size() || p.admin_nets_v6.size())
|
||||
{
|
||||
os << "admin nets:";
|
||||
for (auto const& net : p.admin_nets_v4)
|
||||
{
|
||||
os << net.to_string();
|
||||
os << ", ";
|
||||
}
|
||||
for (auto const& net : p.admin_nets_v6)
|
||||
{
|
||||
os << net.to_string();
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
if (p.secure_gateway_nets_v4.size() || p.secure_gateway_nets_v6.size())
|
||||
{
|
||||
os << "secure_gateway nets:";
|
||||
for (auto const& net : p.secure_gateway_nets_v4)
|
||||
{
|
||||
os << net.to_string();
|
||||
os << ", ";
|
||||
}
|
||||
for (auto const& net : p.secure_gateway_nets_v6)
|
||||
{
|
||||
os << net.to_string();
|
||||
os << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
os << p.protocols() << ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
static void
|
||||
populate(
|
||||
Section const& section,
|
||||
std::string const& field,
|
||||
std::ostream& log,
|
||||
std::vector<boost::asio::ip::network_v4>& nets4,
|
||||
std::vector<boost::asio::ip::network_v6>& nets6)
|
||||
{
|
||||
auto const optResult = section.get(field);
|
||||
if (!optResult)
|
||||
return;
|
||||
|
||||
std::stringstream ss(*optResult);
|
||||
std::string ip;
|
||||
|
||||
while (std::getline(ss, ip, ','))
|
||||
{
|
||||
boost::algorithm::trim(ip);
|
||||
bool v4;
|
||||
boost::asio::ip::network_v4 v4Net;
|
||||
boost::asio::ip::network_v6 v6Net;
|
||||
|
||||
try
|
||||
{
|
||||
// First, check to see if 0.0.0.0 or ipv6 equivalent was configured,
|
||||
// which means all IP addresses.
|
||||
auto const addr = beast::IP::Endpoint::from_string_checked(ip);
|
||||
if (addr)
|
||||
{
|
||||
if (is_unspecified(*addr))
|
||||
{
|
||||
nets4.push_back(
|
||||
boost::asio::ip::make_network_v4("0.0.0.0/0"));
|
||||
nets6.push_back(boost::asio::ip::make_network_v6("::/0"));
|
||||
// No reason to allow more IPs--it would be redundant.
|
||||
break;
|
||||
}
|
||||
|
||||
// The configured address is a single IP (or else addr would
|
||||
// be unset). We need this to be a subnet, so append
|
||||
// the number of network bits to make a subnet of 1,
|
||||
// depending on type.
|
||||
v4 = addr->is_v4();
|
||||
std::string addressString = addr->to_string();
|
||||
if (v4)
|
||||
{
|
||||
addressString += "/32";
|
||||
v4Net = boost::asio::ip::make_network_v4(addressString);
|
||||
}
|
||||
else
|
||||
{
|
||||
addressString += "/128";
|
||||
v6Net = boost::asio::ip::make_network_v6(addressString);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Since addr is empty, assume that the entry is
|
||||
// for a subnet which includes trailing /0-32 or /0-128
|
||||
// depending on ip type.
|
||||
// First, see if it's an ipv4 subnet. If not, try ipv6.
|
||||
// If that throws, then there's nothing we can do with
|
||||
// the entry.
|
||||
try
|
||||
{
|
||||
v4Net = boost::asio::ip::make_network_v4(ip);
|
||||
v4 = true;
|
||||
}
|
||||
catch (boost::system::system_error const&)
|
||||
{
|
||||
v6Net = boost::asio::ip::make_network_v6(ip);
|
||||
v4 = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Confirm that the address entry is the same as the subnet's
|
||||
// underlying network address.
|
||||
// 10.1.2.3/24 makes no sense. The underlying network address
|
||||
// is 10.1.2.0/24.
|
||||
if (v4)
|
||||
{
|
||||
if (v4Net != v4Net.canonical())
|
||||
{
|
||||
log << "The configured subnet " << v4Net.to_string()
|
||||
<< " is not the same as the network address, which is "
|
||||
<< v4Net.canonical().to_string();
|
||||
Throw<std::exception>();
|
||||
}
|
||||
nets4.push_back(v4Net);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (v6Net != v6Net.canonical())
|
||||
{
|
||||
log << "The configured subnet " << v6Net.to_string()
|
||||
<< " is not the same as the network address, which is "
|
||||
<< v6Net.canonical().to_string();
|
||||
Throw<std::exception>();
|
||||
}
|
||||
nets6.push_back(v6Net);
|
||||
}
|
||||
}
|
||||
catch (boost::system::system_error const& e)
|
||||
{
|
||||
log << "Invalid value '" << ip << "' for key '" << field << "' in ["
|
||||
<< section.name() << "]: " << e.what();
|
||||
Throw<std::exception>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parse_Port(ParsedPort& port, Section const& section, std::ostream& log)
|
||||
{
|
||||
{
|
||||
auto const optResult = section.get("ip");
|
||||
if (optResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
port.ip = boost::asio::ip::address::from_string(*optResult);
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log << "Invalid value '" << *optResult << "' for key 'ip' in ["
|
||||
<< section.name() << "]";
|
||||
Rethrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const optResult = section.get("port");
|
||||
if (optResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
port.port = beast::lexicalCastThrow<std::uint16_t>(*optResult);
|
||||
|
||||
// Port 0 is not supported
|
||||
if (*port.port == 0)
|
||||
Throw<std::exception>();
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log << "Invalid value '" << *optResult << "' for key "
|
||||
<< "'port' in [" << section.name() << "]";
|
||||
Rethrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const optResult = section.get("protocol");
|
||||
if (optResult)
|
||||
{
|
||||
for (auto const& s : beast::rfc2616::split_commas(
|
||||
optResult->begin(), optResult->end()))
|
||||
port.protocol.insert(s);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const lim = get(section, "limit", "unlimited");
|
||||
|
||||
if (!boost::iequals(lim, "unlimited"))
|
||||
{
|
||||
try
|
||||
{
|
||||
port.limit =
|
||||
safe_cast<int>(beast::lexicalCastThrow<std::uint16_t>(lim));
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log << "Invalid value '" << lim << "' for key "
|
||||
<< "'limit' in [" << section.name() << "]";
|
||||
Rethrow();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto const optResult = section.get("send_queue_limit");
|
||||
if (optResult)
|
||||
{
|
||||
try
|
||||
{
|
||||
port.ws_queue_limit =
|
||||
beast::lexicalCastThrow<std::uint16_t>(*optResult);
|
||||
|
||||
// Queue must be greater than 0
|
||||
if (port.ws_queue_limit == 0)
|
||||
Throw<std::exception>();
|
||||
}
|
||||
catch (std::exception const&)
|
||||
{
|
||||
log << "Invalid value '" << *optResult << "' for key "
|
||||
<< "'send_queue_limit' in [" << section.name() << "]";
|
||||
Rethrow();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Default Websocket send queue size limit
|
||||
port.ws_queue_limit = 100;
|
||||
}
|
||||
}
|
||||
|
||||
populate(section, "admin", log, port.admin_nets_v4, port.admin_nets_v6);
|
||||
populate(
|
||||
section,
|
||||
"secure_gateway",
|
||||
log,
|
||||
port.secure_gateway_nets_v4,
|
||||
port.secure_gateway_nets_v6);
|
||||
|
||||
set(port.user, "user", section);
|
||||
set(port.password, "password", section);
|
||||
set(port.admin_user, "admin_user", section);
|
||||
set(port.admin_password, "admin_password", section);
|
||||
set(port.ssl_key, "ssl_key", section);
|
||||
set(port.ssl_cert, "ssl_cert", section);
|
||||
set(port.ssl_chain, "ssl_chain", section);
|
||||
set(port.ssl_ciphers, "ssl_ciphers", section);
|
||||
|
||||
port.pmd_options.server_enable =
|
||||
section.value_or("permessage_deflate", true);
|
||||
port.pmd_options.client_max_window_bits =
|
||||
section.value_or("client_max_window_bits", 15);
|
||||
port.pmd_options.server_max_window_bits =
|
||||
section.value_or("server_max_window_bits", 15);
|
||||
port.pmd_options.client_no_context_takeover =
|
||||
section.value_or("client_no_context_takeover", false);
|
||||
port.pmd_options.server_no_context_takeover =
|
||||
section.value_or("server_no_context_takeover", false);
|
||||
port.pmd_options.compLevel = section.value_or("compress_level", 8);
|
||||
port.pmd_options.memLevel = section.value_or("memory_level", 4);
|
||||
}
|
||||
|
||||
} // namespace ripple
|
||||
Reference in New Issue
Block a user