1 /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3 *     Copyright 2015 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 
18 #if !defined(SUBDOC_PATH_H) && defined(__cplusplus)
19 #define SUBDOC_PATH_H
20 
21 #include "subdoc-api.h"
22 #include "jsonsl_header.h"
23 #include <string>
24 #include <list>
25 
26 
27 typedef jsonsl_jpr_component_st PathComponent;
28 
29 class PathComponentInfo : public jsonsl_jpr_st {
30 public:
PathComponentInfo(PathComponent *comps = NULL, size_t n = 0)31     PathComponentInfo(PathComponent *comps = NULL, size_t n = 0) {
32         components = comps;
33         ncomponents = n;
34         basestr = NULL;
35         orig = NULL;
36         norig = 0;
37         match_type = 0;
38     }
39 
size() const40     size_t size() const { return ncomponents; }
41 
empty() const42     bool empty() const { return size() == 0; }
43 
operator [](size_t ix) const44     PathComponent& operator[](size_t ix) const { return get_component(ix); }
get_component(size_t ix) const45     PathComponent& get_component(size_t ix) const { return components[ix]; }
back() const46     PathComponent& back() const { return get_component(size()-1); }
47 
48     /**Adds a component (without bounds checking)
49      * @return the newly added component*/
add(jsonsl_jpr_type_t ptype)50     PathComponent& add(jsonsl_jpr_type_t ptype) {
51         PathComponent& ret = get_component(size());
52         ret.ptype = ptype;
53         ncomponents++;
54         return ret;
55     }
56 
pop()57     void pop() {
58         ncomponents--;
59     }
60 
61     typedef PathComponent *iterator;
begin() const62     iterator begin() const { return components; }
end() const63     iterator end() const { return components + size(); }
64 };
65 
66 namespace Subdoc {
67 /**
68  * Path limits:
69  *
70  * Path limits are designed to avoid abuse of the server by making paths too
71  * deep. The jsonsl parser has a fixed limit of depth (adjustable at runtime,
72  * but it is still fixed when allocating it).
73  *
74  * In the context of JSONSL, each JSON document contains an ephemeral "root"
75  * object which is at level 0. The actual top-level object (the list or object)
76  * is considered to be at level 1, and any of its children are considered to be
77  * level 2 and so on. Thus for example
78  *
79  * @code
80  * L0
81  *    L1
82  *    {
83  *       L2
84  *       "foo"
85  *       :
86  *       "bar"
87  *    }
88  * @endcode
89  *
90  * and so on.
91  *
92  * It also follows that a maximum depth of 1 only allows a top level (empty)
93  * object.
94  *
95  */
96 class Limits {
97 public:
98     static const size_t MAX_COMPONENTS = 32;
99     static const size_t PARSER_DEPTH = MAX_COMPONENTS + 1;
100     static const size_t PATH_COMPONENTS_ALLOC = MAX_COMPONENTS + 1;
101 };
102 
103 class Path : public PathComponentInfo {
104 public:
105     typedef PathComponent Component;
106     typedef PathComponentInfo CompInfo;
107 
108     Path();
109     ~Path();
110     void clear();
111     int parse(const char *, size_t);
parse(const char *s)112     int parse(const char *s) { return parse(s, strlen(s)); }
parse(const std::string& s)113     int parse(const std::string& s) { return parse(s.c_str(), s.size()); }
114 
115     Component components_s[Limits::PATH_COMPONENTS_ALLOC];
116     jsonsl_error_t add_array_index(long ixnum);
117     bool has_negix; /* True if there is a negative array index in the path */
118 private:
119     inline const char * convert_escaped(const char *src, size_t &len);
120     inline int add_num_component(const char *component, size_t len);
121     inline int add_str_component(const char *component, size_t len, int n_backtick);
122     inline int parse_bracket(const char *path, size_t len, size_t *n_comsumed);
123     inline int parse_string(const char *path, size_t len, size_t *n_consumed);
124 
125     std::list<std::string*> m_cached;
126     std::list<std::string*> m_used;
127 };
128 }
129 
130 #endif
131