Skip to content

Commit a234878

Browse files
Remove "x-opencmw-method" header and "bodyOverride"
HTTP GET is majordomo Get, HTTP PUT/POST is majordomo Set, GET with "LongPollingIdx" query parameter retrieves cached NOTIFY messages, we don't need more at the moment.
1 parent 33b83b7 commit a234878

File tree

8 files changed

+63
-68
lines changed

8 files changed

+63
-68
lines changed

concepts/client/pre.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ if (typeof XMLHttpRequest === 'undefined') {
4747

4848
// Set the additional headers
4949
res.setHeader('Keep-Alive', 'timeout=5, max=5');
50-
res.setHeader('X-OPENCMW-SERVICE-NAME', 'dns');
51-
res.setHeader('X-OPENCMW-TOPIC', '//s?signal_type=&signal_unit=&signal_name=&service_type=&service_name=&port=-1&hostname=&protocol=&signal_rate=nan&contextType=application%2Foctet-stream');
50+
res.setHeader('x-opencmw-service-name', 'dns');
51+
res.setHeader('x-opencmw-topic', '//s?signal_type=&signal_unit=&signal_name=&service_type=&service_name=&port=-1&hostname=&protocol=&signal_rate=nan&contextType=application%2Foctet-stream');
5252

5353
// Send the binary response
5454
const binaryData = Buffer.from('ffffffff040000005961530001000000602f0da036000000e4010000250000006f70656e636d773a3a736572766963653a3a646e733a3a466c6174456e7472794c69737400ff988e0ac51a000000150000000900000070726f746f636f6c00010000000100000001000000050000006874747000ff335c21ee1a0000002100000009000000686f73746e616d650001000000010000000100000011000000746573742e6578616d706c652e636f6d006881983400160000001000000005000000706f72740001000000010000000100000039050000ffd55573151e000000150000000d000000736572766963655f6e616d6500010000000100000001000000050000007465737400ff846a76151e000000110000000d000000736572766963655f74797065000100000001000000010000000100000000ffc2ad1b281d000000160000000c0000007369676e616c5f6e616d650001000000010000000100000005000000746573743100ffbb0c1f281d000000110000000c0000007369676e616c5f756e69740001000000010000000100000001000000006a17801d281d000000100000000c0000007369676e616c5f726174650001000000010000000100000000007a44ff71c21e281d000000110000000c0000007369676e616c5f74797065000100000001000000010000000100000000fe602f0da03600000000000000250000006f70656e636d773a3a736572766963653a3a646e733a3a466c6174456e7472794c69737400', 'hex');

concepts/majordomo/assets/mustache/ServicesList.mustache

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -96,9 +96,7 @@ input.topicInput { border: 0; width: 100px; border-bottom: 1px solid silver; }
9696
};
9797
9898
listenButton.onclick = () => {
99-
let post = { method: 'GET', headers: { 'x-opencmw-method' : 'POLL' } };
100-
101-
fetch(href + "/" + topicInput.value, post)
99+
fetch(href + "/" + topicInput.value)
102100
.then(response => response.text())
103101
.then(data => {
104102
notificationLabel.innerHTML = data;

concepts/majordomo/assets/mustache/default.mustache

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,14 +174,13 @@
174174
}
175175
176176
function pollingHandler() {
177-
let get = { method: 'GET', headers: { 'x-opencmw-method' : 'POLL' } };
178-
179177
let queryParams = window.opencmwActiveSubscriptionQueryParams;
180178
181179
if (!window.opencmwActiveSubscriptionQueryParams) {
182180
let formMeta = window.opencmwWebForms.replyContextForm;
183181
184182
queryParams = new URLSearchParams();
183+
queryParams.append("LongPollingIdx", "Next");
185184
186185
for (const [key, fieldMeta] of Object.entries(formMeta)) {
187186
const field = document.getElementById(fieldMeta.formId + "_" + fieldMeta.name);
@@ -205,14 +204,14 @@
205204
}
206205
207206
let url = getPageBaseUrl();
208-
url.searchParams.append("LongPollingIdx", "Next");
207+
url.searchParams.set("LongPollingIdx", "Next");
209208
let currentObject = (new URL(document.URL)).pathname;
210-
url.searchParams.append("SubscriptionContext", currentObject + "?" + queryParams.toString());
209+
url.searchParams.set("SubscriptionContext", currentObject + "?" + queryParams.toString());
211210
let address = url.href;
212211
213212
console.log(address);
214213
215-
fetch(address, get)
214+
fetch(address)
216215
.then(response => response.text())
217216
.then(data => {
218217
var checkbox = document.getElementById("subscriptionPollingCheckbox");
@@ -308,12 +307,10 @@
308307
request.send(formData);
309308
310309
} else {
311-
address += '&_bodyOverride=' + JSON.stringify(json);
312310
let post = {
313-
method: 'POST',
314-
headers: { 'Accept' : 'application/json',
315-
'Content-Type': 'application/json',
316-
'X-OPENCMW-METHOD-DIS' : 'SET' },
311+
method: 'POST',
312+
headers: { 'Accept' : 'application/json', 'Content-Type': 'application/json' },
313+
body: JSON.stringify(json),
317314
};
318315
319316
fetch(address, post)

docs/RestUriMapping.md

Lines changed: 7 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -15,23 +15,13 @@ There is no topic in this case.
1515
# Request type specification
1616

1717
The REST backend maps HTTP requests to Majordomo requests.
18-
By default, `PUT` and `POST` HTTP requests are mapped to Majordomo's `Post`,
18+
By default, `PUT` and `POST` HTTP requests are mapped to Majordomo's `Set`,
1919
and `GET` HTTP request is mapped to Majordomo's `Get` request.
2020

21-
It also defines two non-standard HTTP requests -- `SUB`,
22-
which maps to Majordomo's `Subscribe`
23-
and `POLL` which maps to `LongPoll`.
21+
Requests with a query parameter `LongPollingIdx` are treated as `LongPoll` request subscribing to the
22+
given topic (consisting of URI path and other query parameters), with the possible values:
2423

25-
For clients that don't support a custom request operation,
26-
the non-standard HTTP requests can be invoked by defining the
27-
`x-opencmw-method` HTTP header.
28-
29-
If this header is defined, its value is used to override
30-
the HTTP request method.
31-
This means that if HTTP method is `GET` and `x-opencmw-method=POLL`,
32-
that the REST backend will treat it as `LongPoll` request.
33-
34-
Alternatively, one can override the Majordomo method
35-
by setting the `LongPollingIdx` query parameter.
36-
The `Subscription` value of this parameter is mapped to Majordomo's `Subscription` method,
37-
while an integer value will activate the `LongPoll` method.
24+
- `Next`: Redirects to the next notification message that arrives after the request has been processed.
25+
- `Last`: Redirects to the most recent notification message that is in the cache when the request is
26+
processed. If there is no such entry yet, it's treated like `Next`, i.e. waits for the next notification.
27+
- a positive integer value, to retrieve a specific cache entry.

src/client/include/RestClientEmscripten.hpp

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -303,19 +303,18 @@ class RestClient : public ClientBase {
303303
emscripten_fetch_attr_t attr;
304304
emscripten_fetch_attr_init(&attr);
305305

306-
std::string body(cmd.data.asString());
306+
auto payload = std::make_unique<detail::FetchPayload>(std::move(cmd));
307+
attr.userData = payload.get();
307308

308-
if (cmd.command == opencmw::mdp::Command::Set) {
309+
if (payload->command.command == opencmw::mdp::Command::Set) {
309310
strcpy(attr.requestMethod, "POST");
310-
attr.requestData = reinterpret_cast<const char *>(body.data());
311+
auto body = payload->command.data.asString();
312+
attr.requestData = body.data();
311313
attr.requestDataSize = body.size();
312314
} else {
313315
strcpy(attr.requestMethod, "GET");
314316
}
315317

316-
auto payload = std::make_unique<detail::FetchPayload>(std::move(cmd));
317-
attr.userData = payload.get();
318-
detail::fetchPayloads.insert(std::move(payload));
319318
static auto getPayload = [](emscripten_fetch_t *fetch) {
320319
auto *rawPayload = fetch->userData;
321320
auto it = detail::fetchPayloads.find(rawPayload);
@@ -339,8 +338,8 @@ class RestClient : public ClientBase {
339338

340339
// TODO: Pass the payload as POST body: emscripten_fetch(&attr, uri.relativeRef()->data());
341340

342-
const auto uri = URI<>::factory(cmd.topic).addQueryParameter("_bodyOverride", body).build();
343-
emscripten_fetch(&attr, uri.str().data());
341+
emscripten_fetch(&attr, payload->command.topic.str().data());
342+
detail::fetchPayloads.insert(std::move(payload));
344343
}
345344

346345
void startSubscription(Command &&cmd) {

src/client/include/RestClientNative.hpp

Lines changed: 36 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,9 @@ struct SharedQueue {
6363

6464
struct RequestResponse {
6565
// request data
66-
client::Command request;
67-
std::string normalizedTopic;
66+
client::Command request;
67+
std::unique_ptr<IoBuffer> body;
68+
std::string normalizedTopic;
6869

6970
// response data
7071
std::string responseStatus;
@@ -168,11 +169,6 @@ struct ClientSessionBase {
168169
}
169170

170171
void submitRequest(client::Command &&cmd, SubscriptionMode mode, std::string preferredMimeType, std::optional<std::uint64_t> longPollIdx) {
171-
auto topic = cmd.topic;
172-
if (cmd.command == mdp::Command::Set) {
173-
topic = URI<>::UriFactory(topic).addQueryParameter("_bodyOverride", std::string{ cmd.data.asString() }).build();
174-
}
175-
176172
std::string longPollIdxParam;
177173
if (longPollIdx) {
178174
longPollIdxParam = std::to_string(*longPollIdx);
@@ -188,6 +184,8 @@ struct ClientSessionBase {
188184
break;
189185
}
190186
}
187+
188+
auto topic = cmd.topic;
191189
if (!longPollIdxParam.empty()) {
192190
topic = URI<>::UriFactory(topic).addQueryParameter("LongPollingIdx", longPollIdxParam).build();
193191
}
@@ -199,10 +197,13 @@ struct ClientSessionBase {
199197
const auto ts = std::to_string(opencmw::load_test::timestamp().count());
200198
#endif
201199
constexpr uint8_t noCopy = NGHTTP2_NV_FLAG_NO_COPY_NAME | NGHTTP2_NV_FLAG_NO_COPY_VALUE;
200+
201+
const auto method = (cmd.command == mdp::Command::Set) ? u8span("POST") : u8span("GET");
202+
202203
auto headers = std::vector{
203-
nv(u8span(":method"), u8span("GET"), noCopy), //
204-
nv(u8span(":path"), u8span(path)), //
205-
nv(u8span(":scheme"), u8span(scheme)), //
204+
nv(u8span(":method"), method, noCopy), //
205+
nv(u8span(":path"), u8span(path)), //
206+
nv(u8span(":scheme"), u8span(scheme)), //
206207
nv(u8span(":authority"), u8span(host)),
207208
#ifdef OPENCMW_PROFILE_HTTP
208209
nv(u8span("x-timestamp"), u8span(ts))
@@ -212,9 +213,6 @@ struct ClientSessionBase {
212213
headers.push_back(nv(u8span("accept"), u8span(preferredMimeType)));
213214
headers.push_back(nv(u8span("content-type"), u8span(preferredMimeType)));
214215
}
215-
if (cmd.command == mdp::Command::Set) {
216-
headers.push_back(nv(u8span("x-opencmw-method"), u8span("PUT"), noCopy));
217-
}
218216

219217
RequestResponse rr;
220218
rr.request = std::move(cmd);
@@ -224,7 +222,12 @@ struct ClientSessionBase {
224222
rr.normalizedTopic = rr.request.topic.str();
225223
}
226224

227-
const TStreamId streamId = self().submitRequestImpl(headers);
225+
if (!rr.request.data.empty()) {
226+
// we need a pointer that survives rr being moved
227+
rr.body = std::make_unique<IoBuffer>(std::move(rr.request.data));
228+
}
229+
230+
const TStreamId streamId = self().submitRequestImpl(headers, rr.body.get());
228231
if (streamId < 0) {
229232
rr.reportError(std::format("Could not submit request: {}", nghttp2_strerror(streamId)));
230233
return;
@@ -486,8 +489,25 @@ struct Http2ClientSession : public ClientSessionBase<Http2ClientSession, int32_t
486489
return _socket._state == TcpSocket::Connected ? _writeBuffer.wantsToWrite(_session) : (_socket._state == TcpSocket::Connecting || _socket._state == TcpSocket::SSLConnectWantsWrite);
487490
}
488491

489-
int32_t submitRequestImpl(const std::vector<nghttp2_nv> &headers) {
490-
auto streamId = nghttp2_submit_request(_session, nullptr, headers.data(), headers.size(), nullptr, nullptr);
492+
int32_t submitRequestImpl(const std::vector<nghttp2_nv> &headers, IoBuffer *body) {
493+
nghttp2_data_provider2 data_prd;
494+
data_prd.read_callback = nullptr;
495+
496+
if (body && !body->empty()) {
497+
data_prd.source.ptr = body;
498+
data_prd.read_callback = [](nghttp2_session *, int32_t /*stream_id*/, uint8_t *buf, size_t length, uint32_t *data_flags, nghttp2_data_source *source, void * /*user_data*/) {
499+
auto ioBuffer = static_cast<IoBuffer *>(source->ptr);
500+
const std::size_t copy_len = std::min(length, ioBuffer->size() - ioBuffer->position());
501+
std::copy(ioBuffer->data() + ioBuffer->position(), ioBuffer->data() + ioBuffer->position() + copy_len, buf);
502+
ioBuffer->skip(static_cast<int>(copy_len));
503+
if (ioBuffer->position() == ioBuffer->size()) {
504+
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
505+
}
506+
return static_cast<ssize_t>(copy_len);
507+
};
508+
}
509+
510+
auto streamId = nghttp2_submit_request2(_session, nullptr, headers.data(), headers.size(), &data_prd, nullptr);
491511
if (streamId < 0) {
492512
HTTP_DBG("Client::submitRequest: nghttp2_submit_request failed: {}", nghttp2_strerror(streamId));
493513
}

src/client/test/pre.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,8 @@ if (typeof XMLHttpRequest === 'undefined') {
3838
// Set the additional headers
3939
//res.setHeader('Access-Control-Allow-Origin', '127.0.0.1,localhost');
4040
res.setHeader('Keep-Alive', 'timeout=5, max=5');
41-
res.setHeader('X-OPENCMW-SERVICE-NAME', 'dns');
42-
res.setHeader('X-OPENCMW-TOPIC', '//s?signal_type=&signal_unit=&signal_name=&service_type=&service_name=&port=-1&hostname=&protocol=&signal_rate=nan&contextType=application%2Foctet-stream');
41+
res.setHeader('x-opencmw-service-name', 'dns');
42+
res.setHeader('x-opencmw-topic', '//s?signal_type=&signal_unit=&signal_name=&service_type=&service_name=&port=-1&hostname=&protocol=&signal_rate=nan&contextType=application%2Foctet-stream');
4343

4444
// Send the binary response
4545
const binaryData = Buffer.from('ffffffff040000005961530001000000602f0da036000000e4010000250000006f70656e636d773a3a736572766963653a3a646e733a3a466c6174456e7472794c69737400ff988e0ac51a000000150000000900000070726f746f636f6c00010000000100000001000000050000006874747000ff335c21ee1a0000002100000009000000686f73746e616d650001000000010000000100000011000000746573742e6578616d706c652e636f6d006881983400160000001000000005000000706f72740001000000010000000100000039050000ffd55573151e000000150000000d000000736572766963655f6e616d6500010000000100000001000000050000007465737400ff846a76151e000000110000000d000000736572766963655f74797065000100000001000000010000000100000000ffc2ad1b281d000000160000000c0000007369676e616c5f6e616d650001000000010000000100000005000000746573743100ffbb0c1f281d000000110000000c0000007369676e616c5f756e69740001000000010000000100000001000000006a17801d281d000000100000000c0000007369676e616c5f726174650001000000010000000100000000007a44ff71c21e281d000000110000000c0000007369676e616c5f74797065000100000001000000010000000100000000fe602f0da03600000000000000250000006f70656e636d773a3a736572766963653a3a646e733a3a466c6174456e7472794c69737400', 'hex');

src/majordomo/include/majordomo/RestServer.hpp

Lines changed: 1 addition & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,7 @@ enum class RestMethod {
260260

261261
inline RestMethod parseMethod(std::string_view methodString) {
262262
using enum RestMethod;
263-
return methodString == "POLL" ? LongPoll
264-
: methodString == "PUT" ? Post
263+
return methodString == "PUT" ? Post
265264
: methodString == "POST" ? Post
266265
: methodString == "GET" ? Get
267266
: Invalid;
@@ -585,7 +584,6 @@ struct SessionBase {
585584

586585
std::string path;
587586
std::string_view method;
588-
std::string_view xOpencmwMethod;
589587

590588
for (const auto &[name, value] : request.rawHeaders) {
591589
if (name == ":path") {
@@ -596,8 +594,6 @@ struct SessionBase {
596594
request.contentType = value;
597595
} else if (name == "accept") {
598596
request.accept = value;
599-
} else if (name == "x-opencmw-method") {
600-
xOpencmwMethod = value;
601597
}
602598
}
603599

@@ -630,8 +626,6 @@ struct SessionBase {
630626
} else if (qkey == "SubscriptionContext") {
631627
request.topic = mdp::Topic::fromMdpTopic(URI<>(qvalue.value_or("")));
632628
haveSubscriptionContext = true;
633-
} else if (qkey == "_bodyOverride") {
634-
request.payload = qvalue.value_or("");
635629
} else {
636630
if (qvalue) {
637631
factory = std::move(factory).addQueryParameter(qkey, qvalue.value());
@@ -652,9 +646,6 @@ struct SessionBase {
652646
return;
653647
}
654648

655-
if (request.method == RestMethod::Invalid && !xOpencmwMethod.empty()) {
656-
request.method = parseMethod(xOpencmwMethod);
657-
}
658649
if (request.method == RestMethod::Invalid) {
659650
request.method = parseMethod(method);
660651
}

0 commit comments

Comments
 (0)