# Bazaar merge directive format 2 (Bazaar 0.90) # revision_id: kinkie@squid-cache.org-20140530095211-rcmo2jsnjisc3w0i # target_branch: file:///home/kinkie/squid/workspace/trunk/ # testament_sha1: 54574ace0d1030b23d7411f122950c7525c8bef0 # timestamp: 2014-05-30 11:52:25 +0200 # base_revision_id: squid3@treenet.co.nz-20140528113834-\ # do5q31cu02nez5b8 # # Begin patch === modified file 'configure.ac' --- configure.ac 2014-05-11 19:12:35 +0000 +++ configure.ac 2014-05-27 08:23:05 +0000 @@ -3467,6 +3467,7 @@ src/ipc/Makefile src/ssl/Makefile src/mgr/Makefile + src/parser/Makefile src/snmp/Makefile contrib/Makefile icons/Makefile === modified file 'src/Makefile.am' --- src/Makefile.am 2014-04-30 10:50:09 +0000 +++ src/Makefile.am 2014-05-27 08:23:05 +0000 @@ -46,8 +46,8 @@ LoadableModules.h \ LoadableModules.cc -SUBDIRS = base anyp comm eui acl format fs repl -DIST_SUBDIRS = base anyp comm eui acl format fs repl +SUBDIRS = base anyp parser comm eui acl format fs repl +DIST_SUBDIRS = base anyp parser comm eui acl format fs repl if ENABLE_AUTH SUBDIRS += auth @@ -647,6 +647,7 @@ $(ADAPTATION_LIBS) \ $(ESI_LIBS) \ $(SNMP_LIBS) \ + parser/libsquid-parser.la \ $(top_builddir)/lib/libmisccontainers.la \ $(top_builddir)/lib/libmiscencoding.la \ $(top_builddir)/lib/libmiscutil.la \ === added directory 'src/parser' === added file 'src/parser/Makefile.am' --- src/parser/Makefile.am 1970-01-01 00:00:00 +0000 +++ src/parser/Makefile.am 2013-12-31 10:42:11 +0000 @@ -0,0 +1,49 @@ +include $(top_srcdir)/src/Common.am +include $(top_srcdir)/src/TestHeaders.am + +EXTRA_PROGRAMS = \ + testTokenizer + +check_PROGRAMS += testTokenizer +TESTS += testTokenizer + +noinst_LTLIBRARIES = libsquid-parser.la + +libsquid_parser_la_SOURCES = \ + Tokenizer.h \ + Tokenizer.cc + +SBUF_SOURCE= \ + $(top_srcdir)/src/base/CharacterSet.h \ + $(top_srcdir)/src/SBuf.h \ + $(top_srcdir)/src/SBuf.cc \ + $(top_srcdir)/src/MemBlob.h \ + $(top_srcdir)/src/MemBlob.cc \ + $(top_srcdir)/src/OutOfBoundsException.h \ + $(top_srcdir)/src/SBufExceptions.h \ + $(top_srcdir)/src/SBufExceptions.cc \ + $(top_srcdir)/src/String.cc \ + $(top_srcdir)/src/SquidString.h \ + $(top_srcdir)/src/base/TextException.h \ + $(top_srcdir)/src/base/TextException.cc + +testTokenizer_SOURCES = \ + $(SBUF_SOURCE) \ + testTokenizer.h \ + testTokenizer.cc \ + Tokenizer.h +nodist_testTokenizer_SOURCES = \ + $(top_srcdir)/src/tests/testMain.cc \ + $(top_srcdir)/src/tests/stub_mem.cc \ + $(top_srcdir)/src/tests/stub_debug.cc \ + $(top_srcdir)/src/tests/stub_time.cc \ + $(top_srcdir)/src/tests/stub_SBufDetailedStats.cc +testTokenizer_LDFLAGS = $(LIBADD_DL) +testTokenizer_LDADD = \ + libsquid-parser.la \ + $(top_builddir)/lib/libmiscutil.la \ + $(top_builddir)/src/base/libbase.la \ + $(SQUID_CPPUNIT_LIBS) \ + $(SQUID_CPPUNIT_LA) \ + $(COMPAT_LIB) +testTokenizer_DEPENDENCIES = $(SQUID_CPPUNIT_LA) === added file 'src/parser/Tokenizer.cc' --- src/parser/Tokenizer.cc 1970-01-01 00:00:00 +0000 +++ src/parser/Tokenizer.cc 2014-05-30 09:42:45 +0000 @@ -0,0 +1,132 @@ +#include "squid.h" +#include "parser/Tokenizer.h" + +bool +Parser::Tokenizer::token(SBuf &returnedToken, const CharacterSet &delimiters) +{ + SBuf savebuf(buf_); + SBuf retval; + SBuf::size_type tokenLen = 0; + skip(delimiters); + // can't use prefix as we're looking for the first char not in delimiters + tokenLen = buf_.findFirstOf(delimiters); // not found = npos => consume to end + retval = buf_.consume(tokenLen); + skip(delimiters); + returnedToken = retval; + return true; +} + +bool +Parser::Tokenizer::prefix(SBuf &returnedToken, const CharacterSet &tokenChars, const SBuf::size_type limit) +{ + SBuf::size_type prefixLen = buf_.substr(0,limit).findFirstNotOf(tokenChars); + if (prefixLen == 0) + return false; + returnedToken = buf_.consume(prefixLen); + return true; +} + +bool +Parser::Tokenizer::skip(const CharacterSet &tokenChars) +{ + SBuf::size_type prefixLen = buf_.findFirstNotOf(tokenChars); + if (prefixLen == 0) + return false; + buf_.consume(prefixLen); + return true; +} + +bool +Parser::Tokenizer::skip(const SBuf &tokenToSkip) +{ + if (buf_.startsWith(tokenToSkip)) { + buf_.consume(tokenToSkip.length()); + return true; + } + return false; +} + +bool +Parser::Tokenizer::skip(const char tokenChar) +{ + if (buf_[0] == tokenChar) { + buf_.consume(1); + return true; + } + return false; +} + +/* reworked from compat/strtoll.c */ +bool +Parser::Tokenizer::int64(int64_t & result, int base) +{ + if (buf_.isEmpty()) + return false; + + //fixme: account for buf_.size() + bool neg = false; + const char *s = buf_.rawContent(); + const char *end = buf_.rawContent() + buf_.length(); + + if (*s == '-') { + neg = true; + ++s; + } else if (*s == '+') { + ++s; + } + if (s >= end) return false; + if (( base == 0 || base == 16) && *s == '0' && (s+1 <= end ) && + tolower(*(s+1)) == 'x') { + s += 2; + base = 16; + } + if (base == 0) { + if ( *s == '0') { + base = 8; + ++s; + } else { + base = 10; + } + } + if (s >= end) return false; + + uint64_t cutoff; + + cutoff = neg ? -static_cast(INT64_MIN) : INT64_MAX; + int cutlim = cutoff % static_cast(base); + cutoff /= static_cast(base); + + int any = 0, c; + int64_t acc = 0; + for (c = *s++; s <= end; c = *s++) { + if (xisdigit(c)) { + c -= '0'; + } else if (xisalpha(c)) { + c -= xisupper(c) ? 'A' - 10 : 'a' - 10; + } else { + break; + } + if (c >= base) + break; + if (any < 0 || static_cast(acc) > cutoff || (static_cast(acc) == cutoff && c > cutlim)) + any = -1; + else { + any = 1; + acc *= base; + acc += c; + } + } + + if (any == 0) // nothing was parsed + return false; + if (any < 0) { + acc = neg ? INT64_MIN : INT64_MAX; + errno = ERANGE; + return false; + } else if (neg) + acc = -acc; + + result = acc; + buf_.consume(s - buf_.rawContent() -1); + return true; +} === added file 'src/parser/Tokenizer.h' --- src/parser/Tokenizer.h 1970-01-01 00:00:00 +0000 +++ src/parser/Tokenizer.h 2014-05-27 08:34:55 +0000 @@ -0,0 +1,90 @@ +#ifndef SQUID_PARSER_TOKENIZER_H_ +#define SQUID_PARSER_TOKENIZER_H_ + +#include "base/CharacterSet.h" +#include "SBuf.h" + +/// Generic protocol-agnostic parsing tools +namespace Parser { + +/** + * Lexical processor to tokenize a buffer. + * + * Allows arbitrary delimiters and token character sets to + * be provided by callers. + * + * All methods start from the beginning of the input buffer. + * Methods returning true consume bytes from the buffer. + * Methods returning false have no side-effects. + */ +class Tokenizer { +public: + explicit Tokenizer(const SBuf &inBuf) : buf_(inBuf) {} + + // return a copy the current contents of the parse buffer + const SBuf buf() const { return buf_; } + + /// whether the end of the buffer has been reached + bool atEnd() const { return buf_.isEmpty(); } + + /// the remaining unprocessed section of buffer + const SBuf& remaining() const { return buf_; } + + /// reinitialize processing for a new buffer + void reset(const SBuf &newBuf) { buf_ = newBuf; } + + /** Basic strtok(3): + * Skips all leading delimiters (if any), + * accumulates all characters up to the next delimiter (a token), and + * skips all trailing delimiters (if any). + * + * Want to extract delimiters? Use prefix() instead. + */ + bool token(SBuf &returnedToken, const CharacterSet &delimiters); + + /** Accumulates all sequential permitted characters up to an optional length limit. + * + * \retval true one or more characters were found, the sequence (string) is placed in returnedToken + * \retval false no characters from the permitted set were found + */ + bool prefix(SBuf &returnedToken, const CharacterSet &tokenChars, SBuf::size_type limit = SBuf::npos); + + /** skips all sequential characters from the set, in any order + * + * \return whether one or more characters in the set were found + */ + bool skip(const CharacterSet &tokenChars); + + /** skips a given character sequence (string) + * + * \return whether the exact character sequence was found and skipped + */ + bool skip(const SBuf &tokenToSkip); + + /** skips a given single character + * + * \return whether the character was found and skipped + */ + bool skip(const char tokenChar); + + /** parse an unsigned int64_t at the beginning of the buffer + * + * strtoll(3)-alike function: tries to parse unsigned 64-bit integer + * at the beginning of the parse buffer, in the base specified by the user + * or guesstimated; consumes the parsed characters. + * + * \param result Output value. Not touched if parsing is unsuccessful. + * \param base Specify base to do the parsing in, with the same restrictions + * as strtoll. Defaults to 0 (meaning guess) + * + * \return whether the parsing was successful + */ + bool int64(int64_t &result, int base = 0); + +private: + SBuf buf_; ///< yet unparsed input +}; + +} /* namespace Parser */ + +#endif /* SQUID_PARSER_TOKENIZER_H_ */ === added file 'src/parser/testTokenizer.cc' --- src/parser/testTokenizer.cc 1970-01-01 00:00:00 +0000 +++ src/parser/testTokenizer.cc 2014-05-30 09:42:45 +0000 @@ -0,0 +1,218 @@ +#include "squid.h" +#include "base/CharacterSet.h" +#include "parser/Tokenizer.h" +#include "testTokenizer.h" + +CPPUNIT_TEST_SUITE_REGISTRATION( testTokenizer ); + +SBuf text("GET http://resource.com/path HTTP/1.1\r\n" + "Host: resource.com\r\n" + "Cookie: laijkpk3422r j1noin \r\n" + "\r\n"); +const CharacterSet alpha("alpha","abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"); +const CharacterSet whitespace("whitespace"," \r\n"); +const CharacterSet crlf("crlf","\r\n"); +const CharacterSet tab("tab","\t"); +const CharacterSet numbers("numbers","0123456789"); + +void +testTokenizer::testTokenizerPrefix() +{ + Parser::Tokenizer t(text); + SBuf s; + + // successful prefix tokenization + CPPUNIT_ASSERT(t.prefix(s,alpha)); + CPPUNIT_ASSERT_EQUAL(SBuf("GET"),s); + CPPUNIT_ASSERT(t.prefix(s,whitespace)); + CPPUNIT_ASSERT_EQUAL(SBuf(" "),s); + + //no match (first char is not in the prefix set) + CPPUNIT_ASSERT(!t.prefix(s,whitespace)); + CPPUNIT_ASSERT_EQUAL(SBuf(" "),s); + + // one more match to set S to something meaningful + CPPUNIT_ASSERT(t.prefix(s,alpha)); + CPPUNIT_ASSERT_EQUAL(SBuf("http"),s); + + //no match (no characters from the character set in the prefix) + CPPUNIT_ASSERT(!t.prefix(s,tab)); + CPPUNIT_ASSERT_EQUAL(SBuf("http"),s); //output SBuf left untouched + + // match until the end of the sample + CharacterSet all(whitespace); + all += alpha; + all += crlf; + all += numbers; + all.add(':').add('.').add('/'); + CPPUNIT_ASSERT(t.prefix(s,all)); + CPPUNIT_ASSERT_EQUAL(SBuf(),t.remaining()); +} + +void +testTokenizer::testTokenizerSkip() +{ + Parser::Tokenizer t(text); + SBuf s; + + // first scenario: patterns match + // prep for test + CPPUNIT_ASSERT(t.prefix(s,alpha)); + CPPUNIT_ASSERT_EQUAL(SBuf("GET"),s); + + // test skip testing character set + CPPUNIT_ASSERT(t.skip(whitespace)); + // check that skip was right + CPPUNIT_ASSERT(t.prefix(s,alpha)); + CPPUNIT_ASSERT_EQUAL(SBuf("http"),s); + + //check skip prefix + CPPUNIT_ASSERT(t.skip(SBuf("://"))); + // verify + CPPUNIT_ASSERT(t.prefix(s,alpha)); + CPPUNIT_ASSERT_EQUAL(SBuf("resource"),s); + + // no skip + CPPUNIT_ASSERT(!t.skip(alpha)); + CPPUNIT_ASSERT(!t.skip(SBuf("://"))); + CPPUNIT_ASSERT(!t.skip('a')); + +} + +void +testTokenizer::testTokenizerToken() +{ + Parser::Tokenizer t(text); + SBuf s; + + // first scenario: patterns match + CPPUNIT_ASSERT(t.token(s,whitespace)); + CPPUNIT_ASSERT_EQUAL(SBuf("GET"),s); + CPPUNIT_ASSERT(t.token(s,whitespace)); + CPPUNIT_ASSERT_EQUAL(SBuf("http://resource.com/path"),s); + CPPUNIT_ASSERT(t.token(s,whitespace)); + CPPUNIT_ASSERT_EQUAL(SBuf("HTTP/1.1"),s); + CPPUNIT_ASSERT(t.token(s,whitespace)); + CPPUNIT_ASSERT_EQUAL(SBuf("Host:"),s); + +} + +void +testTokenizer::testCharacterSet() +{ + +} + +void +testTokenizer::testTokenizerInt64() +{ + // successful parse in base 10 + { + int64_t rv; + Parser::Tokenizer t(SBuf("1234")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv, 10)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // successful parse, autodetect base + { + int64_t rv; + Parser::Tokenizer t(SBuf("1234")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // successful parse, autodetect base + { + int64_t rv; + Parser::Tokenizer t(SBuf("01234")); + const int64_t benchmark = 01234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // successful parse, autodetect base + { + int64_t rv; + Parser::Tokenizer t(SBuf("0x12f4")); + const int64_t benchmark = 0x12f4; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // API mismatch: don't eat leading space + { + int64_t rv; + Parser::Tokenizer t(SBuf(" 1234")); + CPPUNIT_ASSERT(!t.int64(rv)); + } + + // API mismatch: don't eat multiple leading spaces + { + int64_t rv; + Parser::Tokenizer t(SBuf(" 1234")); + CPPUNIT_ASSERT(!t.int64(rv)); + } + + // trailing spaces + { + int64_t rv; + Parser::Tokenizer t(SBuf("1234 foo")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf(" foo"), t.buf()); + } + + // trailing nonspaces + { + int64_t rv; + Parser::Tokenizer t(SBuf("1234foo")); + const int64_t benchmark = 1234; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf("foo"), t.buf()); + } + + // trailing nonspaces + { + int64_t rv; + Parser::Tokenizer t(SBuf("0x1234foo")); + const int64_t benchmark = 0x1234f; + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf("oo"), t.buf()); + } + + // overflow + { + int64_t rv; + Parser::Tokenizer t(SBuf("1029397752385698678762234")); + CPPUNIT_ASSERT(!t.int64(rv)); + } + + // buffered sub-string parsing + { + int64_t rv; + SBuf base("1029397752385698678762234"); + const int64_t benchmark = 22; + Parser::Tokenizer t(base.substr(base.length()-4,2)); + CPPUNIT_ASSERT_EQUAL(SBuf("22"),t.buf()); + CPPUNIT_ASSERT(t.int64(rv)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + } + + // base-16, prefix + { + int64_t rv; + SBuf base("deadbeefrow"); + const int64_t benchmark=0xdeadbeef; + Parser::Tokenizer t(base); + CPPUNIT_ASSERT(t.int64(rv,16)); + CPPUNIT_ASSERT_EQUAL(benchmark,rv); + CPPUNIT_ASSERT_EQUAL(SBuf("row"),t.buf()); + + } +} === added file 'src/parser/testTokenizer.h' --- src/parser/testTokenizer.h 1970-01-01 00:00:00 +0000 +++ src/parser/testTokenizer.h 2014-05-26 13:04:01 +0000 @@ -0,0 +1,24 @@ +#ifndef SQUID_TESTTOKENIZER_H_ +#define SQUID_TESTTOKENIZER_H_ + +#include + +class testTokenizer : public CPPUNIT_NS::TestFixture +{ + CPPUNIT_TEST_SUITE( testTokenizer ); + CPPUNIT_TEST ( testCharacterSet ); + CPPUNIT_TEST ( testTokenizerPrefix ); + CPPUNIT_TEST ( testTokenizerSkip ); + CPPUNIT_TEST ( testTokenizerToken ); + CPPUNIT_TEST ( testTokenizerInt64 ); + CPPUNIT_TEST_SUITE_END(); + +protected: + void testTokenizerPrefix(); + void testTokenizerSkip(); + void testTokenizerToken(); + void testCharacterSet(); + void testTokenizerInt64(); +}; + +#endif /* SQUID_TESTTOKENIZER_H_ */ # Begin bundle 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 n45kXETEp/8XckU4UJA53ehN