ParsingBuffer.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 1996-2023 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#include "squid.h"
10#include "sbuf/Stream.h"
11#include "SquidMath.h"
12#include "store/ParsingBuffer.h"
13
14#include <iostream>
15
16// Several Store::ParsingBuffer() methods use assert() because the corresponding
17// failure means there is a good chance that somebody have already read from (or
18// written to) the wrong memory location. Since this buffer is used for storing
19// HTTP response bytes, such failures may corrupt traffic. No Assure() handling
20// code can safely recover from such failures.
21
23 readerSuppliedMemory_(initialSpace)
24{
25}
26
28const char *
30{
31 return extraMemory_ ? extraMemory_->rawContent() : readerSuppliedMemory_.data;
32}
33
34size_t
36{
37 return extraMemory_ ? (extraMemory_->length() + extraMemory_->spaceSize()) : readerSuppliedMemory_.length;
38}
39
40size_t
42{
43 return extraMemory_ ? extraMemory_->length() : readerSuppliedMemoryContentSize_;
44}
45
46void
47Store::ParsingBuffer::appended(const char * const newBytes, const size_t newByteCount)
48{
49 // a positive newByteCount guarantees that, after the first assertion below
50 // succeeds, the second assertion will not increment a nil memory() pointer
51 if (!newByteCount)
52 return;
53
54 // these checks order guarantees that memory() is not nil in the second assertion
55 assert(newByteCount <= spaceSize()); // the new bytes end in our space
56 assert(memory() + contentSize() == newBytes); // the new bytes start in our space
57 // and now we know that newBytes is not nil either
58
59 if (extraMemory_)
60 extraMemory_->rawAppendFinish(newBytes, newByteCount);
61 else
62 readerSuppliedMemoryContentSize_ = *IncreaseSum(readerSuppliedMemoryContentSize_, newByteCount);
63
64 assert(contentSize() <= capacity()); // paranoid
65}
66
67void
68Store::ParsingBuffer::consume(const size_t parsedBytes)
69{
70 Assure(contentSize() >= parsedBytes); // more conservative than extraMemory_->consume()
71 if (extraMemory_) {
72 extraMemory_->consume(parsedBytes);
73 } else {
74 readerSuppliedMemoryContentSize_ -= parsedBytes;
75 if (parsedBytes && readerSuppliedMemoryContentSize_)
76 memmove(readerSuppliedMemory_.data, memory() + parsedBytes, readerSuppliedMemoryContentSize_);
77 }
78}
79
82{
83 const auto size = spaceSize();
84 const auto start = extraMemory_ ?
85 extraMemory_->rawAppendStart(size) :
86 (readerSuppliedMemory_.data + readerSuppliedMemoryContentSize_);
87 return StoreIOBuffer(spaceSize(), 0, start);
88}
89
91Store::ParsingBuffer::makeSpace(const size_t pageSize)
92{
93 growSpace(pageSize);
94 auto result = space();
95 Assure(result.length >= pageSize);
96 result.length = pageSize;
97 return result;
98}
99
102{
103 // This const_cast is a StoreIOBuffer API limitation: That class does not
104 // support a "constant content view", even though it is used as such a view.
105 return StoreIOBuffer(contentSize(), 0, const_cast<char*>(memory()));
106}
107
109void
110Store::ParsingBuffer::growSpace(const size_t minimumSpaceSize)
111{
112 const auto capacityIncreaseAttempt = IncreaseSum(contentSize(), minimumSpaceSize);
113 if (!capacityIncreaseAttempt)
114 throw TextException(ToSBuf("no support for a single memory block of ", contentSize(), '+', minimumSpaceSize, " bytes"), Here());
115 const auto newCapacity = *capacityIncreaseAttempt;
116
117 if (newCapacity <= capacity())
118 return; // already have enough space; no reallocation is needed
119
120 debugs(90, 7, "growing to provide " << minimumSpaceSize << " in " << *this);
121
122 if (extraMemory_) {
123 extraMemory_->reserveCapacity(newCapacity);
124 } else {
125 SBuf newStorage;
126 newStorage.reserveCapacity(newCapacity);
127 newStorage.append(readerSuppliedMemory_.data, readerSuppliedMemoryContentSize_);
128 extraMemory_ = std::move(newStorage);
129 }
130 Assure(spaceSize() >= minimumSpaceSize);
131}
132
133SBuf
135{
136 return extraMemory_ ? *extraMemory_ : SBuf(content().data, content().length);
137}
138
139size_t
141{
142 if (extraMemory_)
143 return extraMemory_->spaceSize();
144
145 assert(readerSuppliedMemoryContentSize_ <= readerSuppliedMemory_.length);
146 return readerSuppliedMemory_.length - readerSuppliedMemoryContentSize_;
147}
148
151void
153{
154 *makeSpace(1).data = 0;
155}
156
159{
160 const auto bytesToPack = contentSize();
161 // until our callers do not have to work around legacy code expectations
162 Assure(bytesToPack);
163
164 // if we accumulated more bytes at some point, any extra metadata should
165 // have been consume()d by now, allowing readerSuppliedMemory_.data reuse
166 Assure(bytesToPack <= readerSuppliedMemory_.length);
167
168 auto result = readerSuppliedMemory_;
169 result.length = bytesToPack;
170 Assure(result.data);
171
172 if (!extraMemory_) {
173 // no accumulated bytes copying because they are in readerSuppliedMemory_
174 debugs(90, 7, "quickly exporting " << result.length << " bytes via " << readerSuppliedMemory_);
175 } else {
176 debugs(90, 7, "slowly exporting " << result.length << " bytes from " << extraMemory_->id << " back into " << readerSuppliedMemory_);
177 memmove(result.data, extraMemory_->rawContent(), result.length);
178 }
179
180 return result;
181}
182
183void
184Store::ParsingBuffer::print(std::ostream &os) const
185{
186 os << "size=" << contentSize();
187
188 if (extraMemory_) {
189 os << " capacity=" << capacity();
190 os << " extra=" << extraMemory_->id;
191 }
192
193 // report readerSuppliedMemory_ (if any) even if we are no longer using it
194 // for content storage; it affects packBack() and related parsing logic
195 if (readerSuppliedMemory_.length)
196 os << ' ' << readerSuppliedMemory_;
197}
198
#define Assure(condition)
Definition: Assure.h:35
#define Here()
source code location of the caller
Definition: Here.h:15
int size
Definition: ModDevPoll.cc:75
std::optional< S > IncreaseSum(const S s, const T t)
argument pack expansion termination for IncreaseSum<S, T, Args...>()
Definition: SquidMath.h:144
#define assert(EX)
Definition: assert.h:17
Definition: SBuf.h:94
void reserveCapacity(size_type minCapacity)
Definition: SBuf.cc:105
SBuf & append(const SBuf &S)
Definition: SBuf.cc:185
void consume(size_t)
get rid of previously appended() prefix of a given size
void growSpace(size_t)
makes sure we have the requested number of bytes, allocates enough memory if needed
size_t contentSize() const
the total number of append()ed bytes that were not consume()d
void print(std::ostream &) const
summarizes object state (for debugging)
StoreIOBuffer packBack()
StoreIOBuffer space()
const char * memory() const
a read-only content start (or nil for some zero-size buffers)
StoreIOBuffer content() const
ParsingBuffer()=default
creates buffer without any space or content
SBuf toSBuf() const
export content() into SBuf, avoiding content copying when possible
StoreIOBuffer makeSpace(size_t pageSize)
size_t spaceSize() const
the number of bytes in the space() buffer
size_t capacity() const
the maximum number of bytes we can store without allocating more space
void appended(const char *, size_t)
remember the new bytes received into the previously provided space()
an std::runtime_error with thrower location info
Definition: TextException.h:21
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Stream.h:194
SBuf ToSBuf(Args &&... args)
slowly stream-prints all arguments into a freshly allocated SBuf
Definition: Stream.h:63

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors