|
|
@ -89,6 +89,69 @@ static bool ParseHashStr(const string& strReq, uint256& v) |
|
|
|
return true; |
|
|
|
return true; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static bool rest_headers(AcceptedConnection* conn, |
|
|
|
|
|
|
|
string& strReq, |
|
|
|
|
|
|
|
map<string, string>& mapHeaders, |
|
|
|
|
|
|
|
bool fRun) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
vector<string> params; |
|
|
|
|
|
|
|
enum RetFormat rf = ParseDataFormat(params, strReq); |
|
|
|
|
|
|
|
vector<string> path; |
|
|
|
|
|
|
|
boost::split(path, params[0], boost::is_any_of("/")); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (path.size() != 2) |
|
|
|
|
|
|
|
throw RESTERR(HTTP_BAD_REQUEST, "No header count specified. Use /rest/headers/<count>/<hash>.<ext>."); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
long count = strtol(path[0].c_str(), NULL, 10); |
|
|
|
|
|
|
|
if (count < 1 || count > 2000) |
|
|
|
|
|
|
|
throw RESTERR(HTTP_BAD_REQUEST, "Header count out of range: " + path[0]); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string hashStr = path[1]; |
|
|
|
|
|
|
|
uint256 hash; |
|
|
|
|
|
|
|
if (!ParseHashStr(hashStr, hash)) |
|
|
|
|
|
|
|
throw RESTERR(HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<CBlockHeader> headers; |
|
|
|
|
|
|
|
headers.reserve(count); |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
LOCK(cs_main); |
|
|
|
|
|
|
|
BlockMap::const_iterator it = mapBlockIndex.find(hash); |
|
|
|
|
|
|
|
const CBlockIndex *pindex = (it != mapBlockIndex.end()) ? it->second : NULL; |
|
|
|
|
|
|
|
while (pindex != NULL && chainActive.Contains(pindex)) { |
|
|
|
|
|
|
|
headers.push_back(pindex->GetBlockHeader()); |
|
|
|
|
|
|
|
if (headers.size() == (unsigned long)count) |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
pindex = chainActive.Next(pindex); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CDataStream ssHeader(SER_NETWORK, PROTOCOL_VERSION); |
|
|
|
|
|
|
|
BOOST_FOREACH(const CBlockHeader &header, headers) { |
|
|
|
|
|
|
|
ssHeader << header; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (rf) { |
|
|
|
|
|
|
|
case RF_BINARY: { |
|
|
|
|
|
|
|
string binaryHeader = ssHeader.str(); |
|
|
|
|
|
|
|
conn->stream() << HTTPReplyHeader(HTTP_OK, fRun, binaryHeader.size(), "application/octet-stream") << binaryHeader << std::flush; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
case RF_HEX: { |
|
|
|
|
|
|
|
string strHex = HexStr(ssHeader.begin(), ssHeader.end()) + "\n"; |
|
|
|
|
|
|
|
conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush; |
|
|
|
|
|
|
|
return true; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
default: { |
|
|
|
|
|
|
|
throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: .bin, .hex)"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// not reached
|
|
|
|
|
|
|
|
return true; // continue to process further HTTP reqs on this cxn
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static bool rest_block(AcceptedConnection* conn, |
|
|
|
static bool rest_block(AcceptedConnection* conn, |
|
|
|
string& strReq, |
|
|
|
string& strReq, |
|
|
|
map<string, string>& mapHeaders, |
|
|
|
map<string, string>& mapHeaders, |
|
|
@ -224,6 +287,7 @@ static const struct { |
|
|
|
{"/rest/tx/", rest_tx}, |
|
|
|
{"/rest/tx/", rest_tx}, |
|
|
|
{"/rest/block/notxdetails/", rest_block_notxdetails}, |
|
|
|
{"/rest/block/notxdetails/", rest_block_notxdetails}, |
|
|
|
{"/rest/block/", rest_block_extended}, |
|
|
|
{"/rest/block/", rest_block_extended}, |
|
|
|
|
|
|
|
{"/rest/headers/", rest_headers}, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
bool HTTPReq_REST(AcceptedConnection* conn, |
|
|
|
bool HTTPReq_REST(AcceptedConnection* conn, |
|
|
|