1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  *     Copyright 2016 Couchbase, Inc.
4  *
5  *   Licensed under the Apache License, Version 2.0 (the "License");
6  *   you may not use this file except in compliance with the License.
7  *   You may obtain a copy of the License at
8  *
9  *       http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *   Unless required by applicable law or agreed to in writing, software
12  *   distributed under the License is distributed on an "AS IS" BASIS,
13  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *   See the License for the specific language governing permissions and
15  *   limitations under the License.
16  */
17 #pragma once
18 #include "client_connection.h"
19 #include <boost/optional/optional_fwd.hpp>
20 #include <mcbp/protocol/header.h>
21 #include <mcbp/protocol/response.h>
22 #include <memcached/durability_spec.h>
23 #include <nlohmann/json.hpp>
24 #include <platform/sized_buffer.h>
25 #include <unordered_set>
26 
27 class FrameInfo;
28 
29 /**
30  * This is the base class used for binary protocol commands. You probably
31  * want to use one of the subclasses. Do not subclass this class directly,
32  * rather, instantiate/derive from BinprotCommandT or BinprotGenericCommand
33  */
34 class BinprotCommand {
35 public:
36     BinprotCommand() = default;
37 
38     virtual ~BinprotCommand() = default;
39 
40     cb::mcbp::ClientOpcode getOp() const;
41 
42     const std::string& getKey() const;
43 
44     uint64_t getCas() const;
45 
46     virtual void clear();
47 
48     BinprotCommand& setKey(std::string key_);
49 
50     BinprotCommand& setCas(uint64_t cas_);
51 
52     BinprotCommand& setOp(cb::mcbp::ClientOpcode cmd_);
53 
54     BinprotCommand& setVBucket(Vbid vbid);
55 
56     BinprotCommand& setOpaque(uint32_t opaq);
57 
58     /// Add a frame info object to the stream
59     BinprotCommand& addFrameInfo(const FrameInfo& fi);
60 
61     /// Add something you want to put into the frame info section of the
62     /// packet (in the case you want to create illegal frame encodings
63     /// to make sure that the server handle them correctly)
64     BinprotCommand& addFrameInfo(cb::const_byte_buffer section);
65 
66     /**
67      * Encode the command to a buffer.
68      * @param buf The buffer
69      * @note the buffer's contents are _not_ reset, and the encoded command
70      *       is simply appended to it.
71      *
72      * The default implementation is to encode the standard header fields.
73      * The key itself is not added to the buffer.
74      */
75     virtual void encode(std::vector<uint8_t>& buf) const;
76 
77     struct Encoded {
78         /**
79          * 'scratch' space for data which isn't owned by anything and is
80          * generated on demand. Any data here is sent before the data in the
81          * buffers.
82          */
83         std::vector<uint8_t> header;
84 
85         /** The actual buffers to be sent */
86         std::vector<cb::const_byte_buffer> bufs;
87     };
88 
89     /**
90      * Encode data into an 'Encoded' object.
91      * @return an `Encoded` object which may be sent on the wire.
92      *
93      * Note that unlike the vector<uint8_t> variant, the actual buffers
94      * are not copied into the new structure, so ensure the command object
95      * (which owns the buffers), or the original buffers (if the command object
96      * doesn't own the buffers either; see e.g.
97      * BinprotMutationCommand::setValueBuffers()) remain in tact between this
98      * call and actually sending it.
99      *
100      * The default implementation simply copies what encode(vector<uint8_t>)
101      * does into Encoded::header, and Encoded::bufs contains a single
102      * element.
103      */
104     virtual Encoded encode() const;
105 protected:
106     /**
107      * This class exposes a tri-state expiry object, to allow for a 0-value
108      * expiry. This is not used directly by this class, but is used a bit in
109      * subclasses
110      */
111     class ExpiryValue {
112     public:
113         void assign(uint32_t value_);
114         void clear();
115         bool isSet() const;
116         uint32_t getValue() const;
117 
118     private:
119         bool set = false;
120         uint32_t value = 0;
121     };
122 
123     /**
124      * Writes the header to the buffer
125      * @param buf Buffer to write to
126      * @param payload_len Payload length (excluding keylen and extlen)
127      * @param extlen Length of extras
128      */
129     void writeHeader(std::vector<uint8_t>& buf,
130                      size_t payload_len = 0,
131                      size_t extlen = 0) const;
132 
133     cb::mcbp::ClientOpcode opcode = cb::mcbp::ClientOpcode::Invalid;
134     std::string key;
135     uint64_t cas = 0;
136     Vbid vbucket = Vbid(0);
137     uint32_t opaque{0xdeadbeef};
138 
139     /// The frame info sections to inject into the packet
140     std::vector<uint8_t> frame_info;
141 
142 private:
143     /**
144      * Fills the header with the current fields.
145      *
146      * @param[out] header header to write to
147      * @param payload_len length of the "value" of the payload
148      * @param extlen extras length.
149      */
150     void fillHeader(cb::mcbp::Request& header,
151                     size_t payload_len = 0,
152                     size_t extlen = 0) const;
153 };
154 
155 /**
156  * For use with subclasses of @class MemcachedCommand. This installs setter
157  * methods which
158  * return the actual class rather than TestCmd.
159  *
160  * @code{.c++}
161  * class SomeCmd : public MemcachedCommandT<SomeCmd> {
162  *   // ...
163  * };
164  * @endcode
165  *
166  * And therefore allows subclasses to be used like so:
167  *
168  * @code{.c++}
169  * MyCommand cmd;
170  * cmd.setKey("foo").
171  *     setExpiry(300).
172  *     setCas(0xdeadbeef);
173  *
174  * @endcode
175  */
176 template <typename T,
177           cb::mcbp::ClientOpcode OpCode = cb::mcbp::ClientOpcode::Invalid>
178 class BinprotCommandT : public BinprotCommand {
179 public:
BinprotCommandT()180     BinprotCommandT() {
181         setOp(OpCode);
182     }
183 };
184 
185 /**
186  * Convenience class for constructing ad-hoc commands with no special semantics.
187  * Ideally, you should use another class which provides nicer wrapper functions.
188  */
189 class BinprotGenericCommand : public BinprotCommandT<BinprotGenericCommand> {
190 public:
191     BinprotGenericCommand(cb::mcbp::ClientOpcode opcode,
192                           const std::string& key_,
193                           const std::string& value_);
194     BinprotGenericCommand(cb::mcbp::ClientOpcode opcode,
195                           const std::string& key_);
196     BinprotGenericCommand(cb::mcbp::ClientOpcode opcode);
197     BinprotGenericCommand();
198     BinprotGenericCommand& setValue(std::string value_);
199     BinprotGenericCommand& setExtras(const std::vector<uint8_t>& buf);
200 
201     // Use for setting a simple value as an extras
202     template <typename T>
setExtrasValue(T value)203     BinprotGenericCommand& setExtrasValue(T value) {
204         std::vector<uint8_t> buf;
205         buf.resize(sizeof(T));
206         memcpy(buf.data(), &value, sizeof(T));
207         return setExtras(buf);
208     }
209 
210     void clear() override;
211 
212     void encode(std::vector<uint8_t>& buf) const override;
213 
214 protected:
215     std::string value;
216     std::vector<uint8_t> extras;
217 };
218 
219 class BinprotResponse {
220 public:
221     bool isSuccess() const;
222 
223     /** Get the opcode for the response */
224     cb::mcbp::ClientOpcode getOp() const;
225 
226     /** Get the status code for the response */
227     cb::mcbp::Status getStatus() const;
228 
229     size_t getExtlen() const;
230 
231     /** Get the length of packet (minus the header) */
232     size_t getBodylen() const;
233 
234     size_t getFramingExtraslen() const;
235 
236     /**
237      * Get the length of the header. This is a static function as it is
238      * always 24
239      */
240     static size_t getHeaderLen();
241     uint64_t getCas() const;
242     protocol_binary_datatype_t getDatatype() const;
243 
244     /**
245      * Get a pointer to the key returned in the packet, if a key is present.
246      * Use #getKeyLen() to determine this.
247      */
248     cb::const_char_buffer getKey() const;
249 
250     std::string getKeyString() const;
251 
252     /**
253      * Get a pointer to the "data" or "value" part of the response. This is
254      * any payload content _after_ the key and extras (if present
255      */
256     cb::const_byte_buffer getData() const;
257 
258     std::string getDataString() const;
259 
260     const cb::mcbp::Response& getResponse() const;
261 
262     /**
263      * Retrieve the approximate time spent on the server
264      */
265     boost::optional<std::chrono::microseconds> getTracingData() const;
266 
267     /**
268      * Populate this response from a response
269      * @param srcbuf The buffer containing the response.
270      *
271      * The input parameter here is forced to be an rvalue reference because
272      * we don't want careless copying of potentially large payloads.
273      */
274     virtual void assign(std::vector<uint8_t>&& srcbuf);
275 
276     virtual void clear();
277 
278     virtual ~BinprotResponse() = default;
279 
280 protected:
281     const cb::mcbp::Header& getHeader() const;
282     std::vector<uint8_t> payload;
283 };
284 
285 class BinprotSubdocCommand : public BinprotCommandT<BinprotSubdocCommand> {
286 public:
287     BinprotSubdocCommand();
288 
289     explicit BinprotSubdocCommand(cb::mcbp::ClientOpcode cmd_);
290 
291     // Old-style constructors. These are all used by testapp_subdoc.
292     BinprotSubdocCommand(cb::mcbp::ClientOpcode cmd_,
293                          const std::string& key_,
294                          const std::string& path_);
295 
296     BinprotSubdocCommand(
297             cb::mcbp::ClientOpcode cmd,
298             const std::string& key,
299             const std::string& path,
300             const std::string& value,
301             protocol_binary_subdoc_flag flags = SUBDOC_FLAG_NONE,
302             mcbp::subdoc::doc_flag docFlags = mcbp::subdoc::doc_flag::None,
303             uint64_t cas = 0);
304 
305     BinprotSubdocCommand& setPath(std::string path_);
306     BinprotSubdocCommand& setValue(std::string value_);
307     BinprotSubdocCommand& addPathFlags(protocol_binary_subdoc_flag flags_);
308     BinprotSubdocCommand& addDocFlags(mcbp::subdoc::doc_flag flags_);
309     BinprotSubdocCommand& setExpiry(uint32_t value_);
310     const std::string& getPath() const;
311     const std::string& getValue() const;
312     protocol_binary_subdoc_flag getFlags() const;
313 
314     void encode(std::vector<uint8_t>& buf) const override;
315 
316 private:
317     std::string path;
318     std::string value;
319     BinprotCommand::ExpiryValue expiry;
320     protocol_binary_subdoc_flag flags = SUBDOC_FLAG_NONE;
321     mcbp::subdoc::doc_flag doc_flags = mcbp::subdoc::doc_flag::None;
322 };
323 
324 class BinprotSubdocResponse : public BinprotResponse {
325 public:
326     const std::string& getValue() const;
327 
328     void clear() override;
329 
330     void assign(std::vector<uint8_t>&& srcbuf) override;
331 
332     bool operator==(const BinprotSubdocResponse& other) const;
333 
334 private:
335     std::string value;
336 };
337 
338 class BinprotSubdocMultiMutationCommand
339     : public BinprotCommandT<BinprotSubdocMultiMutationCommand,
340                              cb::mcbp::ClientOpcode::SubdocMultiMutation> {
341 public:
342     BinprotSubdocMultiMutationCommand();
343 
344     struct MutationSpecifier {
345         cb::mcbp::ClientOpcode opcode;
346         protocol_binary_subdoc_flag flags;
347         std::string path;
348         std::string value;
349     };
350 
351     BinprotSubdocMultiMutationCommand(
352             std::string key,
353             std::vector<MutationSpecifier> specs,
354             mcbp::subdoc::doc_flag docFlags,
355             const boost::optional<cb::durability::Requirements>& durReqs = {});
356 
357     void encode(std::vector<uint8_t>& buf) const override;
358 
359     BinprotSubdocMultiMutationCommand& addDocFlag(
360             mcbp::subdoc::doc_flag docFlag);
361 
362     BinprotSubdocMultiMutationCommand& addMutation(
363             const MutationSpecifier& spec);
364 
365     BinprotSubdocMultiMutationCommand& addMutation(
366             cb::mcbp::ClientOpcode opcode,
367             protocol_binary_subdoc_flag flags,
368             const std::string& path,
369             const std::string& value);
370 
371     BinprotSubdocMultiMutationCommand& setExpiry(uint32_t expiry_);
372 
373     BinprotSubdocMultiMutationCommand& setDurabilityReqs(
374             const cb::durability::Requirements& durReqs);
375 
376     MutationSpecifier& at(size_t index);
377 
378     MutationSpecifier& operator[](size_t index);
379 
380     bool empty() const;
381 
382     size_t size() const;
383 
384     void clearMutations();
385 
386     void clearDocFlags();
387 
388 protected:
389     std::vector<MutationSpecifier> specs;
390     ExpiryValue expiry;
391     mcbp::subdoc::doc_flag docFlags;
392 };
393 
394 class BinprotSubdocMultiMutationResponse : public BinprotResponse {
395 public:
396     struct MutationResult {
397         uint8_t index;
398         cb::mcbp::Status status;
399         std::string value;
400     };
401 
402     void assign(std::vector<uint8_t>&& buf) override;
403 
404     void clear() override;
405 
406     const std::vector<MutationResult>& getResults() const;
407 
408 protected:
409     std::vector<MutationResult> results;
410 };
411 
412 class BinprotSubdocMultiLookupCommand
413     : public BinprotCommandT<BinprotSubdocMultiLookupCommand,
414                              cb::mcbp::ClientOpcode::SubdocMultiLookup> {
415 public:
416     BinprotSubdocMultiLookupCommand();
417 
418     struct LookupSpecifier {
419         cb::mcbp::ClientOpcode opcode;
420         protocol_binary_subdoc_flag flags;
421         std::string path;
422     };
423 
424     BinprotSubdocMultiLookupCommand(std::string key,
425                                     std::vector<LookupSpecifier> specs,
426                                     mcbp::subdoc::doc_flag docFlags);
427 
428     void encode(std::vector<uint8_t>& buf) const override;
429 
430     BinprotSubdocMultiLookupCommand& addLookup(const LookupSpecifier& spec);
431 
432     BinprotSubdocMultiLookupCommand& addLookup(
433             const std::string& path,
434             cb::mcbp::ClientOpcode opcode = cb::mcbp::ClientOpcode::SubdocGet,
435             protocol_binary_subdoc_flag flags = SUBDOC_FLAG_NONE);
436 
437     BinprotSubdocMultiLookupCommand& addGet(
438             const std::string& path,
439             protocol_binary_subdoc_flag flags = SUBDOC_FLAG_NONE);
440     BinprotSubdocMultiLookupCommand& addExists(
441             const std::string& path,
442             protocol_binary_subdoc_flag flags = SUBDOC_FLAG_NONE);
443     BinprotSubdocMultiLookupCommand& addGetcount(
444             const std::string& path,
445             protocol_binary_subdoc_flag flags = SUBDOC_FLAG_NONE);
446     BinprotSubdocMultiLookupCommand& addDocFlag(mcbp::subdoc::doc_flag docFlag);
447 
448     void clearLookups();
449 
450     LookupSpecifier& at(size_t index);
451 
452     LookupSpecifier& operator[](size_t index);
453 
454     bool empty() const;
455 
456     size_t size() const;
457 
458     void clearDocFlags();
459 
460     /**
461      * This is used for testing only!
462      */
463     BinprotSubdocMultiLookupCommand& setExpiry_Unsupported(uint32_t expiry_);
464 
465 protected:
466     std::vector<LookupSpecifier> specs;
467     ExpiryValue expiry;
468     mcbp::subdoc::doc_flag docFlags;
469 };
470 
471 class BinprotSubdocMultiLookupResponse : public BinprotResponse {
472 public:
473     BinprotSubdocMultiLookupResponse() = default;
474     explicit BinprotSubdocMultiLookupResponse(BinprotResponse&& other);
475 
476     struct LookupResult {
477         cb::mcbp::Status status;
478         std::string value;
479     };
480 
481     const std::vector<LookupResult>& getResults() const;
482 
483     void clear() override;
484 
485     void assign(std::vector<uint8_t>&& srcbuf) override;
486 
487 protected:
488     void decode();
489     std::vector<LookupResult> results;
490 };
491 
492 class BinprotSaslAuthCommand
493     : public BinprotCommandT<BinprotSaslAuthCommand,
494                              cb::mcbp::ClientOpcode::SaslAuth> {
495 public:
496     void setMechanism(const std::string& mech_);
497 
498     void setChallenge(cb::const_char_buffer data);
499 
500     void encode(std::vector<uint8_t>&) const override;
501 
502 private:
503     std::string challenge;
504 };
505 
506 class BinprotSaslStepCommand
507     : public BinprotCommandT<BinprotSaslStepCommand,
508                              cb::mcbp::ClientOpcode::SaslStep> {
509 public:
510     void setMechanism(const std::string& mech);
511 
512     void setChallenge(cb::const_char_buffer data);
513 
514     void encode(std::vector<uint8_t>&) const override;
515 
516 private:
517     std::string challenge;
518 };
519 
520 class BinprotHelloCommand
521     : public BinprotCommandT<BinprotHelloCommand,
522                              cb::mcbp::ClientOpcode::Hello> {
523 public:
524     explicit BinprotHelloCommand(const std::string& client_id);
525     BinprotHelloCommand& enableFeature(cb::mcbp::Feature feature,
526                                        bool enabled = true);
527 
528     void encode(std::vector<uint8_t>& buf) const override;
529 
530 private:
531     std::unordered_set<uint16_t> features;
532 };
533 
534 class BinprotHelloResponse : public BinprotResponse {
535 public:
536     BinprotHelloResponse() = default;
537     explicit BinprotHelloResponse(BinprotResponse&& other);
538 
539     void assign(std::vector<uint8_t>&& buf) override;
540     const std::vector<cb::mcbp::Feature>& getFeatures() const;
541 
542 protected:
543     void decode();
544     std::vector<cb::mcbp::Feature> features;
545 };
546 
547 class BinprotCreateBucketCommand
548     : public BinprotCommandT<BinprotCreateBucketCommand,
549                              cb::mcbp::ClientOpcode::CreateBucket> {
550 public:
551     explicit BinprotCreateBucketCommand(const char* name);
552 
553     void setConfig(const std::string& module, const std::string& config);
554     void encode(std::vector<uint8_t>& buf) const override;
555 
556 private:
557     std::vector<uint8_t> module_config;
558 };
559 
560 class BinprotGetCommand
561     : public BinprotCommandT<BinprotGetCommand, cb::mcbp::ClientOpcode::Get> {
562 public:
563     void encode(std::vector<uint8_t>& buf) const override;
564 };
565 
566 class BinprotGetAndLockCommand
567     : public BinprotCommandT<BinprotGetAndLockCommand,
568                              cb::mcbp::ClientOpcode::GetLocked> {
569 public:
570     BinprotGetAndLockCommand();
571 
572     void encode(std::vector<uint8_t>& buf) const override;
573 
574     BinprotGetAndLockCommand& setLockTimeout(uint32_t timeout);
575 
576 protected:
577     uint32_t lock_timeout;
578 };
579 
580 class BinprotGetAndTouchCommand
581     : public BinprotCommandT<BinprotGetAndTouchCommand,
582                              cb::mcbp::ClientOpcode::Gat> {
583 public:
584     explicit BinprotGetAndTouchCommand(std::string key = {}, uint32_t exp = 0);
585 
586     void encode(std::vector<uint8_t>& buf) const override;
587 
588     bool isQuiet() const;
589 
590     BinprotGetAndTouchCommand& setQuiet(bool quiet = true);
591 
592     BinprotGetAndTouchCommand& setExpirytime(uint32_t timeout);
593 
594 protected:
595     uint32_t expirytime;
596 };
597 
598 class BinprotGetResponse : public BinprotResponse {
599 public:
600     BinprotGetResponse() = default;
BinprotGetResponse(BinprotResponse&& other)601     explicit BinprotGetResponse(BinprotResponse&& other)
602         : BinprotResponse(other) {
603     }
604     uint32_t getDocumentFlags() const;
605 };
606 
607 using BinprotGetAndLockResponse = BinprotGetResponse;
608 using BinprotGetAndTouchResponse = BinprotGetResponse;
609 
610 class BinprotUnlockCommand
611     : public BinprotCommandT<BinprotGetCommand,
612                              cb::mcbp::ClientOpcode::UnlockKey> {
613 public:
614     void encode(std::vector<uint8_t>& buf) const override;
615 };
616 
617 using BinprotUnlockResponse = BinprotResponse;
618 
619 class BinprotTouchCommand
620     : public BinprotCommandT<BinprotGetAndTouchCommand,
621                              cb::mcbp::ClientOpcode::Touch> {
622 public:
623     explicit BinprotTouchCommand(std::string key = {}, uint32_t exp = 0);
624     void encode(std::vector<uint8_t>& buf) const override;
625 
626     BinprotTouchCommand& setExpirytime(uint32_t timeout);
627 
628 protected:
629     uint32_t expirytime = 0;
630 };
631 
632 using BinprotTouchResponse = BinprotResponse;
633 
634 class BinprotGetCmdTimerCommand
635     : public BinprotCommandT<BinprotGetCmdTimerCommand,
636                              cb::mcbp::ClientOpcode::GetCmdTimer> {
637 public:
638     BinprotGetCmdTimerCommand() = default;
639     explicit BinprotGetCmdTimerCommand(cb::mcbp::ClientOpcode opcode);
640     BinprotGetCmdTimerCommand(const std::string& bucket,
641                               cb::mcbp::ClientOpcode opcode);
642 
643     void encode(std::vector<uint8_t>& buf) const override;
644 
645     void setOpcode(cb::mcbp::ClientOpcode opcode);
646 
647     void setBucket(const std::string& bucket);
648 
649 protected:
650     cb::mcbp::ClientOpcode opcode = cb::mcbp::ClientOpcode::Invalid;
651 };
652 
653 class BinprotGetCmdTimerResponse : public BinprotResponse {
654 public:
655     void assign(std::vector<uint8_t>&& buf) override;
656 
657     nlohmann::json getTimings() const;
658 
659 private:
660     nlohmann::json timings;
661 };
662 
663 class BinprotVerbosityCommand
664     : public BinprotCommandT<BinprotVerbosityCommand,
665                              cb::mcbp::ClientOpcode::Verbosity> {
666 public:
667     void encode(std::vector<uint8_t>& buf) const override;
668 
669     void setLevel(int level);
670 
671 protected:
672     int level;
673 };
674 
675 using BinprotVerbosityResponse = BinprotResponse;
676 
677 using BinprotIsaslRefreshCommand =
678         BinprotCommandT<BinprotGenericCommand,
679                         cb::mcbp::ClientOpcode::IsaslRefresh>;
680 
681 using BinprotIsaslRefreshResponse = BinprotResponse;
682 
683 class BinprotMutationCommand : public BinprotCommandT<BinprotMutationCommand> {
684 public:
685     BinprotMutationCommand& setMutationType(MutationType);
686     BinprotMutationCommand& setDocumentInfo(const DocumentInfo& info);
687 
688     BinprotMutationCommand& setValue(std::vector<uint8_t>&& value_);
689 
690     template <typename T>
691     BinprotMutationCommand& setValue(const T& value_);
692 
693     BinprotMutationCommand& addValueBuffer(cb::const_byte_buffer buf);
694 
695     BinprotMutationCommand& setDatatype(uint8_t datatype_);
696     BinprotMutationCommand& setDatatype(cb::mcbp::Datatype datatype_);
697     BinprotMutationCommand& setDocumentFlags(uint32_t flags_);
698     BinprotMutationCommand& setExpiry(uint32_t expiry_);
699 
700     void encode(std::vector<uint8_t>& buf) const override;
701     Encoded encode() const override;
702 
703 private:
704     void encodeHeader(std::vector<uint8_t>& buf) const;
705 
706     /** This contains our copied value (i.e. setValue) */
707     std::vector<uint8_t> value;
708     /** This contains value references (e.g. addValueBuffer/setValueBuffers) */
709     std::vector<cb::const_byte_buffer> value_refs;
710 
711     BinprotCommand::ExpiryValue expiry;
712     uint32_t flags = 0;
713     uint8_t datatype = 0;
714 };
715 
716 class BinprotMutationResponse : public BinprotResponse {
717 public:
718     BinprotMutationResponse() = default;
719     explicit BinprotMutationResponse(BinprotResponse&& other);
720 
721     void assign(std::vector<uint8_t>&& buf) override;
722 
723     const MutationInfo& getMutationInfo() const;
724 
725 protected:
726     void decode();
727     MutationInfo mutation_info;
728 };
729 
730 class BinprotIncrDecrCommand : public BinprotCommandT<BinprotIncrDecrCommand> {
731 public:
732     BinprotIncrDecrCommand& setDelta(uint64_t delta_);
733 
734     BinprotIncrDecrCommand& setInitialValue(uint64_t initial_);
735 
736     BinprotIncrDecrCommand& setExpiry(uint32_t expiry_);
737 
738     void encode(std::vector<uint8_t>& buf) const override;
739 
740 private:
741     uint64_t delta = 0;
742     uint64_t initial = 0;
743     BinprotCommand::ExpiryValue expiry;
744 };
745 
746 class BinprotIncrDecrResponse : public BinprotMutationResponse {
747 public:
748     BinprotIncrDecrResponse() = default;
749     explicit BinprotIncrDecrResponse(BinprotResponse&& other);
750     uint64_t getValue() const;
751 
752     void assign(std::vector<uint8_t>&& buf) override;
753 
754 protected:
755     void decode();
756     uint64_t value = 0;
757 };
758 
759 class BinprotRemoveCommand
760     : public BinprotCommandT<BinprotRemoveCommand,
761                              cb::mcbp::ClientOpcode::Delete> {
762 public:
763     void encode(std::vector<uint8_t>& buf) const override;
764 };
765 
766 using BinprotRemoveResponse = BinprotMutationResponse;
767 
768 class BinprotGetErrorMapCommand
769     : public BinprotCommandT<BinprotGetErrorMapCommand,
770                              cb::mcbp::ClientOpcode::GetErrorMap> {
771 public:
772     void setVersion(uint16_t version_);
773 
774     void encode(std::vector<uint8_t>& buf) const override;
775 private:
776     uint16_t version = 0;
777 };
778 
779 using BinprotGetErrorMapResponse = BinprotResponse;
780 
781 class BinprotDcpOpenCommand : public BinprotGenericCommand {
782 public:
783     /**
784      * DCP Open
785      *
786      * @param name the name of the DCP stream to create
787      * @param seqno_ the sequence number for the stream
788      * @param flags_ the open flags
789      */
790     explicit BinprotDcpOpenCommand(const std::string& name,
791                                    uint32_t seqno_ = 0,
792                                    uint32_t flags_ = 0);
793 
794     void setConsumerName(std::string name);
795 
796     /**
797      * Make this a producer stream
798      *
799      * @return this
800      */
801     BinprotDcpOpenCommand& makeProducer();
802 
803     /**
804      * Make this a consumer stream
805      *
806      * @return this
807      */
808     BinprotDcpOpenCommand& makeConsumer();
809 
810     /**
811      * Let the stream include xattrs (if any)
812      *
813      * @return this
814      */
815     BinprotDcpOpenCommand& makeIncludeXattr();
816 
817     /**
818      * Don't add any values into the stream
819      *
820      * @return this
821      */
822     BinprotDcpOpenCommand& makeNoValue();
823 
824     /**
825      * Set an arbitrary flag value. This may be used in order to test
826      * the sanity checks on the server
827      *
828      * @param flags the raw 32 bit flag section to inject
829      * @return this
830      */
831     BinprotDcpOpenCommand& setFlags(uint32_t flags);
832 
833     void encode(std::vector<uint8_t>& buf) const override;
834 
835 private:
836     uint32_t seqno;
837     uint32_t flags;
838     nlohmann::json payload;
839 };
840 
841 class BinprotDcpStreamRequestCommand : public BinprotGenericCommand {
842 public:
843     BinprotDcpStreamRequestCommand();
844 
845     BinprotDcpStreamRequestCommand& setDcpFlags(uint32_t value);
846 
847     BinprotDcpStreamRequestCommand& setDcpReserved(uint32_t value);
848 
849     BinprotDcpStreamRequestCommand& setDcpStartSeqno(uint64_t value);
850 
851     BinprotDcpStreamRequestCommand& setDcpEndSeqno(uint64_t value);
852 
853     BinprotDcpStreamRequestCommand& setDcpVbucketUuid(uint64_t value);
854 
855     BinprotDcpStreamRequestCommand& setDcpSnapStartSeqno(uint64_t value);
856 
857     BinprotDcpStreamRequestCommand& setDcpSnapEndSeqno(uint64_t value);
858 
859     void encode(std::vector<uint8_t>& buf) const override;
860 
861 private:
862     // The byteorder is fixed when we append the members to the packet
863     uint32_t dcp_flags;
864     uint32_t dcp_reserved;
865     uint64_t dcp_start_seqno;
866     uint64_t dcp_end_seqno;
867     uint64_t dcp_vbucket_uuid;
868     uint64_t dcp_snap_start_seqno;
869     uint64_t dcp_snap_end_seqno;
870 };
871 
872 class BinprotDcpAddStreamCommand : public BinprotGenericCommand {
873 public:
874     explicit BinprotDcpAddStreamCommand(uint32_t flags);
875     void encode(std::vector<uint8_t>& buf) const override;
876 
877 protected:
878     uint32_t flags;
879 };
880 
881 class BinprotGetFailoverLogCommand : public BinprotGenericCommand {
882 public:
BinprotGetFailoverLogCommand()883     BinprotGetFailoverLogCommand()
884         : BinprotGenericCommand(cb::mcbp::ClientOpcode::GetFailoverLog){};
885 };
886 
887 class BinprotSetParamCommand
888     : public BinprotGenericCommand {
889 public:
890     BinprotSetParamCommand(cb::mcbp::request::SetParamPayload::Type type_,
891                            const std::string& key_,
892                            const std::string& value_);
893 
894     void encode(std::vector<uint8_t>& buf) const override;
895 
896 protected:
897     const cb::mcbp::request::SetParamPayload::Type type;
898     const std::string value;
899 };
900 
901 class BinprotSetWithMetaCommand
902     : public BinprotGenericCommand {
903 public:
904     BinprotSetWithMetaCommand(const Document& doc,
905                               Vbid vbucket,
906                               uint64_t operationCas,
907                               uint64_t seqno,
908                               uint32_t options,
909                               std::vector<uint8_t>& meta);
910 
911     BinprotSetWithMetaCommand& setQuiet(bool quiet);
912 
913     uint32_t getFlags() const;
914 
915     BinprotSetWithMetaCommand& setFlags(uint32_t flags);
916 
917     uint32_t getExptime() const;
918 
919     BinprotSetWithMetaCommand& setExptime(uint32_t exptime);
920 
921     uint64_t getSeqno() const;
922 
923     BinprotSetWithMetaCommand& setSeqno(uint64_t seqno);
924 
925     uint64_t getMetaCas() const;
926 
927     BinprotSetWithMetaCommand& setMetaCas(uint64_t cas);
928 
929     const std::vector<uint8_t>& getMeta();
930 
931     BinprotSetWithMetaCommand& setMeta(const std::vector<uint8_t>& meta);
932 
933     void encode(std::vector<uint8_t>& buf) const override;
934 
935 protected:
936     Document doc;
937     uint64_t seqno;
938     uint64_t operationCas;
939     uint32_t options;
940     std::vector<uint8_t> meta;
941 };
942 
943 class BinprotDelWithMetaCommand : public BinprotGenericCommand {
944 public:
945     BinprotDelWithMetaCommand(Document doc,
946                               Vbid vbucket,
947                               uint32_t flags,
948                               uint32_t delete_time,
949                               uint64_t seqno,
950                               uint64_t operationCas,
951                               bool quiet = false);
952 
953     void encode(std::vector<uint8_t>& buf) const override;
954 
955 protected:
956     const Document doc;
957     const uint32_t flags;
958     const uint32_t delete_time;
959     const uint64_t seqno;
960     const uint64_t operationCas;
961 };
962 
963 class BinprotSetControlTokenCommand : public BinprotGenericCommand {
964 public:
965     BinprotSetControlTokenCommand(uint64_t token_, uint64_t oldtoken);
966 
967     void encode(std::vector<uint8_t>& buf) const override;
968 
969 protected:
970     const uint64_t token;
971 };
972 
973 class BinprotSetClusterConfigCommand : public BinprotGenericCommand {
974 public:
975     BinprotSetClusterConfigCommand(uint64_t token_,
976                                    std::string config,
977                                    int revision = -1,
978                                    const std::string& bucket = {});
979 
980     void encode(std::vector<uint8_t>& buf) const override;
981 
982 protected:
983     const std::string config;
984     int revision;
985 };
986 
987 class BinprotObserveSeqnoCommand : public BinprotGenericCommand {
988 public:
989     BinprotObserveSeqnoCommand(Vbid vbid, uint64_t uuid);
990 
991     void encode(std::vector<uint8_t>& buf) const override;
992 
993 private:
994     uint64_t uuid;
995 };
996 
997 class BinprotObserveSeqnoResponse : public BinprotResponse {
998 public:
999     BinprotObserveSeqnoResponse() = default;
1000     explicit BinprotObserveSeqnoResponse(BinprotResponse&& other);
1001     void assign(std::vector<uint8_t>&& buf) override;
1002 
1003     ObserveInfo info;
1004 
1005 protected:
1006     void decode();
1007 };
1008 
1009 class BinprotUpdateUserPermissionsCommand : public BinprotGenericCommand {
1010 public:
1011     BinprotUpdateUserPermissionsCommand(std::string payload);
1012 
1013     void encode(std::vector<uint8_t>& buf) const override;
1014 
1015 protected:
1016     const std::string payload;
1017 };
1018 
1019 using BinprotAuthProviderCommand =
1020         BinprotCommandT<BinprotGenericCommand,
1021                         cb::mcbp::ClientOpcode::AuthProvider>;
1022 
1023 using BinprotRbacRefreshCommand =
1024         BinprotCommandT<BinprotGenericCommand,
1025                         cb::mcbp::ClientOpcode::RbacRefresh>;
1026 
1027 class BinprotAuditPutCommand : public BinprotGenericCommand {
1028 public:
1029     BinprotAuditPutCommand(uint32_t id, std::string payload);
1030 
1031     void encode(std::vector<uint8_t>& buf) const override;
1032 
1033 protected:
1034     const uint32_t id;
1035     const std::string payload;
1036 };
1037 
1038 class BinprotSetVbucketCommand : public BinprotGenericCommand {
1039 public:
1040     BinprotSetVbucketCommand(Vbid vbid,
1041                              vbucket_state_t state,
1042                              nlohmann::json payload);
1043 
1044     void encode(std::vector<uint8_t>& buf) const override;
1045 
1046 protected:
1047     const vbucket_state_t state;
1048     const nlohmann::json payload;
1049 };
1050