1 /*
2  * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 86    ESI processing */
10 
11 #include "squid.h"
12 #include "Debug.h"
13 #include "esi/Segment.h"
14 #include "SquidString.h"
15 
16 CBDATA_CLASS_INIT(ESISegment);
17 
18 void
ESISegmentFreeList(ESISegment::Pointer & head)19 ESISegmentFreeList (ESISegment::Pointer &head)
20 {
21     while (head.getRaw()) {
22         ESISegment::Pointer temp = head;
23         head = head->next;
24         temp->next = NULL;
25     }
26 }
27 
28 size_t
space() const29 ESISegment::space() const
30 {
31     assert (len <= sizeof(buf));
32     return sizeof (buf) - len;
33 }
34 
35 void
adsorbList(ESISegment::Pointer from)36 ESISegment::adsorbList (ESISegment::Pointer from)
37 {
38     assert (next.getRaw() == NULL);
39     assert (from.getRaw() != NULL);
40     /* prevent worst case */
41     assert (!(len == 0 && from->len == space() ));
42     Pointer copyFrom = from;
43 
44     while (copyFrom.getRaw() && space() >= copyFrom->len) {
45         assert (append (copyFrom) == copyFrom->len);
46         copyFrom = copyFrom->next;
47     }
48 
49     next = copyFrom;
50 }
51 
52 void
ListTransfer(ESISegment::Pointer & from,ESISegment::Pointer & to)53 ESISegment::ListTransfer (ESISegment::Pointer &from, ESISegment::Pointer &to)
54 {
55     if (!to.getRaw()) {
56         to = from;
57         from = NULL;
58         return;
59     }
60 
61     ESISegment::Pointer temp = to->tail();
62     temp->adsorbList (from);
63     from = NULL;
64 }
65 
66 size_t
listLength() const67 ESISegment::listLength() const
68 {
69     size_t result = 0;
70     ESISegment const* temp = this;
71 
72     while (temp) {
73         result += temp->len;
74         temp = temp->next.getRaw();
75     }
76 
77     return result;
78 }
79 
80 char *
listToChar() const81 ESISegment::listToChar() const
82 {
83     size_t length = listLength();
84     char *rv = (char *)xmalloc (length + 1);
85     assert (rv);
86     rv [length] = '\0';
87 
88     ESISegment::Pointer temp = this;
89     size_t pos = 0;
90 
91     while (temp.getRaw()) {
92         memcpy(&rv[pos], temp->buf, temp->len);
93         pos += temp->len;
94         temp = temp->next;
95     }
96 
97     return rv;
98 }
99 
100 void
listAppend(char const * s,size_t length)101 ESISegment::listAppend (char const *s, size_t length)
102 {
103     assert (next.getRaw() == NULL);
104     ESISegment::Pointer output = this;
105     /* copy the string to output */
106     size_t pos=0;
107 
108     while (pos < length) {
109         if (output->space() == 0) {
110             assert (output->next.getRaw() == NULL);
111             output->next = new ESISegment;
112             output = output->next;
113         }
114 
115         pos += output->append(s + pos, length - pos);
116     }
117 }
118 
119 void
ListAppend(ESISegment::Pointer & head,char const * s,size_t len)120 ESISegment::ListAppend (ESISegment::Pointer &head, char const *s, size_t len)
121 {
122     if (!head.getRaw())
123         head = new ESISegment;
124 
125     head->tail()->listAppend (s, len);
126 }
127 
128 /* XXX: if needed, make this iterative */
129 ESISegment::Pointer
cloneList() const130 ESISegment::cloneList () const
131 {
132     ESISegment::Pointer result = new ESISegment (*this);
133     result->next = next.getRaw() ? next->cloneList() : NULL;
134     return result;
135 }
136 
137 size_t
append(char const * appendBuffer,size_t appendLength)138 ESISegment::append(char const *appendBuffer, size_t appendLength)
139 {
140     size_t toCopy = min(appendLength, space());
141     memcpy(&buf[len], appendBuffer, toCopy);
142     len += toCopy;
143     return toCopy;
144 }
145 
146 size_t
append(ESISegment::Pointer from)147 ESISegment::append(ESISegment::Pointer from)
148 {
149     return append (from->buf, from->len);
150 }
151 
152 ESISegment const *
tail() const153 ESISegment::tail() const
154 {
155     ESISegment const *result = this;
156 
157     while (result->next.getRaw())
158         result = result->next.getRaw();
159 
160     return result;
161 }
162 
163 ESISegment *
tail()164 ESISegment::tail()
165 {
166     ESISegment::Pointer result = this;
167 
168     while (result->next.getRaw())
169         result = result->next;
170 
171     return result.getRaw();
172 }
173 
ESISegment(ESISegment const & old)174 ESISegment::ESISegment(ESISegment const &old) : len (0), next(NULL)
175 {
176     append (old.buf, old.len);
177 }
178 
179 void
dumpToLog() const180 ESISegment::dumpToLog() const
181 {
182     ESISegment::Pointer temp = this;
183 
184     while (temp.getRaw()) {
185         temp->dumpOne();
186         temp = temp->next;
187     }
188 }
189 
190 void
dumpOne() const191 ESISegment::dumpOne() const
192 {
193     String temp;
194     temp.limitInit(buf, len);
195     debugs(86, 9, "ESISegment::dumpOne: \"" << temp << "\"");
196 }
197 
198