couchbase 3.2.4 → 3.2.5

Sign up to get free protection for your applications and to get access to all the features.
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";