merge cpp-ports

Sat, 24 Sep 2022 17:11:57 +0200

author
Olaf Wintermann <olaf.wintermann@gmail.com>
date
Sat, 24 Sep 2022 17:11:57 +0200
changeset 386
b91f8efadb63
parent 385
a1f4cb076d2f (current diff)
parent 365
2ea1ed291e9f (diff)
child 387
f5caf41b4db6

merge cpp-ports

src/server/daemon/webserver.c file | annotate | diff | comparison | revisions
src/server/util/pblock.c file | annotate | diff | comparison | revisions
src/server/util/pblock.cpp file | annotate | diff | comparison | revisions
src/server/util/pblock.h file | annotate | diff | comparison | revisions
src/server/util/uri.c file | annotate | diff | comparison | revisions
src/server/util/uri.cpp file | annotate | diff | comparison | revisions
src/server/util/util.h file | annotate | diff | comparison | revisions
--- a/src/server/daemon/webserver.c	Sat Sep 24 16:26:10 2022 +0200
+++ b/src/server/daemon/webserver.c	Sat Sep 24 17:11:57 2022 +0200
@@ -45,7 +45,7 @@
 #include "../public/nsapi.h"
 #include "../public/auth.h"
 #include "../util/systhr.h"
-#include "../util/io.h"
+#include "../util/pblock.h"
 #include "../util/util.h"
 
 #include <ucx/utils.h>
@@ -57,7 +57,6 @@
 #include "configmanager.h"
 #include "httplistener.h"
 #include "webserver.h"
-#include "log.h"
 #include "auth.h"
 #include "srvctrl.h"
 #include "resourcepool.h"
@@ -76,6 +75,8 @@
     }
     
     // init NSAPI functions
+    pblock_init_default_keys();
+    atexit(pblock_free_default_keys);
     func_init();
     add_functions(webserver_funcs);
     
--- a/src/server/util/LinkedList.hh	Sat Sep 24 16:26:10 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,274 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- *
- * THE BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without 
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer. 
- * Redistributions in binary form must reproduce the above copyright notice, 
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution. 
- *
- * Neither the name of the  nor the names of its contributors may be
- * used to endorse or promote products derived from this software without 
- * specific prior written permission. 
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef _LINKED_LIST_H_
-#define _LINKED_LIST_H_
-
-/*
- *   Provided a template implementation of a simple linked list. 
- * It is a reference based container (stores the pointers to the
- * objects contained) It doesn't check for duplicates etc and find
- * (delete) will find(delete) the first occurence of an element.
- *
- * Iterator class can be used for traversal using the "++" operator.
- */
-template <class C> class CList; // forward declaration
-template <class C> class CListIterator; // forward declaration
-template <class C> class CListConstIterator; // forward declaration
-
-template <class C> class CListElmt {
-  friend class CList<C>;
-  friend class CListIterator<C>;
-  friend class CListConstIterator<C>;
-  private:
-    CListElmt(C* refP, int id) : _refP(refP), _nextP(0), _prevP(0), _id(id)
-        {
-                // Nothing really has to be done here
-        };
-
-
-  private:
-    int       _id;    
-    C         *_refP;
-#if defined(AIX)
-    CListElmt<C> *_nextP;
-    CListElmt<C> *_prevP;
-#else
-    CListElmt *_nextP;
-    CListElmt *_prevP;
-#endif
-};
-
-//
-// NOTE : If you need the find functionality, make sure that 
-//  class C has "==" defined.
-//
-template <class C> class CList {
-  friend class CListIterator<C>;
-  friend class CListConstIterator<C>;
-  private:
-    CListElmt<C>* _headP;
-    CListElmt<C>* _tailP;
-    CListElmt<C>* Lookup(C * memberP)
-        {
-                CListElmt<C> *curEltP = _headP;
-                
-                while (curEltP)
-                {
-                        if (curEltP->_refP == memberP) 
-                                break;
-                        curEltP = curEltP->_nextP;
-                };
-                return(curEltP);
-        };
-    
-    int _nextId;
-    int _numElts;
-    int autoDestroy;
-    C* Remove(CListElmt<C> *elmtP)
-        {
-                C  *recP = NULL;
-                if (elmtP)
-                {
-                        if (elmtP->_nextP)
-                                elmtP->_nextP->_prevP = elmtP->_prevP;
-                        if (elmtP->_prevP)
-                                elmtP->_prevP->_nextP = elmtP->_nextP;
-                        if (elmtP == _tailP)
-                                _tailP = elmtP->_prevP;
-                        if (elmtP == _headP)
-                                _headP = _headP->_nextP;
-                        recP = elmtP->_refP;
-                        _numElts--;
-                        delete elmtP;
-                };
-                if ( (1==autoDestroy) && recP) {
-                        delete recP;
-                        recP = NULL;
-                }
-                
-                return(recP);
-        };
-    
-
-  public:
-    CList() :  _headP(0), _tailP(0), _nextId(0), _numElts(0), autoDestroy(0)
-        {
-                // Nothing really has to be done here
-        };
-        
-    void setAutoDestroy(int setting)
-        {
-                autoDestroy = setting;
-        };
-
-    virtual ~CList()
-        {
-                while (_headP)
-                        Remove(_headP);
-        };
-
-    int NextId()
-        {
-                return _nextId;
-        };
-
-    int Append(C* refP)
-        {
-                CListElmt<C> *newElmtP = new CListElmt<C>(refP, _nextId++);
-                newElmtP->_prevP = _tailP;
-                if (_tailP)
-                        _tailP->_nextP = newElmtP;
-                if (_headP == 0)
-                        _headP = newElmtP;
-                _tailP = newElmtP;
-                _numElts++;
-                return(newElmtP->_id);
-        };
-
-    int Member(C* memberP)
-        {
-                return(Lookup(memberP) != 0);
-        };
-    
-    int Delete(C* memberP)
-        {
-                CListElmt<C> *listElmtP = Lookup(memberP);
-                if (listElmtP)
-                {
-                        (void) Remove(listElmtP);
-                        return(1);
-                }
-                return(0);
-        };
-    
-    int NumEntries() const { return _numElts; }
-    C* Find(C* memberP) // Lookup based on == operator for class C
-        {
-                CListElmt<C> *curEltP = _headP;
-        
-                while (curEltP)
-                {
-                        if (curEltP->_refP == memberP) 
-                                break;
-                        curEltP = curEltP->_nextP;
-                };
-                return(curEltP ? curEltP->_refP : 0);
-        };
-    
-    C* First() { return(_headP ? _headP->_refP : 0); }
-    C* Last() { return(_tailP ? _tailP->_refP : 0); }
-};
-
-template <class C> class CListIterator {
-  private:
-    CList<C>* _listP;
-    int _curId;
-  public:
-    CListIterator(CList<C>* linkedListP) : _listP(linkedListP), _curId(-1)
-        {
-                // Nothing more to be done
-        };
-    
-    virtual ~CListIterator()
-        {
-                _listP = NULL;
-        };
-    
-    C* operator++() // Define ++ operator to move forward along the list.
-        {
-                C *valueP = NULL;
-                CListElmt<C> *curEltP = _listP->_headP;
-
-                while (curEltP)
-                {
-                        if (curEltP->_id > _curId)
-                        {
-                                _curId = curEltP->_id;
-                                return(curEltP->_refP);
-                        }
-                        curEltP = curEltP->_nextP;
-                }
-                _curId = -1;
-                return(NULL);
-        };
-    
-    void operator()() // Overload the function operator to reset the iterator
-        {
-                _curId = -1;
-        };
-    
-};
-
-template <class C> class CListConstIterator {
-  private:
-    const CList<C>* _listP;
-    int _curId;
-  public:
-    CListConstIterator(const CList<C>* linkedListP)
-        : _listP(linkedListP), _curId(-1)
-        {
-                // Nothing more to be done
-        };
-    
-    virtual ~CListConstIterator()
-        {
-                _listP = NULL;
-        };
-    
-    const C* operator++() // Define ++ operator to move forward along the list.
-        {
-                const C *valueP = NULL;
-                const CListElmt<C> *curEltP = _listP->_headP;
-
-                while (curEltP)
-                {
-                        if (curEltP->_id > _curId)
-                        {
-                                _curId = curEltP->_id;
-                                return(curEltP->_refP);
-                        }
-                        curEltP = curEltP->_nextP;
-                }
-                _curId = -1;
-                return(NULL);
-        };
-    
-    void operator()() // Overload the function operator to reset the iterator
-        {
-                _curId = -1;
-        };
-    
-};
-
-#endif // _LINKED_LIST_H_
--- a/src/server/util/Makefile	Sat Sep 24 16:26:10 2022 +0200
+++ b/src/server/util/Makefile	Sat Sep 24 17:11:57 2022 +0200
@@ -30,7 +30,3 @@
 
 $(UTIL_OBJPRE)%.o: util/%.c
 	$(CC) -o $@ -c $(UTIL_CFLAGS) $(CFLAGS) $<
