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/impl/Handler.h>
28 #include <ripple/rpc/ShardArchiveHandler.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  {
75  std::string(jss::shards), "an array");
76  }
77 
78  // Validate shards
79  static const std::string ext {".tar.lz4"};
81  for (auto& it : context.params[jss::shards])
82  {
83  // Validate the index
84  if (!it.isMember(jss::index))
85  return RPC::missing_field_error(jss::index);
86  auto& jv {it[jss::index]};
87  if (!(jv.isUInt() || (jv.isInt() && jv.asInt() >= 0)))
88  {
90  std::string(jss::index), "an unsigned integer");
91  }
92 
93  // Validate the URL
94  if (!it.isMember(jss::url))
95  return RPC::missing_field_error(jss::url);
96  parsedURL url;
97  auto unparsedURL = it[jss::url].asString();
98  if (!parseUrl(url, unparsedURL) ||
99  url.domain.empty() || url.path.empty())
100  {
101  return RPC::invalid_field_error(jss::url);
102  }
103  if (url.scheme != "https")
104  return RPC::expected_field_error(std::string(jss::url), "HTTPS");
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("Invalid field '" +
111  std::string(jss::url) + "', invalid archive name");
112  }
113  if (!boost::iends_with(archiveName, ext))
114  {
115  return RPC::make_param_error("Invalid field '" +
116  std::string(jss::url) + "', invalid archive extension");
117  }
118 
119  // Check for duplicate indexes
120  if (!archives.emplace(jv.asUInt(),
121  std::make_pair(std::move(url), unparsedURL)).second)
122  {
123  return RPC::make_param_error("Invalid field '" +
124  std::string(jss::index) + "', duplicate shard ids.");
125  }
126  }
127 
129 
130  try
131  {
135  context.app,
136  context.app.getJobQueue());
137 
138  if(!handler)
140  "Failed to create ShardArchiveHandler.");
141 
142  if(!handler->init())
144  "Failed to initiate ShardArchiveHandler.");
145  }
146  catch (std::exception const& e)
147  {
149  std::string("Failed to start download: ") +
150  e.what());
151  }
152 
153  for (auto& [index, url] : archives)
154  {
155  if (!handler->add(index, std::move(url)))
156  {
157  return RPC::make_param_error("Invalid field '" +
158  std::string(jss::index) + "', shard id " +
159  std::to_string(index) + " exists or being acquired");
160  }
161  }
162 
163  // Begin downloading.
164  if (!handler->start())
165  {
166  handler->release();
167  return rpcError(rpcINTERNAL);
168  }
169 
170  std::string s {"Downloading shard"};
171  preShards = shardStore->getPreShards();
172  if (!std::all_of(preShards.begin(), preShards.end(), ::isdigit))
173  s += "s";
174  return RPC::makeObjectValue(s + " " + preShards);
175 }
176 
177 } // 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:122
std::map::emplace
T emplace(T... args)
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:131
ripple::RPC::expected_field_error
Json::Value expected_field_error(std::string const &name, std::string const &type)
Definition: ErrorCodes.h:286
ripple::RPC::missing_field_error
Json::Value missing_field_error(std::string const &name)
Definition: ErrorCodes.h:229
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:53
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:720
ripple::rpcNOT_ENABLED
@ rpcNOT_ENABLED
Definition: ErrorCodes.h:60
Json::Value::isMember
bool isMember(const char *key) const
Return true if the object has a member named key.
Definition: json_value.cpp:961
std::map
STL class.
ripple::rpcError
Json::Value rpcError(int iError, Json::Value jvResult)
Definition: RPCErr.cpp:28
ripple::rpcINTERNAL
@ rpcINTERNAL
Definition: ErrorCodes.h:131
Json::Value::isArray
bool isArray() const
Definition: json_value.cpp:1056
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:54
ripple::RPC::ShardArchiveHandler::hasInstance
static bool hasInstance()
Definition: ShardArchiveHandler.cpp:81
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:61
ripple::parsedURL::scheme
std::string scheme
Definition: StringUtilities.h:126
std::make_pair
T make_pair(T... args)
ripple::parsedURL::domain
std::string domain
Definition: StringUtilities.h:129
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:219
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:264
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:182
ripple::RPC::ShardArchiveHandler::getInstance
static pointer getInstance()
Definition: ShardArchiveHandler.cpp:50
std::exception::what
T what(T... args)
Json::Value
Represents a JSON value.
Definition: json_value.h:141