| 178 | } |
| 179 | |
| 180 | static bool rest_headers(const std::any& context, |
| 181 | HTTPRequest* req, |
| 182 | const std::string& uri_part) |
| 183 | { |
| 184 | if (!CheckWarmup(req)) |
| 185 | return false; |
| 186 | std::string param; |
| 187 | const RESTResponseFormat rf = ParseDataFormat(param, uri_part); |
| 188 | std::vector<std::string> path = SplitString(param, '/'); |
| 189 | |
| 190 | std::string raw_count; |
| 191 | std::string hashStr; |
| 192 | if (path.size() == 2) { |
| 193 | // deprecated path: /rest/headers/<count>/<hash> |
| 194 | hashStr = path[1]; |
| 195 | raw_count = path[0]; |
| 196 | } else if (path.size() == 1) { |
| 197 | // new path with query parameter: /rest/headers/<hash>?count=<count> |
| 198 | hashStr = path[0]; |
| 199 | try { |
| 200 | raw_count = req->GetQueryParameter("count").value_or("5"); |
| 201 | } catch (const std::runtime_error& e) { |
| 202 | return RESTERR(req, HTTP_BAD_REQUEST, e.what()); |
| 203 | } |
| 204 | } else { |
| 205 | return RESTERR(req, HTTP_BAD_REQUEST, "Invalid URI format. Expected /rest/headers/<hash>.<ext>?count=<count>"); |
| 206 | } |
| 207 | |
| 208 | const auto parsed_count{ToIntegral<size_t>(raw_count)}; |
| 209 | if (!parsed_count.has_value() || *parsed_count < 1 || *parsed_count > MAX_REST_HEADERS_RESULTS) { |
| 210 | return RESTERR(req, HTTP_BAD_REQUEST, strprintf("Header count is invalid or out of acceptable range (1-%u): %s", MAX_REST_HEADERS_RESULTS, raw_count)); |
| 211 | } |
| 212 | |
| 213 | auto hash{uint256::FromHex(hashStr)}; |
| 214 | if (!hash) { |
| 215 | return RESTERR(req, HTTP_BAD_REQUEST, "Invalid hash: " + hashStr); |
| 216 | } |
| 217 | |
| 218 | const CBlockIndex* tip = nullptr; |
| 219 | std::vector<const CBlockIndex*> headers; |
| 220 | headers.reserve(*parsed_count); |
| 221 | ChainstateManager* maybe_chainman = GetChainman(context, req); |
| 222 | if (!maybe_chainman) return false; |
| 223 | ChainstateManager& chainman = *maybe_chainman; |
| 224 | { |
| 225 | LOCK(cs_main); |
| 226 | CChain& active_chain = chainman.ActiveChain(); |
| 227 | tip = active_chain.Tip(); |
| 228 | const CBlockIndex* pindex{chainman.m_blockman.LookupBlockIndex(*hash)}; |
| 229 | while (pindex != nullptr && active_chain.Contains(*pindex)) { |
| 230 | headers.push_back(pindex); |
| 231 | if (headers.size() == *parsed_count) { |
| 232 | break; |
| 233 | } |
| 234 | pindex = active_chain.Next(*pindex); |
| 235 | } |
| 236 | } |
| 237 |
nothing calls this directly
no test coverage detected