-
-$(UTIL_OBJPRE)%.o: util/%.cpp
-	$(CXX) -o $@ -c $(UTIL_CFLAGS) $(CFLAGS) $<
-	
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/util/pblock.c	Sat Sep 24 17:11:57 2022 +0200
@@ -0,0 +1,1421 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ *
+ * THE BSD LICENSE
+ *
+ * Redistribution and use in source and binary forms, with or without 
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer. 
+ * Redistributions in binary form must reproduce the above copyright notice, 
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution. 
+ *
+ * Neither the name of the  nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without 
+ * specific prior written permission. 
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * pblock.c: Handles Parameter Blocks
+ * 
+ * See pblock.h for public documentation.
+ * 
+ * Rob McCool
+ * 
+ * This code uses property lists to implement pblocks.
+ */
+
+
+#include "pblock.h"
+#include "plist_pvt.h"
+#include "plist.h"
+#include "util.h"   /* util_itoa */
+#include "pool.h"
+#include "systhr.h"
+
+#define MALLOC_POOL_HANDLE (thread_malloc_key != -1 ? (pool_handle_t *)systhread_getdata(thread_malloc_key) : getThreadMallocPool())
+
+static int thread_malloc_key = -1;
+static int _pblock_str2pblock(const char* str, pblock* pb, PRBool lowerCase);
+
+static pool_handle_t *getThreadMallocPool()
+{
+    pool_handle_t *thread_malloc_pool = 0;
+
+    thread_malloc_key = getThreadMallocKey();
+    if (thread_malloc_key != -1) {
+        thread_malloc_pool = (pool_handle_t *)systhread_getdata(thread_malloc_key);
+    }
+
+    return thread_malloc_pool;
+}
+
+/* ---------------------- pb_key static initializers ---------------------- */
+
+/*
+ * pb_key
+ *
+ * Contains a precomputed hash value for a specific pblock variable name.
+ */
+typedef struct pb_key pb_key;
+struct pb_key {
+    const char *name;
+    int namelen; 
+    unsigned int hashval;
+    int sizendx;
+    int hashndx;
+};
+
+#define PB_KEY_LIST_BUCKET_COUNT 0x7f // has to be (2^n - 1)
+
+struct pb_key_list_bucket {
+    pb_key **elements;
+    unsigned size;
+};
+
+struct pb_key_list {
+    struct pb_key_list_bucket buckets[PB_KEY_LIST_BUCKET_COUNT + 1];
+};
+
+static void _pb_key_list_insert(struct pb_key_list *hashList, unsigned int hashval, pb_key* element) {
+    struct pb_key_list_bucket *bucket = &hashList->buckets[hashval & PB_KEY_LIST_BUCKET_COUNT];
+    size_t idx = bucket->size;
+    bucket->size++;
+    bucket->elements = realloc(bucket->elements, sizeof(pb_key*) * bucket->size);
+    if (bucket->elements == NULL) abort();
+    bucket->elements[idx] = element;
+}
+
+static struct pb_key_list _pbKeys;
+
+static const pb_key *_create_key(const char *name)
+{
+    /* Create a new pb_key */
+    pb_key *key = malloc(sizeof(pb_key));
+    if (key == NULL) abort();
+    key->name = STRDUP(name);
+    key->namelen = strlen(name);
+    key->hashval = PListHash(name);
+    key->sizendx = 0;
+    key->hashndx = key->hashval % PLSIZENDX(0);
+
+    /* Group pb_keys by hashval for later retrieval */
+    _pb_key_list_insert(&_pbKeys, key->hashval, key);
+
+    return key;
+}
+
+const pb_key *pb_key_accept;
+const pb_key *pb_key_accept_charset;
+const pb_key *pb_key_accept_encoding;
+const pb_key *pb_key_accept_language;
+const pb_key *pb_key_accept_ranges;
+const pb_key *pb_key_actual_route;
+const pb_key *pb_key_age;
+const pb_key *pb_key_always_allow_chunked;
+const pb_key *pb_key_always_use_keep_alive;
+const pb_key *pb_key_auth_cert;
+const pb_key *pb_key_auth_expiring;
+const pb_key *pb_key_auth_group;
+const pb_key *pb_key_auth_type;
+const pb_key *pb_key_auth_user;
+const pb_key *pb_key_authorization;
+const pb_key *pb_key_browser;
+const pb_key *pb_key_c2p_cl;
+const pb_key *pb_key_c2p_hl;
+const pb_key *pb_key_cache_info;
+const pb_key *pb_key_charset;
+const pb_key *pb_key_check_http_server;
+const pb_key *pb_key_ChunkedRequestBufferSize;
+const pb_key *pb_key_ChunkedRequestTimeout;
+const pb_key *pb_key_cipher;
+const pb_key *pb_key_clf_request;
+const pb_key *pb_key_cli_status;
+const pb_key *pb_key_client_cert_nickname;
+const pb_key *pb_key_client_ip;
+const pb_key *pb_key_close;
+const pb_key *pb_key_connect_timeout;
+const pb_key *pb_key_connection;
+const pb_key *pb_key_cont;
+const pb_key *pb_key_content_encoding;
+const pb_key *pb_key_content_language;
+const pb_key *pb_key_content_length;
+const pb_key *pb_key_content_location;
+const pb_key *pb_key_content_md5;
+const pb_key *pb_key_content_range;
+const pb_key *pb_key_content_type;
+const pb_key *pb_key_cookie;
+const pb_key *pb_key_date;
+const pb_key *pb_key_DATE_GMT;
+const pb_key *pb_key_DATE_LOCAL;
+const pb_key *pb_key_dir;
+const pb_key *pb_key_Directive;
+const pb_key *pb_key_dns;
+const pb_key *pb_key_DOCUMENT_NAME;
+const pb_key *pb_key_DOCUMENT_URI;
+const pb_key *pb_key_domain;
+const pb_key *pb_key_enc;
+const pb_key *pb_key_engine;
+const pb_key *pb_key_error_action;
+const pb_key *pb_key_error_desc;
+const pb_key *pb_key_error_fn;
+const pb_key *pb_key_escape;
+const pb_key *pb_key_escaped;
+const pb_key *pb_key_etag;
+const pb_key *pb_key_expect;
+const pb_key *pb_key_expires;
+const pb_key *pb_key_expr;
+const pb_key *pb_key_filter;
+const pb_key *pb_key_find_pathinfo_forward;
+const pb_key *pb_key_flushTimer;
+const pb_key *pb_key_fn;
+const pb_key *pb_key_from;
+const pb_key *pb_key_full_headers;
+const pb_key *pb_key_hdr;
+const pb_key *pb_key_host;
+const pb_key *pb_key_hostname;
+const pb_key *pb_key_if_match;
+const pb_key *pb_key_if_modified_since;
+const pb_key *pb_key_if_none_match;
+const pb_key *pb_key_if_range;
+const pb_key *pb_key_if_unmodified_since;
+const pb_key *pb_key_ip;
+const pb_key *pb_key_iponly;
+const pb_key *pb_key_issuer_dn;
+const pb_key *pb_key_jroute;
+const pb_key *pb_key_keep_alive;
+const pb_key *pb_key_keep_alive_timeout;
+const pb_key *pb_key_keysize;
+const pb_key *pb_key_lang;
+const pb_key *pb_key_last_modified;
+const pb_key *pb_key_level;
+const pb_key *pb_key_location;
+const pb_key *pb_key_lock_owner;
+const pb_key *pb_key_magnus_charset;
+const pb_key *pb_key_magnus_internal;
+const pb_key *pb_key_magnus_internal_dav_src;
+const pb_key *pb_key_magnus_internal_default_acls_only;
+const pb_key *pb_key_magnus_internal_error_j2ee;
+const pb_key *pb_key_magnus_internal_j2ee_nsapi;
+const pb_key *pb_key_magnus_internal_preserve_srvhdrs;
+const pb_key *pb_key_magnus_internal_set_request_status;
+const pb_key *pb_key_magnus_internal_set_response_status;
+const pb_key *pb_key_magnus_internal_webapp_errordesc;
+const pb_key *pb_key_matched_browser;
+const pb_key *pb_key_max_age;
+const pb_key *pb_key_max_forwards;
+const pb_key *pb_key_message;
+const pb_key *pb_key_method;
+const pb_key *pb_key_name;
+const pb_key *pb_key_nocache;
+const pb_key *pb_key_nostat;
+const pb_key *pb_key_ntrans_base;
+const pb_key *pb_key_offline_origin_addr;
+const pb_key *pb_key_offline_proxy_addr;
+const pb_key *pb_key_origin_addr;
+const pb_key *pb_key_p2c_cl;
+const pb_key *pb_key_p2c_hl;
+const pb_key *pb_key_p2r_cl;
+const pb_key *pb_key_p2r_hl;
+const pb_key *pb_key_parse_timeout;
+const pb_key *pb_key_password;
+const pb_key *pb_key_path;
+const pb_key *pb_key_PATH_INFO;
+const pb_key *pb_key_path_info;
+const pb_key *pb_key_pblock;
+const pb_key *pb_key_poll_interval;
+const pb_key *pb_key_pool; // new
+const pb_key *pb_key_port;
+const pb_key *pb_key_ppath;
+const pb_key *pb_key_pragma;
+const pb_key *pb_key_process_request_body;
+const pb_key *pb_key_process_response_body;
+const pb_key *pb_key_protocol;
+const pb_key *pb_key_proxy_addr;
+const pb_key *pb_key_proxy_agent;
+const pb_key *pb_key_proxy_auth_cert;
+const pb_key *pb_key_proxy_authorization;
+const pb_key *pb_key_proxy_cipher;
+const pb_key *pb_key_proxy_issuer_dn;
+const pb_key *pb_key_proxy_jroute;
+const pb_key *pb_key_proxy_keysize;
+const pb_key *pb_key_proxy_ping;
+const pb_key *pb_key_proxy_request;
+const pb_key *pb_key_proxy_secret_keysize;
+const pb_key *pb_key_proxy_ssl_id;
+const pb_key *pb_key_proxy_user_dn;
+const pb_key *pb_key_query;
+const pb_key *pb_key_QUERY_STRING;
+const pb_key *pb_key_QUERY_STRING_UNESCAPED;
+const pb_key *pb_key_r2p_cl;
+const pb_key *pb_key_r2p_hl;
+const pb_key *pb_key_range;
+const pb_key *pb_key_referer;
+const pb_key *pb_key_reformat_request_headers;
+const pb_key *pb_key_remote_status;
+const pb_key *pb_key_request_jroute;
+const pb_key *pb_key_required_rights;
+const pb_key *pb_key_retries;
+const pb_key *pb_key_rewrite_content_location;
+const pb_key *pb_key_rewrite_host;
+const pb_key *pb_key_rewrite_location;
+const pb_key *pb_key_rewrite_set_cookie;
+const pb_key *pb_key_root;
+const pb_key *pb_key_route;
+const pb_key *pb_key_route_cookie;
+const pb_key *pb_key_route_hdr;
+const pb_key *pb_key_route_offline;
+const pb_key *pb_key_script_name;
+const pb_key *pb_key_secret_keysize;
+const pb_key *pb_key_secure;
+const pb_key *pb_key_server;
+const pb_key *pb_key_set_cookie;
+const pb_key *pb_key_socks_addr;
+const pb_key *pb_key_ssl_id;
+const pb_key *pb_key_ssl_unclean_shutdown;
+const pb_key *pb_key_status;
+const pb_key *pb_key_sticky_cookie;
+const pb_key *pb_key_sticky_param;
+const pb_key *pb_key_suppress_request_headers;
+const pb_key *pb_key_svr_status;
+const pb_key *pb_key_timeout;
+const pb_key *pb_key_to;
+const pb_key *pb_key_transfer_encoding;
+const pb_key *pb_key_transmit_timeout;
+const pb_key *pb_key_tunnel_non_http_response;
+const pb_key *pb_key_type;
+const pb_key *pb_key_upstream_jroute;
+const pb_key *pb_key_uri;
+const pb_key *pb_key_url;
+const pb_key *pb_key_url_prefix;
+const pb_key *pb_key_UseOutputStreamSize;
+const pb_key *pb_key_user;
+const pb_key *pb_key_user_agent;
+const pb_key *pb_key_user_dn;
+const pb_key *pb_key_validate_server_cert;
+const pb_key *pb_key_value;
+const pb_key *pb_key_vary;
+const pb_key *pb_key_via;
+const pb_key *pb_key_warning;
+const pb_key *pb_key_depth;
+const pb_key *pb_key_if;
+const pb_key *pb_key_vfs;
+const pb_key *pb_key_dav;
+const pb_key *pb_key_vfsclass;
+const pb_key *pb_key_davclass;
+
+NSAPI_PUBLIC void pblock_init_default_keys(void) {
+    pb_key_accept = _create_key("accept");
+    pb_key_accept_charset = _create_key("accept-charset");
+    pb_key_accept_encoding = _create_key("accept-encoding");
+    pb_key_accept_language = _create_key("accept-language");
+    pb_key_accept_ranges = _create_key("accept-ranges");
+    pb_key_actual_route = _create_key("actual-route");
+    pb_key_age = _create_key("age");
+    pb_key_always_allow_chunked = _create_key("always-allow-chunked");
+    pb_key_always_use_keep_alive = _create_key("always-use-keep-alive");
+    pb_key_auth_cert = _create_key("auth-cert");
+    pb_key_auth_expiring = _create_key("auth-expiring");
+    pb_key_auth_group = _create_key("auth-group");
+    pb_key_auth_type = _create_key("auth-type");
+    pb_key_auth_user = _create_key("auth-user");
+    pb_key_authorization = _create_key("authorization");
+    pb_key_browser = _create_key("browser");
+    pb_key_c2p_cl = _create_key("c2p-cl");
+    pb_key_c2p_hl = _create_key("c2p-hl");
+    pb_key_cache_info = _create_key("cache-info");
+    pb_key_charset = _create_key("charset");
+    pb_key_check_http_server = _create_key("check-http-server");
+    pb_key_ChunkedRequestBufferSize = _create_key("ChunkedRequestBufferSize");
+    pb_key_ChunkedRequestTimeout = _create_key("ChunkedRequestTimeout");
+    pb_key_cipher = _create_key("cipher");
+    pb_key_clf_request = _create_key("clf-request");
+    pb_key_cli_status = _create_key("cli-status");
+    pb_key_client_cert_nickname = _create_key("client-cert-nickname");
+    pb_key_client_ip = _create_key("client-ip");
+    pb_key_close = _create_key("close");
+    pb_key_connect_timeout = _create_key("connect-timeout");
+    pb_key_connection = _create_key("connection");
+    pb_key_cont = _create_key("cont");
+    pb_key_content_encoding = _create_key("content-encoding");
+    pb_key_content_language = _create_key("content-language");
+    pb_key_content_length = _create_key("content-length");
+    pb_key_content_location = _create_key("content-location");
+    pb_key_content_md5 = _create_key("content-md5");
+    pb_key_content_range = _create_key("content-range");
+    pb_key_content_type = _create_key("content-type");
+    pb_key_cookie = _create_key("cookie");
+    pb_key_date = _create_key("date");
+    pb_key_DATE_GMT = _create_key("DATE_GMT");
+    pb_key_DATE_LOCAL = _create_key("DATE_LOCAL");
+    pb_key_dir = _create_key("dir");
+    pb_key_Directive = _create_key("Directive");
+    pb_key_dns = _create_key("dns");
+    pb_key_DOCUMENT_NAME = _create_key("DOCUMENT_NAME");
+    pb_key_DOCUMENT_URI = _create_key("DOCUMENT_URI");
+    pb_key_domain = _create_key("domain");
+    pb_key_enc = _create_key("enc");
+    pb_key_engine = _create_key("engine");
+    pb_key_error_action = _create_key("error-action");
+    pb_key_error_desc = _create_key("error-desc");
+    pb_key_error_fn = _create_key("error-fn");
+    pb_key_escape = _create_key("escape");
+    pb_key_escaped = _create_key("escaped");
+    pb_key_etag = _create_key("etag");
+    pb_key_expect = _create_key("expect");
+    pb_key_expires = _create_key("expires");
+    pb_key_expr = _create_key("expr");
+    pb_key_filter = _create_key("filter");
+    pb_key_find_pathinfo_forward = _create_key("find-pathinfo-forward");
+    pb_key_flushTimer = _create_key("flushTimer");
+    pb_key_fn = _create_key("fn");
+    pb_key_from = _create_key("from");
+    pb_key_full_headers = _create_key("full-headers");
+    pb_key_hdr = _create_key("hdr");
+    pb_key_host = _create_key("host");
+    pb_key_hostname = _create_key("hostname");
+    pb_key_if_match = _create_key("if-match");
+    pb_key_if_modified_since = _create_key("if-modified-since");
+    pb_key_if_none_match = _create_key("if-none-match");
+    pb_key_if_range = _create_key("if-range");
+    pb_key_if_unmodified_since = _create_key("if-unmodified-since");
+    pb_key_ip = _create_key("ip");
+    pb_key_iponly = _create_key("iponly");
+    pb_key_issuer_dn = _create_key("issuer_dn");
+    pb_key_jroute = _create_key("jroute");
+    pb_key_keep_alive = _create_key("keep-alive");
+    pb_key_keep_alive_timeout = _create_key("keep-alive-timeout");
+    pb_key_keysize = _create_key("keysize");
+    pb_key_lang = _create_key("lang");
+    pb_key_last_modified = _create_key("last-modified");
+    pb_key_level = _create_key("level");
+    pb_key_location = _create_key("location");
+    pb_key_lock_owner = _create_key("lock-owner");
+    pb_key_magnus_charset = _create_key("magnus-charset");
+    pb_key_magnus_internal = _create_key("magnus-internal");
+    pb_key_magnus_internal_dav_src = _create_key("magnus-internal/dav-src");
+    pb_key_magnus_internal_default_acls_only = _create_key("magnus-internal/default-acls-only");
+    pb_key_magnus_internal_error_j2ee = _create_key("magnus-internal/error-j2ee");
+    pb_key_magnus_internal_j2ee_nsapi = _create_key("magnus-internal/j2ee-nsapi");
+    pb_key_magnus_internal_preserve_srvhdrs = _create_key("magnus-internal/preserve-srvhdrs-after-req-restart");
+    pb_key_magnus_internal_set_request_status = _create_key("magnus-internal/set-request-status");
+    pb_key_magnus_internal_set_response_status = _create_key("magnus-internal/set-response-status");
+    pb_key_magnus_internal_webapp_errordesc = _create_key("magnus-internal/webapp-errordesc");
+    pb_key_matched_browser = _create_key("matched-browser");
+    pb_key_max_age = _create_key("max-age");
+    pb_key_max_forwards = _create_key("max-forwards");
+    pb_key_message = _create_key("message");
+    pb_key_method = _create_key("method");
+    pb_key_name = _create_key("name");
+    pb_key_nocache = _create_key("nocache");
+    pb_key_nostat = _create_key("nostat");
+    pb_key_ntrans_base = _create_key("ntrans-base");
+    pb_key_offline_origin_addr = _create_key("offline-origin-addr");
+    pb_key_offline_proxy_addr = _create_key("offline-proxy-addr");
+    pb_key_origin_addr = _create_key("origin-addr");
+    pb_key_p2c_cl = _create_key("p2c-cl");
+    pb_key_p2c_hl = _create_key("p2c-hl");
+    pb_key_p2r_cl = _create_key("p2r-cl");
+    pb_key_p2r_hl = _create_key("p2r-hl");
+    pb_key_parse_timeout = _create_key("parse-timeout");
+    pb_key_password = _create_key("password");
+    pb_key_path = _create_key("path");
+    pb_key_PATH_INFO = _create_key("PATH_INFO");
+    pb_key_path_info = _create_key("path-info");
+    pb_key_pblock = _create_key("pblock");
+    pb_key_poll_interval = _create_key("poll-interval");
+    pb_key_pool = _create_key("pool"); // new
+    pb_key_port = _create_key("port");
+    pb_key_ppath = _create_key("ppath");
+    pb_key_pragma = _create_key("pragma");
+    pb_key_process_request_body = _create_key("process-request-body");
+    pb_key_process_response_body = _create_key("process-response-body");
+    pb_key_protocol = _create_key("protocol");
+    pb_key_proxy_addr = _create_key("proxy-addr");
+    pb_key_proxy_agent = _create_key("proxy-agent");
+    pb_key_proxy_auth_cert = _create_key("proxy-auth-cert");
+    pb_key_proxy_authorization = _create_key("proxy-authorization");
+    pb_key_proxy_cipher = _create_key("proxy-cipher");
+    pb_key_proxy_issuer_dn = _create_key("proxy-issuer-dn");
+    pb_key_proxy_jroute = _create_key("proxy-jroute");
+    pb_key_proxy_keysize = _create_key("proxy-keysize");
+    pb_key_proxy_ping = _create_key("proxy-ping");
+    pb_key_proxy_request = _create_key("proxy-request");
+    pb_key_proxy_secret_keysize = _create_key("proxy-secret-keysize");
+    pb_key_proxy_ssl_id = _create_key("proxy-ssl-id");
+    pb_key_proxy_user_dn = _create_key("proxy-user-dn");
+    pb_key_query = _create_key("query");
+    pb_key_QUERY_STRING = _create_key("QUERY_STRING");
+    pb_key_QUERY_STRING_UNESCAPED = _create_key("QUERY_STRING_UNESCAPED");
+    pb_key_r2p_cl = _create_key("r2p-cl");
+    pb_key_r2p_hl = _create_key("r2p-hl");
+    pb_key_range = _create_key("range");
+    pb_key_referer = _create_key("referer");
+    pb_key_reformat_request_headers = _create_key("reformat-request-headers");
+    pb_key_remote_status = _create_key("remote-status");
+    pb_key_request_jroute = _create_key("request-jroute");
+    pb_key_required_rights = _create_key("required-rights");
+    pb_key_retries = _create_key("retries");
+    pb_key_rewrite_content_location = _create_key("rewrite-content-location");
+    pb_key_rewrite_host = _create_key("rewrite-host");
+    pb_key_rewrite_location = _create_key("rewrite-location");
+    pb_key_rewrite_set_cookie = _create_key("rewrite-set-cookie");
+    pb_key_root = _create_key("root");
+    pb_key_route = _create_key("route");
+    pb_key_route_cookie = _create_key("route-cookie");
+    pb_key_route_hdr = _create_key("route-hdr");
+    pb_key_route_offline = _create_key("route-offline");
+    pb_key_script_name = _create_key("script-name");
+    pb_key_secret_keysize = _create_key("secret-keysize");
+    pb_key_secure = _create_key("secure");
+    pb_key_server = _create_key("server");
+    pb_key_set_cookie = _create_key("set-cookie");
+    pb_key_socks_addr = _create_key("socks_addr");
+    pb_key_ssl_id = _create_key("ssl-id");
+    pb_key_ssl_unclean_shutdown = _create_key("ssl-unclean-shutdown");
+    pb_key_status = _create_key("status");
+    pb_key_sticky_cookie = _create_key("sticky-cookie");
+    pb_key_sticky_param = _create_key("sticky-param");
+    pb_key_suppress_request_headers = _create_key("suppress-request-headers");
+    pb_key_svr_status = _create_key("svr-status");
+    pb_key_timeout = _create_key("timeout");
+    pb_key_to = _create_key("to");
+    pb_key_transfer_encoding = _create_key("transfer-encoding");
+    pb_key_transmit_timeout = _create_key("transmit-timeout");
+    pb_key_tunnel_non_http_response = _create_key("tunnel-non-http-response");
+    pb_key_type = _create_key("type");
+    pb_key_upstream_jroute = _create_key("upstream-jroute");
+    pb_key_uri = _create_key("uri");
+    pb_key_url = _create_key("url");
+    pb_key_url_prefix = _create_key("url-prefix");
+    pb_key_UseOutputStreamSize = _create_key("UseOutputStreamSize");
+    pb_key_user = _create_key("user");
+    pb_key_user_agent = _create_key("user-agent");
+    pb_key_user_dn = _create_key("user_dn");
+    pb_key_validate_server_cert = _create_key("validate-server-cert");
+    pb_key_value = _create_key("value");
+    pb_key_vary = _create_key("vary");
+    pb_key_via = _create_key("via");
+    pb_key_warning = _create_key("warning");
+    pb_key_depth = _create_key("depth");
+    pb_key_if = _create_key("if");
+    pb_key_vfs = _create_key("vfs");
+    pb_key_dav = _create_key("dav");
+    pb_key_vfsclass = _create_key("vfsclass");
+    pb_key_davclass = _create_key("davclass");
+}
+
+NSAPI_PUBLIC void pblock_free_default_keys(void) {
+    for (unsigned i = 0 ; i < PB_KEY_LIST_BUCKET_COUNT ; i++) {
+        unsigned count = _pbKeys.buckets[i].size;
+        if (count > 0) {
+            pb_key **keys = _pbKeys.buckets[i].elements;
+            for (unsigned j = 0 ; j < count ; j++) {
+                free(keys[j]);
+            }
+            free(keys);
+        }
+    }
+}
+
+/* ------------------------------ _find_key ------------------------------- */
+
+static inline const pb_key *_find_key(const char *name, unsigned int hashval)
+{
+    /* Check to see if name corresponds to a pb_key */
+    struct pb_key_list_bucket *bucket = &_pbKeys.buckets[hashval & PB_KEY_LIST_BUCKET_COUNT];
+    for (unsigned i = 0 ; i < bucket->size ; i++) {
+        pb_key *key = bucket->elements[i];
+        if (key->hashval == hashval && !strcmp(key->name, name)) {
+            return key;
+        }
+    }
+    return NULL;
+}
+
+
+/* --------------------------- _get_hash_index ---------------------------- */
+
+static inline int _get_hash_index(const PListStruct_t *pl, const pb_key *key)
+{
+    /* Get the hash index from the key.  Requires a symbol table. */
+    int i;
+    if (key->sizendx == pl->pl_symtab->pt_sizendx)
+        i = key->hashndx;
+    else
+        i = key->hashval % PLSIZENDX(pl->pl_symtab->pt_sizendx);
+    return i;
+}
+
+
+/* ---------------------------- _param_create ----------------------------- */
+
+static inline pb_param *_param_create(pool_handle_t *pool_handle, const char *name, int namelen, const char *value, int valuelen)
+{
+    PLValueStruct_t *ret;
+
+    ret = (PLValueStruct_t *)pool_malloc(pool_handle, sizeof(PLValueStruct_t));
+
+    ret->pv_pbentry.param = &ret->pv_pbparam;
+    ret->pv_pbentry.next = 0;
+    ret->pv_next = 0;
+    ret->pv_type = 0;
+    ret->pv_mempool = pool_handle;
+
+    if (name || namelen) {
+        ret->pv_name = (char*)pool_malloc(pool_handle, namelen + 1);
+        if (name) {
+            memcpy(ret->pv_name, name, namelen);
+            ret->pv_name[namelen] = '\0';
+        } else {
+            ret->pv_name[0] = '\0';
+        }
+    } else {
+        ret->pv_name = 0;
+    }
+
+    if (value || valuelen) {
+        ret->pv_value = (char*)pool_malloc(pool_handle, valuelen + 1);
+        if (value) {
+            memcpy(ret->pv_value, value, valuelen);
+            ret->pv_value[valuelen] = '\0';
+        } else {
+            ret->pv_value[0] = '\0';
+        }
+    } else {
+        ret->pv_value = 0;
+    }
+
+    return &ret->pv_pbparam;
+}
+
+
+/* ----------------------- pblock_key_param_create  ----------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_key_param_create(pblock *pb, const pb_key *key, const char *value, int valuelen)
+{
+    /*
+     * Allocate a PLValueStruct_t from the property list's memory pool.
+     */
+    PListStruct_t *pl = PBTOPL(pb);
+    return _param_create(pl->pl_mempool, key->name, key->namelen, value, valuelen);
+}
+
+
+/* ------------------------- pblock_param_create -------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_param_create(pblock *pb, const char *name, const char *value)
+{
+    /*
+     * Allocate a PLValueStruct_t from the property list's memory pool.
+     */
+    PListStruct_t *pl = PBTOPL(pb);
+    return _param_create(pl->pl_mempool, name, name ? strlen(name) : 0, value, value ? strlen(value) : 0);
+}
+
+
+/* ----------------------------- param_create ----------------------------- */
+
+NSAPI_PUBLIC pb_param *param_create(const char *name, const char *value)
+{
+    /*
+     * Allocate a PLValueStruct_t containing the pb_param that will
+     * be returned.  Normally PLValueStruct_ts are allocated from the
+     * memory pool associated with a property list, but we don't have
+     * that here, so we just use the thread's pool and indicate we were
+     * allocated from a specific pool.
+     */
+    return _param_create(system_pool(), name, name ? strlen(name) : 0, value, value ? strlen(value) : 0);
+}
+
+
+/* ------------------------------ param_free ------------------------------ */
+
+NSAPI_PUBLIC int param_free(pb_param *pp)
+{
+    if (pp) {
+        PLValueStruct_t *pv = PATOPV(pp);
+
+        /* Don't bother if the pblock was allocated from a pool */
+        if (!pv->pv_mempool) {
+            pool_free(pv->pv_mempool, pv->pv_name);
+            pool_free(pv->pv_mempool, pv->pv_value);
+            pool_free(pv->pv_mempool, pv);
+        }
+
+        return 1;
+    }
+
+    return 0;
+}
+
+
+/* -------------------------- pblock_create_pool -------------------------- */
+
+NSAPI_PUBLIC pblock *pblock_create_pool(pool_handle_t *pool_handle, int n)
+{
+    /* Create a property list with n property indices */
+    PListStruct_t *plist = (PListStruct_t *)PListCreate(pool_handle, n, 0, 0);
+    if (!plist)
+        return NULL;
+
+    plist->pl_resvpi = 0;
+
+    return &plist->pl_pb;
+}
+
+
+/* ----------------------------- pblock_pool ------------------------------ */
+
+NSAPI_PUBLIC pool_handle_t *pblock_pool(pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+    return pl->pl_mempool;
+}
+
+
+/* ---------------------------- pblock_create ----------------------------- */
+
+NSAPI_PUBLIC pblock *pblock_create(int n)
+{
+    return pblock_create_pool(MALLOC_POOL_HANDLE, n);
+}
+
+
+/* ----------------------------- pblock_free ------------------------------ */
+
+NSAPI_PUBLIC void pblock_free(pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+    PLValueStruct_t **ppval;
+    PLValueStruct_t *pv;
+    int i;
+
+    if (!pb) {
+        return;
+    }
+
+    /* If the pools are enabled, this routine has no effect anyway, so 
+     * just return. 
+     */
+    if (pl->pl_mempool || pool_enabled()) {
+        return;
+    }
+
+    /* Free the property name symbol table if any */
+    if (pl->pl_symtab) {
+        pool_free(pl->pl_mempool, (void *)(pl->pl_symtab));
+    }
+
+    ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+    /* Loop over the initialized property indices */
+    for (i = 0; i < pl->pl_initpi; ++i) {
+
+        /* Got a property here? */
+        pv = ppval[i];
+        if (pv) {
+
+            param_free(&pv->pv_pbparam);
+        }
+    }
+
+    /* Free the array of pointers to property values */
+    pool_free(pl->pl_mempool, (void *)ppval);
+
+    /* Free the property list head */
+    pool_free(pl->pl_mempool, (void *)pl);
+}
+
+
+/* ------------------------------ pblock_key ------------------------------ */
+
+NSAPI_PUBLIC const pb_key *pblock_key(const char *name)
+{
+    if (!name)
+        return NULL;
+
+    return _find_key(name, PListHash(name));
+}
+
+
+/* --------------------------- pblock_kpinsert ---------------------------- */
+
+NSAPI_PUBLIC void pblock_kpinsert(const pb_key *key, pb_param *pp, pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+    PLValueStruct_t *pv = PATOPV(pp);
+
+    //PR_ASSERT(pv->pv_mempool == pl->pl_mempool); // TODO
+
+    /* Check to see if the name corresponds to a pb_key */
+    unsigned int hashval;
+    if (!key) {
+        hashval = PListHash(pv->pv_name);
+        key = _find_key(pv->pv_name, hashval);
+    }
+
+    /* Find property index */
+    int pindex = PListGetFreeIndex(pl);
+    if (pindex < 1) {
+        /* Error - invalid property index */
+        printf("Error - invalid property index\n");
+        return;
+    }
+
+    /* Allocate/grow the symbol table as needed */
+    PLSymbolTable_t *pt = PListSymbolTable(pl);
+    if (!pt) {
+        printf("!pt\n");
+        return;
+    }
+
+    /* Add PLValueStruct_t to the property list */
+    PLValueStruct_t **ppval = (PLValueStruct_t **)(pl->pl_ppval);
+    pv->pv_pbkey = key;
+    pv->pv_pi = pindex;
+    ppval[pv->pv_pi - 1] = pv;
+
+    /* Add name to symbol table */
+    int i = key ? _get_hash_index(pl, key) : (hashval % PLSIZENDX(pt->pt_sizendx));
+    pv->pv_next = pt->pt_hash[i];
+    pt->pt_hash[i] = pv;
+    pt->pt_nsyms++;
+
+    //PR_ASSERT(param_key(pp) == key); // TODO
+}
+
+
+/* ---------------------------- pblock_pinsert ---------------------------- */
+
+NSAPI_PUBLIC void pblock_pinsert(pb_param *pp, pblock *pb)
+{
+    pblock_kpinsert(NULL, pp, pb);
+}
+
+
+/* --------------------------- pblock_nvinsert ---------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_nvinsert(const char *name, const char *value, pblock *pb)
+{
+    pb_param *pp = pblock_param_create(pb, name, value);
+    if (pp)
+        pblock_kpinsert(NULL, pp, pb);
+    return pp;
+}
+
+
+/* --------------------------- pblock_kvinsert ---------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_kvinsert(const pb_key *key, const char *value, int valuelen, pblock *pb)
+{
+    pb_param *pp = pblock_key_param_create(pb, key, value, valuelen);
+    if (pp)
+        pblock_kpinsert(key, pp, pb);
+    return pp;
+}
+
+
+/* --------------------------- pblock_nninsert ---------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_nninsert(const char *name, int value, pblock *pb)
+{
+    char num[UTIL_ITOA_SIZE];
+
+    util_itoa(value, num);
+    return pblock_nvinsert(name, num, pb);
+}
+
+
+/* --------------------------- pblock_kninsert ---------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_kninsert(const pb_key *key, int value, pblock *pb)
+{
+    pb_param *pp = pblock_key_param_create(pb, key, NULL, UTIL_ITOA_SIZE);
+    if (pp) {
+        util_itoa(value, pp->value);
+        pblock_kpinsert(key, pp, pb);
+    }
+    return pp;
+}
+
+
+/* --------------------------- pblock_kllinsert --------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_kllinsert(const pb_key *key, int64_t value, pblock *pb)
+{
+    pb_param *pp = pblock_key_param_create(pb, key, NULL, UTIL_I64TOA_SIZE);
+    if (pp) {
+        util_i64toa(value, pp->value);
+        pblock_kpinsert(key, pp, pb);
+    }
+    return pp;
+}
+
+
+/* ---------------------------pblock_nvlinsert ---------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_nvlinsert(const char *name, int namelen, const char *value, int valuelen, pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+
+    pb_param *pp = _param_create(pl->pl_mempool, name, namelen, value, valuelen);
+
+    if(pp) {
+        pblock_kpinsert(NULL, pp, pb);
+    }
+
+    return pp;
+}
+
+
+/* ---------------------------- pblock_findkey ---------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_findkey(const pb_key *key, const pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+
+    /* Lookup key by examining symbol table */
+    if (pl->pl_symtab) {
+        int i = _get_hash_index(pl, key);
+        PLValueStruct_t *pv;
+
+        /* Search hash collision list for matching name */
+        for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) {
+            if (pv->pv_pbkey == key)
+                return &pv->pv_pbparam;
+        }
+    }
+
+    return NULL;
+}
+
+
+/* -------------------------- pblock_findkeyval --------------------------- */
+
+NSAPI_PUBLIC char *pblock_findkeyval(const pb_key *key, const pblock *pb)
+{
+    pb_param *pp = pblock_findkey(key, pb);
+    return pp ? pp->value : NULL;
+}
+
+
+/* ---------------------------- pblock_findval ---------------------------- */
+
+NSAPI_PUBLIC char *pblock_findval(const char *name, const pblock *pb)
+{
+    void *pvalue = 0;
+
+    (void)PListFindValue((PList_t)(PBTOPL(pb)), name, &pvalue, 0);
+
+    return (char *)pvalue;
+}
+
+
+/* ------------------------------ pblock_fr ------------------------------ */
+
+NSAPI_PUBLIC pb_param *pblock_fr(const char *name, pblock *pb, int remove)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+    PLValueStruct_t **ppval;
+    PLValueStruct_t **pvp;
+    PLValueStruct_t *pv = NULL;
+    int pindex;
+    int i;
+
+    if (pl->pl_symtab) {
+
+        /* Compute hash index of specified property name */
+        i = PListHashName(pl->pl_symtab, name);
+
+        /* Search hash collision list for matching name */
+        for (pvp = &pl->pl_symtab->pt_hash[i];
+             (pv = *pvp); pvp = &(*pvp)->pv_next) {
+
+            if (!strcmp(name, pv->pv_name)) {
+
+                if (remove) {
+                    /* Remove PLValueStruct_t from symbol table */
+                    *pvp = pv->pv_next;
+                    pl->pl_symtab->pt_nsyms--;
+
+                    /* Remove it from pl_ppval too */
+                    ppval = (PLValueStruct_t **)(pl->pl_ppval);
+                    pindex = pv->pv_pi;
+                    ppval[pindex - 1] = 0;
+                }
+                break;
+            }
+        }
+    }
+
+    return (pv) ? &pv->pv_pbparam : NULL;
+}
+
+
+/* --------------------------- pblock_removekey --------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_removekey(const pb_key *key, pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+    PLValueStruct_t **ppval;
+    PLValueStruct_t **pvp;
+    PLValueStruct_t *pv = NULL;
+    int pindex;
+    int i;
+
+    if (pl->pl_symtab) {
+        /* Lookup hash index for specified property key */
+        i = _get_hash_index(pl, key);
+
+        /* Search hash collision list for matching key */
+        for (pvp = &pl->pl_symtab->pt_hash[i]; (pv = *pvp); pvp = &pv->pv_next) {
+            /* If this value has the requested key... */
+            if (pv->pv_pbkey == key) {
+                /* Remove PLValueStruct_t from symbol table */
+                *pvp = pv->pv_next;
+                pl->pl_symtab->pt_nsyms--;
+
+                /* Remove it from pl_ppval too */
+                ppval = (PLValueStruct_t **)(pl->pl_ppval);
+                pindex = pv->pv_pi;
+                ppval[pindex - 1] = 0;
+
+                break;
+            }
+        }
+    }
+
+    return (pv) ? &pv->pv_pbparam : NULL;
+}
+
+
+/* -------------------------- pblock_removeone --------------------------- */
+
+NSAPI_PUBLIC pb_param *pblock_removeone(pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+
+    if (pl && pl->pl_symtab) {
+        /* Search hash buckets */
+        for (int i = 0; i < PLSIZENDX(pl->pl_symtab->pt_sizendx); i++) {
+            /* Search hash collision list */
+            PLValueStruct_t *pv = pl->pl_symtab->pt_hash[i];
+            if (pv) {
+                /* Remove PLValueStruct_t from symbol table */
+                pl->pl_symtab->pt_hash[i] = pv->pv_next;
+                pl->pl_symtab->pt_nsyms--;
+
+                /* Remove it from pl_ppval too */
+                PLValueStruct_t **ppval = (PLValueStruct_t**)pl->pl_ppval;
+                ppval[pv->pv_pi - 1] = 0;
+
+                return &pv->pv_pbparam;
+            }
+        }
+    }
+
+    return NULL;
+}
+
+
+/* -------------------------- pblock_str2pblock --------------------------- */
+
+
+int _verify_pbstr(const char *str)
+{
+    const char *cp;
+    const char *scp;
+    int np;
+    int state;
+    int quote;
+
+    for(cp = str, np = 0, state = 0; *cp; ) {
+        switch (state) {
+        case 0:                 /* skipping leading spaces */
+
+            while (*cp && isspace(*cp)) ++cp;
+            if (*cp == '=') {
+                return -1;
+            }
+            if (*cp) state = 1;
+            break;
+
+        case 1:                 /* scanning parameter name */
+
+            scp = cp;
+            while (*cp && (*cp != '=') && !isspace(*cp)) ++cp;
+            if (*cp == '=') ++cp;
+            else cp = scp;
+            state = 2;
+            break;
+
+        case 2:                 /* scanning parameter value */
+            quote = 0;
+            if (*cp == '\"') {
+                quote = 1;
+                ++cp;
+            }
+            for (;;) {
+                if (*cp == '\\') {
+                    ++cp;
+                    if (*cp == 0) {
+                        return -1;
+                    }
+                }
+                else if (*cp == '\"') {
+                    if (!quote) {
+                        return -1;
+                    }
+                    ++np;
+                    ++cp;
+                    quote = 0;
+                    state = 0;
+                    break;
+                }
+                else if (!quote && (!*cp || isspace(*cp))) {
+                    ++np;
+                    if (*cp) ++cp;
+                    state = 0;
+                    break;
+                }
+                else if (*cp == 0) {
+                    return -1;
+                }
+                ++cp;
+            }
+            if (quote) {
+                return -1;
+            }
+            break;
+        }
+    }
+
+    return (state == 0) ? np : -1;
+}
+
+NSAPI_PUBLIC int
+INTpblock_str2pblock_lowercasename(const char *str, pblock *pb)
+{
+    return _pblock_str2pblock(str, pb, PR_TRUE);
+}
+
+NSAPI_PUBLIC int pblock_str2pblock(const char *str, pblock *pb)
+{
+    return _pblock_str2pblock(str, pb, PR_FALSE);
+}
+
+int
+_pblock_str2pblock(const char* str, pblock* pb, PRBool lowerCase)
+{
+    char *cpy;
+    char *cp;
+    char *dp;
+    char *pname;
+    char *pvalue;
+    int np;
+    int quote;
+    int state;
+    char numbuf[UTIL_ITOA_SIZE];
+
+    if((np = _verify_pbstr(str)) < 1)
+        return -1;
+
+    while (*str && isspace(*str)) ++str;
+
+    cpy = STRDUP(str);
+
+    for (np = 0, cp = cpy, state = 0; *cp; ) {
+        switch (state) {
+
+        case 0:                 /* skipping leading spaces */
+
+            while (*cp && isspace(*cp)) ++cp;
+            if (*cp) state = 1;
+            break;
+
+        case 1:                 /* scanning parameter name */
+
+            pname = cp;
+            while (*cp && (*cp != '=') && !isspace(*cp)) ++cp;
+            if (*cp == '=') {
+                *cp++ = 0;
+            }
+            else {
+                cp = pname;
+                pname = numbuf;
+                util_itoa(np+1, numbuf);
+            }
+            state = 2;
+            break;
+
+        case 2:                 /* scanning parameter value */
+            quote = 0;
+            if (*cp == '\"') {
+                quote = 1;
+                ++cp;
+            }
+            for (pvalue = cp, dp = cp; ; ++cp, ++dp) {
+                if (*cp == '\\') {
+                    ++cp;
+                }
+                else if (*cp == '\"') {
+                    ++np;
+                    ++cp;
+                    *dp = 0;
+                    quote = 0;
+                    state = 0;
+                    break;
+                }
+                else if (!quote && ((*cp == 0) || isspace(*cp))) {
+                    ++np;
+                    if (*cp != 0) {
+                        ++cp;
+                    }
+                    *dp = 0;
+                    state = 0;
+                    break;
+                }
+                if (cp != dp) *dp = *cp;
+            }
+            if (lowerCase == PR_TRUE) {
+                for (char* p = pname; *p; p++) {
+                    *p = tolower(*p);
+                }
+            }
+            pblock_nvinsert(pname, pvalue, pb);
+            break;
+        }
+    }
+
+    FREE(cpy);
+
+    return np;
+}
+
+
+/* -------------------------- pblock_pblock2str --------------------------- */
+
+
+NSAPI_PUBLIC char *pblock_pblock2str(const pblock *pb, char *str)
+{
+    char *s = str, *t, *u;
+    PListStruct_t *pl = PBTOPL(pb);
+    PLValueStruct_t **ppval;
+    PLValueStruct_t *pv;
+    int i;
+    int sl;
+    int xlen;
+
+    ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+    /* Loop over the initialized property indices */
+    for (i = 0, xlen = 0; i < pl->pl_initpi; ++i) {
+
+        /* Got a property here? */
+        pv = ppval[i];
+        if (pv && pv->pv_name) {
+
+            int ln = strlen(pv->pv_name);
+            int lv = strlen((char *)(pv->pv_value));
+
+            /* Check for " or \ because we'll have to escape them */
+            for (t = (char *)(pv->pv_value); *t; ++t) {
+                if ((*t == '\"') || (*t == '\\')) ++lv;
+            }
+
+            /* 4: two quotes, =, and a null */
+            xlen += (ln + lv + 4);
+        }
+    }
+
+    /* Allocate string to hold parameter settings, or increase size */
+    if (!s) {
+        s = (char *)MALLOC(xlen);
+        s[0] = '\0';
+        t = &s[0];
+        sl = xlen;
+    }
+    else {
+        sl = strlen(s);
+        t = &s[sl];
+        sl += xlen;
+        s = (char *)REALLOC(s, sl);
+    }
+
+    /* Loop over the initialized property indices */
+    for (i = 0; i < pl->pl_initpi; ++i) {
+
+        /* Got a property here? */
+        pv = ppval[i];
+        if (pv && pv->pv_name) {
+
+            if (t != s) *t++ = ' ';
+
+            for (u = pv->pv_name; *u; ) *t++ = *u++;
+
+            *t++ = '=';
+            *t++ = '\"';
+
+            for (u = (char *)(pv->pv_value); *u; ) {
+                if ((*u == '\\') || (*u == '\"')) *t++ = '\\';
+                *t++ = *u++;
+            }
+
+            *t++ = '\"';
+            *t = '\0';
+        }
+    }
+
+    return s;
+}
+
+
+/* ----------------------------- pblock_copy ------------------------------ */
+
+
+NSAPI_PUBLIC int pblock_copy(const pblock *src, pblock *dst)
+{
+    PListStruct_t *pl = PBTOPL(src);
+    PLValueStruct_t **ppval;
+    PLValueStruct_t *pv;
+    int rv = 0;
+    int i;
+
+    ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+    for (i = 0; i < pl->pl_initpi; ++i) {
+        pv = ppval[i];
+        if (pv) {
+            if (pv->pv_pbkey) {
+                if (pv->pv_pbkey != pb_key_magnus_internal) {
+                    if (!pblock_kvinsert(pv->pv_pbkey, (char *)(pv->pv_value), strlen(pv->pv_value), dst))
+                        rv = -1;
+                }
+            } else {
+                if (!pblock_nvinsert(pv->pv_name, (char *)(pv->pv_value), dst))
+                    rv = -1;
+            }
+        }
+    }
+
+    return rv;
+}
+
+/* ---------------------------- pblock_dup -------------------------------- */
+
+NSAPI_PUBLIC pblock *pblock_dup(const pblock *src)
+{
+    pblock *dst;
+
+    if (!src)
+        return NULL;
+
+    if ( (dst = pblock_create(src->hsize)) )
+        pblock_copy(src, dst);
+
+    return dst;
+}
+
+
+/* ---------------------------- pblock_pb2env ----------------------------- */
+
+
+NSAPI_PUBLIC char **pblock_pb2env(const pblock *pb, char **env)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+    PLValueStruct_t **ppval;
+    PLValueStruct_t *pv;
+    int i;
+    int nval;
+    int pos;
+
+    /* Find out how many there are. */
+    
+    ppval = (PLValueStruct_t **)(pl->pl_ppval);
+
+    for (i = 0, nval = 0; i < pl->pl_initpi; ++i) {
+        if (ppval[i]) ++nval;
+    }
+    
+    env = util_env_create(env, nval, &pos);
+
+    for (i = 0; i < pl->pl_initpi; ++i) {
+        pv = ppval[i];
+        if (pv) {
+            env[pos++] = util_env_str(pv->pv_name, (char *)(pv->pv_value));
+        }
+    }
+    env[pos] = NULL;
+
+    return env;
+}
+
+
+/* ---------------------------- pblock_replace ---------------------------- */
+
+NSAPI_PUBLIC char * pblock_replace(const char *name,
+                                   char * new_value, pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+
+    /* Replace an existing value */
+    pb_param *pp = pblock_find(name, pb);
+    if (!pp)
+        return NULL;
+    pool_free(pl->pl_mempool, pp->value);
+    pp->value = new_value;
+
+    return new_value;
+}
+
+
+/* --------------------------- pblock_nvreplace --------------------------- */
+
+NSAPI_PUBLIC void pblock_nvreplace (const char *name, const char *value, pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+
+    /* Replace an existing value or insert a new value */
+    pb_param *pp = pblock_find(name, pb);
+    if (pp) {
+        pool_free(pl->pl_mempool, pp->value);
+        pp->value = pool_strdup(pl->pl_mempool, value);
+    } else {
+        pblock_nvinsert(name, value, pb);
+    }
+}
+
+
+/* --------------------------- pblock_kvreplace --------------------------- */
+
+NSAPI_PUBLIC void pblock_kvreplace(const pb_key *key, const char *value, int valuelen, pblock *pb)
+{
+    PListStruct_t *pl = PBTOPL(pb);
+
+    /* Replace an existing value or insert a new value */
+    pb_param *pp = pblock_findkey(key, pb);
+    if (pp) {
+        pool_free(pl->pl_mempool, pp->value);
+        pp->value = (char*)pool_malloc(pl->pl_mempool, valuelen + 1);
+        memcpy(pp->value, value, valuelen + 1);
+    } else {
+        pblock_kvinsert(key, value, valuelen, pb);
+    }
+}
--- a/src/server/util/pblock.cpp	Sat Sep 24 16:26:10 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1217 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- *
- * THE BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without 
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer. 
- * Redistributions in binary form must reproduce the above copyright notice, 
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution. 
- *
- * Neither the name of the  nor the names of its contributors may be
- * used to endorse or promote products derived from this software without 
- * specific prior written permission. 
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/*
- * pblock.c: Handles Parameter Blocks
- * 
- * See pblock.h for public documentation.
- * 
- * Rob McCool
- * 
- * This code uses property lists to implement pblocks.
- */
-
-
-#include <limits.h>
-#include "pblock.h"
-#include "plist_pvt.h"
-#include "plist.h"
-#include "LinkedList.hh"
-#include "util.h"   /* util_itoa */
-#include "pool.h"
-#include "systhr.h"
-
-#define MALLOC_POOL_HANDLE (thread_malloc_key != -1 ? (pool_handle_t *)systhread_getdata(thread_malloc_key) : getThreadMallocPool())
-
-static int thread_malloc_key = -1;
-static int _pblock_str2pblock(const char* str, pblock* pb, PRBool lowerCase);
-
-static pool_handle_t *getThreadMallocPool()
-{
-    pool_handle_t *thread_malloc_pool = 0;
-
-    thread_malloc_key = getThreadMallocKey();
-    if (thread_malloc_key != -1) {
-        thread_malloc_pool = (pool_handle_t *)systhread_getdata(thread_malloc_key);
-    }
-
-    return thread_malloc_pool;
-}
-
-/* ------------------------------- HashList ------------------------------- */
-
-template <class Name, class Value>
-class HashList {
-public:
-    HashList(int mask)
-    : _mask(mask),
-      _list(new CList<Value>[mask + 1])
-    { }
-
-    void Insert(Name name, Value *value)
-    {
-        _list[name & _mask].Append(value);
-    }
-
-    const CList<Value>& Find(Name name)
-    {
-        return _list[name & _mask];
-    }
-
-private:
-    CList<Value> *_list;
-    unsigned int _mask;
-};
-
-/* ---------------------- pb_key static initializers ---------------------- */
-
-/*
- * pb_key
- *
- * Contains a precomputed hash value for a specific pblock variable name.
- */
-typedef struct pb_key pb_key;
-struct pb_key {
-    const char *name;
-    int namelen; 
-    unsigned int hashval;
-    int sizendx;
-    int hashndx;
-};
-
-static HashList<unsigned int, pb_key> _hashKeys(0x7f);
-CList<pb_key> _listKeys;
-
-static const pb_key *const _create_key(const char *name, int sizendx = 0)
-{
-    /* Create a the new pb_key */
-    pb_key *key = (pb_key*)malloc(sizeof(pb_key));
-    key->name = STRDUP(name);
-    key->namelen = strlen(name);
-    key->hashval = PListHash(name);
-    key->sizendx = sizendx;
-    key->hashndx = key->hashval % PLSIZENDX(sizendx);
-
-    /* Group pb_keys by hashval for later retrieval */
-    _hashKeys.Insert(key->hashval, key);
-
-    /* Keep a list of all the registered keys */
-    _listKeys.Append(key);
-
-    return key;
-}
-
-const pb_key *const pb_key_accept = _create_key("accept");
-const pb_key *const pb_key_accept_charset = _create_key("accept-charset");
-const pb_key *const pb_key_accept_encoding = _create_key("accept-encoding");
-const pb_key *const pb_key_accept_language = _create_key("accept-language");
-const pb_key *const pb_key_accept_ranges = _create_key("accept-ranges");
-const pb_key *const pb_key_actual_route = _create_key("actual-route");
-const pb_key *const pb_key_age = _create_key("age");
-const pb_key *const pb_key_always_allow_chunked = _create_key("always-allow-chunked");
-const pb_key *const pb_key_always_use_keep_alive = _create_key("always-use-keep-alive");
-const pb_key *const pb_key_auth_cert = _create_key("auth-cert");
-const pb_key *const pb_key_auth_expiring = _create_key("auth-expiring");
-const pb_key *const pb_key_auth_group = _create_key("auth-group");
-const pb_key *const pb_key_auth_type = _create_key("auth-type");
-const pb_key *const pb_key_auth_user = _create_key("auth-user");
-const pb_key *const pb_key_authorization = _create_key("authorization");
-const pb_key *const pb_key_browser = _create_key("browser");
-const pb_key *const pb_key_c2p_cl = _create_key("c2p-cl");
-const pb_key *const pb_key_c2p_hl = _create_key("c2p-hl");
-const pb_key *const pb_key_cache_info = _create_key("cache-info");
-const pb_key *const pb_key_charset = _create_key("charset");
-const pb_key *const pb_key_check_http_server = _create_key("check-http-server");
-const pb_key *const pb_key_ChunkedRequestBufferSize = _create_key("ChunkedRequestBufferSize");
-const pb_key *const pb_key_ChunkedRequestTimeout = _create_key("ChunkedRequestTimeout");
-const pb_key *const pb_key_cipher = _create_key("cipher");
-const pb_key *const pb_key_clf_request = _create_key("clf-request");
-const pb_key *const pb_key_cli_status = _create_key("cli-status");
-const pb_key *const pb_key_client_cert_nickname = _create_key("client-cert-nickname");
-const pb_key *const pb_key_client_ip = _create_key("client-ip");
-const pb_key *const pb_key_close = _create_key("close");
-const pb_key *const pb_key_connect_timeout = _create_key("connect-timeout");
-const pb_key *const pb_key_connection = _create_key("connection");
-const pb_key *const pb_key_cont = _create_key("cont");
-const pb_key *const pb_key_content_encoding = _create_key("content-encoding");
-const pb_key *const pb_key_content_language = _create_key("content-language");
-const pb_key *const pb_key_content_length = _create_key("content-length");
-const pb_key *const pb_key_content_location = _create_key("content-location");
-const pb_key *const pb_key_content_md5 = _create_key("content-md5");
-const pb_key *const pb_key_content_range = _create_key("content-range");
-const pb_key *const pb_key_content_type = _create_key("content-type");
-const pb_key *const pb_key_cookie = _create_key("cookie");
-const pb_key *const pb_key_date = _create_key("date");
-const pb_key *const pb_key_DATE_GMT = _create_key("DATE_GMT");
-const pb_key *const pb_key_DATE_LOCAL = _create_key("DATE_LOCAL");
-const pb_key *const pb_key_dir = _create_key("dir");
-const pb_key *const pb_key_Directive = _create_key("Directive");
-const pb_key *const pb_key_dns = _create_key("dns");
-const pb_key *const pb_key_DOCUMENT_NAME = _create_key("DOCUMENT_NAME");
-const pb_key *const pb_key_DOCUMENT_URI = _create_key("DOCUMENT_URI");
-const pb_key *const pb_key_domain = _create_key("domain");
-const pb_key *const pb_key_enc = _create_key("enc");
-const pb_key *const pb_key_engine = _create_key("engine");
-const pb_key *const pb_key_error_action = _create_key("error-action");
-const pb_key *const pb_key_error_desc = _create_key("error-desc");
-const pb_key *const pb_key_error_fn = _create_key("error-fn");
-const pb_key *const pb_key_escape = _create_key("escape");
-const pb_key *const pb_key_escaped = _create_key("escaped");
-const pb_key *const pb_key_etag = _create_key("etag");
-const pb_key *const pb_key_expect = _create_key("expect");
-const pb_key *const pb_key_expires = _create_key("expires");
-const pb_key *const pb_key_expr = _create_key("expr");
-const pb_key *const pb_key_filter = _create_key("filter");
-const pb_key *const pb_key_find_pathinfo_forward = _create_key("find-pathinfo-forward");
-const pb_key *const pb_key_flushTimer = _create_key("flushTimer");
-const pb_key *const pb_key_fn = _create_key("fn");
-const pb_key *const pb_key_from = _create_key("from");
-const pb_key *const pb_key_full_headers = _create_key("full-headers");
-const pb_key *const pb_key_hdr = _create_key("hdr");
-const pb_key *const pb_key_host = _create_key("host");
-const pb_key *const pb_key_hostname = _create_key("hostname");
-const pb_key *const pb_key_if_match = _create_key("if-match");
-const pb_key *const pb_key_if_modified_since = _create_key("if-modified-since");
-const pb_key *const pb_key_if_none_match = _create_key("if-none-match");
-const pb_key *const pb_key_if_range = _create_key("if-range");
-const pb_key *const pb_key_if_unmodified_since = _create_key("if-unmodified-since");
-const pb_key *const pb_key_ip = _create_key("ip");
-const pb_key *const pb_key_iponly = _create_key("iponly");
-const pb_key *const pb_key_issuer_dn = _create_key("issuer_dn");
-const pb_key *const pb_key_jroute = _create_key("jroute");
-const pb_key *const pb_key_keep_alive = _create_key("keep-alive");
-const pb_key *const pb_key_keep_alive_timeout = _create_key("keep-alive-timeout");
-const pb_key *const pb_key_keysize = _create_key("keysize");
-const pb_key *const pb_key_lang = _create_key("lang");
-const pb_key *const pb_key_LAST_MODIFIED = _create_key("LAST_MODIFIED");
-const pb_key *const pb_key_last_modified = _create_key("last-modified");
-const pb_key *const pb_key_level = _create_key("level");
-const pb_key *const pb_key_location = _create_key("location");
-const pb_key *const pb_key_lock_owner = _create_key("lock-owner");
-const pb_key *const pb_key_magnus_charset = _create_key("magnus-charset");
-const pb_key *const pb_key_magnus_internal = _create_key("magnus-internal");
-const pb_key *const pb_key_magnus_internal_dav_src = _create_key("magnus-internal/dav-src");
-const pb_key *const pb_key_magnus_internal_default_acls_only = _create_key("magnus-internal/default-acls-only");
-const pb_key *const pb_key_magnus_internal_error_j2ee = _create_key("magnus-internal/error-j2ee");
-const pb_key *const pb_key_magnus_internal_j2ee_nsapi = _create_key("magnus-internal/j2ee-nsapi");
-const pb_key *const pb_key_magnus_internal_preserve_srvhdrs = _create_key("magnus-internal/preserve-srvhdrs-after-req-restart");
-const pb_key *const pb_key_magnus_internal_set_request_status = _create_key("magnus-internal/set-request-status");
-const pb_key *const pb_key_magnus_internal_set_response_status = _create_key("magnus-internal/set-response-status");
-const pb_key *const pb_key_magnus_internal_webapp_errordesc = _create_key("magnus-internal/webapp-errordesc");
-const pb_key *const pb_key_matched_browser = _create_key("matched-browser");
-const pb_key *const pb_key_max_age = _create_key("max-age");
-const pb_key *const pb_key_max_forwards = _create_key("max-forwards");
-const pb_key *const pb_key_message = _create_key("message");
-const pb_key *const pb_key_method = _create_key("method");
-const pb_key *const pb_key_name = _create_key("name");
-const pb_key *const pb_key_nocache = _create_key("nocache");
-const pb_key *const pb_key_nostat = _create_key("nostat");
-const pb_key *const pb_key_ntrans_base = _create_key("ntrans-base");
-const pb_key *const pb_key_offline_origin_addr = _create_key("offline-origin-addr");
-const pb_key *const pb_key_offline_proxy_addr = _create_key("offline-proxy-addr");
-const pb_key *const pb_key_origin_addr = _create_key("origin-addr");
-const pb_key *const pb_key_p2c_cl = _create_key("p2c-cl");
-const pb_key *const pb_key_p2c_hl = _create_key("p2c-hl");
-const pb_key *const pb_key_p2r_cl = _create_key("p2r-cl");
-const pb_key *const pb_key_p2r_hl = _create_key("p2r-hl");
-const pb_key *const pb_key_parse_timeout = _create_key("parse-timeout");
-const pb_key *const pb_key_password = _create_key("password");
-const pb_key *const pb_key_path = _create_key("path");
-const pb_key *const pb_key_PATH_INFO = _create_key("PATH_INFO");
-const pb_key *const pb_key_path_info = _create_key("path-info");
-const pb_key *const pb_key_pblock = _create_key("pblock");
-const pb_key *const pb_key_poll_interval = _create_key("poll-interval");
-const pb_key *const pb_key_pool = _create_key("pool"); // new
-const pb_key *const pb_key_port = _create_key("port");
-const pb_key *const pb_key_ppath = _create_key("ppath");
-const pb_key *const pb_key_pragma = _create_key("pragma");
-const pb_key *const pb_key_process_request_body = _create_key("process-request-body");
-const pb_key *const pb_key_process_response_body = _create_key("process-response-body");
-const pb_key *const pb_key_protocol = _create_key("protocol");
-const pb_key *const pb_key_proxy_addr = _create_key("proxy-addr");
-const pb_key *const pb_key_proxy_agent = _create_key("proxy-agent");
-const pb_key *const pb_key_proxy_auth_cert = _create_key("proxy-auth-cert");
-const pb_key *const pb_key_proxy_authorization = _create_key("proxy-authorization");
-const pb_key *const pb_key_proxy_cipher = _create_key("proxy-cipher");
-const pb_key *const pb_key_proxy_issuer_dn = _create_key("proxy-issuer-dn");
-const pb_key *const pb_key_proxy_jroute = _create_key("proxy-jroute");
-const pb_key *const pb_key_proxy_keysize = _create_key("proxy-keysize");
-const pb_key *const pb_key_proxy_ping = _create_key("proxy-ping");
-const pb_key *const pb_key_proxy_request = _create_key("proxy-request");
-const pb_key *const pb_key_proxy_secret_keysize = _create_key("proxy-secret-keysize");
-const pb_key *const pb_key_proxy_ssl_id = _create_key("proxy-ssl-id");
-const pb_key *const pb_key_proxy_user_dn = _create_key("proxy-user-dn");
-const pb_key *const pb_key_query = _create_key("query");
-const pb_key *const pb_key_QUERY_STRING = _create_key("QUERY_STRING");
-const pb_key *const pb_key_QUERY_STRING_UNESCAPED = _create_key("QUERY_STRING_UNESCAPED");
-const pb_key *const pb_key_r2p_cl = _create_key("r2p-cl");
-const pb_key *const pb_key_r2p_hl = _create_key("r2p-hl");
-const pb_key *const pb_key_range = _create_key("range");
-const pb_key *const pb_key_referer = _create_key("referer");
-const pb_key *const pb_key_reformat_request_headers = _create_key("reformat-request-headers");
-const pb_key *const pb_key_remote_status = _create_key("remote-status");
-const pb_key *const pb_key_request_jroute = _create_key("request-jroute");
-const pb_key *const pb_key_required_rights = _create_key("required-rights");
-const pb_key *const pb_key_retries = _create_key("retries");
-const pb_key *const pb_key_rewrite_content_location = _create_key("rewrite-content-location");
-const pb_key *const pb_key_rewrite_host = _create_key("rewrite-host");
-const pb_key *const pb_key_rewrite_location = _create_key("rewrite-location");
-const pb_key *const pb_key_rewrite_set_cookie = _create_key("rewrite-set-cookie");
-const pb_key *const pb_key_root = _create_key("root");
-const pb_key *const pb_key_route = _create_key("route");
-const pb_key *const pb_key_route_cookie = _create_key("route-cookie");
-const pb_key *const pb_key_route_hdr = _create_key("route-hdr");
-const pb_key *const pb_key_route_offline = _create_key("route-offline");
-const pb_key *const pb_key_script_name = _create_key("script-name");
-const pb_key *const pb_key_secret_keysize = _create_key("secret-keysize");
-const pb_key *const pb_key_secure = _create_key("secure");
-const pb_key *const pb_key_server = _create_key("server");
-const pb_key *const pb_key_set_cookie = _create_key("set-cookie");
-const pb_key *const pb_key_socks_addr = _create_key("socks_addr");
-const pb_key *const pb_key_ssl_id = _create_key("ssl-id");
-const pb_key *const pb_key_ssl_unclean_shutdown = _create_key("ssl-unclean-shutdown");
-const pb_key *const pb_key_status = _create_key("status");
-const pb_key *const pb_key_sticky_cookie = _create_key("sticky-cookie");
-const pb_key *const pb_key_sticky_param = _create_key("sticky-param");
-const pb_key *const pb_key_suppress_request_headers = _create_key("suppress-request-headers");
-const pb_key *const pb_key_svr_status = _create_key("svr-status");
-const pb_key *const pb_key_timeout = _create_key("timeout");
-const pb_key *const pb_key_to = _create_key("to");
-const pb_key *const pb_key_transfer_encoding = _create_key("transfer-encoding");
-const pb_key *const pb_key_transmit_timeout = _create_key("transmit-timeout");
-const pb_key *const pb_key_tunnel_non_http_response = _create_key("tunnel-non-http-response");
-const pb_key *const pb_key_type = _create_key("type");
-const pb_key *const pb_key_upstream_jroute = _create_key("upstream-jroute");
-const pb_key *const pb_key_uri = _create_key("uri");
-const pb_key *const pb_key_url = _create_key("url");
-const pb_key *const pb_key_url_prefix = _create_key("url-prefix");
-const pb_key *const pb_key_UseOutputStreamSize = _create_key("UseOutputStreamSize");
-const pb_key *const pb_key_user = _create_key("user");
-const pb_key *const pb_key_user_agent = _create_key("user-agent");
-const pb_key *const pb_key_user_dn = _create_key("user_dn");
-const pb_key *const pb_key_validate_server_cert = _create_key("validate-server-cert");
-const pb_key *const pb_key_value = _create_key("value");
-const pb_key *const pb_key_vary = _create_key("vary");
-const pb_key *const pb_key_via = _create_key("via");
-const pb_key *const pb_key_warning = _create_key("warning");
-const pb_key *const pb_key_depth = _create_key("depth");
-const pb_key *const pb_key_if = _create_key("if");
-const pb_key *const pb_key_vfs = _create_key("vfs");
-const pb_key *const pb_key_dav = _create_key("dav");
-const pb_key *const pb_key_vfsclass = _create_key("vfsclass");
-const pb_key *const pb_key_davclass = _create_key("davclass");
-
-/* ------------------------------ _find_key ------------------------------- */
-
-static inline const pb_key *_find_key(const char *name, unsigned int hashval)
-{
-    /* Check to see if name corresponds to a pb_key */
-    CListConstIterator<pb_key> iter(&_hashKeys.Find(hashval));
-    const pb_key *key;
-    while((key = ++iter)) {
-        if (key->hashval == hashval && !strcmp(key->name, name))
-            return key;
-    }
-    return NULL;
-}
-
-
-/* --------------------------- _get_hash_index ---------------------------- */
-
-static inline int _get_hash_index(const PListStruct_t *pl, const pb_key *key)
-{
-    /* Get the hash index from the key.  Requires a symbol table. */
-    int i;
-    if (key->sizendx == pl->pl_symtab->pt_sizendx)
-        i = key->hashndx;
-    else
-        i = key->hashval % PLSIZENDX(pl->pl_symtab->pt_sizendx);
-    return i;
-}
-
-
-/* ---------------------------- _param_create ----------------------------- */
-
-static inline pb_param *_param_create(pool_handle_t *pool_handle, const char *name, int namelen, const char *value, int valuelen)
-{
-    PLValueStruct_t *ret;
-
-    ret = (PLValueStruct_t *)pool_malloc(pool_handle, sizeof(PLValueStruct_t));
-
-    ret->pv_pbentry.param = &ret->pv_pbparam;
-    ret->pv_pbentry.next = 0;
-    ret->pv_next = 0;
-    ret->pv_type = 0;
-    ret->pv_mempool = pool_handle;
-
-    if (name || namelen) {
-        ret->pv_name = (char*)pool_malloc(pool_handle, namelen + 1);
-        if (name) {
-            memcpy(ret->pv_name, name, namelen);
-            ret->pv_name[namelen] = '\0';
-        } else {
-            ret->pv_name[0] = '\0';
-        }
-    } else {
-        ret->pv_name = 0;
-    }
-
-    if (value || valuelen) {
-        ret->pv_value = (char*)pool_malloc(pool_handle, valuelen + 1);
-        if (value) {
-            memcpy(ret->pv_value, value, valuelen);
-            ret->pv_value[valuelen] = '\0';
-        } else {
-            ret->pv_value[0] = '\0';
-        }
-    } else {
-        ret->pv_value = 0;
-    }
-
-    return &ret->pv_pbparam;
-}
-
-
-/* ----------------------- pblock_key_param_create  ----------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_key_param_create(pblock *pb, const pb_key *key, const char *value, int valuelen)
-{
-    /*
-     * Allocate a PLValueStruct_t from the property list's memory pool.
-     */
-    PListStruct_t *pl = PBTOPL(pb);
-    return _param_create(pl->pl_mempool, key->name, key->namelen, value, valuelen);
-}
-
-
-/* ------------------------- pblock_param_create -------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_param_create(pblock *pb, const char *name, const char *value)
-{
-    /*
-     * Allocate a PLValueStruct_t from the property list's memory pool.
-     */
-    PListStruct_t *pl = PBTOPL(pb);
-    return _param_create(pl->pl_mempool, name, name ? strlen(name) : 0, value, value ? strlen(value) : 0);
-}
-
-
-/* ----------------------------- param_create ----------------------------- */
-
-NSAPI_PUBLIC pb_param *param_create(const char *name, const char *value)
-{
-    /*
-     * Allocate a PLValueStruct_t containing the pb_param that will
-     * be returned.  Normally PLValueStruct_ts are allocated from the
-     * memory pool associated with a property list, but we don't have
-     * that here, so we just use the thread's pool and indicate we were
-     * allocated from a specific pool.
-     */
-    return _param_create(system_pool(), name, name ? strlen(name) : 0, value, value ? strlen(value) : 0);
-}
-
-
-/* ------------------------------ param_free ------------------------------ */
-
-NSAPI_PUBLIC int param_free(pb_param *pp)
-{
-    if (pp) {
-        PLValueStruct_t *pv = PATOPV(pp);
-
-        /* Don't bother if the pblock was allocated from a pool */
-        if (!pv->pv_mempool) {
-            pool_free(pv->pv_mempool, pv->pv_name);
-            pool_free(pv->pv_mempool, pv->pv_value);
-            pool_free(pv->pv_mempool, pv);
-        }
-
-        return 1;
-    }
-
-    return 0;
-}
-
-
-/* -------------------------- pblock_create_pool -------------------------- */
-
-NSAPI_PUBLIC pblock *pblock_create_pool(pool_handle_t *pool_handle, int n)
-{
-    /* Create a property list with n property indices */
-    PListStruct_t *plist = (PListStruct_t *)PListCreate(pool_handle, n, 0, 0);
-    if (!plist)
-        return NULL;
-
-    plist->pl_resvpi = 0;
-
-    return &plist->pl_pb;
-}
-
-
-/* ----------------------------- pblock_pool ------------------------------ */
-
-NSAPI_PUBLIC pool_handle_t *pblock_pool(pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-    return pl->pl_mempool;
-}
-
-
-/* ---------------------------- pblock_create ----------------------------- */
-
-NSAPI_PUBLIC pblock *pblock_create(int n)
-{
-    return pblock_create_pool(MALLOC_POOL_HANDLE, n);
-}
-
-
-/* ----------------------------- pblock_free ------------------------------ */
-
-NSAPI_PUBLIC void pblock_free(pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-    PLValueStruct_t **ppval;
-    PLValueStruct_t *pv;
-    int i;
-
-    if (!pb) {
-        return;
-    }
-
-    /* If the pools are enabled, this routine has no effect anyway, so 
-     * just return. 
-     */
-    if (pl->pl_mempool || pool_enabled()) {
-        return;
-    }
-
-    /* Free the property name symbol table if any */
-    if (pl->pl_symtab) {
-        pool_free(pl->pl_mempool, (void *)(pl->pl_symtab));
-    }
-
-    ppval = (PLValueStruct_t **)(pl->pl_ppval);
-
-    /* Loop over the initialized property indices */
-    for (i = 0; i < pl->pl_initpi; ++i) {
-
-        /* Got a property here? */
-        pv = ppval[i];
-        if (pv) {
-
-            param_free(&pv->pv_pbparam);
-        }
-    }
-
-    /* Free the array of pointers to property values */
-    pool_free(pl->pl_mempool, (void *)ppval);
-
-    /* Free the property list head */
-    pool_free(pl->pl_mempool, (void *)pl);
-}
-
-
-/* ------------------------------ pblock_key ------------------------------ */
-
-NSAPI_PUBLIC const pb_key *pblock_key(const char *name)
-{
-    if (!name)
-        return NULL;
-
-    return _find_key(name, PListHash(name));
-}
-
-
-/* --------------------------- pblock_kpinsert ---------------------------- */
-
-NSAPI_PUBLIC void pblock_kpinsert(const pb_key *key, pb_param *pp, pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-    PLValueStruct_t *pv = PATOPV(pp);
-
-    //PR_ASSERT(pv->pv_mempool == pl->pl_mempool); // TODO
-
-    /* Check to see if the name corresponds to a pb_key */
-    unsigned int hashval;
-    if (!key) {
-        hashval = PListHash(pv->pv_name);
-        key = _find_key(pv->pv_name, hashval);
-    }
-
-    /* Find property index */
-    int pindex = PListGetFreeIndex(pl);
-    if (pindex < 1) {
-        /* Error - invalid property index */
-        printf("Error - invalid property index\n");
-        return;
-    }
-
-    /* Allocate/grow the symbol table as needed */
-    PLSymbolTable_t *pt = PListSymbolTable(pl);
-    if (!pt) {
-        printf("!pt\n");
-        return;
-    }
-
-    /* Add PLValueStruct_t to the property list */
-    PLValueStruct_t **ppval = (PLValueStruct_t **)(pl->pl_ppval);
-    pv->pv_pbkey = key;
-    pv->pv_pi = pindex;
-    ppval[pv->pv_pi - 1] = pv;
-
-    /* Add name to symbol table */
-    int i = key ? _get_hash_index(pl, key) : (hashval % PLSIZENDX(pt->pt_sizendx));
-    pv->pv_next = pt->pt_hash[i];
-    pt->pt_hash[i] = pv;
-    pt->pt_nsyms++;
-
-    //PR_ASSERT(param_key(pp) == key); // TODO
-}
-
-
-/* ---------------------------- pblock_pinsert ---------------------------- */
-
-NSAPI_PUBLIC void pblock_pinsert(pb_param *pp, pblock *pb)
-{
-    pblock_kpinsert(NULL, pp, pb);
-}
-
-
-/* --------------------------- pblock_nvinsert ---------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_nvinsert(const char *name, const char *value, pblock *pb)
-{
-    pb_param *pp = pblock_param_create(pb, name, value);
-    if (pp)
-        pblock_kpinsert(NULL, pp, pb);
-    return pp;
-}
-
-
-/* --------------------------- pblock_kvinsert ---------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_kvinsert(const pb_key *key, const char *value, int valuelen, pblock *pb)
-{
-    pb_param *pp = pblock_key_param_create(pb, key, value, valuelen);
-    if (pp)
-        pblock_kpinsert(key, pp, pb);
-    return pp;
-}
-
-
-/* --------------------------- pblock_nninsert ---------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_nninsert(const char *name, int value, pblock *pb)
-{
-    char num[UTIL_ITOA_SIZE];
-
-    util_itoa(value, num);
-    return pblock_nvinsert(name, num, pb);
-}
-
-
-/* --------------------------- pblock_kninsert ---------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_kninsert(const pb_key *key, int value, pblock *pb)
-{
-    pb_param *pp = pblock_key_param_create(pb, key, NULL, UTIL_ITOA_SIZE);
-    if (pp) {
-        util_itoa(value, pp->value);
-        pblock_kpinsert(key, pp, pb);
-    }
-    return pp;
-}
-
-
-/* --------------------------- pblock_kllinsert --------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_kllinsert(const pb_key *key, int64_t value, pblock *pb)
-{
-    pb_param *pp = pblock_key_param_create(pb, key, NULL, UTIL_I64TOA_SIZE);
-    if (pp) {
-        util_i64toa(value, pp->value);
-        pblock_kpinsert(key, pp, pb);
-    }
-    return pp;
-}
-
-
-/* ---------------------------pblock_nvlinsert ---------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_nvlinsert(const char *name, int namelen, const char *value, int valuelen, pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-
-    pb_param *pp = _param_create(pl->pl_mempool, name, namelen, value, valuelen);
-
-    if(pp) {
-        pblock_kpinsert(NULL, pp, pb);
-    }
-
-    return pp;
-}
-
-
-/* ---------------------------- pblock_findkey ---------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_findkey(const pb_key *key, const pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-
-    /* Lookup key by examining symbol table */
-    if (pl->pl_symtab) {
-        int i = _get_hash_index(pl, key);
-        PLValueStruct_t *pv;
-
-        /* Search hash collision list for matching name */
-        for (pv = pl->pl_symtab->pt_hash[i]; pv; pv = pv->pv_next) {
-            if (pv->pv_pbkey == key)
-                return &pv->pv_pbparam;
-        }
-    }
-
-    return NULL;
-}
-
-
-/* -------------------------- pblock_findkeyval --------------------------- */
-
-NSAPI_PUBLIC char *pblock_findkeyval(const pb_key *key, const pblock *pb)
-{
-    pb_param *pp = pblock_findkey(key, pb);
-    return pp ? pp->value : NULL;
-}
-
-
-/* ---------------------------- pblock_findval ---------------------------- */
-
-NSAPI_PUBLIC char *pblock_findval(const char *name, const pblock *pb)
-{
-    void *pvalue = 0;
-
-    (void)PListFindValue((PList_t)(PBTOPL(pb)), name, &pvalue, 0);
-
-    return (char *)pvalue;
-}
-
-
-/* ------------------------------ pblock_fr ------------------------------ */
-
-NSAPI_PUBLIC pb_param *pblock_fr(const char *name, pblock *pb, int remove)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-    PLValueStruct_t **ppval;
-    PLValueStruct_t **pvp;
-    PLValueStruct_t *pv = NULL;
-    int pindex;
-    int i;
-
-    if (pl->pl_symtab) {
-
-        /* Compute hash index of specified property name */
-        i = PListHashName(pl->pl_symtab, name);
-
-        /* Search hash collision list for matching name */
-        for (pvp = &pl->pl_symtab->pt_hash[i];
-             (pv = *pvp); pvp = &(*pvp)->pv_next) {
-
-            if (!strcmp(name, pv->pv_name)) {
-
-                if (remove) {
-                    /* Remove PLValueStruct_t from symbol table */
-                    *pvp = pv->pv_next;
-                    pl->pl_symtab->pt_nsyms--;
-
-                    /* Remove it from pl_ppval too */
-                    ppval = (PLValueStruct_t **)(pl->pl_ppval);
-                    pindex = pv->pv_pi;
-                    ppval[pindex - 1] = 0;
-                }
-                break;
-            }
-        }
-    }
-
-    return (pv) ? &pv->pv_pbparam : NULL;
-}
-
-
-/* --------------------------- pblock_removekey --------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_removekey(const pb_key *key, pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-    PLValueStruct_t **ppval;
-    PLValueStruct_t **pvp;
-    PLValueStruct_t *pv = NULL;
-    int pindex;
-    int i;
-
-    if (pl->pl_symtab) {
-        /* Lookup hash index for specified property key */
-        i = _get_hash_index(pl, key);
-
-        /* Search hash collision list for matching key */
-        for (pvp = &pl->pl_symtab->pt_hash[i]; (pv = *pvp); pvp = &pv->pv_next) {
-            /* If this value has the requested key... */
-            if (pv->pv_pbkey == key) {
-                /* Remove PLValueStruct_t from symbol table */
-                *pvp = pv->pv_next;
-                pl->pl_symtab->pt_nsyms--;
-
-                /* Remove it from pl_ppval too */
-                ppval = (PLValueStruct_t **)(pl->pl_ppval);
-                pindex = pv->pv_pi;
-                ppval[pindex - 1] = 0;
-
-                break;
-            }
-        }
-    }
-
-    return (pv) ? &pv->pv_pbparam : NULL;
-}
-
-
-/* -------------------------- pblock_removeone --------------------------- */
-
-NSAPI_PUBLIC pb_param *pblock_removeone(pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-
-    if (pl && pl->pl_symtab) {
-        /* Search hash buckets */
-        for (int i = 0; i < PLSIZENDX(pl->pl_symtab->pt_sizendx); i++) {
-            /* Search hash collision list */
-            PLValueStruct_t *pv = pl->pl_symtab->pt_hash[i];
-            if (pv) {
-                /* Remove PLValueStruct_t from symbol table */
-                pl->pl_symtab->pt_hash[i] = pv->pv_next;
-                pl->pl_symtab->pt_nsyms--;
-
-                /* Remove it from pl_ppval too */
-                PLValueStruct_t **ppval = (PLValueStruct_t**)pl->pl_ppval;
-                ppval[pv->pv_pi - 1] = 0;
-
-                return &pv->pv_pbparam;
-            }
-        }
-    }
-
-    return NULL;
-}
-
-
-/* -------------------------- pblock_str2pblock --------------------------- */
-
-
-int _verify_pbstr(const char *str)
-{
-    const char *cp;
-    const char *scp;
-    int np;
-    int state;
-    int quote;
-
-    for(cp = str, np = 0, state = 0; *cp; ) {
-        switch (state) {
-        case 0:                 /* skipping leading spaces */
-
-            while (*cp && isspace(*cp)) ++cp;
-            if (*cp == '=') {
-                return -1;
-            }
-            if (*cp) state = 1;
-            break;
-
-        case 1:                 /* scanning parameter name */
-
-            scp = cp;
-            while (*cp && (*cp != '=') && !isspace(*cp)) ++cp;
-            if (*cp == '=') ++cp;
-            else cp = scp;
-            state = 2;
-            break;
-
-        case 2:                 /* scanning parameter value */
-            quote = 0;
-            if (*cp == '\"') {
-                quote = 1;
-                ++cp;
-            }
-            for (;;) {
-                if (*cp == '\\') {
-                    ++cp;
-                    if (*cp == 0) {
-                        return -1;
-                    }
-                }
-                else if (*cp == '\"') {
-                    if (!quote) {
-                        return -1;
-                    }
-                    ++np;
-                    ++cp;
-                    quote = 0;
-                    state = 0;
-                    break;
-                }
-                else if (!quote && (!*cp || isspace(*cp))) {
-                    ++np;
-                    if (*cp) ++cp;
-                    state = 0;
-                    break;
-                }
-                else if (*cp == 0) {
-                    return -1;
-                }
-                ++cp;
-            }
-            if (quote) {
-                return -1;
-            }
-            break;
-        }
-    }
-
-    return (state == 0) ? np : -1;
-}
-
-NSAPI_PUBLIC int
-INTpblock_str2pblock_lowercasename(const char *str, pblock *pb)
-{
-    return _pblock_str2pblock(str, pb, PR_TRUE);
-}
-
-NSAPI_PUBLIC int pblock_str2pblock(const char *str, pblock *pb)
-{
-    return _pblock_str2pblock(str, pb, PR_FALSE);
-}
-
-int
-_pblock_str2pblock(const char* str, pblock* pb, PRBool lowerCase)
-{
-    char *cpy;
-    char *cp;
-    char *dp;
-    char *pname;
-    char *pvalue;
-    int np;
-    int quote;
-    int state;
-    char numbuf[UTIL_ITOA_SIZE];
-
-    if((np = _verify_pbstr(str)) < 1)
-        return -1;
-
-    while (*str && isspace(*str)) ++str;
-
-    cpy = STRDUP(str);
-
-    for (np = 0, cp = cpy, state = 0; *cp; ) {
-        switch (state) {
-
-        case 0:                 /* skipping leading spaces */
-
-            while (*cp && isspace(*cp)) ++cp;
-            if (*cp) state = 1;
-            break;
-
-        case 1:                 /* scanning parameter name */
-
-            pname = cp;
-            while (*cp && (*cp != '=') && !isspace(*cp)) ++cp;
-            if (*cp == '=') {
-                *cp++ = 0;
-            }
-            else {
-                cp = pname;
-                pname = numbuf;
-                util_itoa(np+1, numbuf);
-            }
-            state = 2;
-            break;
-
-        case 2:                 /* scanning parameter value */
-            quote = 0;
-            if (*cp == '\"') {
-                quote = 1;
-                ++cp;
-            }
-            for (pvalue = cp, dp = cp; ; ++cp, ++dp) {
-                if (*cp == '\\') {
-                    ++cp;
-                }
-                else if (*cp == '\"') {
-                    ++np;
-                    ++cp;
-                    *dp = 0;
-                    quote = 0;
-                    state = 0;
-                    break;
-                }
-                else if (!quote && ((*cp == 0) || isspace(*cp))) {
-                    ++np;
-                    if (*cp != 0) {
-                        ++cp;
-                    }
-                    *dp = 0;
-                    state = 0;
-                    break;
-                }
-                if (cp != dp) *dp = *cp;
-            }
-            if (lowerCase == PR_TRUE) {
-                for (char* p = pname; *p; p++) {
-                    *p = tolower(*p);
-                }
-            }
-            pblock_nvinsert(pname, pvalue, pb);
-            break;
-        }
-    }
-
-    FREE(cpy);
-
-    return np;
-}
-
-
-/* -------------------------- pblock_pblock2str --------------------------- */
-
-
-NSAPI_PUBLIC char *pblock_pblock2str(const pblock *pb, char *str)
-{
-    register char *s = str, *t, *u;
-    PListStruct_t *pl = PBTOPL(pb);
-    PLValueStruct_t **ppval;
-    PLValueStruct_t *pv;
-    int i;
-    int sl;
-    int xlen;
-
-    ppval = (PLValueStruct_t **)(pl->pl_ppval);
-
-    /* Loop over the initialized property indices */
-    for (i = 0, xlen = 0; i < pl->pl_initpi; ++i) {
-
-        /* Got a property here? */
-        pv = ppval[i];
-        if (pv && pv->pv_name) {
-
-            int ln = strlen(pv->pv_name);
-            int lv = strlen((char *)(pv->pv_value));
-
-            /* Check for " or \ because we'll have to escape them */
-            for (t = (char *)(pv->pv_value); *t; ++t) {
-                if ((*t == '\"') || (*t == '\\')) ++lv;
-            }
-
-            /* 4: two quotes, =, and a null */
-            xlen += (ln + lv + 4);
-        }
-    }
-
-    /* Allocate string to hold parameter settings, or increase size */
-    if (!s) {
-        s = (char *)MALLOC(xlen);
-        s[0] = '\0';
-        t = &s[0];
-        sl = xlen;
-    }
-    else {
-        sl = strlen(s);
-        t = &s[sl];
-        sl += xlen;
-        s = (char *)REALLOC(s, sl);
-    }
-
-    /* Loop over the initialized property indices */
-    for (i = 0; i < pl->pl_initpi; ++i) {
-
-        /* Got a property here? */
-        pv = ppval[i];
-        if (pv && pv->pv_name) {
-
-            if (t != s) *t++ = ' ';
-
-            for (u = pv->pv_name; *u; ) *t++ = *u++;
-
-            *t++ = '=';
-            *t++ = '\"';
-
-            for (u = (char *)(pv->pv_value); *u; ) {
-                if ((*u == '\\') || (*u == '\"')) *t++ = '\\';
-                *t++ = *u++;
-            }
-
-            *t++ = '\"';
-            *t = '\0';
-        }
-    }
-
-    return s;
-}
-
-
-/* ----------------------------- pblock_copy ------------------------------ */
-
-
-NSAPI_PUBLIC int pblock_copy(const pblock *src, pblock *dst)
-{
-    PListStruct_t *pl = PBTOPL(src);
-    PLValueStruct_t **ppval;
-    PLValueStruct_t *pv;
-    int rv = 0;
-    int i;
-
-    ppval = (PLValueStruct_t **)(pl->pl_ppval);
-
-    for (i = 0; i < pl->pl_initpi; ++i) {
-        pv = ppval[i];
-        if (pv) {
-            if (pv->pv_pbkey) {
-                if (pv->pv_pbkey != pb_key_magnus_internal) {
-                    if (!pblock_kvinsert(pv->pv_pbkey, (char *)(pv->pv_value), strlen(pv->pv_value), dst))
-                        rv = -1;
-                }
-            } else {
-                if (!pblock_nvinsert(pv->pv_name, (char *)(pv->pv_value), dst))
-                    rv = -1;
-            }
-        }
-    }
-
-    return rv;
-}
-
-/* ---------------------------- pblock_dup -------------------------------- */
-
-NSAPI_PUBLIC pblock *pblock_dup(const pblock *src)
-{
-    pblock *dst;
-
-    if (!src)
-        return NULL;
-
-    if ( (dst = pblock_create(src->hsize)) )
-        pblock_copy(src, dst);
-
-    return dst;
-}
-
-
-/* ---------------------------- pblock_pb2env ----------------------------- */
-
-
-NSAPI_PUBLIC char **pblock_pb2env(const pblock *pb, char **env)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-    PLValueStruct_t **ppval;
-    PLValueStruct_t *pv;
-    int i;
-    int nval;
-    int pos;
-
-    /* Find out how many there are. */
-    
-    ppval = (PLValueStruct_t **)(pl->pl_ppval);
-
-    for (i = 0, nval = 0; i < pl->pl_initpi; ++i) {
-        if (ppval[i]) ++nval;
-    }
-    
-    env = util_env_create(env, nval, &pos);
-
-    for (i = 0; i < pl->pl_initpi; ++i) {
-        pv = ppval[i];
-        if (pv) {
-            env[pos++] = util_env_str(pv->pv_name, (char *)(pv->pv_value));
-        }
-    }
-    env[pos] = NULL;
-
-    return env;
-}
-
-
-/* ---------------------------- pblock_replace ---------------------------- */
-
-NSAPI_PUBLIC char * pblock_replace(const char *name,
-                                   char * new_value, pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-
-    /* Replace an existing value */
-    pb_param *pp = pblock_find(name, pb);
-    if (!pp)
-        return NULL;
-    pool_free(pl->pl_mempool, pp->value);
-    pp->value = new_value;
-
-    return new_value;
-}
-
-
-/* --------------------------- pblock_nvreplace --------------------------- */
-
-NSAPI_PUBLIC void pblock_nvreplace (const char *name, const char *value, pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-
-    /* Replace an existing value or insert a new value */
-    pb_param *pp = pblock_find(name, pb);
-    if (pp) {
-        pool_free(pl->pl_mempool, pp->value);
-        pp->value = pool_strdup(pl->pl_mempool, value);
-    } else {
-        pblock_nvinsert(name, value, pb);
-    }
-}
-
-
-/* --------------------------- pblock_kvreplace --------------------------- */
-
-NSAPI_PUBLIC void pblock_kvreplace(const pb_key *key, const char *value, int valuelen, pblock *pb)
-{
-    PListStruct_t *pl = PBTOPL(pb);
-
-    /* Replace an existing value or insert a new value */
-    pb_param *pp = pblock_findkey(key, pb);
-    if (pp) {
-        pool_free(pl->pl_mempool, pp->value);
-        pp->value = (char*)pool_malloc(pl->pl_mempool, valuelen + 1);
-        memcpy(pp->value, value, valuelen + 1);
-    } else {
-        pblock_kvinsert(key, value, valuelen, pb);
-    }
-}
--- a/src/server/util/pblock.h	Sat Sep 24 16:26:10 2022 +0200
+++ b/src/server/util/pblock.h	Sat Sep 24 17:11:57 2022 +0200
@@ -109,204 +109,208 @@
 
 typedef struct pb_key pb_key;
 
