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 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")
103  return RPC::expected_field_error(std::string(jss::url), "HTTPS");
104 
105  // URL must point to an lz4 compressed tar archive '.tar.lz4'
106  auto archiveName{url.path.substr(url.path.find_last_of("/\\") + 1)};
107  if (archiveName.empty() || archiveName.size() <= ext.size())
108  {
109  return RPC::make_param_error(
110  "Invalid field '" + std::string(jss::url) +
111  "', invalid archive name");
112  }
113  if (!boost::iends_with(archiveName, ext))
114  {
115  return RPC::make_param_error(
116  "Invalid field '" + std::string(jss::url) +
117  "', invalid archive extension");
118  }
119 
120  // Check for duplicate indexes
121  if (!archives
122  .emplace(
123  jv.asUInt(), std::make_pair(std::move(url), unparsedURL))
124  .second)
125  {
126  return RPC::make_param_error(
127  "Invalid field '" + std::string(jss::index) +
128  "', duplicate shard ids.");
129  }
130  }
131 
133 
134  try
135  {
139  context.app, context.app.getJobQueue());
140 
141  if (!handler)
142  return RPC::make_error(
143  rpcINTERNAL, "Failed to create ShardArchiveHandler.");
144 
145  if (!handler->init())
146  return RPC::make_error(
147  rpcINTERNAL, "Failed to initiate ShardArchiveHandler.");
148  }
149  catch (std::exception const& e)
150  {
151  return RPC::make_error(
152  rpcINTERNAL, std::string("Failed to start download: ") + e.what());
153  }
154 
155  for (auto& [index, url] : archives)
156  {
157  if (!handler->add(index, std::move(url)))
158  {
159  return RPC::make_param_error(
160  "Invalid field '" + std::string(jss::index) + "', shard id " +
161  std::to_string(index) + " exists or being acquired");
162  }
163  }
164 
165  // Begin downloading.
166  if (!handler->start())
167  {
168  handler->release();
169  return rpcError(rpcINTERNAL);
170  }
171 
172  std::string s{"Downloading shard"};
173  preShards = shardStore->getPreShards();
174  if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit))
175  s += "s";
176  return RPC::makeObjectValue(s + " " + preShards);
177 }
178 
179 } // namespace ripple
ripple::RPC::JsonContext
Definition: Context.h:52
std::string
STL class.
std::shared_ptr
STL class.
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::parsedURL
Definition: StringUtilities.h:123
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:132
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::Role::ADMIN
@ ADMIN
std::string::find_last_of
T find_last_of(T... args)
std::to_string
T to_string(T... args)
ripple::Application::getJobQueue
virtual JobQueue & getJobQueue()=0
ripple::parseUrl
bool parseUrl(parsedURL &pUrl, std::string const &strUrl)
Definition: StringUtilities.cpp:55
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::hasInstance
static bool hasInstance()
Definition: ShardArchiveHandler.cpp:83
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:127
std::make_pair
T make_pair(T... args)
ripple::parsedURL::domain
std::string domain
Definition: StringUtilities.h:130
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:63
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
ripple::RPC::ShardArchiveHandler::getInstance
static pointer getInstance()
Definition: ShardArchiveHandler.cpp:52
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:145