Skip to content

Commit 8a5c951

Browse files
committed
[REST] make selection of output-format mandatory, support dot url syntax
1. Remove the default format (binary) because `rest/block/<hash>/Hex` would end up delivering binary data. 2. List available formats when chosen format was not found (reduces need for documentation) 3. Change url syntax to dot extension like format chosing (like `rest/tx/<hash>.json`
1 parent 108b19f commit 8a5c951

File tree

1 file changed

+57
-32
lines changed

1 file changed

+57
-32
lines changed

src/rest.cpp

Lines changed: 57 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,24 @@ using namespace std;
1818
using namespace json_spirit;
1919

2020
enum RetFormat {
21+
RF_UNDEF,
2122
RF_BINARY,
2223
RF_HEX,
2324
RF_JSON,
2425
};
2526

2627
static const struct {
2728
enum RetFormat rf;
28-
const char *name;
29+
const char* name;
2930
} rf_names[] = {
30-
{ RF_BINARY, "binary" }, // default, if match not found
31-
{ RF_HEX, "hex" },
32-
{ RF_JSON, "json" },
31+
{RF_UNDEF, ""},
32+
{RF_BINARY, "bin"},
33+
{RF_HEX, "hex"},
34+
{RF_JSON, "json"},
3335
};
3436

35-
class RestErr {
37+
class RestErr
38+
{
3639
public:
3740
enum HTTPStatusCode status;
3841
string message;
@@ -49,15 +52,34 @@ static RestErr RESTERR(enum HTTPStatusCode status, string message)
4952
return re;
5053
}
5154

52-
static enum RetFormat ParseDataFormat(const string& format)
55+
static enum RetFormat ParseDataFormat(vector<string>& params, const string strReq)
5356
{
54-
for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
55-
if (format == rf_names[i].name)
56-
return rf_names[i].rf;
57+
boost::split(params, strReq, boost::is_any_of("."));
58+
if (params.size() > 1) {
59+
for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
60+
if (params[1] == rf_names[i].name)
61+
return rf_names[i].rf;
62+
}
5763

5864
return rf_names[0].rf;
5965
}
6066

67+
static string AvailableDataFormatsString()
68+
{
69+
string formats = "";
70+
for (unsigned int i = 0; i < ARRAYLEN(rf_names); i++)
71+
if (strlen(rf_names[i].name) > 0) {
72+
formats.append(".");
73+
formats.append(rf_names[i].name);
74+
formats.append(", ");
75+
}
76+
77+
if (formats.length() > 0)
78+
return formats.substr(0, formats.length() - 2);
79+
80+
return formats;
81+
}
82+
6183
static bool ParseHashStr(const string& strReq, uint256& v)
6284
{
6385
if (!IsHex(strReq) || (strReq.size() != 64))
@@ -67,15 +89,13 @@ static bool ParseHashStr(const string& strReq, uint256& v)
6789
return true;
6890
}
6991

70-
static bool rest_block(AcceptedConnection *conn,
92+
static bool rest_block(AcceptedConnection* conn,
7193
string& strReq,
7294
map<string, string>& mapHeaders,
7395
bool fRun)
7496
{
7597
vector<string> params;
76-
boost::split(params, strReq, boost::is_any_of("/"));
77-
78-
enum RetFormat rf = ParseDataFormat(params.size() > 1 ? params[1] : string(""));
98+
enum RetFormat rf = ParseDataFormat(params, strReq);
7999

80100
string hashStr = params[0];
81101
uint256 hash;
@@ -105,7 +125,7 @@ static bool rest_block(AcceptedConnection *conn,
105125
}
106126

107127
case RF_HEX: {
108-
string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";;
128+
string strHex = HexStr(ssBlock.begin(), ssBlock.end()) + "\n";
109129
conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
110130
return true;
111131
}
@@ -115,22 +135,24 @@ static bool rest_block(AcceptedConnection *conn,
115135
string strJSON = write_string(Value(objBlock), false) + "\n";
116136
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
117137
return true;
118-
}
138+
}
139+
140+
default: {
141+
throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
142+
}
119143
}
120144

121145
// not reached
122-
return true; // continue to process further HTTP reqs on this cxn
146+
return true; // continue to process further HTTP reqs on this cxn
123147
}
124148

125-
static bool rest_tx(AcceptedConnection *conn,
149+
static bool rest_tx(AcceptedConnection* conn,
126150
string& strReq,
127151
map<string, string>& mapHeaders,
128152
bool fRun)
129153
{
130154
vector<string> params;
131-
boost::split(params, strReq, boost::is_any_of("/"));
132-
133-
enum RetFormat rf = ParseDataFormat(params.size() > 1 ? params[1] : string(""));
155+
enum RetFormat rf = ParseDataFormat(params, strReq);
134156

135157
string hashStr = params[0];
136158
uint256 hash;
@@ -153,7 +175,7 @@ static bool rest_tx(AcceptedConnection *conn,
153175
}
154176

155177
case RF_HEX: {
156-
string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";;
178+
string strHex = HexStr(ssTx.begin(), ssTx.end()) + "\n";
157179
conn->stream() << HTTPReply(HTTP_OK, strHex, fRun, false, "text/plain") << std::flush;
158180
return true;
159181
}
@@ -165,42 +187,45 @@ static bool rest_tx(AcceptedConnection *conn,
165187
conn->stream() << HTTPReply(HTTP_OK, strJSON, fRun) << std::flush;
166188
return true;
167189
}
190+
191+
default: {
192+
throw RESTERR(HTTP_NOT_FOUND, "output format not found (available: " + AvailableDataFormatsString() + ")");
193+
}
168194
}
169195

170196
// not reached
171-
return true; // continue to process further HTTP reqs on this cxn
197+
return true; // continue to process further HTTP reqs on this cxn
172198
}
173199

174200
static const struct {
175-
const char *prefix;
176-
bool (*handler)(AcceptedConnection *conn,
201+
const char* prefix;
202+
bool (*handler)(AcceptedConnection* conn,
177203
string& strURI,
178204
map<string, string>& mapHeaders,
179205
bool fRun);
180206
} uri_prefixes[] = {
181-
{ "/rest/tx/", rest_tx },
182-
{ "/rest/block/", rest_block },
207+
{"/rest/tx/", rest_tx},
208+
{"/rest/block/", rest_block},
183209
};
184210

185-
bool HTTPReq_REST(AcceptedConnection *conn,
211+
bool HTTPReq_REST(AcceptedConnection* conn,
186212
string& strURI,
187213
map<string, string>& mapHeaders,
188214
bool fRun)
189215
{
190216
try {
191217
std::string statusmessage;
192-
if(RPCIsInWarmup(&statusmessage))
193-
throw RESTERR(HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: "+statusmessage);
194-
218+
if (RPCIsInWarmup(&statusmessage))
219+
throw RESTERR(HTTP_SERVICE_UNAVAILABLE, "Service temporarily unavailable: " + statusmessage);
220+
195221
for (unsigned int i = 0; i < ARRAYLEN(uri_prefixes); i++) {
196222
unsigned int plen = strlen(uri_prefixes[i].prefix);
197223
if (strURI.substr(0, plen) == uri_prefixes[i].prefix) {
198224
string strReq = strURI.substr(plen);
199225
return uri_prefixes[i].handler(conn, strReq, mapHeaders, fRun);
200226
}
201227
}
202-
}
203-
catch (RestErr& re) {
228+
} catch (RestErr& re) {
204229
conn->stream() << HTTPReply(re.status, re.message + "\r\n", false, false, "text/plain") << std::flush;
205230
return false;
206231
}

0 commit comments

Comments
 (0)