couchbase 3.2.4 → 3.2.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/binding.gyp +5 -0
  2. package/deps/lcb/CMakeLists.txt +1 -1
  3. package/deps/lcb/RELEASE_NOTES.markdown +12 -0
  4. package/deps/lcb/cmake/Modules/GetVersionInfo.cmake +1 -1
  5. package/deps/lcb/doc/Doxyfile +1 -1
  6. package/deps/lcb/gyp_config/common/libcouchbase/configuration.h +3 -3
  7. package/deps/lcb/include/libcouchbase/couchbase.h +52 -0
  8. package/deps/lcb/include/libcouchbase/error.h +4 -1
  9. package/deps/lcb/libcouchbase.gyp +7 -1
  10. package/deps/lcb/src/capi/cmd_counter.hh +12 -0
  11. package/deps/lcb/src/capi/cmd_exists.hh +12 -0
  12. package/deps/lcb/src/capi/cmd_get.hh +12 -0
  13. package/deps/lcb/src/capi/cmd_get_replica.hh +14 -1
  14. package/deps/lcb/src/capi/cmd_query.cc +13 -0
  15. package/deps/lcb/src/capi/cmd_query.hh +22 -14
  16. package/deps/lcb/src/capi/cmd_remove.hh +12 -0
  17. package/deps/lcb/src/capi/cmd_store.hh +12 -0
  18. package/deps/lcb/src/capi/cmd_subdoc.hh +12 -0
  19. package/deps/lcb/src/capi/cmd_touch.hh +12 -0
  20. package/deps/lcb/src/capi/cmd_unlock.hh +12 -0
  21. package/deps/lcb/src/capi/collection_qualifier.hh +4 -6
  22. package/deps/lcb/src/internal.h +2 -1
  23. package/deps/lcb/src/mcserver/negotiate.cc +3 -0
  24. package/deps/lcb/src/n1ql/n1ql.cc +5 -1
  25. package/deps/lcb/src/n1ql/query_handle.cc +55 -30
  26. package/deps/lcb/src/n1ql/query_handle.hh +14 -2
  27. package/deps/lcb/src/operations/counter.cc +12 -0
  28. package/deps/lcb/src/operations/exists.cc +12 -0
  29. package/deps/lcb/src/operations/get.cc +12 -0
  30. package/deps/lcb/src/operations/get_replica.cc +18 -6
  31. package/deps/lcb/src/operations/remove.cc +12 -0
  32. package/deps/lcb/src/operations/store.cc +12 -0
  33. package/deps/lcb/src/operations/subdoc.cc +12 -0
  34. package/deps/lcb/src/operations/touch.cc +12 -0
  35. package/deps/lcb/src/operations/unlock.cc +12 -0
  36. package/deps/lcb/src/search/search_handle.cc +1 -2
  37. package/deps/lcb/src/ssl/ssl_common.c +1 -1
  38. package/deps/lcb/src/utilities.cc +21 -0
  39. package/deps/lcb/src/utilities.h +3 -0
  40. package/deps/lcb/tests/iotests/mock-environment.cc +10 -1
  41. package/deps/lcb/tests/iotests/mock-environment.h +2 -1
  42. package/deps/lcb/tests/iotests/serverparams.h +7 -2
  43. package/deps/lcb/tests/iotests/t_ratelimit.cc +729 -0
  44. package/deps/lcb/tests/iotests/testutil.cc +174 -0
  45. package/deps/lcb/tests/iotests/testutil.h +53 -0
  46. package/dist/analyticsexecutor.js +2 -2
  47. package/dist/analyticsindexmanager.js +3 -3
  48. package/dist/binarycollection.d.ts +17 -0
  49. package/dist/binding.js +1 -1
  50. package/dist/bindingutilities.js +5 -1
  51. package/dist/bucketmanager.d.ts +1 -22
  52. package/dist/bucketmanager.js +5 -5
  53. package/dist/cluster.js +1 -1
  54. package/dist/collection.js +6 -6
  55. package/dist/collectionmanager.js +2 -2
  56. package/dist/connection.js +3 -3
  57. package/dist/connspec.js +5 -1
  58. package/dist/couchbase.js +5 -1
  59. package/dist/httpexecutor.js +5 -1
  60. package/dist/logging.js +1 -1
  61. package/dist/queryexecutor.js +3 -3
  62. package/dist/searchindexmanager.js +1 -1
  63. package/dist/usermanager.js +2 -2
  64. package/dist/utilities.d.ts +1 -2
  65. package/dist/utilities.js +9 -2
  66. package/dist/viewexecutor.js +1 -1
  67. package/package.json +1 -1
  68. package/src/uv-plugin-all.cpp +1 -0
  69. package/dist/cas.d.ts +0 -0
  70. package/dist/cas.js +0 -1
