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.role != Role::ADMIN)
52  return rpcError(rpcNO_PERMISSION);
53 
54  // The shard store must be configured
55  auto shardStore{context.app.getShardStore()};
56  if (!shardStore)
57  return rpcError(rpcNOT_ENABLED);
58 
59  // Return status update if already downloading
60  auto preShards{shardStore->getPreShards()};
61  if (!preShards.empty())
62  {
63  std::string s{"Download already in progress. Shard"};
64  if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit))
65  s += "s";
66  return RPC::makeObjectValue(s + " " + preShards);
67  }
68 
69  if (!context.params.isMember(jss::shards))
70  return RPC::missing_field_error(jss::shards);
71  if (!context.params[jss::shards].isArray() ||
72  context.params[jss::shards].size() == 0)
73  {
74  return RPC::expected_field_error(std::string(jss::shards), "an array");
75  }
76 
77  // Validate shards
78  static const std::string ext{".tar.lz4"};
80  for (auto& it : context.params[jss::shards])
81  {
82  // Validate the index
83  if (!it.isMember(jss::index))
84  return RPC::missing_field_error(jss::index);
85  auto& jv{it[jss::index]};
86  if (!(jv.isUInt() || (jv.isInt() && jv.asInt() >= 0)))
87  {
89  std::string(jss::index), "an unsigned integer");
90  }
91 
92  // Validate the URL
93  if (!it.isMember(jss::url))
94  return RPC::missing_field_error(jss::url);
95  parsedURL url;
96  auto unparsedURL = it[jss::url].asString();
97  if (!parseUrl(url, unparsedURL) || url.domain.empty() ||
98  url.path.empty())
99  {
100  return RPC::invalid_field_error(jss::url);
101  }
102  if (url.scheme != "https" && url.scheme != "http")
104  std::string(jss::url), "HTTPS or HTTP");
105 
106  // URL must point to an lz4 compressed tar archive '.tar.lz4'
107  auto archiveName{url.path.substr(url.path.find_last_of("/\\") + 1)};
108  if (archiveName.empty() || archiveName.size() <= ext.size())
109  {
110  return RPC::make_param_error(
111  "Invalid field '" + std::string(jss::url) +
112  "', invalid archive name");
113  }
114  if (!boost::iends_with(archiveName, ext))
115  {
116  return RPC::make_param_error(
117  "Invalid field '" + std::string(jss::url) +
118  "', invalid archive extension");
119  }
120 
121  // Check for duplicate indexes
122  if (!archives
123  .emplace(
124  jv.asUInt(), std::make_pair(std::move(url), unparsedURL))
125  .second)
126  {
127  return RPC::make_param_error(
128  "Invalid field '" + std::string(jss::index) +
129  "', duplicate shard ids.");
130  }
131  }
132 
133  RPC::ShardArchiveHandler* handler = nullptr;
134 
135  try
136  {
137  handler = context.app.getShardArchiveHandler();
138 
139  if (!handler)
140  return RPC::make_error(
141  rpcINTERNAL, "Failed to create ShardArchiveHandler.");
142  }
143  catch (std::exception const& e)
144  {
145  return RPC::make_error(
146  rpcINTERNAL, std::string("Failed to start download: ") + e.what());
147  }
148 
149  for (auto& [index, url] : archives)
150  {
151  if (!handler->add(index, std::move(url)))
152  {
153  return RPC::make_param_error(
154  "Invalid field '" + std::string(jss::index) + "', shard id " +
155  std::to_string(index) + " exists or being acquired");
156  }
157  }
158 
159  // Begin downloading.
160  if (!handler->start())
161  {
162  handler->release();
163  return rpcError(rpcINTERNAL);
164  }
165 
166  std::string s{"Downloading shard"};
167  preShards = shardStore->getPreShards();
168  if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit))
169  s += "s";
170  return RPC::makeObjectValue(s + " " + preShards);
171 }
172 
173 } // 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:256
ripple::doDownloadShard
Json::Value doDownloadShard(RPC::JsonContext &context)
RPC command that downloads and import shard archives.
Definition: DownloadShard.cpp:49
std::exception
STL class.
ripple::RPC::ShardArchiveHandler::add
bool add(std::uint32_t shardIndex, std::pair< parsedURL, std::string > &&url)
Definition: ShardArchiveHandler.cpp:217
ripple::parsedURL
Definition: StringUtilities.h:100
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:109
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:302
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:236
ripple::RPC::ShardArchiveHandler::release
void release()
Definition: ShardArchiveHandler.cpp:308
ripple::Role::ADMIN
@ ADMIN
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::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:29
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:39
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:104
std::make_pair
T make_pair(T... args)
ripple::parsedURL::domain
std::string domain
Definition: StringUtilities.h:107
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:224
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:278
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:202
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