You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2012/06/13 22:18:14 UTC
[4/11] Moved these plugins from the separate git repo
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/HttpHeader.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/HttpHeader.h b/plugins/experimental/esi/lib/HttpHeader.h
new file mode 100644
index 0000000..bdef5ce
--- /dev/null
+++ b/plugins/experimental/esi/lib/HttpHeader.h
@@ -0,0 +1,45 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _ESI_HTTP_HEADER_H
+
+#define _ESI_HTTP_HEADER_H
+
+#include <list>
+
+namespace EsiLib {
+
+struct HttpHeader {
+ const char *name;
+ int name_len;
+ const char *value;
+ int value_len;
+ HttpHeader(const char *n = 0, int n_len = -1, const char *v = 0, int v_len = -1)
+ : name(n), name_len(n_len), value(v), value_len(v_len) { };
+};
+
+typedef std::list<HttpHeader> HttpHeaderList;
+
+};
+
+#endif // _ESI_HTTP_HEADER_H
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/IncludeHandlerFactory.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/IncludeHandlerFactory.h b/plugins/experimental/esi/lib/IncludeHandlerFactory.h
new file mode 100644
index 0000000..2845d49
--- /dev/null
+++ b/plugins/experimental/esi/lib/IncludeHandlerFactory.h
@@ -0,0 +1,54 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _INCLUDE_HANDLER_FACTORY_H
+
+#define _INCLUDE_HANDLER_FACTORY_H
+
+#include <string>
+#include "SpecialIncludeHandler.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+EsiLib::SpecialIncludeHandler *createSpecialIncludeHandler(EsiLib::Variables &esi_vars,
+ EsiLib::Expression &esi_expr,
+ HttpDataFetcher &fetcher,
+ const std::string &id);
+
+#ifdef __cplusplus
+}
+#endif
+
+namespace EsiLib {
+
+typedef SpecialIncludeHandler *(*SpecialIncludeHandlerCreator)(Variables &esi_vars,
+ Expression &esi_expr,
+ HttpDataFetcher &fetcher,
+ const std::string &id);
+
+};
+
+#endif
+
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/SpecialIncludeHandler.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/SpecialIncludeHandler.h b/plugins/experimental/esi/lib/SpecialIncludeHandler.h
new file mode 100644
index 0000000..d062d5f
--- /dev/null
+++ b/plugins/experimental/esi/lib/SpecialIncludeHandler.h
@@ -0,0 +1,72 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _ESI_SPECIAL_INCLUDE_HANDLER
+
+#define _ESI_SPECIAL_INCLUDE_HANDLER
+
+#include "HttpDataFetcher.h"
+#include "Variables.h"
+#include "Expression.h"
+
+namespace EsiLib {
+
+class SpecialIncludeHandler {
+
+public:
+
+ SpecialIncludeHandler(Variables &esi_vars,
+ Expression &esi_expr, HttpDataFetcher &http_fetcher)
+ : _esi_vars(esi_vars), _esi_expr(esi_expr), _http_fetcher(http_fetcher) {
+ }
+
+ virtual int handleInclude(const char *data, int data_len) = 0;
+
+ virtual void handleParseComplete() = 0;
+
+ /** trivial implementation */
+ virtual DataStatus getIncludeStatus(int include_id) {
+ const char *data;
+ int data_len;
+ return getData(include_id, data, data_len) ? STATUS_DATA_AVAILABLE : STATUS_ERROR;
+ }
+
+ virtual bool getData(int include_id, const char *&data, int &data_len) = 0;
+
+ virtual void getFooter(const char *&footer, int &footer_len) {
+ footer_len = 0;
+ }
+
+ virtual ~SpecialIncludeHandler() { };
+
+protected:
+
+ Variables &_esi_vars;
+ Expression &_esi_expr;
+ HttpDataFetcher &_http_fetcher;
+
+};
+
+};
+
+#endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/Stats.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/Stats.cc b/plugins/experimental/esi/lib/Stats.cc
new file mode 100644
index 0000000..9f265f3
--- /dev/null
+++ b/plugins/experimental/esi/lib/Stats.cc
@@ -0,0 +1,69 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "Stats.h"
+
+using namespace EsiLib;
+
+namespace EsiLib {
+namespace Stats {
+const char *STAT_NAMES[Stats::MAX_STAT_ENUM] = {
+ "esi.n_os_docs",
+ "esi.n_cache_docs",
+ "esi.n_parse_errs",
+ "esi.n_includes",
+ "esi.n_include_errs",
+ "esi.n_spcl_includes",
+ "esi.n_spcl_include_errs"
+};
+
+int g_stat_indices[Stats::MAX_STAT_ENUM];
+StatSystem *g_system = 0;
+
+void init(StatSystem *system) {
+ g_system = system;
+ if (g_system) {
+ for (int i = 0; i < Stats::MAX_STAT_ENUM; ++i) {
+//FIXME doesn't return avalue.
+g_system->create(i);
+/* if (!g_system->create(i)) {
+ Utils::ERROR_LOG("[%s] Unable to create stat [%s]", __FUNCTION__, Stats::STAT_NAMES[i]);
+ }*/
+ }
+ }
+}
+
+//FIXME step should be TSMgmtInt but for some reason the linker is having some strange int vs long name mangling issue.
+void increment(Stats::STAT st, int step/* = 1 */) {
+ if (g_system) {
+//FIXME doesn't return avalue.
+g_system->increment(st, step);
+/*
+ if (!g_system->increment(st, step)) {
+ Utils::ERROR_LOG("[%s] Unable to increment stat [%s] by step [%d]", __FUNCTION__, step,
+ Stats::STAT_NAMES[st]);
+ }
+*/
+ }
+}
+}}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/Stats.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/Stats.h b/plugins/experimental/esi/lib/Stats.h
new file mode 100644
index 0000000..d2036bc
--- /dev/null
+++ b/plugins/experimental/esi/lib/Stats.h
@@ -0,0 +1,66 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _ESI_STATS_H
+
+#define _ESI_STATS_H
+
+#include "Utils.h"
+#include <ts/ts.h>
+
+namespace EsiLib {
+
+/** interface that stat systems should implement */
+class StatSystem {
+public:
+ virtual void create(int handle) = 0;
+//FIXME step should be TSMgmtInt
+ virtual void increment(int handle, int step = 1) = 0;
+ virtual ~StatSystem() { };
+};
+
+namespace Stats {
+
+enum STAT { N_OS_DOCS = 0,
+ N_CACHE_DOCS = 1,
+ N_PARSE_ERRS = 2,
+ N_INCLUDES = 3,
+ N_INCLUDE_ERRS = 4,
+ N_SPCL_INCLUDES = 5,
+ N_SPCL_INCLUDE_ERRS = 6,
+ MAX_STAT_ENUM = 7 };
+
+extern const char *STAT_NAMES[MAX_STAT_ENUM];
+extern int g_stat_indices[Stats::MAX_STAT_ENUM];
+extern StatSystem *g_system;
+
+void init(StatSystem *system);
+
+void increment(STAT st, int step = 1);
+
+};
+
+};
+
+
+#endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/StringHash.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/StringHash.h b/plugins/experimental/esi/lib/StringHash.h
new file mode 100644
index 0000000..6739cef
--- /dev/null
+++ b/plugins/experimental/esi/lib/StringHash.h
@@ -0,0 +1,47 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _STRING_HASH_H
+
+#define _STRING_HASH_H
+
+#include <string>
+#include <ext/hash_map>
+
+namespace EsiLib {
+
+struct StringHasher {
+ inline size_t operator ()(const std::string &str) const {
+ return __gnu_cxx::hash<const char *>()(str.c_str());
+ };
+};
+
+typedef __gnu_cxx::hash_map<std::string, std::string, StringHasher> StringHash;
+
+template<typename T>
+class StringKeyHash : public __gnu_cxx::hash_map<std::string, T, StringHasher> {
+};
+
+};
+
+#endif // _STRING_HASH_H
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/Utils.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/Utils.cc b/plugins/experimental/esi/lib/Utils.cc
new file mode 100644
index 0000000..047fbe6
--- /dev/null
+++ b/plugins/experimental/esi/lib/Utils.cc
@@ -0,0 +1,195 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "Utils.h"
+
+#include <sstream>
+
+using namespace EsiLib;
+
+ComponentBase::Debug Utils::DEBUG_LOG(0);
+ComponentBase::Error Utils::ERROR_LOG(0);
+
+#define DEBUG_TAG "EsiUtils"
+
+using std::string;
+
+void
+Utils::init(ComponentBase::Debug debug_func, ComponentBase::Error error_func) {
+ DEBUG_LOG = debug_func;
+ ERROR_LOG = error_func;
+}
+
+bool
+Utils::getAttribute(const string &data, const string &attr, size_t curr_pos, size_t end_pos,
+ Attribute &attr_info,
+ size_t *term_pos /* = 0 */, char terminator /* = 0 */) {
+ size_t attr_start = data.find(attr, curr_pos);
+ if (attr_start >= end_pos) {
+ ERROR_LOG("[%s] Tag has no [%.*s] attribute", __FUNCTION__, attr.size(), attr.data());
+ return false;
+ }
+ curr_pos = attr_start + attr.size();
+ bool equals_found = false;
+ for (; curr_pos < end_pos; ++curr_pos) {
+ if (data[curr_pos] == ' ') {
+ continue;
+ } else {
+ if (data[curr_pos] == '=') {
+ equals_found = true;
+ }
+ break;
+ }
+ }
+ if (!equals_found) {
+ ERROR_LOG("[%s] Attribute [%.*s] has no value", __FUNCTION__, attr.size(), attr.data());
+ return false;
+ }
+ ++curr_pos;
+ if (curr_pos == end_pos) {
+ ERROR_LOG("[%s] No space for value after [%.*s] attribute", __FUNCTION__, attr.size(), attr.data());
+ return false;
+ }
+ bool in_quoted_part = false;
+ bool quoted = false;
+ size_t i;
+ for (i = curr_pos; i < end_pos; ++i) {
+ if (data[i] == '"') {
+ quoted = true;
+ in_quoted_part = !in_quoted_part;
+ }
+ else if (data[i] == ' ') {
+ if (!in_quoted_part) {
+ break;
+ }
+ } else if (terminator && !in_quoted_part && (data[i] == terminator)) {
+ break;
+ }
+ }
+ const char *data_start_ptr = data.data();
+ if (in_quoted_part) {
+ ERROR_LOG("[%s] Unterminated quote in value for attribute [%.*s] starting at [%.10s]",
+ __FUNCTION__, attr.size(), attr.data(), data_start_ptr + curr_pos);
+ return false;
+ }
+ if (terminator && term_pos) {
+ *term_pos = data.find(terminator, i);
+ if (*term_pos >= end_pos) {
+ ERROR_LOG("[%s] Unterminated attribute [%.*s]", __FUNCTION__, attr.size(), attr.data());
+ return false;
+ }
+ }
+ attr_info.name = data_start_ptr + attr_start;
+ attr_info.name_len = attr.size();
+ attr_info.value = data_start_ptr + curr_pos;
+ attr_info.value_len = i - curr_pos;
+ if (quoted) {
+ ++attr_info.value;
+ attr_info.value_len -= 2;
+ }
+ return true;
+}
+
+void
+Utils::parseKeyValueConfig(const std::list<string> &lines, KeyValueMap &kvMap) {
+ string key, value;
+ std::istringstream iss;
+ for (std::list<string>::const_iterator list_iter = lines.begin(); list_iter != lines.end(); ++list_iter) {
+ const string &conf_line = *list_iter; // handy reference
+ if (!conf_line.size() || (conf_line[0] == '#')) {
+ continue;
+ }
+ iss.clear();
+ iss.str(conf_line);
+ if (iss.good()) {
+ iss >> key;
+ iss >> value;
+ if (key.size() && value.size()) {
+ kvMap.insert(KeyValueMap::value_type(key, value));
+ DEBUG_LOG(DEBUG_TAG, "[%s] Read value [%s] for key [%s]", __FUNCTION__, value.c_str(), key.c_str());
+ }
+ }
+ key.clear();
+ value.clear();
+ }
+}
+
+void
+Utils::parseAttributes(const char *data, int data_len, AttributeList &attr_list,
+ const char *pair_separators /* = " " */) {
+ attr_list.clear();
+ if (!data || (data_len <= 0)) {
+ return;
+ }
+ char separator_lookup[256] = { 0 };
+ int i;
+ for (i = 0; pair_separators[i]; ++i) {
+ separator_lookup[static_cast<unsigned int>(pair_separators[i])] = 1;
+ }
+ Attribute attr;
+ bool inside_quotes = false, end_of_attribute;
+ bool escape_on = false;
+ for (i = 0; (i < data_len) && ((isspace(data[i]) || separator_lookup[static_cast<unsigned int>(data[i])]));
+ ++i);
+ attr.name = data + i;
+ attr.value = 0;
+ for (; i <= data_len; ++i) {
+ end_of_attribute = false;
+ if (i == data_len) {
+ end_of_attribute = true;
+ } else if (separator_lookup[static_cast<unsigned int>(data[i])] && !inside_quotes) {
+ end_of_attribute = true;
+ } // else ignore separator when in quotes
+ if (end_of_attribute) {
+ if (!inside_quotes) {
+ if (attr.value > attr.name) {
+ attr.value_len = data + i - attr.value;
+ trimWhiteSpace(attr.name, attr.name_len);
+ trimWhiteSpace(attr.value, attr.value_len);
+ if (attr.value[0] == '"') {
+ ++attr.value;
+ attr.value_len -= 2;
+ }
+ if (attr.name_len && attr.value_len) {
+ DEBUG_LOG(DEBUG_TAG, "[%s] Added attribute with name [%.*s] and value [%.*s]",
+ __FUNCTION__, attr.name_len, attr.name, attr.value_len, attr.value);
+ attr_list.push_back(attr);
+ } // else ignore empty name/value
+ } // else ignore attribute with no value
+ } // else ignore variable with unterminated quotes
+ for(; (i < data_len) && ((isspace(data[i]) || separator_lookup[static_cast<unsigned int>(data[i])]));
+ ++i);
+ attr.name = data + i;
+ attr.value = 0;
+ inside_quotes = false;
+ } else if (data[i] == '"') {
+ if (!escape_on) {
+ inside_quotes = !inside_quotes;
+ }
+ } else if ((data[i] == '=') && !attr.value && !inside_quotes) {
+ attr.value = data + i + 1;
+ attr.name_len = data + i - attr.name;
+ }
+ escape_on = (data[i] == '\\') ? true : false;
+ }
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/Utils.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/Utils.h b/plugins/experimental/esi/lib/Utils.h
new file mode 100644
index 0000000..6308e7c
--- /dev/null
+++ b/plugins/experimental/esi/lib/Utils.h
@@ -0,0 +1,118 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _ESI_UTILS_H
+
+#define _ESI_UTILS_H
+
+#include "DocNode.h"
+#include "ComponentBase.h"
+
+#include <cstring>
+#include <string>
+#include <map>
+#include <list>
+#include <ctype.h>
+
+namespace EsiLib {
+
+namespace Utils {
+
+ extern ComponentBase::Debug DEBUG_LOG;
+
+ extern ComponentBase::Error ERROR_LOG;
+
+ void init(ComponentBase::Debug debug_func, ComponentBase::Error error_func);
+
+ // looks for the given attribute in given data; a terminator can
+ // also be specified apart from the end_pos; attr_info will point
+ // to data inside data string
+ bool getAttribute(const std::string &data, const std::string &attr, size_t curr_pos, size_t end_pos,
+ Attribute &attr_info, size_t *term_pos = 0, char terminator = 0);
+
+ // less specialized version of method above
+ inline bool getAttribute(const std::string &data, const char *attr, Attribute &attr_info) {
+ return getAttribute(data, std::string(attr), 0, data.size(), attr_info);
+ }
+
+ // trims leading and trailing white space; input arguments
+ // will be modified to reflect trimmed data
+ inline void trimWhiteSpace(const char *&data, int &data_len) {
+ if (!data) {
+ data_len = 0;
+ } else {
+ if (data_len == -1) {
+ data_len = strlen(data);
+ }
+ int i, j;
+ for (i = 0; ((i < data_len) && isspace(data[i])); ++i);
+ for (j = (data_len - 1); ((j > i) && isspace(data[j])); --j);
+ data += i;
+ data_len = j - i + 1;
+ }
+ }
+
+ // does case insensitive comparison
+ inline bool areEqual(const char *str1, int str1_len, const char *str2, int str2_len) {
+ if (str1_len == str2_len) {
+ return (strncasecmp(str1, str2, str1_len) == 0);
+ }
+ return false;
+ }
+
+ inline bool areEqual(const char *str1, int str1_len, const std::string &str2) {
+ return areEqual(str1, str1_len, str2.data(), static_cast<int>(str2.size()));
+ }
+
+ // parses a string of name=value attributes separated by any character in pair_separators;
+ void parseAttributes(const char *data, int data_len, AttributeList &attr_list,
+ const char *pair_separators = " ");
+
+ inline void parseAttributes(const std::string &data, AttributeList &attr_list,
+ const char *pair_separators = " ") {
+ parseAttributes(data.data(), data.size(), attr_list, pair_separators);
+ }
+
+ typedef std::map<std::string, std::string> KeyValueMap;
+
+ // parses given lines (assumes <key><whitespace><value> format) and
+ // stores them in supplied map; Lines beginning with '#' are ignored
+ void parseKeyValueConfig(const std::list<std::string> &lines, KeyValueMap &kvMap);
+
+ inline std::string unescape(const char *str, int len = -1) {
+ std::string retval("");
+ if (str) {
+ for (int i = 0; (((len == -1) && (str[i] != '\0')) || (i < len)); ++i) {
+ if (str[i] != '\\') {
+ retval += str[i];
+ }
+ }
+ }
+ return retval;
+ }
+
+};
+
+};
+
+#endif
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/Variables.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/Variables.cc b/plugins/experimental/esi/lib/Variables.cc
new file mode 100644
index 0000000..d753172
--- /dev/null
+++ b/plugins/experimental/esi/lib/Variables.cc
@@ -0,0 +1,427 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include "Variables.h"
+#include "Attribute.h"
+#include "Utils.h"
+
+#include <errno.h>
+
+using std::list;
+using std::pair;
+using std::string;
+using namespace EsiLib;
+
+const string Variables::EMPTY_STRING("");
+const string Variables::TRUE_STRING("true");
+const string Variables::VENDOR_STRING("vendor");
+const string Variables::VERSION_STRING("version");
+const string Variables::PLATFORM_STRING("platform");
+const string Variables::SIMPLE_HEADERS[] = { string("HOST"),
+ string("REFERER"),
+ string("") };
+
+const string Variables::SPECIAL_HEADERS[] = { string("ACCEPT-LANGUAGE"),
+ string("COOKIE"),
+ string("USER-AGENT"),
+ string("QUERY_STRING"),
+ string("") };
+
+const string Variables::NORM_SIMPLE_HEADERS[] = { string("HTTP_HOST"),
+ string("HTTP_REFERER"),
+ string("") };
+
+const string Variables::NORM_SPECIAL_HEADERS[] = { string("HTTP_ACCEPT_LANGUAGE"),
+ string("HTTP_COOKIE"),
+ string("HTTP_USER_AGENT"),
+ string("QUERY_STRING"),
+ string("") };
+
+inline string &
+Variables::_toUpperCase(string &str) const {
+ for (size_t i = 0; i < str.size(); ++i) {
+ if ((str[i] >= 'a') && (str[i] <= 'z')) {
+ str[i] = 'A' + (str[i] - 'a');
+ }
+ }
+ return str;
+}
+
+inline int
+Variables::_searchHeaders(const string headers[], const char *name, int name_len) const {
+ int curr_header_size;
+ for (int i = 0; (curr_header_size = static_cast<int>(headers[i].size())); ++i) {
+ if ((name_len == curr_header_size) &&
+ (strncasecmp(headers[i].data(), name, curr_header_size) == 0)) {
+ return i;
+ }
+ }
+ return -1;
+}
+
+inline void
+Variables::_insert(StringHash &hash, const std::string &key, const std::string &value) {
+ std::pair<StringHash::iterator, bool> result = hash.insert(StringHash::value_type(key, value));
+ if (!result.second) {
+ result.first->second = value;
+ }
+}
+
+void
+Variables::populate(const HttpHeader &header) {
+ if (header.name && header.name_len && header.value && header.value_len) {
+
+ // doing this because we can't change our const input arg
+ int name_len = (header.name_len == -1) ? strlen(header.name) : header.name_len;
+ int value_len = (header.value_len == -1) ? strlen(header.value) : header.value_len;
+
+ // we need to save the cookie string to build the jar from
+ if ((name_len == 6) && (strncasecmp(header.name, "Cookie", 6) == 0)) {
+ _releaseCookieJar();
+ if (_cookie_str.size()) {
+ _cookie_str.append(", ");
+ }
+ _cookie_str.append(header.value, value_len);
+ }
+
+ if (_headers_parsed) {
+ _parseHeader(header.name, name_len, header.value, value_len);
+ } else {
+ int match_index = _searchHeaders(SIMPLE_HEADERS, header.name, name_len);
+ if (match_index != -1) {
+ _cached_simple_headers[match_index].push_back(string(header.value, value_len));
+ } else {
+ match_index = _searchHeaders(SPECIAL_HEADERS, header.name, name_len);
+ if (match_index != -1) {
+ _cached_special_headers[match_index].push_back(string(header.value, value_len));
+ } else {
+ _debugLog(_debug_tag.c_str(), "[%s] Not retaining header [%.*s]", __FUNCTION__, name_len,
+ header.name);
+ }
+ }
+ }
+ }
+}
+
+inline void
+Variables::_parseSimpleHeader(SimpleHeader hdr, const string &value) {
+ _debugLog(_debug_tag.c_str(), "[%s] Inserting value for simple header [%s]",
+ __FUNCTION__, SIMPLE_HEADERS[hdr].c_str());
+ _simple_data[NORM_SIMPLE_HEADERS[hdr]] = value;
+}
+
+inline void
+Variables::_parseSimpleHeader(SimpleHeader hdr, const char *value, int value_len) {
+ _parseSimpleHeader(hdr, string(value, value_len));
+}
+
+void
+Variables::_parseSpecialHeader(SpecialHeader hdr, const char *value, int value_len) {
+ switch (hdr) {
+ case HTTP_ACCEPT_LANGUAGE:
+ _parseAcceptLangString(value, value_len);
+ break;
+ case HTTP_COOKIE:
+ _parseCookieString(value, value_len);
+ break;
+ case HTTP_USER_AGENT:
+ _parseUserAgentString(value, value_len);
+ break;
+ default:
+ _debugLog(_debug_tag.c_str(), "[%s] Skipping unrecognized header", __FUNCTION__);
+ break;
+ }
+}
+
+void
+Variables::_parseHeader(const char *name, int name_len, const char *value, int value_len) {
+ int match_index = _searchHeaders(SIMPLE_HEADERS, name, name_len);
+ if (match_index != -1) {
+ _parseSimpleHeader(static_cast<SimpleHeader>(match_index), value, value_len);
+ } else {
+ match_index = _searchHeaders(SPECIAL_HEADERS, name, name_len);
+ if (match_index != -1) {
+ _parseSpecialHeader(static_cast<SpecialHeader>(match_index), value, value_len);
+ } else {
+ _debugLog(_debug_tag.c_str(), "[%s] Unrecognized header [%.*s]", __FUNCTION__, value_len, value);
+ }
+ }
+}
+
+void
+Variables::_parseQueryString(const char *query_string, int query_string_len) {
+ _insert(_simple_data, string("QUERY_STRING"), string(query_string, query_string_len));
+ AttributeList attr_list;
+ Utils::parseAttributes(query_string, query_string_len, attr_list, "&");
+ for (AttributeList::iterator iter = attr_list.begin(); iter != attr_list.end(); ++iter) {
+ _debugLog(_debug_tag.c_str(), "[%s] Inserting query string variable [%.*s] with value [%.*s]",
+ __FUNCTION__, iter->name_len, iter->name, iter->value_len, iter->value);
+ _insert(_dict_data[QUERY_STRING], string(iter->name, iter->name_len),
+ string(iter->value, iter->value_len));
+ }
+}
+
+void
+Variables::_parseCachedHeaders() {
+ _debugLog(_debug_tag.c_str(), "[%s] Parsing headers", __FUNCTION__);
+ for (int i = 0; i < N_SIMPLE_HEADERS; ++i) {
+ for (HeaderValueList::iterator value_iter = _cached_simple_headers[i].begin();
+ value_iter != _cached_simple_headers[i].end(); ++value_iter) {
+ _parseSimpleHeader(static_cast<SimpleHeader>(i), *value_iter);
+ }
+ }
+ for (int i = 0; i < N_SPECIAL_HEADERS; ++i) {
+ for (HeaderValueList::iterator value_iter = _cached_special_headers[i].begin();
+ value_iter != _cached_special_headers[i].end(); ++value_iter) {
+ _parseSpecialHeader(static_cast<SpecialHeader>(i), value_iter->data(), value_iter->size());
+ }
+ }
+}
+
+const std::string &
+Variables::getValue(const string &name) const {
+ if (!_headers_parsed || !_query_string_parsed) {
+ // we need to do this because we want to
+ // 1) present const getValue() to clients
+ // 2) parse lazily (only on demand)
+ Variables &non_const_self = const_cast<Variables &>(*this);
+ if (!_headers_parsed) {
+ non_const_self._parseCachedHeaders();
+ non_const_self._headers_parsed = true;
+ }
+ if (!_query_string_parsed) {
+ int query_string_size = static_cast<int>(_query_string.size());
+ if (query_string_size) {
+ non_const_self._parseQueryString(_query_string.data(), query_string_size);
+ non_const_self._query_string_parsed = true;
+ }
+ }
+ }
+ string search_key(name);
+ _toUpperCase(search_key);
+ StringHash::const_iterator iter = _simple_data.find(search_key);
+ if (iter != _simple_data.end()) {
+ _debugLog(_debug_tag.c_str(), "[%s] Found value [%.*s] for variable [%.*s] in simple data",
+ __FUNCTION__, iter->second.size(), iter->second.data(), name.size(), name.data());
+ return iter->second;
+ }
+ const char *header;
+ int header_len;
+ const char *attr;
+ int attr_len;
+ if (!_parseDictVariable(name, header, header_len, attr, attr_len)) {
+ _debugLog(_debug_tag.c_str(), "[%s] Unmatched simple variable [%.*s] not in dict variable form",
+ __FUNCTION__, name.size(), name.data());
+ return EMPTY_STRING;
+ }
+ int dict_index = _searchHeaders(NORM_SPECIAL_HEADERS, header, header_len); // ignore the HTTP_ prefix
+ if (dict_index == -1) {
+ _debugLog(_debug_tag.c_str(), "[%s] Dict variable [%.*s] refers to unknown dictionary",
+ __FUNCTION__, name.size(), name.data());
+ return EMPTY_STRING;
+ }
+
+ // change variable name to use only the attribute field
+ search_key.assign(attr, attr_len);
+
+ iter = _dict_data[dict_index].find(search_key);
+
+ if (dict_index == HTTP_ACCEPT_LANGUAGE) {
+ _debugLog(_debug_tag.c_str(), "[%s] Returning boolean literal for lang variable [%.*s]",
+ __FUNCTION__, search_key.size(), search_key.data());
+ return (iter == _dict_data[dict_index].end()) ? EMPTY_STRING : TRUE_STRING;
+ }
+
+ if (iter != _dict_data[dict_index].end()) {
+ _debugLog(_debug_tag.c_str(), "[%s] Found variable [%.*s] in %s dictionary with value [%.*s]",
+ __FUNCTION__, search_key.size(), search_key.data(), NORM_SPECIAL_HEADERS[dict_index].c_str(),
+ iter->second.size(), iter->second.data());
+ return iter->second;
+ }
+
+ size_t cookie_part_divider = (dict_index == HTTP_COOKIE) ? search_key.find(';') : search_key.size();
+ if (cookie_part_divider && (cookie_part_divider < (search_key.size() - 1))) {
+ _debugLog(_debug_tag.c_str(), "[%s] Cookie variable [%s] refers to sub cookie",
+ __FUNCTION__, search_key.c_str());
+ return _getSubCookieValue(search_key, cookie_part_divider);
+ }
+
+ _debugLog(_debug_tag.c_str(), "[%s] Found no value for dict variable [%s]", __FUNCTION__, name.c_str());
+ return EMPTY_STRING;
+}
+
+const string &
+Variables::_getSubCookieValue(const string &cookie_str, size_t cookie_part_divider) const {
+ if (!_cookie_jar_created) {
+ if (_cookie_str.size()) {
+ Variables &non_const_self = const_cast<Variables &>(*this); // same reasoning as in getValue()
+ // TODO - code was here
+ non_const_self._cookie_jar_created = true;
+ } else {
+ _debugLog(_debug_tag.c_str(), "[%s] Cookie string empty; nothing to construct jar from", __FUNCTION__);
+ }
+ }
+ if (_cookie_jar_created) {
+ // we need to do this as we are going to manipulate the 'divider'
+ // character, and we don't need to create a copy of the string for
+ // that; hence this shortcut
+ string &non_const_cookie_str = const_cast<string &>(cookie_str);
+
+ non_const_cookie_str[cookie_part_divider] = '\0'; // make sure cookie name is NULL terminated
+ const char *cookie_name = non_const_cookie_str.data(); /* above NULL will take effect */
+ const char *part_name =
+ non_const_cookie_str.c_str() /* NULL terminate the part */ + cookie_part_divider + 1;
+ bool user_name = (part_name[0] == 'u') && (part_name[1] == '\0');
+ if (user_name) {
+ part_name = "l";
+ }
+ // TODO - code was here
+ const char *sub_cookie_value = NULL;
+ non_const_cookie_str[cookie_part_divider] = ';'; // restore before returning
+ if (!sub_cookie_value) {
+ _debugLog(_debug_tag.c_str(), "[%s] Could not find value for part [%s] of cookie [%.*s]", __FUNCTION__,
+ part_name, cookie_part_divider, cookie_name);
+ return EMPTY_STRING;
+ } else {
+ // we need to do this as have to return a string reference
+ string &retval = const_cast<Variables &>(*this)._cached_sub_cookie_value;
+
+ if (user_name) {
+ char unscrambled_login[256];
+ // TODO - code was here
+ _debugLog(_debug_tag.c_str(), "[%s] Unscrambled login name to [%s]", __FUNCTION__, unscrambled_login);
+ retval.assign(unscrambled_login);
+ } else {
+ _debugLog(_debug_tag.c_str(), "[%s] Got value [%s] for cookie name [%.*s] and part [%s]",
+ __FUNCTION__, sub_cookie_value, cookie_part_divider, cookie_name, part_name);
+ retval.assign(sub_cookie_value);
+ }
+ return retval;
+ }
+ } else {
+ _errorLog("[%s] Cookie jar not available; Returning empty string", __FUNCTION__);
+ return EMPTY_STRING;
+ }
+}
+
+void
+Variables::clear() {
+ _simple_data.clear();
+ for (int i = 0; i < N_SPECIAL_HEADERS; ++i) {
+ _dict_data[i].clear();
+ _cached_special_headers[i].clear();
+ }
+ for (int i = 0; i < N_SIMPLE_HEADERS; ++i) {
+ _cached_simple_headers[i].clear();
+ }
+ _query_string.clear();
+ _headers_parsed = _query_string_parsed = false;
+ _cookie_str.clear();
+ _releaseCookieJar();
+}
+
+void
+Variables::_parseCookieString(const char *str, int str_len) {
+ AttributeList cookies;
+ Utils::parseAttributes(str, str_len, cookies, ";,");
+ for (AttributeList::iterator iter = cookies.begin(); iter != cookies.end(); ++iter) {
+ _insert(_dict_data[HTTP_COOKIE], string(iter->name, iter->name_len), string(iter->value, iter->value_len));
+ _debugLog(_debug_tag.c_str(), "[%s] Inserted cookie with name [%.*s] and value [%.*s]", __FUNCTION__,
+ iter->name_len, iter->name, iter->value_len, iter->value);
+ }
+}
+
+void
+Variables::_parseUserAgentString(const char *str, int str_len) {
+ string user_agent_str(str, str_len); // need NULL-terminated version
+ // TODO - code was here
+ char version_buf[64];
+ // TODO - code was here
+ _insert(_dict_data[HTTP_USER_AGENT], VERSION_STRING, version_buf);
+}
+
+void
+Variables::_parseAcceptLangString(const char *str, int str_len) {
+ int i;
+ for(i = 0; (i < str_len) && ((isspace(str[i]) || str[i] == ',')); ++i);
+ const char *lang = str + i;
+ int lang_len;
+ for (; i <= str_len; ++i) {
+ if ((i == str_len) || (str[i] == ',')) {
+ lang_len = str + i - lang;
+ for (; lang_len && isspace(lang[lang_len - 1]); --lang_len);
+ if (lang_len) {
+ _insert(_dict_data[HTTP_ACCEPT_LANGUAGE], string(lang, lang_len), EMPTY_STRING);
+ _debugLog(_debug_tag.c_str(), "[%s] Added language [%.*s]", __FUNCTION__, lang_len, lang);
+ }
+ for(; (i < str_len) && ((isspace(str[i]) || str[i] == ',')); ++i);
+ lang = str + i;
+ }
+ }
+}
+
+bool
+Variables::_parseDictVariable(const std::string &variable, const char *&header, int &header_len,
+ const char *&attr, int &attr_len) const {
+ const char *var_ptr = variable.data();
+ int var_size = variable.size();
+ if ((var_size <= 4) || (variable[var_size - 1] != '}')) {
+ return false;
+ }
+ int paranth_index = -1;
+ for (int i = 0; i < (var_size - 1); ++i) {
+ if (variable[i] == '{') {
+ if (paranth_index != -1) {
+ _debugLog(_debug_tag.c_str(), "[%s] Cannot have multiple paranthesis in dict variable [%.*s]",
+ __FUNCTION__, var_size, var_ptr);
+ return false;
+ }
+ paranth_index = i;
+ }
+ if (variable[i] == '}') {
+ _debugLog(_debug_tag.c_str(), "[%s] Cannot have multiple paranthesis in dict variable [%.*s]",
+ __FUNCTION__, var_size, var_ptr);
+ return false;
+ }
+ }
+ if (paranth_index == -1) {
+ _debugLog(_debug_tag.c_str(), "[%s] Could not find opening paranthesis in variable [%.*s]",
+ __FUNCTION__, var_size, var_ptr);
+ return false;
+ }
+ if (paranth_index == 0) {
+ _debugLog(_debug_tag.c_str(), "[%s] Dict variable has no dict name [%.*s]",
+ __FUNCTION__, var_size, var_ptr);
+ return false;
+ }
+ if (paranth_index == (var_size - 2)) {
+ _debugLog(_debug_tag.c_str(), "[%s] Dict variable has no attribute name [%.*s]",
+ __FUNCTION__, var_size, var_ptr);
+ return false;
+ }
+ header = var_ptr;
+ header_len = paranth_index;
+ attr = var_ptr + paranth_index + 1;
+ attr_len = var_size - header_len - 2;
+ return true;
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/Variables.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/Variables.h b/plugins/experimental/esi/lib/Variables.h
new file mode 100644
index 0000000..7bc985c
--- /dev/null
+++ b/plugins/experimental/esi/lib/Variables.h
@@ -0,0 +1,156 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _ESI_VARIABLES_H
+
+#define _ESI_VARIABLES_H
+
+#include <list>
+#include <boost/noncopyable.hpp>
+
+#include <cstring>
+#include "ComponentBase.h"
+#include "StringHash.h"
+#include "HttpHeader.h"
+
+namespace EsiLib {
+
+class Variables : private ComponentBase, boost::noncopyable {
+
+public:
+
+ Variables(const char *debug_tag, ComponentBase::Debug debug_func, ComponentBase::Error error_func)
+ : ComponentBase(debug_tag, debug_func, error_func), _headers_parsed(false), _query_string(""),
+ _query_string_parsed(false), _cookie_jar_created(false) { };
+
+ /** currently 'host', 'referer', 'accept-language', 'cookie' and 'user-agent' headers are parsed */
+ void populate(const HttpHeader &header);
+
+ void populate(const HttpHeaderList &headers) {
+ for (HttpHeaderList::const_iterator iter = headers.begin(); iter != headers.end(); ++iter) {
+ populate(*iter);
+ }
+ };
+
+ void populate(const char *query_string, int query_string_len = -1) {
+ if (query_string && (query_string_len != 0)) {
+ if (query_string_len == -1) {
+ query_string_len = strlen(query_string);
+ }
+ if (_query_string_parsed) {
+ _parseQueryString(query_string, query_string_len);
+ } else {
+ _query_string.assign(query_string, query_string_len);
+ }
+ }
+ }
+
+ /** returns value of specified variable; empty string returned for unknown variable; key
+ * has to be prefixed with 'http_' string for all variable names except 'query_string' */
+ const std::string &getValue(const std::string &name) const;
+
+ /** convenient alternative for method above */
+ const std::string &getValue(const char *name, int name_len = -1) const {
+ if (!name) {
+ return EMPTY_STRING;
+ }
+ std::string var_name;
+ if (name_len == -1) {
+ var_name.assign(name);
+ } else {
+ var_name.assign(name, name_len);
+ }
+ return getValue(var_name);
+ }
+
+ void clear();
+
+ virtual ~Variables() { _releaseCookieJar(); };
+
+private:
+
+ static const std::string EMPTY_STRING;
+ static const std::string TRUE_STRING;
+ static const std::string VENDOR_STRING;
+ static const std::string VERSION_STRING;
+ static const std::string PLATFORM_STRING;
+
+ enum SimpleHeader { HTTP_HOST = 0, HTTP_REFERER = 1 };
+ static const std::string SIMPLE_HEADERS[]; // indices should map to enum values above
+
+ enum SpecialHeader { HTTP_ACCEPT_LANGUAGE = 0, HTTP_COOKIE = 1, HTTP_USER_AGENT = 2, QUERY_STRING = 3 };
+ static const std::string SPECIAL_HEADERS[]; // indices should map to enum values above
+
+ // normalized versions of the headers above; indices should correspond correctly
+ static const std::string NORM_SIMPLE_HEADERS[];
+ static const std::string NORM_SPECIAL_HEADERS[]; // indices should again map to enum values
+
+ static const int N_SIMPLE_HEADERS = HTTP_REFERER + 1;
+ static const int N_SPECIAL_HEADERS = QUERY_STRING + 1;
+
+ StringHash _simple_data;
+ StringHash _dict_data[N_SPECIAL_HEADERS];
+
+ inline std::string &_toUpperCase(std::string &str) const;
+ inline int _searchHeaders(const std::string headers[], const char *name, int name_len) const;
+ bool _parseDictVariable(const std::string &variable, const char *&header, int &header_len,
+ const char *&attr, int &attr_len) const;
+ void _parseCookieString(const char *str, int str_len);
+ void _parseUserAgentString(const char *str, int str_len);
+ void _parseAcceptLangString(const char *str, int str_len);
+ inline void _parseSimpleHeader(SimpleHeader hdr, const std::string &value);
+ inline void _parseSimpleHeader(SimpleHeader hdr, const char *value, int value_len);
+ void _parseSpecialHeader(SpecialHeader hdr, const char *value, int value_len);
+ void _parseCachedHeaders();
+
+ inline void _insert(StringHash &hash, const std::string &key, const std::string &value);
+
+ typedef std::list<std::string> HeaderValueList;
+ HeaderValueList _cached_simple_headers[N_SIMPLE_HEADERS];
+ HeaderValueList _cached_special_headers[N_SPECIAL_HEADERS];
+
+ std::string _cookie_str;
+ bool _headers_parsed;
+ std::string _query_string;
+ bool _query_string_parsed;
+
+ void _parseHeader(const char *name, int name_len, const char *value, int value_len);
+ void _parseQueryString(const char *query_string, int query_string_len);
+
+ // TODO - code was here
+ bool _cookie_jar_created;
+
+ inline void _releaseCookieJar() {
+ if (_cookie_jar_created) {
+ _cookie_jar_created = false;
+ }
+ }
+
+ std::string _cached_sub_cookie_value;
+ const std::string &_getSubCookieValue(const std::string &cookie_str, size_t cookie_part_divider) const;
+
+};
+
+};
+
+#endif // _ESI_VARIABLES_H
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/gzip.cc
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/gzip.cc b/plugins/experimental/esi/lib/gzip.cc
new file mode 100644
index 0000000..0ec0ee4
--- /dev/null
+++ b/plugins/experimental/esi/lib/gzip.cc
@@ -0,0 +1,204 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include "gzip.h"
+#include <zlib.h>
+
+#include "Utils.h"
+
+using namespace EsiLib;
+using std::string;
+
+static const int COMPRESSION_LEVEL = 6;
+static const int ZLIB_MEM_LEVEL = 8;
+
+static const int GZIP_HEADER_SIZE = 10;
+static const int GZIP_TRAILER_SIZE = 8;
+
+static const char MAGIC_BYTE_1 = 0x1f;
+static const char MAGIC_BYTE_2 = 0x8b;
+static const char OS_TYPE = 3; // Unix
+
+static const int BUF_SIZE = 1 << 15; // 32k buffer
+
+template<typename T>
+inline void append(string &out, T data) {
+ for (unsigned int i = 0; i < sizeof(data); ++i) {
+ out += static_cast<char>(data & 0xff);
+ data = data >> 8;
+ }
+}
+
+template<typename T>
+inline void extract(const char *in, T &data) {
+ data = 0;
+ for (int i = (sizeof(data) - 1); i >= 0; --i) {
+ data = data << 8;
+ data = data | static_cast<unsigned char>(*(in + i));
+ }
+}
+
+inline int runDeflateLoop(z_stream &zstrm, int flush, std::string &cdata) {
+ char buf[BUF_SIZE];
+ int deflate_result = Z_OK;
+ do {
+ zstrm.next_out = reinterpret_cast<Bytef *>(buf);
+ zstrm.avail_out = BUF_SIZE;
+ deflate_result = deflate(&zstrm, flush);
+ if ((deflate_result == Z_OK) || (deflate_result == Z_STREAM_END)) {
+ cdata.append(buf, BUF_SIZE - zstrm.avail_out);
+ if ((deflate_result == Z_STREAM_END) || zstrm.avail_out) {
+ break;
+ }
+ } else {
+ break;
+ }
+ } while (true);
+ return deflate_result;
+}
+
+bool
+EsiLib::gzip(const ByteBlockList& blocks, std::string &cdata) {
+ cdata.assign(GZIP_HEADER_SIZE, 0); // reserving space for the header
+ z_stream zstrm;
+ zstrm.zalloc = Z_NULL;
+ zstrm.zfree = Z_NULL;
+ zstrm.opaque = Z_NULL;
+ if (deflateInit2(&zstrm, COMPRESSION_LEVEL, Z_DEFLATED, -MAX_WBITS,
+ ZLIB_MEM_LEVEL, Z_DEFAULT_STRATEGY) != Z_OK) {
+ Utils::ERROR_LOG("[%s] deflateInit2 failed!", __FUNCTION__);
+ return false;
+ }
+
+ int total_data_len = 0;
+ uLong crc = crc32(0, Z_NULL, 0);
+ int deflate_result = Z_OK;
+ int in_data_size = 0;
+ for (ByteBlockList::const_iterator iter = blocks.begin(); iter != blocks.end(); ++iter) {
+ if (iter->data && (iter->data_len > 0)) {
+ zstrm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(iter->data));
+ zstrm.avail_in = iter->data_len;
+ in_data_size += iter->data_len;
+ deflate_result = runDeflateLoop(zstrm, 0, cdata);
+ if (deflate_result != Z_OK) {
+ break; // break out of the blocks iteration
+ }
+ crc = crc32(crc, reinterpret_cast<const Bytef *>(iter->data), iter->data_len);
+ total_data_len += iter->data_len;
+ }
+ }
+ if (!in_data_size) {
+ zstrm.avail_in = 0; // required for the "finish" loop as no data has been given so far
+ }
+ if (deflate_result == Z_OK) {
+ deflate_result = runDeflateLoop(zstrm, Z_FINISH, cdata);
+ }
+ deflateEnd(&zstrm);
+ if (deflate_result != Z_STREAM_END) {
+ Utils::ERROR_LOG("[%s] Failure while deflating; error code %d", __FUNCTION__, deflate_result);
+ return false;
+ }
+ cdata[0] = MAGIC_BYTE_1;
+ cdata[1] = MAGIC_BYTE_2;
+ cdata[2] = Z_DEFLATED;
+ cdata[9] = OS_TYPE;
+ append(cdata, static_cast<uint32_t>(crc));
+ append(cdata, static_cast<int32_t>(total_data_len));
+ return true;
+}
+
+bool
+EsiLib::gunzip(const char *data, int data_len, BufferList &buf_list) {
+ if (!data || (data_len <= (GZIP_HEADER_SIZE + GZIP_TRAILER_SIZE))) {
+ Utils::ERROR_LOG("[%s] Invalid arguments: 0x%p, %d", __FUNCTION__, data, data_len);
+ return false;
+ }
+ if ((data[0] != MAGIC_BYTE_1) || (data[1] != MAGIC_BYTE_2) || (data[2] != Z_DEFLATED) ||
+ (data[9] != OS_TYPE)) {
+ Utils::ERROR_LOG("[%s] Header check failed!", __FUNCTION__);
+ return false;
+ }
+ data += GZIP_HEADER_SIZE;
+ data_len -= (GZIP_HEADER_SIZE + GZIP_TRAILER_SIZE);
+ buf_list.clear();
+ z_stream zstrm;
+ zstrm.zalloc = Z_NULL;
+ zstrm.zfree = Z_NULL;
+ zstrm.opaque = Z_NULL;
+ zstrm.next_in = 0;
+ zstrm.avail_in = 0;
+ if (inflateInit2(&zstrm, -MAX_WBITS) != Z_OK) {
+ Utils::ERROR_LOG("[%s] inflateInit2 failed!", __FUNCTION__);
+ return false;
+ }
+ zstrm.next_in = reinterpret_cast<Bytef *>(const_cast<char *>(data));
+ zstrm.avail_in = data_len;
+ char raw_buf[BUF_SIZE];
+ int inflate_result;
+ int32_t unzipped_data_size = 0;
+ int32_t curr_buf_size;
+ uLong crc = crc32(0, Z_NULL, 0);
+ do {
+ zstrm.next_out = reinterpret_cast<Bytef *>(raw_buf);
+ zstrm.avail_out = BUF_SIZE;
+ inflate_result = inflate(&zstrm, Z_FINISH);
+ curr_buf_size = -1;
+ if ((inflate_result == Z_OK) || (inflate_result == Z_BUF_ERROR)) {
+ curr_buf_size = BUF_SIZE;
+ } else if (inflate_result == Z_STREAM_END) {
+ curr_buf_size = BUF_SIZE - zstrm.avail_out;
+ }
+ if (curr_buf_size == -1) {
+ break;
+ }
+ unzipped_data_size += curr_buf_size;
+ crc = crc32(crc, reinterpret_cast<const Bytef *>(raw_buf), curr_buf_size);
+
+ // push empty object onto list and add data to in-list object to
+ // avoid data copy for temporary
+ buf_list.push_back(string());
+ string &curr_buf = buf_list.back();
+ curr_buf.assign(raw_buf, curr_buf_size);
+
+ if (inflate_result == Z_STREAM_END) {
+ break;
+ }
+ } while (true);
+ inflateEnd(&zstrm);
+ if (inflate_result != Z_STREAM_END) {
+ Utils::ERROR_LOG("[%s] Failure while inflating; error code %d", __FUNCTION__, inflate_result);
+ return false;
+ }
+ int32_t orig_size;
+ uLong orig_crc;
+ extract(data + data_len, orig_crc);
+ extract(data + data_len + 4, orig_size);
+ if ((crc != orig_crc) || (unzipped_data_size != orig_size)) {
+ Utils::ERROR_LOG("[%s] CRC/size error. Expecting (CRC, size) (0x%x, 0x%x); computed (0x%x, 0x%x)",
+ __FUNCTION__, orig_crc, orig_size, crc, unzipped_data_size);
+ return false;
+ }
+ return true;
+}
http://git-wip-us.apache.org/repos/asf/trafficserver/blob/bc13c5e0/plugins/experimental/esi/lib/gzip.h
----------------------------------------------------------------------
diff --git a/plugins/experimental/esi/lib/gzip.h b/plugins/experimental/esi/lib/gzip.h
new file mode 100644
index 0000000..92d81ec
--- /dev/null
+++ b/plugins/experimental/esi/lib/gzip.h
@@ -0,0 +1,55 @@
+/** @file
+
+ A brief file description
+
+ @section license License
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ */
+
+#ifndef _GZIP_H
+
+#define _GZIP_H
+
+#include <string>
+#include <list>
+
+namespace EsiLib {
+
+struct ByteBlock {
+ const char *data;
+ int data_len;
+ ByteBlock(const char *d = 0, int d_len = 0) : data(d), data_len(d_len) { };
+};
+
+typedef std::list<ByteBlock> ByteBlockList;
+
+bool gzip(const ByteBlockList& blocks, std::string &cdata);
+
+inline bool gzip(const char *data, int data_len, std::string &cdata) {
+ ByteBlockList blocks;
+ blocks.push_back(ByteBlock(data, data_len));
+ return gzip(blocks, cdata);
+}
+
+typedef std::list<std::string> BufferList;
+
+bool gunzip(const char *data, int data_len, BufferList &buf_list);
+
+}
+
+#endif // _GZIP_H