xref: /trafficserver/plugins/esi/lib/DocNode.cc (revision 0fb22ae2)
1 /** @file
2 
3   A brief file description
4 
5   @section license License
6 
7   Licensed to the Apache Software Foundation (ASF) under one
8   or more contributor license agreements.  See the NOTICE file
9   distributed with this work for additional information
10   regarding copyright ownership.  The ASF licenses this file
11   to you under the Apache License, Version 2.0 (the
12   "License"); you may not use this file except in compliance
13   with the License.  You may obtain a copy of the License at
14 
15       http://www.apache.org/licenses/LICENSE-2.0
16 
17   Unless required by applicable law or agreed to in writing, software
18   distributed under the License is distributed on an "AS IS" BASIS,
19   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20   See the License for the specific language governing permissions and
21   limitations under the License.
22  */
23 
24 #include "DocNode.h"
25 #include "Utils.h"
26 
27 using std::string;
28 using namespace EsiLib;
29 
30 const char *DocNode::type_names_[] = {"UNKNOWN", "PRE",       "INCLUDE", "COMMENT", "REMOVE", "VARS",         "CHOOSE",
31                                       "WHEN",    "OTHERWISE", "TRY",     "ATTEMPT", "EXCEPT", "HTML_COMMENT", "SPECIAL_INCLUDE"};
32 
33 // helper functions
34 
35 inline void
packString(const char * str,int32_t str_len,string & buffer)36 packString(const char *str, int32_t str_len, string &buffer)
37 {
38   buffer.append(reinterpret_cast<const char *>(&str_len), sizeof(str_len));
39   if (str_len) {
40     buffer.append(str, str_len);
41   }
42 }
43 
44 inline void
unpackString(const char * & packed_data,const char * & item,int32_t & item_len)45 unpackString(const char *&packed_data, const char *&item, int32_t &item_len)
46 {
47   item_len = *(reinterpret_cast<const int32_t *>(packed_data));
48   packed_data += sizeof(int32_t);
49   item = item_len ? packed_data : nullptr;
50   packed_data += item_len;
51 }
52 
53 template <typename T>
54 inline void
unpackItem(const char * & packed_data,T & item)55 unpackItem(const char *&packed_data, T &item)
56 {
57   item = *(reinterpret_cast<const T *>(packed_data));
58   packed_data += sizeof(T);
59 }
60 
61 void
pack(string & buffer) const62 DocNode::pack(string &buffer) const
63 {
64   int32_t orig_buf_size = buffer.size();
65   buffer += DOCNODE_VERSION;
66   buffer.append(sizeof(int32_t), ' '); // reserve space for length
67   buffer.append(reinterpret_cast<const char *>(&type), sizeof(type));
68   packString(data, data_len, buffer);
69   int32_t n_elements = attr_list.size();
70   buffer.append(reinterpret_cast<const char *>(&n_elements), sizeof(n_elements));
71   for (const auto &iter : attr_list) {
72     packString(iter.name, iter.name_len, buffer);
73     packString(iter.value, iter.value_len, buffer);
74   }
75   child_nodes.packToBuffer(buffer);
76   *(reinterpret_cast<int32_t *>(&buffer[orig_buf_size + 1])) = buffer.size() - orig_buf_size;
77 }
78 
79 bool
unpack(const char * packed_data,int packed_data_len,int & node_len)80 DocNode::unpack(const char *packed_data, int packed_data_len, int &node_len)
81 {
82   const char *packed_data_start = packed_data;
83 
84   if (!packed_data || (packed_data_len < static_cast<int>((sizeof(char) + sizeof(int32_t))))) {
85     Utils::ERROR_LOG("[%s] Invalid arguments (%p, %d)", __FUNCTION__, packed_data, packed_data_len);
86     return false;
87   }
88   if (*packed_data != DOCNODE_VERSION) {
89     Utils::ERROR_LOG("[%s] Version %d not in supported set (%d)", __FUNCTION__, static_cast<int>(*packed_data),
90                      static_cast<int>(DOCNODE_VERSION));
91     return false;
92   }
93   ++packed_data;
94 
95   int32_t node_size;
96   unpackItem(packed_data, node_size);
97   if (node_size > packed_data_len) {
98     Utils::ERROR_LOG("[%s] Data size (%d) not sufficient to hold node of size %d", __FUNCTION__, packed_data_len, node_size);
99     return false;
100   }
101   node_len = node_size;
102 
103   unpackItem(packed_data, type);
104 
105   unpackString(packed_data, data, data_len);
106 
107   int32_t n_elements;
108   unpackItem(packed_data, n_elements);
109   Attribute attr;
110   attr_list.clear();
111   for (int i = 0; i < n_elements; ++i) {
112     unpackString(packed_data, attr.name, attr.name_len);
113     unpackString(packed_data, attr.value, attr.value_len);
114     attr_list.push_back(attr);
115   }
116 
117   if (!child_nodes.unpack(packed_data, packed_data_len - (packed_data - packed_data_start))) {
118     Utils::ERROR_LOG("[%s] Could not unpack child nodes", __FUNCTION__);
119     return false;
120   }
121   return true;
122 }
123 
124 void
packToBuffer(string & buffer) const125 DocNodeList::packToBuffer(string &buffer) const
126 {
127   int32_t n_elements = size();
128   buffer.append(reinterpret_cast<const char *>(&n_elements), sizeof(n_elements));
129   for (const auto &iter : *this) {
130     iter.pack(buffer);
131   }
132 }
133 
134 bool
unpack(const char * data,int data_len)135 DocNodeList::unpack(const char *data, int data_len)
136 {
137   if (!data || (data_len < static_cast<int>(sizeof(int32_t)))) {
138     Utils::ERROR_LOG("[%s] Invalid arguments", __FUNCTION__);
139     return false;
140   }
141   const char *data_start = data;
142   int32_t n_elements;
143   unpackItem(data, n_elements);
144   clear();
145   int data_offset = data - data_start, node_size;
146   DocNode node;
147   for (int i = 0; i < n_elements; ++i) {
148     if (!node.unpack(data_start + data_offset, data_len - data_offset, node_size)) {
149       Utils::ERROR_LOG("[%s] Could not unpack node", __FUNCTION__);
150       return false;
151     }
152     data_offset += node_size;
153     push_back(node);
154   }
155   return true;
156 }
157