-extern const pb_key *const pb_key_accept;
-extern const pb_key *const pb_key_accept_charset;
-extern const pb_key *const pb_key_accept_encoding;
-extern const pb_key *const pb_key_accept_language;
-extern const pb_key *const pb_key_accept_ranges;
-extern const pb_key *const pb_key_actual_route;
-extern const pb_key *const pb_key_age;
-extern const pb_key *const pb_key_always_allow_chunked;
-extern const pb_key *const pb_key_always_use_keep_alive;
-extern const pb_key *const pb_key_auth_cert;
-extern const pb_key *const pb_key_auth_expiring;
-extern const pb_key *const pb_key_auth_group;
-extern const pb_key *const pb_key_auth_type;
-extern const pb_key *const pb_key_auth_user;
-extern const pb_key *const pb_key_authorization;
-extern const pb_key *const pb_key_browser;
-extern const pb_key *const pb_key_c2p_cl;
-extern const pb_key *const pb_key_c2p_hl;
-extern const pb_key *const pb_key_cache_info;
-extern const pb_key *const pb_key_charset;
-extern const pb_key *const pb_key_check_http_server;
-extern const pb_key *const pb_key_ChunkedRequestBufferSize;
-extern const pb_key *const pb_key_ChunkedRequestTimeout;
-extern const pb_key *const pb_key_cipher;
-extern const pb_key *const pb_key_clf_request;
-extern const pb_key *const pb_key_cli_status;
-extern const pb_key *const pb_key_client_cert_nickname;
-extern const pb_key *const pb_key_client_ip;
-extern const pb_key *const pb_key_close;
-extern const pb_key *const pb_key_connect_timeout;
-extern const pb_key *const pb_key_connection;
-extern const pb_key *const pb_key_cont;
-extern const pb_key *const pb_key_content_encoding;
-extern const pb_key *const pb_key_content_language;
-extern const pb_key *const pb_key_content_length;
-extern const pb_key *const pb_key_content_location;
-extern const pb_key *const pb_key_content_md5;
-extern const pb_key *const pb_key_content_range;
-extern const pb_key *const pb_key_content_type;
-extern const pb_key *const pb_key_cookie;
-extern const pb_key *const pb_key_date;
-extern const pb_key *const pb_key_DATE_GMT;
-extern const pb_key *const pb_key_DATE_LOCAL;
-extern const pb_key *const pb_key_dir;
-extern const pb_key *const pb_key_Directive;
-extern const pb_key *const pb_key_dns;
-extern const pb_key *const pb_key_DOCUMENT_NAME;
-extern const pb_key *const pb_key_DOCUMENT_URI;
-extern const pb_key *const pb_key_domain;
-extern const pb_key *const pb_key_enc;
-extern const pb_key *const pb_key_engine;
-extern const pb_key *const pb_key_error_action;
-extern const pb_key *const pb_key_error_desc;
-extern const pb_key *const pb_key_error_fn;
-extern const pb_key *const pb_key_escape;
-extern const pb_key *const pb_key_escaped;
-extern const pb_key *const pb_key_etag;
-extern const pb_key *const pb_key_expect;
-extern const pb_key *const pb_key_expires;
-extern const pb_key *const pb_key_expr;
-extern const pb_key *const pb_key_filter;
-extern const pb_key *const pb_key_find_pathinfo_forward;
-extern const pb_key *const pb_key_flushTimer;
-extern const pb_key *const pb_key_fn;
-extern const pb_key *const pb_key_from;
-extern const pb_key *const pb_key_full_headers;
-extern const pb_key *const pb_key_hdr;
-extern const pb_key *const pb_key_host;
-extern const pb_key *const pb_key_hostname;
-extern const pb_key *const pb_key_if_match;
-extern const pb_key *const pb_key_if_modified_since;
-extern const pb_key *const pb_key_if_none_match;
-extern const pb_key *const pb_key_if_range;
-extern const pb_key *const pb_key_if_unmodified_since;
-extern const pb_key *const pb_key_ip;
-extern const pb_key *const pb_key_iponly;
-extern const pb_key *const pb_key_issuer_dn;
-extern const pb_key *const pb_key_jroute;
-extern const pb_key *const pb_key_keep_alive;
-extern const pb_key *const pb_key_keep_alive_timeout;
-extern const pb_key *const pb_key_keysize;
-extern const pb_key *const pb_key_lang;
-extern const pb_key *const pb_key_last_modified;
-extern const pb_key *const pb_key_level;
-extern const pb_key *const pb_key_location;
-extern const pb_key *const pb_key_lock_owner;
-extern const pb_key *const pb_key_magnus_charset;
-extern const pb_key *const pb_key_magnus_internal;
-extern const pb_key *const pb_key_magnus_internal_dav_src;
-extern const pb_key *const pb_key_magnus_internal_default_acls_only;
-extern const pb_key *const pb_key_magnus_internal_error_j2ee;
-extern const pb_key *const pb_key_magnus_internal_j2ee_nsapi;
-extern const pb_key *const pb_key_magnus_internal_preserve_srvhdrs;
-extern const pb_key *const pb_key_magnus_internal_set_request_status;
-extern const pb_key *const pb_key_magnus_internal_set_response_status;
-extern const pb_key *const pb_key_magnus_internal_webapp_errordesc;
-extern const pb_key *const pb_key_matched_browser;
-extern const pb_key *const pb_key_max_age;
-extern const pb_key *const pb_key_max_forwards;
-extern const pb_key *const pb_key_message;
-extern const pb_key *const pb_key_method;
-extern const pb_key *const pb_key_name;
-extern const pb_key *const pb_key_nocache;
-extern const pb_key *const pb_key_nostat;
-extern const pb_key *const pb_key_ntrans_base;
-extern const pb_key *const pb_key_offline_origin_addr;
-extern const pb_key *const pb_key_offline_proxy_addr;
-extern const pb_key *const pb_key_origin_addr;
-extern const pb_key *const pb_key_p2c_cl;
-extern const pb_key *const pb_key_p2c_hl;
-extern const pb_key *const pb_key_p2r_cl;
-extern const pb_key *const pb_key_p2r_hl;
-extern const pb_key *const pb_key_parse_timeout;
-extern const pb_key *const pb_key_password;
-extern const pb_key *const pb_key_path;
-extern const pb_key *const pb_key_PATH_INFO;
-extern const pb_key *const pb_key_path_info;
-extern const pb_key *const pb_key_pblock;
-extern const pb_key *const pb_key_poll_interval;
-extern const pb_key *const pb_key_pool; // new
-extern const pb_key *const pb_key_port;
-extern const pb_key *const pb_key_ppath;
-extern const pb_key *const pb_key_pragma;
-extern const pb_key *const pb_key_process_request_body;
-extern const pb_key *const pb_key_process_response_body;
-extern const pb_key *const pb_key_protocol;
-extern const pb_key *const pb_key_proxy_addr;
-extern const pb_key *const pb_key_proxy_agent;
-extern const pb_key *const pb_key_proxy_auth_cert;
-extern const pb_key *const pb_key_proxy_authorization;
-extern const pb_key *const pb_key_proxy_cipher;
-extern const pb_key *const pb_key_proxy_issuer_dn;
-extern const pb_key *const pb_key_proxy_jroute;
-extern const pb_key *const pb_key_proxy_keysize;
-extern const pb_key *const pb_key_proxy_ping;
-extern const pb_key *const pb_key_proxy_request;
-extern const pb_key *const pb_key_proxy_secret_keysize;
-extern const pb_key *const pb_key_proxy_ssl_id;
-extern const pb_key *const pb_key_proxy_user_dn;
-extern const pb_key *const pb_key_query;
-extern const pb_key *const pb_key_QUERY_STRING;
-extern const pb_key *const pb_key_QUERY_STRING_UNESCAPED;
-extern const pb_key *const pb_key_r2p_cl;
-extern const pb_key *const pb_key_r2p_hl;
-extern const pb_key *const pb_key_range;
-extern const pb_key *const pb_key_referer;
-extern const pb_key *const pb_key_reformat_request_headers;
-extern const pb_key *const pb_key_remote_status;
-extern const pb_key *const pb_key_request_jroute;
-extern const pb_key *const pb_key_required_rights;
-extern const pb_key *const pb_key_retries;
-extern const pb_key *const pb_key_rewrite_content_location;
-extern const pb_key *const pb_key_rewrite_host;
-extern const pb_key *const pb_key_rewrite_location;
-extern const pb_key *const pb_key_rewrite_set_cookie;
-extern const pb_key *const pb_key_root;
-extern const pb_key *const pb_key_route;
-extern const pb_key *const pb_key_route_cookie;
-extern const pb_key *const pb_key_route_hdr;
-extern const pb_key *const pb_key_route_offline;
-extern const pb_key *const pb_key_script_name;
-extern const pb_key *const pb_key_secret_keysize;
-extern const pb_key *const pb_key_secure;
-extern const pb_key *const pb_key_server;
-extern const pb_key *const pb_key_set_cookie;
-extern const pb_key *const pb_key_socks_addr;
-extern const pb_key *const pb_key_ssl_id;
-extern const pb_key *const pb_key_ssl_unclean_shutdown;
-extern const pb_key *const pb_key_status;
-extern const pb_key *const pb_key_sticky_cookie;
-extern const pb_key *const pb_key_sticky_param;
-extern const pb_key *const pb_key_suppress_request_headers;
-extern const pb_key *const pb_key_svr_status;
-extern const pb_key *const pb_key_timeout;
-extern const pb_key *const pb_key_to;
-extern const pb_key *const pb_key_transfer_encoding;
-extern const pb_key *const pb_key_transmit_timeout;
-extern const pb_key *const pb_key_tunnel_non_http_response;
-extern const pb_key *const pb_key_type;
-extern const pb_key *const pb_key_upstream_jroute;
-extern const pb_key *const pb_key_uri;
-extern const pb_key *const pb_key_url;
-extern const pb_key *const pb_key_url_prefix;
-extern const pb_key *const pb_key_UseOutputStreamSize;
-extern const pb_key *const pb_key_user;
-extern const pb_key *const pb_key_user_agent;
-extern const pb_key *const pb_key_user_dn;
-extern const pb_key *const pb_key_validate_server_cert;
-extern const pb_key *const pb_key_value;
-extern const pb_key *const pb_key_vary;
-extern const pb_key *const pb_key_via;
-extern const pb_key *const pb_key_warning;
-extern const pb_key *const pb_key_depth;
-extern const pb_key *const pb_key_if;
-extern const pb_key *const pb_key_vfs;
-extern const pb_key *const pb_key_dav;
-extern const pb_key *const pb_key_vfsclass;
-extern const pb_key *const pb_key_davclass;
+extern const pb_key *pb_key_accept;
+extern const pb_key *pb_key_accept_charset;
+extern const pb_key *pb_key_accept_encoding;
+extern const pb_key *pb_key_accept_language;
+extern const pb_key *pb_key_accept_ranges;
+extern const pb_key *pb_key_actual_route;
+extern const pb_key *pb_key_age;
+extern const pb_key *pb_key_always_allow_chunked;
+extern const pb_key *pb_key_always_use_keep_alive;
+extern const pb_key *pb_key_auth_cert;
+extern const pb_key *pb_key_auth_expiring;
+extern const pb_key *pb_key_auth_group;
+extern const pb_key *pb_key_auth_type;
+extern const pb_key *pb_key_auth_user;
+extern const pb_key *pb_key_authorization;
+extern const pb_key *pb_key_browser;
+extern const pb_key *pb_key_c2p_cl;
+extern const pb_key *pb_key_c2p_hl;
+extern const pb_key *pb_key_cache_info;
+extern const pb_key *pb_key_charset;
+extern const pb_key *pb_key_check_http_server;
+extern const pb_key *pb_key_ChunkedRequestBufferSize;
+extern const pb_key *pb_key_ChunkedRequestTimeout;
+extern const pb_key *pb_key_cipher;
+extern const pb_key *pb_key_clf_request;
+extern const pb_key *pb_key_cli_status;
+extern const pb_key *pb_key_client_cert_nickname;
+extern const pb_key *pb_key_client_ip;
+extern const pb_key *pb_key_close;
+extern const pb_key *pb_key_connect_timeout;
+extern const pb_key *pb_key_connection;
+extern const pb_key *pb_key_cont;
+extern const pb_key *pb_key_content_encoding;
+extern const pb_key *pb_key_content_language;
+extern const pb_key *pb_key_content_length;
+extern const pb_key *pb_key_content_location;
+extern const pb_key *pb_key_content_md5;
+extern const pb_key *pb_key_content_range;
+extern const pb_key *pb_key_content_type;
+extern const pb_key *pb_key_cookie;
+extern const pb_key *pb_key_date;
+extern const pb_key *pb_key_DATE_GMT;
+extern const pb_key *pb_key_DATE_LOCAL;
+extern const pb_key *pb_key_dir;
+extern const pb_key *pb_key_Directive;
+extern const pb_key *pb_key_dns;
+extern const pb_key *pb_key_DOCUMENT_NAME;
+extern const pb_key *pb_key_DOCUMENT_URI;
+extern const pb_key *pb_key_domain;
+extern const pb_key *pb_key_enc;
+extern const pb_key *pb_key_engine;
+extern const pb_key *pb_key_error_action;
+extern const pb_key *pb_key_error_desc;
+extern const pb_key *pb_key_error_fn;
+extern const pb_key *pb_key_escape;
+extern const pb_key *pb_key_escaped;
+extern const pb_key *pb_key_etag;
+extern const pb_key *pb_key_expect;
+extern const pb_key *pb_key_expires;
+extern const pb_key *pb_key_expr;
+extern const pb_key *pb_key_filter;
+extern const pb_key *pb_key_find_pathinfo_forward;
+extern const pb_key *pb_key_flushTimer;
+extern const pb_key *pb_key_fn;
+extern const pb_key *pb_key_from;
+extern const pb_key *pb_key_full_headers;
+extern const pb_key *pb_key_hdr;
+extern const pb_key *pb_key_host;
+extern const pb_key *pb_key_hostname;
+extern const pb_key *pb_key_if_match;
+extern const pb_key *pb_key_if_modified_since;
+extern const pb_key *pb_key_if_none_match;
+extern const pb_key *pb_key_if_range;
+extern const pb_key *pb_key_if_unmodified_since;
+extern const pb_key *pb_key_ip;
+extern const pb_key *pb_key_iponly;
+extern const pb_key *pb_key_issuer_dn;
+extern const pb_key *pb_key_jroute;
+extern const pb_key *pb_key_keep_alive;
+extern const pb_key *pb_key_keep_alive_timeout;
+extern const pb_key *pb_key_keysize;
+extern const pb_key *pb_key_lang;
+extern const pb_key *pb_key_last_modified;
+extern const pb_key *pb_key_level;
+extern const pb_key *pb_key_location;
+extern const pb_key *pb_key_lock_owner;
+extern const pb_key *pb_key_magnus_charset;
+extern const pb_key *pb_key_magnus_internal;
+extern const pb_key *pb_key_magnus_internal_dav_src;
+extern const pb_key *pb_key_magnus_internal_default_acls_only;
+extern const pb_key *pb_key_magnus_internal_error_j2ee;
+extern const pb_key *pb_key_magnus_internal_j2ee_nsapi;
+extern const pb_key *pb_key_magnus_internal_preserve_srvhdrs;
+extern const pb_key *pb_key_magnus_internal_set_request_status;
+extern const pb_key *pb_key_magnus_internal_set_response_status;
+extern const pb_key *pb_key_magnus_internal_webapp_errordesc;
+extern const pb_key *pb_key_matched_browser;
+extern const pb_key *pb_key_max_age;
+extern const pb_key *pb_key_max_forwards;
+extern const pb_key *pb_key_message;
+extern const pb_key *pb_key_method;
+extern const pb_key *pb_key_name;
+extern const pb_key *pb_key_nocache;
+extern const pb_key *pb_key_nostat;
+extern const pb_key *pb_key_ntrans_base;
+extern const pb_key *pb_key_offline_origin_addr;
+extern const pb_key *pb_key_offline_proxy_addr;
+extern const pb_key *pb_key_origin_addr;
+extern const pb_key *pb_key_p2c_cl;
+extern const pb_key *pb_key_p2c_hl;
+extern const pb_key *pb_key_p2r_cl;
+extern const pb_key *pb_key_p2r_hl;
+extern const pb_key *pb_key_parse_timeout;
+extern const pb_key *pb_key_password;
+extern const pb_key *pb_key_path;
+extern const pb_key *pb_key_PATH_INFO;
+extern const pb_key *pb_key_path_info;
+extern const pb_key *pb_key_pblock;
+extern const pb_key *pb_key_poll_interval;
+extern const pb_key *pb_key_pool; // new
+extern const pb_key *pb_key_port;
+extern const pb_key *pb_key_ppath;
+extern const pb_key *pb_key_pragma;
+extern const pb_key *pb_key_process_request_body;
+extern const pb_key *pb_key_process_response_body;
+extern const pb_key *pb_key_protocol;
+extern const pb_key *pb_key_proxy_addr;
+extern const pb_key *pb_key_proxy_agent;
+extern const pb_key *pb_key_proxy_auth_cert;
+extern const pb_key *pb_key_proxy_authorization;
+extern const pb_key *pb_key_proxy_cipher;
+extern const pb_key *pb_key_proxy_issuer_dn;
+extern const pb_key *pb_key_proxy_jroute;
+extern const pb_key *pb_key_proxy_keysize;
+extern const pb_key *pb_key_proxy_ping;
+extern const pb_key *pb_key_proxy_request;
+extern const pb_key *pb_key_proxy_secret_keysize;
+extern const pb_key *pb_key_proxy_ssl_id;
+extern const pb_key *pb_key_proxy_user_dn;
+extern const pb_key *pb_key_query;
+extern const pb_key *pb_key_QUERY_STRING;
+extern const pb_key *pb_key_QUERY_STRING_UNESCAPED;
+extern const pb_key *pb_key_r2p_cl;
+extern const pb_key *pb_key_r2p_hl;
+extern const pb_key *pb_key_range;
+extern const pb_key *pb_key_referer;
+extern const pb_key *pb_key_reformat_request_headers;
+extern const pb_key *pb_key_remote_status;
+extern const pb_key *pb_key_request_jroute;
+extern const pb_key *pb_key_required_rights;
+extern const pb_key *pb_key_retries;
+extern const pb_key *pb_key_rewrite_content_location;
+extern const pb_key *pb_key_rewrite_host;
+extern const pb_key *pb_key_rewrite_location;
+extern const pb_key *pb_key_rewrite_set_cookie;
+extern const pb_key *pb_key_root;
+extern const pb_key *pb_key_route;
+extern const pb_key *pb_key_route_cookie;
+extern const pb_key *pb_key_route_hdr;
+extern const pb_key *pb_key_route_offline;
+extern const pb_key *pb_key_script_name;
+extern const pb_key *pb_key_secret_keysize;
+extern const pb_key *pb_key_secure;
+extern const pb_key *pb_key_server;
+extern const pb_key *pb_key_set_cookie;
+extern const pb_key *pb_key_socks_addr;
+extern const pb_key *pb_key_ssl_id;
+extern const pb_key *pb_key_ssl_unclean_shutdown;
+extern const pb_key *pb_key_status;
+extern const pb_key *pb_key_sticky_cookie;
+extern const pb_key *pb_key_sticky_param;
+extern const pb_key *pb_key_suppress_request_headers;
+extern const pb_key *pb_key_svr_status;
+extern const pb_key *pb_key_timeout;
+extern const pb_key *pb_key_to;
+extern const pb_key *pb_key_transfer_encoding;
+extern const pb_key *pb_key_transmit_timeout;
+extern const pb_key *pb_key_tunnel_non_http_response;
+extern const pb_key *pb_key_type;
+extern const pb_key *pb_key_upstream_jroute;
+extern const pb_key *pb_key_uri;
+extern const pb_key *pb_key_url;
+extern const pb_key *pb_key_url_prefix;
+extern const pb_key *pb_key_UseOutputStreamSize;
+extern const pb_key *pb_key_user;
+extern const pb_key *pb_key_user_agent;
+extern const pb_key *pb_key_user_dn;
+extern const pb_key *pb_key_validate_server_cert;
+extern const pb_key *pb_key_value;
+extern const pb_key *pb_key_vary;
+extern const pb_key *pb_key_via;
+extern const pb_key *pb_key_warning;
+extern const pb_key *pb_key_depth;
+extern const pb_key *pb_key_if;
+extern const pb_key *pb_key_vfs;
+extern const pb_key *pb_key_dav;
+extern const pb_key *pb_key_vfsclass;
+extern const pb_key *pb_key_davclass;
+
+NSAPI_PUBLIC void pblock_init_default_keys(void);
+
+NSAPI_PUBLIC void pblock_free_default_keys(void);
 
 NSAPI_PUBLIC pool_handle_t *pblock_pool(pblock *pb);
 
