rippled
DownloadShard.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012-2014 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/app/main/Application.h>
21 #include <ripple/basics/BasicConfig.h>
22 #include <ripple/net/RPCErr.h>
23 #include <ripple/nodestore/DatabaseShard.h>
24 #include <ripple/protocol/ErrorCodes.h>
25 #include <ripple/protocol/jss.h>
26 #include <ripple/rpc/Context.h>
27 #include <ripple/rpc/ShardArchiveHandler.h>
28 #include <ripple/rpc/impl/Handler.h>
29 
30 #include <boost/algorithm/string.hpp>
31 
32 namespace ripple {
33 
50 {
51  if (context.app.config().reporting())
53 
54  if (context.role != Role::ADMIN)
55  return rpcError(rpcNO_PERMISSION);
56 
57  // The shard store must be configured
58  auto shardStore{context.app.getShardStore()};
59  if (!shardStore)
60  return rpcError(rpcNOT_ENABLED);
61 
62  // Return status update if already downloading
63  auto preShards{shardStore->getPreShards()};
64  if (!preShards.empty())
65  {
66  std::string s{"Download already in progress. Shard"};
67  if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit))
68  s += "s";
69  return RPC::makeObjectValue(s + " " + preShards);
70  }
71 
72  if (!context.params.isMember(jss::shards))
73  return RPC::missing_field_error(jss::shards);
74  if (!context.params[jss::shards].isArray() ||
75  context.params[jss::shards].size() == 0)
76  {
77  return RPC::expected_field_error(std::string(jss::shards), "an array");
78  }
79 
80  // Validate shards
81  static const std::string ext{".tar.lz4"};
83  for (auto& it : context.params[jss::shards])
84  {
85  // Validate the index
86  if (!it.isMember(jss::index))
87  return RPC::missing_field_error(jss::index);
88  auto& jv{it[jss::index]};
89  if (!(jv.isUInt() || (jv.isInt() && jv.asInt() >= 0)))
90  {
92  std::string(jss::index), "an unsigned integer");
93  }
94 
95  // Validate the URL
96  if (!it.isMember(jss::url))
97  return RPC::missing_field_error(jss::url);
98  parsedURL url;
99  auto unparsedURL = it[jss::url].asString();
100  if (!parseUrl(url, unparsedURL) || url.domain.empty() ||
101  url.path.empty())
102  {
103  return RPC::invalid_field_error(jss::url);
104  }
105  if (url.scheme != "https" && url.scheme != "http")
107  std::string(jss::url), "HTTPS or HTTP");
108 
109  // URL must point to an lz4 compressed tar archive '.tar.lz4'
110  auto archiveName{url.path.substr(url.path.find_last_of("/\\") + 1)};
111  if (archiveName.empty() || archiveName.size() <= ext.size())
112  {
113  return RPC::make_param_error(
114  "Invalid field '" + std::string(jss::url) +
115  "', invalid archive name");
116  }
117  if (!boost::iends_with(archiveName, ext))
118  {
119  return RPC::make_param_error(
120  "Invalid field '" + std::string(jss::url) +
121  "', invalid archive extension");
122  }
123 
124  // Check for duplicate indexes
125  if (!archives
126  .emplace(
127  jv.asUInt(), std::make_pair(std::move(url), unparsedURL))
128  .second)
129  {
130  return RPC::make_param_error(
131  "Invalid field '" + std::string(jss::index) +
132  "', duplicate shard ids.");
133  }
134  }
135 
136  RPC::ShardArchiveHandler* handler = nullptr;
137 
138  try
139  {
140  handler = context.app.getShardArchiveHandler();
141 
142  if (!handler)
143  return RPC::make_error(
144  rpcINTERNAL, "Failed to create ShardArchiveHandler.");
145  }
146  catch (std::exception const& e)
147  {
148  return RPC::make_error(
149  rpcINTERNAL, std::string("Failed to start download: ") + e.what());
150  }
151 
152  for (auto& [index, url] : archives)
153  {
154  if (!handler->add(index, std::move(url)))
155  {
156  return RPC::make_param_error(
157  "Invalid field '" + std::string(jss::index) + "', shard id " +
158  std::to_string(index) + " exists or being acquired");
159  }
160  }
161 
162  // Begin downloading.
163  if (!handler->start())
164  {
165  handler->release();
166  return rpcError(rpcINTERNAL);
167  }
168 
169  std::string s{"Downloading shard"};
170  preShards = shardStore->getPreShards();
171  if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit))
172  s += "s";
173  return RPC::makeObjectValue(s + " " + preShards);
174 }
175 
176 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:53
std::string
STL class.
ripple::RPC::ShardArchiveHandler::start
bool start()
Starts downloading and importing archives.
Definition: ShardArchiveHandler.cpp:236
ripple::doDownloadShard
Json::Value doDownloadShard(RPC::JsonContext &context)
RPC command that downloads and import shard archives.
Definition: DownloadShard.cpp:49
ripple::rpcError
Json::Value rpcError(int iError)
Definition: RPCErr.cpp:29
std::exception
STL class.
ripple::RPC::ShardArchiveHandler::add
bool add(std::uint32_t shardIndex, std::pair< parsedURL, std::string > &&url)
Definition: ShardArchiveHandler.cpp:200
ripple::parsedURL
Definition: StringUtilities.h:116
ripple::Application::getShardStore
virtual NodeStore::DatabaseShard * getShardStore()=0
std::all_of
T all_of(T... args)
ripple::RPC::Context::role
Role role
Definition: Context.h:47
ripple::parsedURL::path
std::string path
Definition: StringUtilities.h:125
ripple::rpcREPORTING_UNSUPPORTED
@ rpcREPORTING_UNSUPPORTED
Definition: ErrorCodes.h:141
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:328
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:262
ripple::Config::reporting
bool reporting() const
Definition: Config.h:337
ripple::RPC::ShardArchiveHandler::release
void release()
Definition: ShardArchiveHandler.cpp:288
ripple::Role::ADMIN
@ ADMIN
ripple::Application::config
virtual Config & config()=0
std::string::find_last_of
T find_last_of(T... args)
std::to_string
T to_string(T... args)
ripple::parseUrl
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
Definition: StringUtilities.cpp:47
ripple::RPC::Context::app
Application & app
Definition: Context.h:42
Json::Value::size
UInt size() const
Number of values in array or object.
Definition: json_value.cpp:706
ripple::rpcNOT_ENABLED
@ rpcNOT_ENABLED
Definition: ErrorCodes.h:59
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:932
std::map
STL class.
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:130
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1015
std::string::substr
T substr(T... args)
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::rpcNO_PERMISSION
@ rpcNO_PERMISSION
Definition: ErrorCodes.h:53
ripple::RPC::ShardArchiveHandler
Handles the download and import of one or more shard archives.
Definition: ShardArchiveHandler.h:42
std::string::empty
T empty(T... args)
ripple::RPC::makeObjectValue
Json::Value makeObjectValue(Value const &value, Json::StaticString const &field=jss::message)
Return a Json::objectValue with a single entry.
Definition: Handler.h:63
ripple::parsedURL::scheme
std::string scheme
Definition: StringUtilities.h:120
std::make_pair
T make_pair(T... args)
ripple::parsedURL::domain
std::string domain
Definition: StringUtilities.h:123
ripple::RPC::make_param_error
Json::Value make_param_error(std::string const &message)
Returns a new json object that indicates invalid parameters.
Definition: ErrorCodes.h:250
ripple::RPC::JsonContext::params
Json::Value params
Definition: Context.h:64
ripple::RPC::invalid_field_error
Json::Value invalid_field_error(std::string const &name)
Definition: ErrorCodes.h:304
ripple::RPC::make_error
Json::Value make_error(error_code_i code)
Returns a new json object that reflects the error code.
Definition: ErrorCodes.cpp:178
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145
ripple::Application::getShardArchiveHandler
virtual RPC::ShardArchiveHandler * getShardArchiveHandler(bool tryRecovery=false)=0