Skip to content

Commit a57a824

Browse files
authored
Convert cachekey plugin to use Regex class (PCRE2) instead of PCRE (#12607)
1 parent 570e5a6 commit a57a824

File tree

4 files changed

+744
-114
lines changed

4 files changed

+744
-114
lines changed

plugins/cachekey/pattern.cc

Lines changed: 36 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
/**
2020
* @file pattern.cc
21-
* @brief PRCE related classes.
21+
* @brief Regex related classes.
2222
* @see pattern.h
2323
*/
2424

@@ -41,16 +41,14 @@ replaceString(String &str, const String &from, const String &to)
4141
Pattern::Pattern() : _pattern(""), _replacement("") {}
4242

4343
/**
44-
* @brief Initializes PCRE pattern by providing the subject and replacement strings.
45-
* @param pattern PCRE pattern, a string containing PCRE patterns, capturing groups.
46-
* @param replacement PCRE replacement, a string where $0 ... $9 will be replaced with the corresponding capturing groups
44+
* @brief Initializes Regex pattern by providing the subject and replacement strings.
45+
* @param pattern Regex pattern, a string containing regex patterns, capturing groups.
46+
* @param replacement Regex replacement, a string where $0 ... $9 will be replaced with the corresponding capturing groups
4747
* @return true if successful, false if failure
4848
*/
4949
bool
5050
Pattern::init(const String &pattern, const String &replacement, bool replace)
5151
{
52-
pcreFree();
53-
5452
_pattern.assign(pattern);
5553
_replacement.assign(replacement);
5654
_replace = replace;
@@ -59,17 +57,16 @@ Pattern::init(const String &pattern, const String &replacement, bool replace)
5957

6058
if (!compile()) {
6159
CacheKeyDebug("failed to initialize pattern:'%s', replacement:'%s'", pattern.c_str(), replacement.c_str());
62-
pcreFree();
6360
return false;
6461
}
6562

6663
return true;
6764
}
6865

6966
/**
70-
* @brief Initializes PCRE pattern by providing the pattern only or pattern+replacement in a single configuration string.
67+
* @brief Initializes Regex pattern by providing the pattern only or pattern+replacement in a single configuration string.
7168
* @see init()
72-
* @param config PCRE pattern <pattern> or PCRE pattern + replacement in format /<pattern>/<replacement>/
69+
* @param config Regex pattern <pattern> or Regex pattern + replacement in format /<pattern>/<replacement>/
7370
* @return true if successful, false if failure
7471
*/
7572
bool
@@ -130,32 +127,7 @@ Pattern::init(const String &config)
130127
bool
131128
Pattern::empty() const
132129
{
133-
return _pattern.empty() || nullptr == _re;
134-
}
135-
136-
/**
137-
* @brief Frees PCRE library related resources.
138-
*/
139-
void
140-
Pattern::pcreFree()
141-
{
142-
if (_re) {
143-
pcre_free(_re);
144-
_re = nullptr;
145-
}
146-
147-
if (_extra) {
148-
pcre_free(_extra);
149-
_extra = nullptr;
150-
}
151-
}
152-
153-
/**
154-
* @brief Destructor, frees PCRE related resources.
155-
*/
156-
Pattern::~Pattern()
157-
{
158-
pcreFree();
130+
return _pattern.empty() || _re.empty();
159131
}
160132

161133
/**
@@ -198,23 +170,23 @@ Pattern::process(const String &subject, StringVector &result)
198170
}
199171

200172
/**
201-
* @brief PCRE matches a subject string against the regex pattern.
202-
* @param subject PCRE subject
173+
* @brief Regex matches a subject string against the regex pattern.
174+
* @param subject Regex subject
203175
* @return true - matched, false - did not.
204176
*/
205177
bool
206178
Pattern::match(const String &subject)
207179
{
208-
int matchCount;
209180
CacheKeyDebug("matching '%s' to '%s'", _pattern.c_str(), subject.c_str());
210181

211-
if (!_re) {
182+
if (_re.empty()) {
212183
return false;
213184
}
214185

215-
matchCount = pcre_exec(_re, _extra, subject.c_str(), subject.length(), 0, PCRE_NOTEMPTY, nullptr, 0);
186+
RegexMatches matches;
187+
int matchCount = _re.exec(subject, matches, RE_NOTEMPTY);
216188
if (matchCount < 0) {
217-
if (matchCount != PCRE_ERROR_NOMATCH) {
189+
if (matchCount != RE_ERROR_NOMATCH) {
218190
CacheKeyError("matching error %d", matchCount);
219191
}
220192
return false;
@@ -224,66 +196,60 @@ Pattern::match(const String &subject)
224196
}
225197

226198
/**
227-
* @brief Return all PCRE capture groups that matched in the subject string
228-
* @param subject PCRE subject string
199+
* @brief Return all Regex capture groups that matched in the subject string
200+
* @param subject Regex subject string
229201
* @param result reference to vector of strings containing all capture groups
230202
*/
231203
bool
232204
Pattern::capture(const String &subject, StringVector &result)
233205
{
234-
int matchCount;
235-
int ovector[OVECOUNT];
236-
237206
CacheKeyDebug("capturing '%s' from '%s'", _pattern.c_str(), subject.c_str());
238207

239-
if (!_re) {
208+
if (_re.empty()) {
240209
CacheKeyError("regular expression not initialized");
241210
return false;
242211
}
243212

244-
matchCount = pcre_exec(_re, nullptr, subject.c_str(), subject.length(), 0, PCRE_NOTEMPTY, ovector, OVECOUNT);
213+
RegexMatches matches;
214+
int matchCount = _re.exec(subject, matches, RE_NOTEMPTY);
245215
if (matchCount < 0) {
246-
if (matchCount != PCRE_ERROR_NOMATCH) {
216+
if (matchCount != RE_ERROR_NOMATCH) {
247217
CacheKeyError("matching error %d", matchCount);
248218
}
249219
return false;
250220
}
251221

252222
for (int i = 0; i < matchCount; i++) {
253-
int start = ovector[2 * i];
254-
int length = ovector[2 * i + 1] - ovector[2 * i];
223+
std::string_view capture = matches[i];
224+
String dst(capture.data(), capture.length());
255225

256-
String dst(subject, start, length);
257-
258-
CacheKeyDebug("capturing '%s' %d[%d,%d]", dst.c_str(), i, ovector[2 * i], ovector[2 * i + 1]);
226+
CacheKeyDebug("capturing '%s' %d", dst.c_str(), i);
259227
result.push_back(dst);
260228
}
261229

262230
return true;
263231
}
264232

265233
/**
266-
* @brief Replaces all replacements found in the replacement string with what matched in the PCRE capturing groups.
267-
* @param subject PCRE subject string
234+
* @brief Replaces all replacements found in the replacement string with what matched in the Regex capturing groups.
235+
* @param subject Regex subject string
268236
* @param result reference to A string where the result of the replacement will be stored
269237
* @return true - success, false - nothing matched or failure.
270238
*/
271239
bool
272240
Pattern::replace(const String &subject, String &result)
273241
{
274-
int matchCount;
275-
int ovector[OVECOUNT];
276-
277242
CacheKeyDebug("replacing:'%s' in pattern:'%s', subject:'%s'", _replacement.c_str(), _pattern.c_str(), subject.c_str());
278243

279-
if (!_re || !_replace) {
244+
if (_re.empty() || !_replace) {
280245
CacheKeyError("regular expression not initialized or not configured to replace");
281246
return false;
282247
}
283248

284-
matchCount = pcre_exec(_re, nullptr, subject.c_str(), subject.length(), 0, PCRE_NOTEMPTY, ovector, OVECOUNT);
249+
RegexMatches matches;
250+
int matchCount = _re.exec(subject, matches, RE_NOTEMPTY);
285251
if (matchCount < 0) {
286-
if (matchCount != PCRE_ERROR_NOMATCH) {
252+
if (matchCount != RE_ERROR_NOMATCH) {
287253
CacheKeyError("matching error %d", matchCount);
288254
}
289255
return false;
@@ -299,18 +265,11 @@ Pattern::replace(const String &subject, String &result)
299265

300266
int previous = 0;
301267
for (int i = 0; i < _tokenCount; i++) {
302-
int replIndex = _tokens[i];
303-
int start = ovector[2 * replIndex];
304-
int length = ovector[2 * replIndex + 1] - ovector[2 * replIndex];
305-
306-
/* Handle the case when no match / a group capture result in an empty string */
307-
if (start < 0) {
308-
start = 0;
309-
length = 0;
310-
}
268+
int replIndex = _tokens[i];
269+
std::string_view capture = matches[replIndex];
311270

312271
String src(_replacement, _tokenOffset[i], 2);
313-
String dst(subject, start, length);
272+
String dst(capture.data(), capture.length());
314273

315274
CacheKeyDebug("replacing '%s' with '%s'", src.c_str(), dst.c_str());
316275

@@ -328,37 +287,20 @@ Pattern::replace(const String &subject, String &result)
328287
}
329288

330289
/**
331-
* @brief PCRE compiles the regex, called only during initialization.
290+
* @brief Compiles the regex, called only during initialization.
332291
* @return true if successful, false if not.
333292
*/
334293
bool
335294
Pattern::compile()
336295
{
337-
const char *errPtr; /* PCRE error */
338-
int errOffset; /* PCRE error offset */
296+
std::string error;
297+
int errOffset;
339298

340299
CacheKeyDebug("compiling pattern:'%s', replace: %s, replacement:'%s'", _pattern.c_str(), _replace ? "true" : "false",
341300
_replacement.c_str());
342301

343-
_re = pcre_compile(_pattern.c_str(), /* the pattern */
344-
0, /* options */
345-
&errPtr, /* for error message */
346-
&errOffset, /* for error offset */
347-
nullptr); /* use default character tables */
348-
349-
if (nullptr == _re) {
350-
CacheKeyError("compile of regex '%s' at char %d: %s", _pattern.c_str(), errOffset, errPtr);
351-
352-
return false;
353-
}
354-
355-
_extra = pcre_study(_re, 0, &errPtr);
356-
357-
if ((nullptr == _extra) && (nullptr != errPtr) && (0 != *errPtr)) {
358-
CacheKeyError("failed to study regex '%s': %s", _pattern.c_str(), errPtr);
359-
360-
pcre_free(_re);
361-
_re = nullptr;
302+
if (!_re.compile(_pattern, error, errOffset)) {
303+
CacheKeyError("compile of regex '%s' at char %d: %s", _pattern.c_str(), errOffset, error.c_str());
362304
return false;
363305
}
364306

@@ -394,10 +336,6 @@ Pattern::compile()
394336
}
395337
}
396338

397-
if (!success) {
398-
pcreFree();
399-
}
400-
401339
return success;
402340
}
403341

plugins/cachekey/pattern.h

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,32 +18,26 @@
1818

1919
/**
2020
* @file pattern.h
21-
* @brief PRCE related classes (header file).
21+
* @brief Regex related classes (header file).
2222
*/
2323

2424
#pragma once
2525

2626
#include "tscore/ink_defs.h"
27-
28-
#ifdef HAVE_PCRE_PCRE_H
29-
#include <pcre/pcre.h>
30-
#else
31-
#include <pcre.h>
32-
#endif
27+
#include "tsutil/Regex.h"
3328

3429
#include "common.h"
3530

3631
/**
37-
* @brief PCRE matching, capturing and replacing
32+
* @brief Regex matching, capturing and replacing
3833
*/
3934
class Pattern
4035
{
4136
public:
42-
static const int TOKENCOUNT = 10; /**< @brief Capturing groups $0..$9 */
43-
static const int OVECOUNT = TOKENCOUNT * 3; /**< @brief pcre_exec() array count, handle 10 capture groups */
37+
static const int TOKENCOUNT = 10; /**< @brief Capturing groups $0..$9 */
4438

4539
Pattern();
46-
virtual ~Pattern();
40+
~Pattern() = default;
4741

4842
bool init(const String &pattern, const String &replacement, bool replace);
4943
bool init(const String &config);
@@ -55,13 +49,12 @@ class Pattern
5549

5650
private:
5751
bool compile();
58-
void pcreFree();
5952

60-
pcre *_re = nullptr; /**< @brief PCRE compiled info structure, computed during initialization */
61-
pcre_extra *_extra = nullptr; /**< @brief PCRE study data block, computed during initialization */
53+
Regex _re; /**< @brief Regex compiled object */
6254

63-
String _pattern; /**< @brief PCRE pattern string, containing PCRE patterns and capturing groups. */
64-
String _replacement; /**< @brief PCRE replacement string, containing $0..$9 to be replaced with content of the capturing groups */
55+
String _pattern; /**< @brief Regex pattern string, containing regex patterns and capturing groups. */
56+
String
57+
_replacement; /**< @brief Regex replacement string, containing $0..$9 to be replaced with content of the capturing groups */
6558

6659
bool _replace = false; /**< @brief true if a replacement is needed, false if not, this is to distinguish between an empty
6760
replacement string and no replacement needed case */

0 commit comments

Comments
 (0)