@@ -342,14 +346,7 @@
 
 NSAPI_PUBLIC pb_param *pblock_kllinsert(const pb_key *key, int64_t value, pblock *pb);
 
-#ifdef __cplusplus
-inline const pb_key *param_key(pb_param *pp)
-{
-    return *(const pb_key **)(pp + 1); /* XXX see plist_pvt.h */
-}
-#endif
-
-#define PARAM_KEY(pp) *(const pb_key **)(pp + 1) /* new */
+#define PARAM_KEY(pp) *(const pb_key **)((pp) + 1) /* new */
 
 #ifdef	__cplusplus
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/server/util/uri.c	Sat Sep 24 17:11:57 2022 +0200
@@ -0,0 +1,552 @@
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
+ *
+ * THE BSD LICENSE
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this
+ * list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * Neither the name of the  nor the names of its contributors may be
+ * used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
+ * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifdef XP_WIN32
+#define _MBCS
+#include <windows.h>
+#include <mbctype.h>
+#endif
+
+#include "util.h"
+#include "pool.h"
+//include "frame/conf_api.h"
+//include "support/stringvalue.h"
+
+#ifdef XP_WIN32
+static PRBool _getfullpathname = -1;
+#endif /* XP_WIN32 */
+
+/* --------------------------- util_uri_is_evil --------------------------- */
+
+static inline int allow_dbcs_uri()
+{
+    /*
+    static int flagDbcsUri = -1;
+    if (flagDbcsUri == -1) {
+        flagDbcsUri = StringValue::getBoolean(conf_findGlobal("DbcsUri"));
+    }
+    return flagDbcsUri;
+    */
+    return PR_TRUE;
+}
+
+#ifdef XP_WIN32
+void set_fullpathname(PRBool b)
+{
+    _getfullpathname = b;
+}
+#endif  /*XP_WIN32*/
+
+NSAPI_PUBLIC int util_uri_is_evil_internal(const char *t, int allow_tilde, int allow_dot_dir)
+{
+#ifdef XP_WIN32
+    int flagDbcsUri = allow_dbcs_uri();
+#endif // XP_WIN32
+    PRBool flagEmptySegment = PR_FALSE;
+    int x;
+
+    for (x = 0; t[x]; ++x) {
+        if (t[x] == '/') {
+            if (flagEmptySegment)
+                return 1; // "/;a/b"
+#ifdef XP_WIN32
+            if (t[x+1] == '/' && x != 0)
+#else
+            if (t[x+1] == '/')
+#endif
+                return 1;
+            if (t[x+1] == ';')
+                flagEmptySegment = PR_TRUE; // "/;a/b" is evil, "/a/;b" is not
+            if (t[x+1] == '.') {
+                /* "." at end of line is always prohibited */
+                if (t[x+2] == '\0')
+                    return 1;
+
+                /* "." as a path segment is prohibited conditionally */
+                if (!allow_dot_dir && (t[x+2] == '/' || t[x+2] == ';'))
+                    return 1;
+
+                /* ".." as a path segment is always prohibited */
+                if (t[x+2] == '.' && (t[x+3] == '/' || t[x+3] == ';' || t[x+3] == '\0'))
+                    return 1;
+            }
+        }
+#ifdef XP_WIN32
+        // Don't allow '~' in the filename.  On some filesystems a long name
+        // (e.g. longfilename.htm) can be accessed using '~' bypassing any ACL
+        // checks (e.g. longfi~1.htm).
+        if (!allow_tilde && (t[x] == '~')) {
+            return 1;
+        }
+
+        // Do not allow ':' apart from drive letter. Windows filestream
+        // will treat filename::$DATA as a plain file & display content.
+        // So block it to prevent source viewing vulnerability.
+        if ((t[x] == ':') && x > 1) {
+            return 1;
+        }
+
+        // On NT, the directory "abc...." is the same as "abc"
+        // The only cheap way to catch this globally is to disallow
+        // names with the trailing "."s.  Hopefully this is not over
+        // restrictive.
+        // Also trailing spaces in names can wreak havoc on ACL checks
+        // and name resolution.  Therefore, ban them on the end of a
+        // name.
+        if (((t[x] == '.') || (t[x] == ' ')) &&
+            ((t[x+1] == ';') || (t[x+1] == '/') || (t[x+1] == '\0')))
+        {
+            return 1;
+        }
+
+        // Skip past the second byte of two byte DBCS characters.  Bug 353999
+        if (flagDbcsUri && t[x+1] && IsDBCSLeadByte(t[x])) x++;
+#endif // XP_WIN32
+    }
+    return 0;
+}
+
+NSAPI_PUBLIC int util_uri_is_evil(const char *t)
+{
+    return util_uri_is_evil_internal(t, 0, 0);
+}
+
+
+/* -------------------- util_uri_unescape_and_normalize -------------------- */
+
+#ifdef XP_WIN32
+/* The server calls this function to unescape the URI and also normalize
+ * the uri.  Normalizing the uri converts all "\" characters in the URI
+ * and pathinfo portion to "/".  Does not touch "\" in query strings.
+ */
+NSAPI_PUBLIC
+int util_uri_unescape_and_normalize(pool_handle_t *pool, char *s, char *unnormalized)
+{
+    if(!(util_uri_unescape_strict(s)))
+        return 0;
+
+    if (unnormalized) strcpy(unnormalized, s);
+
+    if (_getfullpathname == -1)
+        _getfullpathname = (_getmbcp() != 0);
+
+    /* Get canonical filename Bugid: 4672869 */
+    if(_getfullpathname && strcmp(s, "*") && (*s == '/' ) ) {
+        char *pzAbsPath = NULL;
+        int pathlen = 0;
+        int len = 0;
+        int ret = 0;
+        if(!(pzAbsPath = util_canonicalize_uri(pool, s, strlen(s), NULL))) {
+            //Error canonicalizing; possibly pointing out of docroot
+            return 0;
+        }
+        char *pzPath = (char *)MALLOC(MAX_PATH + 1); /* reserved byte for trailing slash */
+        char *pzFilename = NULL;
+
+        /* If required length of the buffer(pzPath) is more than the allocated one i.e. MAX_PATH(neglecting the reserved byte for trailing slash), return BAD REQUEST. This will happen if length of uri is more than the specified uri length(257) for MBCS windows */
+        if(!(ret = GetFullPathName(pzAbsPath, MAX_PATH, pzPath, &pzFilename)) || ( ret > MAX_PATH)){
+            FREE(pzAbsPath);
+            FREE(pzPath);
+            return 0;
+        }
+        len = strlen(pzAbsPath);
+        pathlen = strlen( pzPath );
+
+        /*  GetFullPathName behaves differently in case of WINNT and WIN2K */
+        /* o/p string doesn't contain the trailing slash in case of WINNT */
+        /* if i/p is /foo/, we get o/p as c:\foo instead of c:\foo\ */
+        /* Checking if i/p has trailing slash and o/p doesn't have, then */
+        /* adding slash */
+        if ( pzAbsPath[len-1] == '/' && pzPath[pathlen-1] != '\\')
+            strcat( pzPath, "\\");
+        FREE(pzAbsPath);
+        pzFilename = strchr(pzPath, '\\');
+        if(!pzFilename) {
+            FREE(pzPath);
+            return 0;
+        }
+        strcpy(s, pzFilename);
+        FREE(pzPath);
+    }
+
+    util_uri_normalize_slashes(s);
+
+    return 1;
+}
+#endif /* XP_WIN32 */
+
+
+/* ---------------------- util_uri_normalize_slashes ---------------------- */
+
+void util_uri_normalize_slashes(char *s)
+{
+#ifdef XP_WIN32
+    int flagDbcsUri = allow_dbcs_uri();
+
+    while (*s) {
+        if (*s == '\\') {
+            // Normalize '\\' to '/'
+            *s = '/';
+        } else if (flagDbcsUri && s[1] && IsDBCSLeadByte(s[0])) {
+            // Skip past two byte DBCS characters.  Bug 353999
+            s++;
+        }
+        s++;
+    }
+#endif
+}
+
+
+/* --------------------------- util_uri_escape ---------------------------- */
+NSAPI_PUBLIC char *util_uri_escape(char *od, const char *s)
+{
+    int flagDbcsUri = allow_dbcs_uri();
+    char *d;
+
+    if (!od)
+        od = (char *) MALLOC((strlen(s)*3) + 1);
+    d = od;
+
+    while (*s) {
+        if (strchr("% ?#:+&*\"'<>\r\n", *s)) {
+            util_sprintf(d, "%%%02x", (unsigned char)*s);
+            ++s; d += 3;
+        }
+#ifdef XP_WIN32
+        else if (flagDbcsUri && s[1] && IsDBCSLeadByte(s[0]))
+#else
+        // Treat any character with the high bit set as a DBCS lead byte
+        else if (flagDbcsUri && s[1] && (s[0] & 0x80))
+#endif
+	{
+            // Escape the second byte of DBCS characters.  The first byte will
+            // have been escaped already.  IE translates all unescaped '\\'s
+            // into '/'.
+            // Bug 353999
+            util_sprintf(d, "%%%02x%%%02x", (unsigned char)s[0], (unsigned char)s[1]);
+            s += 2; d += 6;
+        }
+        else if (0x80 & *s) {
+            util_sprintf(d, "%%%02x", (unsigned char)*s);
+            ++s; d += 3;
+        } else {
+            *d++ = *s++;
+        }
+    }
+    *d = '\0';
+    return od;
+}
+
+
+/* --------------------------- util_url_escape ---------------------------- */
+
+NSAPI_PUBLIC char *util_url_escape(char *od, const char *s)
+{
+    int flagDbcsUri = allow_dbcs_uri();
+    char *d;
+
+    if (!od)
+        od = (char *) MALLOC((strlen(s)*3) + 1);
+    d = od;
+
+    while (*s) {
+        if (strchr("% +*\"'<>\r\n", *s)) {
+            util_sprintf(d, "%%%02x", (unsigned char)*s);
+            ++s; d += 3;
+        }
+#ifdef XP_WIN32
+        else if (flagDbcsUri && s[1] && IsDBCSLeadByte(s[0]))
+#else
+        // Treat any character with the high bit set as a DBCS lead byte
+        else if (flagDbcsUri && s[1] && (s[0] & 0x80))
+#endif
+	{
+            // Escape the second byte of DBCS characters.  The first byte will
+            // have been escaped already.  IE translates all unescaped '\\'s
+            // into '/'.
+            // Bug 353999
+            util_sprintf(d, "%%%02x%%%02x", (unsigned char)s[0], (unsigned char)s[1]);
+            s += 2; d += 6;
+        }
+        else if (0x80 & *s) {
+            util_sprintf(d, "%%%02x", (unsigned char)*s);
+            ++s; d += 3;
+        } else {
+            *d++ = *s++;
+        }
+    }
+    *d = '\0';
+    return od;
+}
+
+
+/* ------------------------- util_uri_strip_params ------------------------- */
+
+NSAPI_PUBLIC char* util_uri_strip_params(char *uri)
+{
+    // As per RFC2396, URI path segments can contain parameters beginning with
+    // ';'.  These parameters must be removed from the ppath.  Bug 418271
+    char* out;
+    if((out = strchr(uri, ';'))) {
+        char* in = out;
+        while (*in) {
+            if (*in == ';') {
+                // Skip past parameter
+                do in++; while (*in && *in != '/');
+            } else {
+                // Copy non-parameter path data
+                *out++ = *in++;
+            }
+        }
+        *out = 0;
+    }
+    return uri;
+}
+
+
+/* ------------------------ util_canonicalize_uri ------------------------- */
+
+/*
+ * rewrite rules:
+ *   //                       ->  '/'
+ *   /./                      ->  '/'
+ *   /.\0                     ->  '/'
+ *   /foo/../                 ->  '/'
+ *   /foo/..\0                ->  '/'
+ *
+ * Allocate a new string, as otherwise replacing in-line would impact the
+ * RequestURI, i.e. original URI in the request.
+ * Some guidelines in: http://www.ietf.org/rfc/rfc2396.txt
+ *      Uniform Resource Identifiers (URI): Generic Syntax
+ */
+NSAPI_PUBLIC char* util_canonicalize_uri(pool_handle_t *pool, const char *uri, int len, int *pcanonlen)
+{
+    PRBool success = PR_TRUE;
+    const char *in_ptr = uri;
+    int in = 0;
+    int in_len = len;
+
+    //PR_ASSERT(uri != NULL); // TODO
+
+    char* canonPath = (char *)pool_malloc(pool, in_len+1);
+    char* out_ptr = canonPath;
+
+    if (!canonPath) {
+        success = PR_FALSE;
+        goto done;
+    }
+
+
+    /* in goes from 0 .. sURIPath.len-1; out_ptr points to
+     * space where next char from input would be copied to
+     */
+    while (in < in_len) {
+
+        /* If the character isn't '/' then copy it out and move on*/
+        if (in_ptr[0] != '/') {
+            *out_ptr++ = *in_ptr++;
+            in++;
+            continue;
+        }
+
+        /* found '/' and reached end of sURIPath, done */
+        if (in+1 >= in_len) {
+            *out_ptr++ = *in_ptr++;
+            in++;
+            break;
+        }
+
+        /* we have '/' and there are more chars in the string */
+        switch(in_ptr[1]) {
+        case '/':
+            /*  '//' => '/'  */
+            in_ptr++;
+            in++;
+            break;
+
+        case '.':
+            /* we have "/." so far */
+            if (in+2 >= in_len) {
+                /*  the string ends after this; basically ignore '.'
+                 *  make sure the ending / is transferred to output.
+                 */
+                *out_ptr++ = *in_ptr++;
+                goto done;
+            }
+
+            /* more chars after "/."; see if it is a '/' */
+            if (in_ptr[2] == '/') {
+                /* in deed, compact "/./" => "/"; */
+                in_ptr += 2;
+                in += 2;
+                break;
+            }
+
+            if (in_ptr[2] != '.') {
+                /* "/.x" where x is not '.'; copy as is */
+                *out_ptr++ = *in_ptr++;
+                in++;
+                break;
+            }
+
+            /* we have "/.." so far. see if we have either string
+             * ending after this or '/' following.
+             */
+            if (in+3 < in_len && in_ptr[3] != '/' && in_ptr[3] != ';') {
+                /* we have "/..x" here; so copy as is */
+                *out_ptr++ = *in_ptr++;
+                in++;
+            }
+            else {
+                /* we have "foo/../" or "foo/.." at the end; */
+                if (out_ptr == canonPath) {
+                    /* oops, we found "/../" pointing out of docroot */
+                    success = PR_FALSE;
+                    goto done;
+                }
+
+                /* remove the previous segment in the output */
+                for (out_ptr--;
+                     out_ptr != canonPath && out_ptr[0] != '/';
+                     out_ptr--); /* Empty Loop */
+
+                /* point to '/' if the last segment ended with .. then
+                 * leave the '/' before the previous segment.
+                 */
+                if(in+3 == in_len)
+                    out_ptr++;
+
+                /* skip the input as well */
+                in_ptr += 3;
+                in += 3;
+            }
+            break;
+
+        default:
+            /* If we already have '/' at out_ptr we donot need to copy */
+            if (out_ptr == canonPath || *(out_ptr-1) != '/')
+                *out_ptr++ = *in_ptr;
+            in_ptr++; in++;
+            break;
+        }
+    }
+
+done:
+
+    if (success) {
+        /* the path looks fine; return the canonicalized form */
+        unsigned canonLen = (unsigned) (out_ptr - canonPath);
+        canonPath[canonLen] = '\0';
+        if (pcanonlen) *pcanonlen = (int) canonLen;
+    } else {
+        /* error canonicalizing */
+        pool_free(pool, canonPath);
+        canonPath = NULL;
+        if (pcanonlen) *pcanonlen = 0;
+    }
+
+    return canonPath;
+}
+
+
+/* ---------------------- util_canonicalize_redirect ---------------------- */
+
+NSAPI_PUBLIC char* util_canonicalize_redirect(pool_handle_t *pool, const char *baseUri, const char *newUri)
+{
+    //PR_ASSERT(baseUri != NULL); // TODO
+
+    if (*newUri == '/')
+        return util_canonicalize_uri(pool, newUri, strlen(newUri), NULL);
+
+    int bLen = strlen(baseUri);
+    if (bLen > 0 && baseUri[bLen - 1] != '/') {
+        while (bLen > 0 && baseUri[bLen - 1] != '/')
+            bLen--;
+    }
+
+    int pLen = strlen(newUri) + bLen + 1; // 1 for slash
+    char *pUri = (char *)pool_malloc(pool, pLen + 1);
+    if (!pUri)
+        return PR_FALSE;
+
+    memcpy(pUri, baseUri, bLen);
+    pUri[bLen] = '/';
+    strcpy(pUri + bLen + 1, newUri);
+
+    char *rval = util_canonicalize_uri(pool, pUri, pLen, NULL);
+    pool_free(pool, pUri);
+
+    return rval;
+}
+
+
+/* ------------------------ util_host_port_suffix ------------------------- */
+
+NSAPI_PUBLIC const char *util_host_port_suffix(const char *h)
+{
+    /* Return a pointer to the colon preceding the port number in a hostname.
+     *
+     * util_host_port_suffix("foo.com:80") = ":80"
+     * util_host_port_suffix("foo.com") = NULL
+     * util_host_port_suffix("[::]:80") = ":80"
+     * util_host_port_suffix("[::]") = NULL
+     */
+
+    if (h == NULL)
+        return h;
+
+    for (;;) {
+        /* Find end of host, beginning of ":port", or an IPv6 address */
+        for (;;) {
+            char c = *h;
+
+            if (c == '\0')
+                return NULL; /* end of host, no port found */
+
+            if (c == '/')
+                return NULL; /* end of host, no port found */
+
+            if (c == ':')
+                return h; /* found port */
+
+            if (c == '[')
+                break; /* skip IPv6 address */
+
+            h++;
+        }
+
+        /* Skip IPv6 address */
+        while (*h != '\0' && *h != ']')
+            h++;
+    }
+}
--- a/src/server/util/uri.cpp	Sat Sep 24 16:26:10 2022 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,559 +0,0 @@
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
- *
- * THE BSD LICENSE
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are met:
- *
- * Redistributions of source code must retain the above copyright notice, this
- * list of conditions and the following disclaimer.
- * Redistributions in binary form must reproduce the above copyright notice,
- * this list of conditions and the following disclaimer in the documentation
- * and/or other materials provided with the distribution.
- *
- * Neither the name of the  nor the names of its contributors may be
- * used to endorse or promote products derived from this software without
- * specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
- * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifdef XP_WIN32
-#define _MBCS
-#include <windows.h>
-#include <mbctype.h>
-#endif
-
-#include "util.h"
-#include "pool.h"
-//include "frame/conf_api.h"
-//include "support/stringvalue.h"
-
-#ifdef XP_WIN32
-static PRBool _getfullpathname = -1;
-#endif /* XP_WIN32 */
-
-/* --------------------------- util_uri_is_evil --------------------------- */
-
-static inline int allow_dbcs_uri()
-{
-    /*
-    static int flagDbcsUri = -1;
-    if (flagDbcsUri == -1) {
-        flagDbcsUri = StringValue::getBoolean(conf_findGlobal("DbcsUri"));
-    }
-    return flagDbcsUri;
-    */
-    return PR_TRUE;
-}
-
-#ifdef XP_WIN32
-void set_fullpathname(PRBool b)
-{
-    _getfullpathname = b;
-}
-#endif  /*XP_WIN32*/
-
-NSAPI_PUBLIC int util_uri_is_evil_internal(const char *t, int allow_tilde, int allow_dot_dir)
-{
-#ifdef XP_WIN32
-    int flagDbcsUri = allow_dbcs_uri();
-#endif // XP_WIN32
-    PRBool flagEmptySegment = PR_FALSE;
-    register int x;
-
-    for (x = 0; t[x]; ++x) {
-        if (t[x] == '/') {
-            if (flagEmptySegment)
-                return 1; // "/;a/b"
-#ifdef XP_WIN32
-            if (t[x+1] == '/' && x != 0)
-#else
-            if (t[x+1] == '/')
-#endif
-                return 1;
-            if (t[x+1] == ';')
-                flagEmptySegment = PR_TRUE; // "/;a/b" is evil, "/a/;b" is not
-            if (t[x+1] == '.') {
-                /* "." at end of line is always prohibited */
-                if (t[x+2] == '\0')
-                    return 1;
-
-                /* "." as a path segment is prohibited conditionally */
-                if (!allow_dot_dir && (t[x+2] == '/' || t[x+2] == ';'))
-                    return 1;
-
-                /* ".." as a path segment is always prohibited */
-                if (t[x+2] == '.' && (t[x+3] == '/' || t[x+3] == ';' || t[x+3] == '\0'))
-                    return 1;
-            }
-        }
-#ifdef XP_WIN32
-        // Don't allow '~' in the filename.  On some filesystems a long name
-        // (e.g. longfilename.htm) can be accessed using '~' bypassing any ACL
-        // checks (e.g. longfi~1.htm).
-        if (!allow_tilde && (t[x] == '~')) {
-            return 1;
-        }
-
-        // Do not allow ':' apart from drive letter. Windows filestream
-        // will treat filename::$DATA as a plain file & display content.
-        // So block it to prevent source viewing vulnerability.
-        if ((t[x] == ':') && x > 1) {
-            return 1;
-        }
-
-        // On NT, the directory "abc...." is the same as "abc"
-        // The only cheap way to catch this globally is to disallow
-        // names with the trailing "."s.  Hopefully this is not over
-        // restrictive.
-        // Also trailing spaces in names can wreak havoc on ACL checks
-        // and name resolution.  Therefore, ban them on the end of a
-        // name.
-        if (((t[x] == '.') || (t[x] == ' ')) &&
-            ((t[x+1] == ';') || (t[x+1] == '/') || (t[x+1] == '\0')))
-        {
-            return 1;
-        }
-
-        // Skip past the second byte of two byte DBCS characters.  Bug 353999
-        if (flagDbcsUri && t[x+1] && IsDBCSLeadByte(t[x])) x++;
-#endif // XP_WIN32
-    }
-    return 0;
-}
-
-NSAPI_PUBLIC int util_uri_is_evil(const char *t)
-{
-    return util_uri_is_evil_internal(t, 0, 0);
-}
-
-
-/* -------------------- util_uri_unescape_and_normalize -------------------- */
-
-#ifdef XP_WIN32
-/* The server calls this function to unescape the URI and also normalize
- * the uri.  Normalizing the uri converts all "\" characters in the URI
- * and pathinfo portion to "/".  Does not touch "\" in query strings.
- */
-NSAPI_PUBLIC
-int util_uri_unescape_and_normalize(pool_handle_t *pool, char *s, char *unnormalized)
-{
-    if(!(util_uri_unescape_strict(s)))
-        return 0;
-
-    if (unnormalized) strcpy(unnormalized, s);
-
-    if (_getfullpathname == -1)
-        _getfullpathname = (_getmbcp() != 0);
-
-    /* Get canonical filename Bugid: 4672869 */
-    if(_getfullpathname && strcmp(s, "*") && (*s == '/' ) ) {
-        char *pzAbsPath = NULL;
-        int pathlen = 0;
-        int len = 0;
-        int ret = 0;
-        if(!(pzAbsPath = util_canonicalize_uri(pool, s, strlen(s), NULL))) {
-            //Error canonicalizing; possibly pointing out of docroot
-            return 0;
-        }
-        char *pzPath = (char *)MALLOC(MAX_PATH + 1); /* reserved byte for trailing slash */
-        char *pzFilename = NULL;
-
-        /* If required length of the buffer(pzPath) is more than the allocated one i.e. MAX_PATH(neglecting the reserved byte for trailing slash), return BAD REQUEST. This will happen if length of uri is more than the specified uri length(257) for MBCS windows */
-        if(!(ret = GetFullPathName(pzAbsPath, MAX_PATH, pzPath, &pzFilename)) || ( ret > MAX_PATH)){
-            FREE(pzAbsPath);
-            FREE(pzPath);
-            return 0;
-        }
-        len = strlen(pzAbsPath);
-        pathlen = strlen( pzPath );
-
-        /*  GetFullPathName behaves differently in case of WINNT and WIN2K */
-        /* o/p string doesn't contain the trailing slash in case of WINNT */
-        /* if i/p is /foo/, we get o/p as c:\foo instead of c:\foo\ */
-        /* Checking if i/p has trailing slash and o/p doesn't have, then */
-        /* adding slash */
-        if ( pzAbsPath[len-1] == '/' && pzPath[pathlen-1] != '\\')
-            strcat( pzPath, "\\");
-        FREE(pzAbsPath);
-        pzFilename = strchr(pzPath, '\\');
-        if(!pzFilename) {
-            FREE(pzPath);
-            return 0;
-        }
-        strcpy(s, pzFilename);
-        FREE(pzPath);
-    }
-
-    util_uri_normalize_slashes(s);
-
-    return 1;
-}
-#endif /* XP_WIN32 */
-
-
-/* ---------------------- util_uri_normalize_slashes ---------------------- */
-
-void util_uri_normalize_slashes(char *s)
-{
-#ifdef XP_WIN32
-    int flagDbcsUri = allow_dbcs_uri();
-
-    while (*s) {
-        if (*s == '\\') {
-            // Normalize '\\' to '/'
-            *s = '/';
-        } else if (flagDbcsUri && s[1] && IsDBCSLeadByte(s[0])) {
-            // Skip past two byte DBCS characters.  Bug 353999
-            s++;
-        }
-        s++;
-    }
-#endif
-}
-
-
-/* --------------------------- util_uri_escape ---------------------------- */
-NSAPI_PUBLIC char *util_uri_escape(char *od, const char *s)
-{
-    int flagDbcsUri = allow_dbcs_uri();
-    char *d;
-
-    if (!od)
-        od = (char *) MALLOC((strlen(s)*3) + 1);
-    d = od;
-
-    while (*s) {
-        if (strchr("% ?#:+&*\"'<>\r\n", *s)) {
-            util_sprintf(d, "%%%02x", (unsigned char)*s);
-            ++s; d += 3;
-        }
-#ifdef XP_WIN32
-        else if (flagDbcsUri && s[1] && IsDBCSLeadByte(s[0]))
-#else
-        // Treat any character with the high bit set as a DBCS lead byte
-        else if (flagDbcsUri && s[1] && (s[0] & 0x80))
-#endif
-	{
-            // Escape the second byte of DBCS characters.  The first byte will
-            // have been escaped already.  IE translates all unescaped '\\'s
-            // into '/'.
-            // Bug 353999
-            util_sprintf(d, "%%%02x%%%02x", (unsigned char)s[0], (unsigned char)s[1]);
-            s += 2; d += 6;
-        }
-        else if (0x80 & *s) {
-            util_sprintf(d, "%%%02x", (unsigned char)*s);
-            ++s; d += 3;
-        } else {
-            *d++ = *s++;
-        }
-    }
-    *d = '\0';
-    return od;
-}
-
-
-/* --------------------------- util_url_escape ---------------------------- */
-
-NSAPI_PUBLIC char *util_url_escape(char *od, const char *s)
-{
-    int flagDbcsUri = allow_dbcs_uri();
-    char *d;
-
-    if (!od)
-        od = (char *) MALLOC((strlen(s)*3) + 1);
-    d = od;
-
-    while (*s) {
-        if (strchr("% +*\"'<>\r\n", *s)) {
-            util_sprintf(d, "%%%02x", (unsigned char)*s);
-            ++s; d += 3;
-        }
-#ifdef XP_WIN32
-        else if (flagDbcsUri && s[1] && IsDBCSLeadByte(s[0]))
-#else
-        // Treat any character with the high bit set as a DBCS lead byte
-        else if (flagDbcsUri && s[1] && (s[0] & 0x80))
-#endif
-	{
-            // Escape the second byte of DBCS characters.  The first byte will
-            // have been escaped already.  IE translates all unescaped '\\'s
-            // into '/'.
-            // Bug 353999
-            util_sprintf(d, "%%%02x%%%02x", (unsigned char)s[0], (unsigned char)s[1]);
-            s += 2; d += 6;
-        }
-        else if (0x80 & *s) {
-            util_sprintf(d, "%%%02x", (unsigned char)*s);
-            ++s; d += 3;
-        } else {
-            *d++ = *s++;
-        }
-    }
-    *d = '\0';
-    return od;
-}
-
-
-/* ------------------------- util_uri_strip_params ------------------------- */
-
-NSAPI_PUBLIC char* util_uri_strip_params(char *uri)
-{
-    // As per RFC2396, URI path segments can contain parameters beginning with
-    // ';'.  These parameters must be removed from the ppath.  Bug 418271
-    char* out;
-    if((out = strchr(uri, ';'))) {
-        char* in = out;
-        while (*in) {
-            if (*in == ';') {
-                // Skip past parameter
-                do in++; while (*in && *in != '/');
-            } else {
-                // Copy non-parameter path data
-                *out++ = *in++;
-            }
-        }
-        *out = 0;
-    }
-    return uri;
-}
-
-
-/* ------------------------ util_canonicalize_uri ------------------------- */
-
-/*
- * rewrite rules:
- *   //                       ->  '/'
- *   /./                      ->  '/'
- *   /.\0                     ->  '/'
- *   /foo/../                 ->  '/'
- *   /foo/..\0                ->  '/'
- *
- * Allocate a new string, as otherwise replacing in-line would impact the
- * RequestURI, i.e. original URI in the request.
- * Some guidelines in: http://www.ietf.org/rfc/rfc2396.txt
- *      Uniform Resource Identifiers (URI): Generic Syntax
- */
-NSAPI_PUBLIC char* util_canonicalize_uri(pool_handle_t *pool, const char *uri, int len, int *pcanonlen)
-{
-    PRBool success = PR_TRUE;
-    const char *in_ptr = uri;
-    int in = 0;
-    int in_len = len;
-
-    //PR_ASSERT(uri != NULL); // TODO
-
-    char* canonPath = (char *)pool_malloc(pool, in_len+1);
-    char* out_ptr = canonPath;
-
-    if (!canonPath) {
-        success = PR_FALSE;
-        goto done;
-    }
-
-
-    /* in goes from 0 .. sURIPath.len-1; out_ptr points to
-     * space where next char from input would be copied to
-     */
-    while (in < in_len) {
-
-        /* If the character isn't '/' then copy it out and move on*/
-        if (in_ptr[0] != '/') {
-            *out_ptr++ = *in_ptr++;
-            in++;
-            continue;
-        }
-
-        /* found '/' and reached end of sURIPath, done */
-        if (in+1 >= in_len) {
-            *out_ptr++ = *in_ptr++;
-            in++;
-            break;
-        }
-
-        /* we have '/' and there are more chars in the string */
-        switch(in_ptr[1]) {
-        case '/':
-            /*  '//' => '/'  */
-            in_ptr++;
-            in++;
-            break;
-
-        case '.':
-            /* we have "/." so far */
-            if (in+2 >= in_len) {
-                /*  the string ends after this; basically ignore '.'
-                 *  make sure the ending / is transferred to output.
-                 */
-                *out_ptr++ = *in_ptr++;
-                goto done;
-            }
-
-            /* more chars after "/."; see if it is a '/' */
-            if (in_ptr[2] == '/') {
-                /* in deed, compact "/./" => "/"; */
-                in_ptr += 2;
-                in += 2;
-                break;
-            }
-
-            if (in_ptr[2] != '.') {
-                /* "/.x" where x is not '.'; copy as is */
-                *out_ptr++ = *in_ptr++;
-                in++;
-                break;
-            }
-
-            /* we have "/.." so far. see if we have either string
-             * ending after this or '/' following.
-             */
-            if (in+3 < in_len && in_ptr[3] != '/' && in_ptr[3] != ';') {
-                /* we have "/..x" here; so copy as is */
-                *out_ptr++ = *in_ptr++;
-                in++;
-            }
-            else {
-                /* we have "foo/../" or "foo/.." at the end; */
-                if (out_ptr == canonPath) {
-                    /* oops, we found "/../" pointing out of docroot */
-                    success = PR_FALSE;
-                    goto done;
-                }
-
-                /* remove the previous segment in the output */
-                for (out_ptr--;
-                     out_ptr != canonPath && out_ptr[0] != '/';
-                     out_ptr--); /* Empty Loop */
-
-                /* point to '/' if the last segment ended with .. then
-                 * leave the '/' before the previous segment.
-                 */
-                if(in+3 == in_len)
-                    out_ptr++;
-
-                /* skip the input as well */
-                in_ptr += 3;
-                in += 3;
-            }
-            break;
-
-        default:
-            /* If we already have '/' at out_ptr we donot need to copy */
-            if (out_ptr == canonPath || *(out_ptr-1) != '/')
-                *out_ptr++ = *in_ptr;
-            in_ptr++; in++;
-            break;
-        }
-    }
-
-done:
-    int canonLen = 0;
-
-    if (success) {
-        /* the path looks fine; return the canonicalized form */
-        canonLen = out_ptr - canonPath;
-        canonPath[canonLen] = '\0';
-    } else {
-        /* error canonicalizing */
-        pool_free(pool, canonPath);
-        canonPath = NULL;
-    }
-
-    if (pcanonlen)
-        *pcanonlen = canonLen;
-
-    return canonPath;
-}
-
-
-/* ---------------------- util_canonicalize_redirect ---------------------- */
-
-NSAPI_PUBLIC char* util_canonicalize_redirect(pool_handle_t *pool, const char *baseUri, const char *newUri)
-{
-    //PR_ASSERT(baseUri != NULL); // TODO
-
-    if (*newUri == '/')
-        return util_canonicalize_uri(pool, newUri, strlen(newUri), NULL);
-
-    int bLen = strlen(baseUri);
-    if (bLen > 0 && baseUri[bLen - 1] != '/') {
-        while (bLen > 0 && baseUri[bLen - 1] != '/')
-            bLen--;
-    }
-
-    int pLen = strlen(newUri) + bLen + 1; // 1 for slash
-    char *pUri = (char *)pool_malloc(pool, pLen + 1);
-    if (!pUri)
-        return PR_FALSE;
-
-    memcpy(pUri, baseUri, bLen);
-    pUri[bLen] = '/';
-    strcpy(pUri + bLen + 1, newUri);
-
-    char *rval = util_canonicalize_uri(pool, pUri, pLen, NULL);
-    pool_free(pool, pUri);
-
-    return rval;
-}
-
-
-/* ------------------------ util_host_port_suffix ------------------------- */
-
-NSAPI_PUBLIC char *util_host_port_suffix(char *h)
-{
-    return (char *)util_host_port_suffix((const char *)h);
-}
-
-const char *util_host_port_suffix(const char *h)
-{
-    /* Return a pointer to the colon preceding the port number in a hostname.
-     *
-     * util_host_port_suffix("foo.com:80") = ":80"
-     * util_host_port_suffix("foo.com") = NULL
-     * util_host_port_suffix("[::]:80") = ":80"
-     * util_host_port_suffix("[::]") = NULL
-     */
-
-    if (h == NULL)
-        return h;
-
-    for (;;) {
-        /* Find end of host, beginning of ":port", or an IPv6 address */
-        for (;;) {
-            register char c = *h;
-
-            if (c == '\0')
-                return NULL; /* end of host, no port found */
-
-            if (c == '/')
-                return NULL; /* end of host, no port found */
-
-            if (c == ':')
-                return h; /* found port */
-
-            if (c == '[')
-                break; /* skip IPv6 address */
-
-            h++;
-        }
-
-        /* Skip IPv6 address */
-        while (*h != '\0' && *h != ']')
-            h++;
-    }
-}
--- a/src/server/util/util.h	Sat Sep 24 16:26:10 2022 +0200
+++ b/src/server/util/util.h	Sat Sep 24 17:11:57 2022 +0200
@@ -291,8 +291,6 @@
 
 #ifdef __cplusplus
 
-NSAPI_PUBLIC char *util_host_port_suffix(char *h);
-
 NSAPI_PUBLIC const char *util_host_port_suffix(const char *h);
 
 #endif

mercurial