@@ -95,8 +95,8 @@ static void prepare_rowcb(lcb_INSTANCE *instance, int, const lcb_RESPQUERY *row)
95
95
 
96
96
  bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &rc)
97
97
  {
98
- first_error_message.clear();
99
- first_error_code = 0;
98
+ first_error.message.clear();
99
+ first_error.code = 0;
100
100
 
101
101
  Json::Value meta;
102
102
  if (!Json::Reader(Json::Features::strictMode()).parse(row, row + row_len, meta)) {
@@ -105,22 +105,42 @@ bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &
105
105
  const Json::Value &errors = meta["errors"];
106
106
  if (errors.isArray() && !errors.empty()) {
107
107
  const Json::Value &err = errors[0];
108
+ if (err.isMember("retry") && err["retry"].isBool()) {
109
+ first_error.retry = err["retry"].asBool();
110
+ }
111
+ if (err.isMember("reason") && err["reason"].isObject()) {
112
+ const Json::Value &reason = err["reason"];
113
+ if (reason.isMember("code") && reason["code"].isNumeric()) {
114
+ first_error.reason_code = reason["code"].asInt();
115
+ }
116
+ }
108
117
  const Json::Value &msg = err["msg"];
109
118
  if (msg.isString()) {
110
- first_error_message = msg.asString();
119
+ first_error.message = msg.asString();
111
120
  }
112
121
  const Json::Value &code = err["code"];
113
122
  if (code.isNumeric()) {
114
- first_error_code = code.asUInt();
115
- switch (first_error_code) {
123
+ first_error.code = code.asUInt();
124
+ switch (first_error.code) {
116
125
  case 3000:
117
126
  rc = LCB_ERR_PARSING_FAILURE;
118
127
  break;
119
128
  case 12009:
120
129
  rc = LCB_ERR_DML_FAILURE;
121
- if (first_error_message.find("CAS mismatch") != std::string::npos) {
130
+ if (first_error.message.find("CAS mismatch") != std::string::npos) {
122
131
  rc = LCB_ERR_CAS_MISMATCH;
123
132
  }
133
+ switch (first_error.reason_code) {
134
+ case 12033:
135
+ rc = LCB_ERR_CAS_MISMATCH;
136
+ break;
137
+ case 17014:
138
+ rc = LCB_ERR_DOCUMENT_NOT_FOUND;
139
+ break;
140
+ case 17012:
141
+ rc = LCB_ERR_DOCUMENT_EXISTS;
142
+ break;
143
+ }
124
144
  break;
125
145
  case 4040:
126
146
  case 4050:
@@ -132,31 +152,34 @@ bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &
132
152
  break;
133
153
  case 4300:
134
154
  rc = LCB_ERR_PLANNING_FAILURE;
135
- if (!first_error_message.empty()) {
155
+ if (!first_error.message.empty()) {
136
156
  std::regex already_exists("index.+already exists");
137
- if (std::regex_search(first_error_message, already_exists)) {
157
+ if (std::regex_search(first_error.message, already_exists)) {
138
158
  rc = LCB_ERR_INDEX_EXISTS;
139
159
  }
140
160
  }
141
161
  break;
142
162
  case 5000:
143
163
  rc = LCB_ERR_INTERNAL_SERVER_FAILURE;
144
- if (!first_error_message.empty()) {
164
+ if (!first_error.message.empty()) {
145
165
  std::regex already_exists("Index.+already exists"); /* NOTE: case sensitive */
146
166
  std::regex not_found("index.+not found");
147
- if (std::regex_search(first_error_message, already_exists)) {
167
+ if (std::regex_search(first_error.message, already_exists)) {
148
168
  rc = LCB_ERR_INDEX_EXISTS;
149
- } else if (std::regex_search(first_error_message, not_found)) {
169
+ } else if (std::regex_search(first_error.message, not_found)) {
150
170
  rc = LCB_ERR_INDEX_NOT_FOUND;
151
- } else if (first_error_message.find(
171
+ } else if (first_error.message.find(
152
172
  "Limit for number of indexes that can be created per scope has been reached") !=
153
173
  std::string::npos) {
154
174
  rc = LCB_ERR_QUOTA_LIMITED;
155
175
  }
156
176
  }
157
177
  break;
158
- case 12004:
159
178
  case 12016:
179
+ /* see MB-50643 */
180
+ first_error.retry = false;
181
+ /* fallthrough */
182
+ case 12004:
160
183
  rc = LCB_ERR_INDEX_NOT_FOUND;
161
184
  break;
162
185
  case 12003:
@@ -177,14 +200,14 @@ bool lcb_QUERY_HANDLE_::parse_meta(const char *row, size_t row_len, lcb_STATUS &
177
200
  break;
178
201
 
179
202
  default:
180
- if (first_error_code >= 4000 && first_error_code < 5000) {
203
+ if (first_error.code >= 4000 && first_error.code < 5000) {
181
204
  rc = LCB_ERR_PLANNING_FAILURE;
182
- } else if (first_error_code >= 5000 && first_error_code < 6000) {
205
+ } else if (first_error.code >= 5000 && first_error.code < 6000) {
183
206
  rc = LCB_ERR_INTERNAL_SERVER_FAILURE;
184
- } else if (first_error_code >= 10000 && first_error_code < 11000) {
207
+ } else if (first_error.code >= 10000 && first_error.code < 11000) {
185
208
  rc = LCB_ERR_AUTHENTICATION_FAILURE;
186
- } else if ((first_error_code >= 12000 && first_error_code < 13000) ||
187
- (first_error_code >= 14000 && first_error_code < 15000)) {
209
+ } else if ((first_error.code >= 12000 && first_error.code < 13000) ||
210
+ (first_error.code >= 14000 && first_error.code < 15000)) {
188
211
  rc = LCB_ERR_INDEX_FAILURE;
189
212
  }
190
213
  break;
@@ -218,11 +241,13 @@ void lcb_QUERY_HANDLE_::invoke_row(lcb_RESPQUERY *resp, bool is_last)
218
241
  resp->row = static_cast<const char *>(meta_buf.iov_base);
219
242
  resp->nrow = meta_buf.iov_len;
220
243
  parse_meta(resp->row, resp->nrow, resp->ctx.rc);
221
- if (!first_error_message.empty()) {
222
- resp->ctx.first_error_message = first_error_message.c_str();
223
- resp->ctx.first_error_message_len = first_error_message.size();
244
+ resp->ctx.error_response_body = resp->row;
245
+ resp->ctx.error_response_body_len = resp->nrow;
246
+ if (!first_error.message.empty()) {
247
+ resp->ctx.first_error_message = first_error.message.c_str();
248
+ resp->ctx.first_error_message_len = first_error.message.size();
224
249
  }
225
- resp->ctx.first_error_code = first_error_code;
250
+ resp->ctx.first_error_code = first_error.code;
226
251
  if (span_ != nullptr) {
227
252
  lcb::trace::finish_http_span(span_, this);
228
253
  span_ = nullptr;
@@ -358,27 +383,27 @@ lcb_RETRY_ACTION lcb_QUERY_HANDLE_::has_retriable_error(lcb_STATUS &rc)
358
383
  const uint32_t default_backoff = 100 /* ms */;
359
384
  if (rc == LCB_ERR_PREPARED_STATEMENT_FAILURE) {
360
385
  lcb_log(LOGARGS(this, TRACE), LOGFMT "Will retry request. rc: %s, code: %d, msg: %s", LOGID(this),
361
- lcb_strerror_short(rc), first_error_code, first_error_message.c_str());
386
+ lcb_strerror_short(rc), first_error.code, first_error.message.c_str());
362
387
  return {1, default_backoff};
363
388
  }
364
- if (first_error_code == 13014 &&
389
+ if (first_error.code == 13014 &&
365
390
  LCBT_SETTING(instance_, auth)->mode() == LCBAUTH_MODE_DYNAMIC) { // datastore.couchbase.insufficient_credentials
366
391
  auto result = request_credentials(LCBAUTH_REASON_AUTHENTICATION_FAILURE);
367
392
  bool credentials_found = result == LCBAUTH_RESULT_OK;
368
393
  lcb_log(LOGARGS(this, TRACE),
369
394
  LOGFMT "Invalidate credentials and retry request. creds: %s, rc: %s, code: %d, msg: %s", LOGID(this),
370
- credentials_found ? "ok" : "not_found", lcb_strerror_short(rc), first_error_code,
371
- first_error_message.c_str());
395
+ credentials_found ? "ok" : "not_found", lcb_strerror_short(rc), first_error.code,
396
+ first_error.message.c_str());
372
397
  return {credentials_found, default_backoff};
373
398
  }
374
- if (!first_error_message.empty()) {
399
+ if (!first_error.message.empty()) {
375
400
  for (const auto &magic_string : wtf_magic_strings) {
376
- if (first_error_message.find(magic_string) != std::string::npos) {
401
+ if (first_error.message.find(magic_string) != std::string::npos) {
377
402
  lcb_log(LOGARGS(this, TRACE),
378
403
  LOGFMT
379
404
  "Special error message detected. Will retry request. rc: %s (update to %s), code: %d, msg: %s",
380
405
  LOGID(this), lcb_strerror_short(rc), lcb_strerror_short(LCB_ERR_PREPARED_STATEMENT_FAILURE),
381
- first_error_code, first_error_message.c_str());
406
+ first_error.code, first_error.message.c_str());
382
407
  rc = LCB_ERR_PREPARED_STATEMENT_FAILURE;
383
408
  return {1, default_backoff};
384
409
  }
@@ -388,7 +413,7 @@ lcb_RETRY_ACTION lcb_QUERY_HANDLE_::has_retriable_error(lcb_STATUS &rc)
388
413
  if (rc == LCB_SUCCESS) {
389
414
  return {0, 0};
390
415
  }
391
- return lcb_query_should_retry(instance_->settings, this, rc);
416
+ return lcb_query_should_retry(instance_->settings, this, rc, first_error.retry);
392
417
  }
393
418
 
394
419
  lcb_STATUS lcb_QUERY_HANDLE_::issue_htreq(const std::string &body)
@@ -27,6 +27,19 @@
27
27
  #include "capi/cmd_query.hh"
28
28
  #include "query_cache.hh"
29
29
 
30
+ /**
31
+ * @private
32
+ */
33
+ namespace lcb
34
+ {
35
+ struct query_error {
36
+ std::string message{};
37
+ uint32_t code{};
38
+ bool retry{false};
39
+ uint32_t reason_code{0};
40
+ };
41
+ } // namespace lcb
42
+
30
43
  /**
31
44
  * @private
32
45
  */
@@ -296,8 +309,7 @@ struct lcb_QUERY_HANDLE_ : lcb::jsparse::Parser::Actions {
296
309
  /** String of the original statement. Cached here to avoid jsoncpp lookups */
297
310
  std::string statement_;
298
311
  std::string client_context_id_;
299
- std::string first_error_message{};
300
- uint32_t first_error_code{};
312
+ lcb::query_error first_error{};
301
313
 
302
314
  /** Whether we're retrying this */
303
315
  int retries_{0};
@@ -141,6 +141,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdcounter_on_behalf_of(lcb_CMDCOUNTER *cmd, con
141
141
  return cmd->on_behalf_of(std::string(data, data_len));
142
142
  }
143
143
 
144
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdcounter_on_behalf_of_extra_privilege(lcb_CMDCOUNTER *cmd, const char *privilege,
145
+ size_t privilege_len)
146
+ {
147
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
148
+ }
149
+
144
150
  static lcb_STATUS counter_validate(lcb_INSTANCE *instance, const lcb_CMDCOUNTER *cmd)
145
151
  {
146
152
  if (cmd->key().empty()) {
@@ -184,6 +190,12 @@ static lcb_STATUS counter_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_C
184
190
  if (err != LCB_SUCCESS) {
185
191
  return err;
186
192
  }
193
+ for (const auto &privilege : cmd->extra_privileges()) {
194
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
195
+ if (err != LCB_SUCCESS) {
196
+ return err;
197
+ }
198
+ }
187
199
  }
188
200
 
189
201
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -112,6 +112,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdexists_on_behalf_of(lcb_CMDEXISTS *cmd, const
112
112
  return cmd->on_behalf_of(std::string(data, data_len));
113
113
  }
114
114
 
115
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdexists_on_behalf_of_extra_privilege(lcb_CMDEXISTS *cmd, const char *privilege,
116
+ size_t privilege_len)
117
+ {
118
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
119
+ }
120
+
115
121
  static lcb_STATUS exists_validate(lcb_INSTANCE *instance, const lcb_CMDEXISTS *cmd)
116
122
  {
117
123
  if (cmd->key().empty()) {
@@ -139,6 +145,12 @@ static lcb_STATUS exists_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
139
145
  if (err != LCB_SUCCESS) {
140
146
  return err;
141
147
  }
148
+ for (const auto &privilege : cmd->extra_privileges()) {
149
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
150
+ if (err != LCB_SUCCESS) {
151
+ return err;
152
+ }
153
+ }
142
154
  }
143
155
 
144
156
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -129,6 +129,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdget_on_behalf_of(lcb_CMDGET *cmd, const char
129
129
  return cmd->on_behalf_of(std::string(data, data_len));
130
130
  }
131
131
 
132
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdget_on_behalf_of_extra_privilege(lcb_CMDGET *cmd, const char *privilege,
133
+ size_t privilege_len)
134
+ {
135
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
136
+ }
137
+
132
138
  static lcb_STATUS get_validate(lcb_INSTANCE *instance, const lcb_CMDGET *cmd)
133
139
  {
134
140
  if (cmd->key().empty()) {
@@ -159,6 +165,12 @@ static lcb_STATUS get_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMDGE
159
165
  if (err != LCB_SUCCESS) {
160
166
  return err;
161
167
  }
168
+ for (const auto &privilege : cmd->extra_privileges()) {
169
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
170
+ if (err != LCB_SUCCESS) {
171
+ return err;
172
+ }
173
+ }
162
174
  }
163
175
 
164
176
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -144,6 +144,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdgetreplica_on_behalf_of(lcb_CMDGETREPLICA *cm
144
144
  return cmd->on_behalf_of(std::string(data, data_len));
145
145
  }
146
146
 
147
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdgetreplica_on_behalf_of_extra_privilege(lcb_CMDGETREPLICA *cmd,
148
+ const char *privilege, size_t privilege_len)
149
+ {
150
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
151
+ }
152
+
147
153
  struct RGetCookie : mc_REQDATAEX {
148
154
  RGetCookie(void *cookie, lcb_INSTANCE *instance, get_replica_mode, int vb);
149
155
  void decref()
@@ -349,20 +355,26 @@ static lcb_STATUS get_replica_schedule(lcb_INSTANCE *instance, std::shared_ptr<l
349
355
  return LCB_ERR_NO_MATCHING_SERVER;
350
356
  }
351
357
 
352
- /* Initialize the cookie */
353
- auto *rck = new RGetCookie(cmd->cookie(), instance, cmd->mode(), vbid);
354
- rck->start = cmd->start_time_or_default_in_nanoseconds(gethrtime());
355
- rck->deadline =
356
- rck->start + cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
357
-
358
358
  std::vector<std::uint8_t> framing_extras;
359
359
  if (cmd->want_impersonation()) {
360
360
  lcb_STATUS err = lcb::flexible_framing_extras::encode_impersonate_user(cmd->impostor(), framing_extras);
361
361
  if (err != LCB_SUCCESS) {
362
362
  return err;
363
363
  }
364
+ for (const auto &privilege : cmd->extra_privileges()) {
365
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
366
+ if (err != LCB_SUCCESS) {
367
+ return err;
368
+ }
369
+ }
364
370
  }
365
371
 
372
+ /* Initialize the cookie */
373
+ auto *rck = new RGetCookie(cmd->cookie(), instance, cmd->mode(), vbid);
374
+ rck->start = cmd->start_time_or_default_in_nanoseconds(gethrtime());
375
+ rck->deadline =
376
+ rck->start + cmd->timeout_or_default_in_nanoseconds(LCB_US2NS(LCBT_SETTING(instance, operation_timeout)));
377
+
366
378
  /* Initialize the packet */
367
379
  req.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
368
380
  req.request.opcode = PROTOCOL_BINARY_CMD_GET_REPLICA;
@@ -117,6 +117,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdremove_on_behalf_of(lcb_CMDREMOVE *cmd, const
117
117
  return cmd->on_behalf_of(std::string(data, data_len));
118
118
  }
119
119
 
120
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdremove_on_behalf_of_extra_privilege(lcb_CMDREMOVE *cmd, const char *privilege,
121
+ size_t privilege_len)
122
+ {
123
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
124
+ }
125
+
120
126
  static lcb_STATUS remove_validate(lcb_INSTANCE *instance, const lcb_CMDREMOVE *cmd)
121
127
  {
122
128
  if (cmd->key().empty()) {
@@ -159,6 +165,12 @@ static lcb_STATUS remove_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
159
165
  if (err != LCB_SUCCESS) {
160
166
  return err;
161
167
  }
168
+ for (const auto &privilege : cmd->extra_privileges()) {
169
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
170
+ if (err != LCB_SUCCESS) {
171
+ return err;
172
+ }
173
+ }
162
174
  }
163
175
 
164
176
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -234,6 +234,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_on_behalf_of(lcb_CMDSTORE *cmd, const c
234
234
  return cmd->on_behalf_of(std::string(data, data_len));
235
235
  }
236
236
 
237
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdstore_on_behalf_of_extra_privilege(lcb_CMDSTORE *cmd, const char *privilege,
238
+ size_t privilege_len)
239
+ {
240
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
241
+ }
242
+
237
243
  struct DurStoreCtx : mc_REQDATAEX {
238
244
  lcb_INSTANCE *instance;
239
245
  lcb_U16 persist_to;
@@ -400,6 +406,12 @@ static lcb_STATUS store_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMD
400
406
  if (err != LCB_SUCCESS) {
401
407
  return err;
402
408
  }
409
+ for (const auto &privilege : cmd->extra_privileges()) {
410
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
411
+ if (err != LCB_SUCCESS) {
412
+ return err;
413
+ }
414
+ }
403
415
  }
404
416
  auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
405
417
  hdr.request.magic = (ffextlen == 0) ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -409,6 +409,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdsubdoc_on_behalf_of(lcb_CMDSUBDOC *cmd, const
409
409
  return cmd->on_behalf_of(std::string(data, data_len));
410
410
  }
411
411
 
412
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdsubdoc_on_behalf_of_extra_privilege(lcb_CMDSUBDOC *cmd, const char *privilege,
413
+ size_t privilege_len)
414
+ {
415
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
416
+ }
417
+
412
418
  namespace SubdocCmdTraits
413
419
  {
414
420
  enum Options {
@@ -798,6 +804,12 @@ static lcb_STATUS subdoc_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
798
804
  if (rc != LCB_SUCCESS) {
799
805
  return rc;
800
806
  }
807
+ for (const auto &privilege : cmd->extra_privileges()) {
808
+ rc = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
809
+ if (rc != LCB_SUCCESS) {
810
+ return rc;
811
+ }
812
+ }
801
813
  }
802
814
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
803
815
  auto ffextlen = static_cast<std::uint8_t>(framing_extras.size());
@@ -117,6 +117,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdtouch_on_behalf_of(lcb_CMDTOUCH *cmd, const c
117
117
  return cmd->on_behalf_of(std::string(data, data_len));
118
118
  }
119
119
 
120
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdtouch_on_behalf_of_extra_privilege(lcb_CMDTOUCH *cmd, const char *privilege,
121
+ size_t privilege_len)
122
+ {
123
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
124
+ }
125
+
120
126
  static lcb_STATUS touch_validate(lcb_INSTANCE *instance, const lcb_CMDTOUCH *cmd)
121
127
  {
122
128
  if (cmd->key().empty()) {
@@ -142,6 +148,12 @@ static lcb_STATUS touch_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CMD
142
148
  if (err != LCB_SUCCESS) {
143
149
  return err;
144
150
  }
151
+ for (const auto &privilege : cmd->extra_privileges()) {
152
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
153
+ if (err != LCB_SUCCESS) {
154
+ return err;
155
+ }
156
+ }
145
157
  }
146
158
 
147
159
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -106,6 +106,12 @@ LIBCOUCHBASE_API lcb_STATUS lcb_cmdunlock_on_behalf_of(lcb_CMDUNLOCK *cmd, const
106
106
  return cmd->on_behalf_of(std::string(data, data_len));
107
107
  }
108
108
 
109
+ LIBCOUCHBASE_API lcb_STATUS lcb_cmdunlock_on_behalf_of_extra_privilege(lcb_CMDUNLOCK *cmd, const char *privilege,
110
+ size_t privilege_len)
111
+ {
112
+ return cmd->on_behalf_of_add_extra_privilege(std::string(privilege, privilege_len));
113
+ }
114
+
109
115
  static lcb_STATUS unlock_validate(lcb_INSTANCE *instance, const lcb_CMDUNLOCK *cmd)
110
116
  {
111
117
  if (cmd->key().empty()) {
@@ -137,6 +143,12 @@ static lcb_STATUS unlock_schedule(lcb_INSTANCE *instance, std::shared_ptr<lcb_CM
137
143
  if (err != LCB_SUCCESS) {
138
144
  return err;
139
145
  }
146
+ for (const auto &privilege : cmd->extra_privileges()) {
147
+ err = lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(privilege, framing_extras);
148
+ if (err != LCB_SUCCESS) {
149
+ return err;
150
+ }
151
+ }
140
152
  }
141
153
 
142
154
  hdr.request.magic = framing_extras.empty() ? PROTOCOL_BINARY_REQ : PROTOCOL_BINARY_AREQ;
@@ -97,8 +97,7 @@ void lcb_SEARCH_HANDLE_::invoke_row(lcb_RESPSEARCH *resp)
97
97
  } else if (resp->ctx.http_response_code == 400) {
98
98
  if (error_message_.find("not_found") != std::string::npos) {
99
99
  resp->ctx.rc = LCB_ERR_INDEX_NOT_FOUND;
100
- } else if (error_message_.find("CreateIndex, Prepare failed, err: num_fts_indexes") !=
101
- std::string::npos) {
100
+ } else if (error_message_.find("num_fts_indexes") != std::string::npos) {
102
101
  resp->ctx.rc = LCB_ERR_QUOTA_LIMITED;
103
102
  }
104
103
  } else if (resp->ctx.http_response_code == 429) {
@@ -359,7 +359,7 @@ lcbio_pSSLCTX lcbio_ssl_new(const char *tsfile, const char *cafile, const char *
359
359
  }
360
360
  if (cafile && keyfile) {
361
361
  lcb_log(LOGARGS_S(settings, LCB_LOG_DEBUG), "Authenticate with key \"%s\", cert \"%s\"", keyfile, cafile);
362
- if (!SSL_CTX_use_certificate_file(ret->ctx, cafile, SSL_FILETYPE_PEM)) {
362
+ if (!SSL_CTX_use_certificate_chain_file(ret->ctx, cafile)) {
363
363
  *errp = LCB_ERR_SSL_ERROR;
364
364
  goto GT_ERR;
365
365
  }
@@ -214,3 +214,24 @@ lcb_STATUS lcb::flexible_framing_extras::encode_impersonate_user(const std::stri
214
214
  }
215
215
  return LCB_SUCCESS;
216
216
  }
217
+
218
+ lcb_STATUS lcb::flexible_framing_extras::encode_impersonate_users_extra_privilege(
219
+ const std::string &privilege, std::vector<std::uint8_t> &flexible_framing_extras)
220
+ {
221
+ auto privilege_len = privilege.size();
222
+ if (privilege_len > std::numeric_limits<std::uint8_t>::max() + 0xfU) {
223
+ return LCB_ERR_INVALID_ARGUMENT;
224
+ }
225
+ std::uint8_t frame_id = 0x06;
226
+ if (privilege_len < 15) {
227
+ auto frame_size = static_cast<std::uint8_t>(privilege_len);
228
+ flexible_framing_extras.emplace_back(frame_id << 4U | frame_size);
229
+ } else {
230
+ flexible_framing_extras.emplace_back(frame_id << 4U | 0xfU);
231
+ flexible_framing_extras.emplace_back(privilege_len - 0xfU);
232
+ }
233
+ for (const auto byte : privilege) {
234
+ flexible_framing_extras.emplace_back(byte);
235
+ }
236
+ return LCB_SUCCESS;
237
+ }
@@ -29,6 +29,9 @@ namespace lcb
29
29
  namespace flexible_framing_extras
30
30
  {
31
31
  lcb_STATUS encode_impersonate_user(const std::string &username, std::vector<std::uint8_t> &flexible_framing_extras);
32
+
33
+ lcb_STATUS encode_impersonate_users_extra_privilege(const std::string &privilege,
34
+ std::vector<std::uint8_t> &flexible_framing_extras);
32
35
  } // namespace flexible_framing_extras
33
36
  } // namespace lcb
34
37
 
@@ -423,7 +423,16 @@ static void statsCallback(lcb_INSTANCE *instance, lcb_CALLBACK_TYPE, const lcb_R
423
423
  }
424
424
  break;
425
425
  case 7:
426
- version = MockEnvironment::VERSION_70;
426
+ switch (minor) {
427
+ case 0:
428
+ version = MockEnvironment::VERSION_70;
429
+ break;
430
+ case 1:
431
+ version = MockEnvironment::VERSION_71;
432
+ break;
433
+ default:
434
+ break;
435
+ }
427
436
  break;
428
437
  default:
429
438
  break;
@@ -246,7 +246,8 @@ class MockEnvironment : public ::testing::Environment
246
246
  VERSION_60 = 10,
247
247
  VERSION_65 = 11,
248
248
  VERSION_66 = 12,
249
- VERSION_70 = 13
249
+ VERSION_70 = 13,
250
+ VERSION_71 = 14,
250
251
  };
251
252
 
252
253
  void SetUp() override;
@@ -37,10 +37,15 @@ class ServerParams
37
37
  void makeConnectParams(lcb_CREATEOPTS *&crst, lcb_io_opt_t io, lcb_INSTANCE_TYPE type = LCB_TYPE_BUCKET)
38
38
  {
39
39
  lcb_createopts_create(&crst, type);
40
- if (host.find("couchbase://") == 0) {
40
+ if (host.find("couchbase") == 0) {
41
41
  connstr = host;
42
42
  // deactivate dnssrv and compression, use cccp bootstrap
43
- connstr += "?dnssrv=off&bootstrap_on=cccp&compression=off";
43
+ if (host.find("?") == std::string::npos) {
44
+ connstr += "?";
45
+ } else {
46
+ connstr += "&";
47
+ }
48
+ connstr += "dnssrv=off&bootstrap_on=cccp&compression=off";
44
49
  } else {
45
50
  if (mcNodes.empty() || type == LCB_TYPE_CLUSTER) {
46
51
  connstr = "couchbase://" + host + "=http";