<someurl>?field1=value1&field2=value2 into [(field1, value1), (field2, value2)].The semantics of query strings don't seem to be very well defined. Where there could be ambiguities, I have looked at what Perl CGI.pm does and implemented that.
I've added a fairly comprehensive test suite for the code. With the patch we pass the old and new tests.
The current uri->query field is always unescaped during parsing. I have changed so it always stored in its raw form. This because otherwise it's impossible to parse query strings such as: file:///tmp/test.html?test=%26&second=%26 which can be generated by web browsers. If anyone was relying on the current semantics, then it seems to me that they cannot parse such query strings correctly.
Rich. -- Emerging Technologies, Red Hat http://et.redhat.com/~rjones/ 64 Baker Street, London, W1U 7DF Mobile: +44 7866 314 421 Registered Address: Red Hat UK Ltd, Amberley Place, 107-111 Peascod Street, Windsor, Berkshire, SL4 1TE, United Kingdom. Registered in England and Wales under Company Registration No. 3798903 Directors: Michael Cunningham (USA), Charlie Peters (USA) and David Owens (Ireland)
Index: testURIQuery.c =================================================================== --- testURIQuery.c (revision 0) +++ testURIQuery.c (revision 0) @@ -0,0 +1,157 @@ +/* + * testURIQuery.c : test the xmlURIQuery* functions. + * + * See Copyright for the status of this software. + * + * Author: Richard W.M. Jones <rjones redhat com> + */ + +#include <stdio.h> +#include <string.h> + +#include "libxml.h" + +#include <libxml/xmlmemory.h> +#include <libxml/uri.h> +#include <libxml/globals.h> + +/* This code reads in the list of URLs, one per line, from stdin. + * For each one it writes out several variations which exercise + * all the xmlURIQuery* functions. + */ +int +main (void) +{ + const char *query; + char line[1024], *str = NULL; + xmlURIPtr uri = NULL; + xmlURIQueryFieldsPtr fields = NULL, field; + int errors = 0; + int b, len; + + while (fgets (line, sizeof line, stdin)) { + /* Strip trailing \n. */ + len = xmlStrlen (BAD_CAST line); + if (len > 0 && line[len-1] == '\n') + line[len-1] = '\0'; + + /* Ignore lines which begin with '#' and blank lines. */ + if (line[0] == '\0' || line[0] == '#') + continue; + + /* Parse the URI. */ + uri = xmlParseURI (line); + if (!uri) { + printf ("testURIQuery: xmlParseURI: %s: failed\n", line); + errors++; + goto next; + } + + printf ("%s\n", line); + query = uri->query; + printf ("\tquery string = %s\n", query ? query : "NULL"); + + /* Parse the query string and write out the list of fields. */ + if (xmlURIQueryParse (query, NULL, &fields) != 0) { + printf ("testURIQuery: xmlURIQueryParse: failed\n"); + errors++; + goto next; + } + for (field = fields; field; field = field->next) { + printf ("\tname = %s\n\tvalue = %s\n", + field->name ? field->name : "NULL", + field->value ? field->value : "NULL"); + if (field->ignore) + printf ("testURIQuery: field->ignore should be 0\n"); + } + + /* Recreate query string with all fields. */ + if (xmlURIQueryCreate (fields, NULL, &str) != 0) { + printf ("testURIQuery: xmlURIQueryCreate: failed\n"); + errors++; + goto next; + } + printf ("\treassembled query = %s\n", str ? str : "NULL"); + if (str) xmlFree (str); + str = NULL; + + /* Mark some of the fields to be ignored and reassemble. */ + for (field = fields; field; field = field->next) { + if (xmlStrncasecmp (BAD_CAST field->name, BAD_CAST "del", 3) == 0) + field->ignore = 1; + } + if (xmlURIQueryCreate (fields, NULL, &str) != 0) { + printf ("testURIQuery: xmlURIQueryCreate: failed\n"); + errors++; + goto next; + } + printf ("\treassembled query - del* = %s\n", str ? str : "NULL"); + if (str) xmlFree (str); + str = NULL; + + xmlFreeURIQueryFields (fields); + fields = NULL; + + /* Try the high-level Exists function on the original URI. */ + if (xmlURIQueryExists (query, "check", &b) != 0) { + printf ("testURIQuery: xmlURIQueryExists: failed\n"); + errors++; + goto next; + } + printf ("\tcheck field exists = %s\n", b ? "true" : "false"); + + /* Try the high-level IsTrue function on the original URI. */ + if (xmlURIQueryIsTrue (query, "check", &b) != 0) { + printf ("testURIQuery: xmlURIQueryIsTrue: failed\n"); + errors++; + goto next; + } + printf ("\tcheck field is true = %s\n", b ? "true" : "false"); + + /* Try the high-level GetSingle function on the original URI. */ + if (xmlURIQueryGetSingle (query, "check", &str) != 0) { + printf ("testURIQuery: xmlURIQueryGetSingle: failed\n"); + errors++; + goto next; + } + printf ("\tcheck field = %s\n", str ? str : "not present"); + if (str) xmlFree (str); + str = NULL; + + /* Try the high-level GetMultiple function on the original URI. */ + if (xmlURIQueryGetMultiple (query, "check", &fields) != 0) { + printf ("testURIQuery: xmlURIQueryGetMultiple: failed\n"); + errors++; + goto next; + } + for (field = fields; field; field = field->next) { + printf ("\t\tcheck field name = %s\n\t\tvalue = %s\n", + field->name ? field->name : "NULL", + field->value ? field->value : "NULL"); + if (field->ignore) + printf ("testURIQuery: field->ignore should be 0\n"); + } + xmlFreeURIQueryFields (fields); + fields = NULL; + + /* Try the high-level Remove function on the original URI. */ + if (xmlURIQueryRemove (query, "remove", &str) != 0) { + printf ("testURIQuery: xmlURIQueryRemove: failed\n"); + errors++; + goto next; + } + printf ("\treassembled query - remove = %s\n", str ? str : "NULL"); + if (str) xmlFree (str); + str = NULL; + + next: + if (str) xmlFree (str); + if (fields) xmlFreeURIQueryFields (fields); + if (uri) xmlFreeURI (uri); + + fflush (stdout); + } + + xmlMemoryDump(); + return errors ? 1 : 0; +} Index: uri.c =================================================================== --- uri.c (revision 3604) +++ uri.c (working copy) @@ -17,6 +17,7 @@ #include <libxml/uri.h> #include <libxml/globals.h> #include <libxml/xmlerror.h> +#include <libxml/tree.h> /************************************************************************ * * @@ -1031,12 +1032,11 @@ } if (uri->query) { - segment = - xmlURIEscapeStr(BAD_CAST uri->query, BAD_CAST ";/?:@&=+,$"); - NULLCHK(segment) + /* Assume the query has already been escaped. This is the only + * sensible way to deal with queries like: first=%26&second=%26 + */ ret = xmlStrcat(ret, BAD_CAST "?"); - ret = xmlStrcat(ret, segment); - xmlFree(segment); + ret = xmlStrcat(ret, BAD_CAST uri->query); } if (uri->opaque) { @@ -1129,10 +1129,10 @@ if (uri != NULL) { if (uri->query != NULL) xmlFree(uri->query); - if (uri->cleanup & 2) - uri->query = STRNDUP(*str, cur - *str); - else - uri->query = xmlURIUnescapeString(*str, cur - *str, NULL); + /* Do not attempt to unescape the query. See xmlURIQuery* + * functions instead. + */ + uri->query = STRNDUP(*str, cur - *str); } *str = cur; return (0); @@ -2510,5 +2510,507 @@ xmlFree(cal); return(ret); } + +/************************************************************************ + * * + * Low-level parse and create functions for query strings * + * * + ************************************************************************/ + +/** + * xmlURIQueryCreate: + * @fields: Linked list of fields + * @separator: Separator, if NULL uses the default ("&") + * @query_out: The returned query string. + * + * This function concatenates the linked list of (field name, field value) + * pairs into a query string. + * + * If any field has the 'ignore' field set, it is ignored and not + * concatenated into the query string. + * + * If a field with the same name appears more than once, then it will + * appear multiple times in the query string. Web browsers generate + * such query strings, and query string parsers handle them in + * various ways. (See xmlURIQueryGetSingle and xmlURIQueryGetMultiple). + * + * The field name and value are URI-escaped properly before being + * added to the query. + * + * The returned query string should be freed by the caller. If + * fields is NULL then query_out will be set to NULL. + * + * Returns 0 if successful or an error code. + */ +int +xmlURIQueryCreate (xmlURIQueryFieldsPtr fields, + const char *separator, + char **query_out) +{ + /* List of characters which are safe inside names or values, + * apart from '@', IS_MARK and IS_ALPHANUM. Best to escape + * as much as possible. Certainly '=', '&' and '#' must NEVER + * be added to this list. + */ + static const xmlChar *special_chars = BAD_CAST ""; + + int append_sep = 0, sep_len; + xmlBufferPtr buf; + xmlChar *str; + int rv; + + if (query_out) *query_out = NULL; + if (!fields) return 0; + + if (separator == NULL) { + separator = "&"; + sep_len = 1; + } else + sep_len = xmlStrlen (BAD_CAST separator); + + buf = xmlBufferCreate (); + if (!buf) return -1; + + rv = 0; + while (fields) { + if (!fields->ignore) { + if (append_sep) { + rv = xmlBufferAdd (buf, BAD_CAST separator, sep_len); + if (rv != 0) goto error; + } + append_sep = 1; + + str = xmlURIEscapeStr (BAD_CAST fields->name, special_chars); + if (!str) { rv = XML_ERR_NO_MEMORY; goto error; } + rv = xmlBufferAdd (buf, str, xmlStrlen (str)); + xmlFree (str); + if (rv != 0) goto error; + + rv = xmlBufferAdd (buf, BAD_CAST "=", 1); + if (rv != 0) goto error; + str = xmlURIEscapeStr (BAD_CAST fields->value, special_chars); + if (!str) { rv = XML_ERR_NO_MEMORY; goto error; } + rv = xmlBufferAdd (buf, str, xmlStrlen (str)); + xmlFree (str); + if (rv != 0) goto error; + } + + fields = fields->next; + } + + if (query_out && buf->content) { + *query_out = (char *) xmlStrdup (buf->content); + if (!*query_out) { + rv = XML_ERR_NO_MEMORY; + goto error; + } + } + + error: + if (buf) + xmlBufferFree (buf); + return rv; +} + +/** + * xmlURIQueryParse: + * @query: Query string to parse. + * @separator: Separator, if NULL uses the default ("&") + * @fields_out: Returned linked list of fields, or NULL if query is empty. + * + * This function parses the query string and returns a list of + * (field name, field value) pairs of fields found in the query + * string. + * + * Field names are not unique, and for a given query string this + * function may return the same name several times + * (eg. "name=val1&name=val2"). Web browsers generate such query + * strings. + * + * The returned list should be freed by the caller (see + * xmlFreeURIQueryFields). If the query string passed in is + * NULL or an empty string, then fields_out will be set to NULL. + * + * The field name and value are URI-unescaped properly when parsed + * out of the query. If the value is missing, it is set to "". + * If the name is missing then the field is ignored. This behaviour + * is consistent with Perl's CGI.pm. + * + * The ignore flags are set to 0 (see xmlURIQueryCreate). + * + * Returns 0 if successful or an error code. + */ +int +xmlURIQueryParse (const char *query_, + const char *separator, + xmlURIQueryFieldsPtr *fields_out) +{ + xmlURIQueryFieldsPtr fields, field, *prev; + int sep_len; + const xmlChar *query = BAD_CAST query_, *end, *eq; + char *name, *value; + + if (fields_out) *fields_out = NULL; + if (!query || query[0] == '\0') return 0; + + if (separator == NULL) { + separator = "&"; + sep_len = 1; + } else + sep_len = xmlStrlen (BAD_CAST separator); + + fields = NULL; + prev = &fields; + + while (*query) { + /* Find the next separator, or end of the string. */ + end = xmlStrstr (query, BAD_CAST separator); + if (!end) end = query + xmlStrlen (query); + + /* Find the first '=' character between here and end. */ + eq = xmlStrchr (query, '='); + if (eq && eq >= end) eq = NULL; + + /* Empty section (eg. "?&"). */ + if (end == query) + goto next; + /* If there is no '=' character, then we have just "name" + * and consistent with CGI.pm we assume value is "". + */ + else if (!eq) { + name = xmlURIUnescapeString ((const char *) query, + end - query, NULL); + value = (char *) xmlStrdup (BAD_CAST ""); + if (!name || !value) goto out_of_memory; + } + /* Or if we have "name=" here (works around annoying + * problem when calling xmlURIUnescapeString with len = 0). + */ + else if (eq+1 == end) { + name = xmlURIUnescapeString ((const char *) query, + eq - query, NULL); + value = (char *) xmlStrdup (BAD_CAST ""); + if (!name || !value) goto out_of_memory; + } + /* If the '=' character is at the beginning then we have + * "=value" and consistent with CGI.pm we _ignore_ this. + */ + else if (query == eq) + goto next; + /* Otherwise it's "name=value". */ + else { + name = xmlURIUnescapeString ((const char *) query, + eq - query, NULL); + value = xmlURIUnescapeString ((const char *) eq+1, + end - (eq+1), NULL); + if (!name || !value) goto out_of_memory; + } + + /* Allocate this field and append to the list. */ + field = xmlMalloc (sizeof *field); + if (!field) goto out_of_memory; + field->next = NULL; + field->name = name; + field->value = value; + field->ignore = 0; + *prev = field; + prev = &field->next; + + next: + query = end; + if (*query) query += sep_len; /* skip separator */ + } + + if (fields_out) *fields_out = fields; + return 0; + + out_of_memory: + xmlFreeURIQueryFields (fields); + return XML_ERR_NO_MEMORY; +} + +/** + * xmlFreeURIQueryFields: + * @fields: Linked list of fields + * + * This function frees the linked list of fields, and all strings + * contained within. + * + * If fields is NULL then this function does nothing. + */ +void +xmlFreeURIQueryFields (xmlURIQueryFieldsPtr fields) +{ + xmlURIQueryFieldsPtr t; + + while (fields) { + if (fields->name) xmlFree (fields->name); + if (fields->value) xmlFree (fields->value); + t = fields; + fields = fields->next; + xmlFree (t); + } +} + +/************************************************************************ + * * + * High-level convenience operations for query strings * + * * + ************************************************************************/ + +/* NB. These functions generally parse the whole string each time + * they are called, so they are useful for occasional use, or code + * where you don't particularly care about raw speed. Otherwise you + * should use the low-level parse function above and work on the + * xmlURIQueryFields structure directly. + */ + +/** + * xmlURIQueryExists: + * @query: The query string (from uri->query) + * @name: The field name (unescaped) + * @bool_out: Boolean returned + * + * Sets bool_out to true if and only if the field name appears in the + * query string with any value (including an empty value). + * + * See also xmlURIQueryIsTrue. + * + * Notes: + * (1) this function parses the query string each time it is called. + * (2) field name comparisons are case-insensitive. + * + * Returns 0 if successful, or an error code. + */ +int +xmlURIQueryExists (const char *query, + const char *name, + int *bool_out) +{ + xmlURIQueryFieldsPtr fields, field; + int rv; + + if (bool_out) *bool_out = 0; + + rv = xmlURIQueryParse (query, NULL, &fields); + if (rv != 0) return rv; + + for (field = fields; field; field = field->next) { + if (xmlStrcasecmp (BAD_CAST field->name, BAD_CAST name) == 0) { + if (bool_out) *bool_out = 1; + break; + } + } + + xmlFreeURIQueryFields (fields); + + return 0; +} + +/** + * xmlURIQueryIsTrue: + * @query: The query string (from uri->query) + * @name: The field name (unescaped) + * @bool_out: Boolean returned + * + * Sets bool_out to true if and only if the field name appears in the + * query string with a "non-false" value. A false value means + * a value which is empty or "0". Thus this function will return + * false for "..&name=&.." or "..&name=0&..", but will return true + * for "..&name=1&.." or "..&name=foo&..". + * + * If the name appears multiple times, then we check if any has a + * non-false value. + * + * (This is the same convention for truthfulness as used in Perl's + * CGI.pm). + * + * See also xmlURIQueryExists. + * + * Notes: + * (1) this function parses the query string each time it is called. + * (2) field name comparisons are case-insensitive. + * + * Returns 0 if successful, or an error code. + */ +static inline int +is_false (const char *value) +{ + return value[0] == '\0' || (value[0] == '0' && value[1] == '\0'); +} + +int +xmlURIQueryIsTrue (const char *query, + const char *name, + int *bool_out) +{ + xmlURIQueryFieldsPtr fields, field; + int rv; + + if (bool_out) *bool_out = 0; + + rv = xmlURIQueryParse (query, NULL, &fields); + if (rv != 0) return rv; + + for (field = fields; field; field = field->next) { + if (xmlStrcasecmp (BAD_CAST field->name, BAD_CAST name) == 0 && + !is_false (field->value)) { + if (bool_out) *bool_out = 1; + break; + } + } + + xmlFreeURIQueryFields (fields); + + return 0; +} + +/** + * xmlURIQueryGetSingle: + * @query: The query string (from uri->query) + * @name: The field name (unescaped) + * @value_out: Value returned (if found) or set to NULL. + * + * Gets the value of the named field from the query string, unescaped. + * The returned value must be freed by the caller. + * + * If the named field cannot be found, sets value_out to NULL. + * + * If the named field appears more than once, the first value is + * the one returned. (See also xmlURIQueryGetMultiple). + * + * Notes: + * (1) this function parses the query string each time it is called. + * (2) field name comparisons are case-insensitive. + * + * Returns 0 if successful, or an error code. + */ +int +xmlURIQueryGetSingle (const char *query, + const char *name, + char **value_out) +{ + xmlURIQueryFieldsPtr fields, field; + int rv; + + if (value_out) *value_out = NULL; + + rv = xmlURIQueryParse (query, NULL, &fields); + if (rv != 0) return rv; + + rv = 0; + for (field = fields; field; field = field->next) { + if (xmlStrcasecmp (BAD_CAST field->name, BAD_CAST name) == 0) { + if (value_out) { + *value_out = (char *) xmlStrdup (BAD_CAST field->value); + if (!*value_out) rv = XML_ERR_NO_MEMORY; + } + break; + } + } + + xmlFreeURIQueryFields (fields); + + return rv; +} + +/** + * xmlURIQueryGetMultiple: + * @query: The query string (from uri->query) + * @name: The field name (unescaped) + * @fields_out: The fields with the given name (or NULL if no fields). + * + * Gets the value(s) of the named field from the query string, unescaped. + * The returned value must be freed by the caller by calling + * xmlFreeURIQueryFields. + * + * If the named field cannot be found, sets fields_out to NULL. + * + * Notes: + * (1) this function parses the query string each time it is called. + * (2) field name comparisons are case-insensitive. + * + * Returns 0 if successful, or an error code. + */ +int +xmlURIQueryGetMultiple (const char *query, + const char *name, + xmlURIQueryFieldsPtr *fields_out) +{ + xmlURIQueryFieldsPtr fields, field, *prev; + int rv; + + if (fields_out) *fields_out = NULL; + + rv = xmlURIQueryParse (query, NULL, &fields); + if (rv != 0) return rv; + + prev = &fields; + field = fields; + while (field) { + if (xmlStrcasecmp (BAD_CAST field->name, BAD_CAST name) == 0) { + /* Keep this field in the linked list. */ + prev = &field->next; + field = field->next; + } else { + /* We're going to remove and free the current field (field). + * '*prev' is the pointer to the current field from the previous, + * and field->next points to the next one. + */ + *prev = field->next; + field->next = NULL; + xmlFreeURIQueryFields (field); + field = *prev; + } + } + + if (fields_out) *fields_out = fields; + + return 0; +} + +/** + * xmlURIQueryRemove: + * @query: The query string (from uri->query) + * @name: The field name (unescaped) + * @query_out: The returned query string. + * + * This function removes all fields named name from the query + * string, constructing a new query string and returning it in + * query_out. + * + * query_out must be freed by the caller. + * + * Notes: + * (1) this function parses the query string each time it is called. + * (2) field name comparisons are case-insensitive. + * + * Returns 0 if successful, or an error code. + */ +int +xmlURIQueryRemove (const char *query, + const char *name, + char **query_out) +{ + xmlURIQueryFieldsPtr fields, field; + int rv; + + if (query_out) *query_out = NULL; + + rv = xmlURIQueryParse (query, NULL, &fields); + if (rv != 0) return rv; + + for (field = fields; field; field = field->next) { + if (xmlStrcasecmp (BAD_CAST field->name, BAD_CAST name) == 0) + field->ignore = 1; + } + + rv = xmlURIQueryCreate (fields, NULL, query_out); + + xmlFreeURIQueryFields (fields); + return rv; +} + + #define bottom_uri #include "elfgcchack.h" Index: include/libxml/uri.h =================================================================== --- include/libxml/uri.h (revision 3604) +++ include/libxml/uri.h (working copy) @@ -83,6 +83,60 @@ XMLPUBFUN xmlChar* XMLCALL xmlPathToURI (const xmlChar *path); +/** + * xmlURIQueryFields: + * + * A query string parsed into a linked list of (field name, field value) pairs. + * + * The name and value strings are stored here without %-escaping. In + * the final query string they may be escaped if necessary. + * + * The ignore field is useful when parsing a query string, removing + * some fields, and leaving the rest. xmlURIQueryParse always sets + * this to zero. xmlURIQueryCreate checks this, and if it is non-zero + * it will ignore that field when constructing the query string. + */ +typedef struct _xmlURIQueryFields xmlURIQueryFields; +typedef xmlURIQueryFields *xmlURIQueryFieldsPtr; +struct _xmlURIQueryFields { + xmlURIQueryFieldsPtr next; /* Linked list chain. */ + char *name; /* Field name (unescaped). */ + char *value; /* Field value (unescaped). */ + int ignore; /* Ignore field in xmlURIQueryCreate. */ +}; + +XMLPUBFUN int XMLCALL + xmlURIQueryParse (const char *query, + const char *separator, + xmlURIQueryFieldsPtr *fields_out); +XMLPUBFUN int XMLCALL + xmlURIQueryCreate (const xmlURIQueryFieldsPtr fields, + const char *separator, + char **query_out); +XMLPUBFUN void XMLCALL + xmlFreeURIQueryFields (xmlURIQueryFieldsPtr fields); + +XMLPUBFUN int XMLCALL + xmlURIQueryExists (const char *query, + const char *name, + int *bool_out); +XMLPUBFUN int XMLCALL + xmlURIQueryIsTrue (const char *query, + const char *name, + int *bool_out); +XMLPUBFUN int XMLCALL + xmlURIQueryGetSingle (const char *query, + const char *name, + char **value_out); +XMLPUBFUN int XMLCALL + xmlURIQueryGetMultiple (const char *query, + const char *name, + xmlURIQueryFieldsPtr *fields_out); +XMLPUBFUN int XMLCALL + xmlURIQueryRemove (const char *query, + const char *name, + char **query_out); + #ifdef __cplusplus } #endif Index: result/URIQuery/test1.data =================================================================== --- result/URIQuery/test1.data (revision 0) +++ result/URIQuery/test1.data (revision 0) @@ -0,0 +1,1524 @@ +/ + query string = NULL + reassembled query = NULL + reassembled query - del* = NULL + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = NULL +/? + query string = + reassembled query = NULL + reassembled query - del* = NULL + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = NULL +/?field1=value1 + query string = field1=value1 + name = field1 + value = value1 + reassembled query = field1=value1 + reassembled query - del* = field1=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1 +/?field1=value1&field2=value2 + query string = field1=value1&field2=value2 + name = field1 + value = value1 + name = field2 + value = value2 + reassembled query = field1=value1&field2=value2 + reassembled query - del* = field1=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2 +/?field1=value1&field2=value2&field3=value3 + query string = field1=value1&field2=value2&field3=value3 + name = field1 + value = value1 + name = field2 + value = value2 + name = field3 + value = value3 + reassembled query = field1=value1&field2=value2&field3=value3 + reassembled query - del* = field1=value1&field2=value2&field3=value3 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2&field3=value3 +/?field1=value1&field2=value2&field3=value3&field4=value4 + query string = field1=value1&field2=value2&field3=value3&field4=value4 + name = field1 + value = value1 + name = field2 + value = value2 + name = field3 + value = value3 + name = field4 + value = value4 + reassembled query = field1=value1&field2=value2&field3=value3&field4=value4 + reassembled query - del* = field1=value1&field2=value2&field3=value3&field4=value4 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2&field3=value3&field4=value4 +/?field1= + query string = field1= + name = field1 + value = + reassembled query = field1= + reassembled query - del* = field1= + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1= +/?=value1 + query string = =value1 + reassembled query = NULL + reassembled query - del* = NULL + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = NULL +/?field1=&field2=value2 + query string = field1=&field2=value2 + name = field1 + value = + name = field2 + value = value2 + reassembled query = field1=&field2=value2 + reassembled query - del* = field1=&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=&field2=value2 +/?=value1&field2=value2 + query string = =value1&field2=value2 + name = field2 + value = value2 + reassembled query = field2=value2 + reassembled query - del* = field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field2=value2 +/?field1=value1&field2= + query string = field1=value1&field2= + name = field1 + value = value1 + name = field2 + value = + reassembled query = field1=value1&field2= + reassembled query - del* = field1=value1&field2= + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2= +/?field1=value1&=value2 + query string = field1=value1&=value2 + name = field1 + value = value1 + reassembled query = field1=value1 + reassembled query - del* = field1=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1 +/?field1=value1&field2=&field3=value3 + query string = field1=value1&field2=&field3=value3 + name = field1 + value = value1 + name = field2 + value = + name = field3 + value = value3 + reassembled query = field1=value1&field2=&field3=value3 + reassembled query - del* = field1=value1&field2=&field3=value3 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=&field3=value3 +/?field1=value1&=value2&field3=value3 + query string = field1=value1&=value2&field3=value3 + name = field1 + value = value1 + name = field3 + value = value3 + reassembled query = field1=value1&field3=value3 + reassembled query - del* = field1=value1&field3=value3 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field3=value3 +/?& + query string = & + reassembled query = NULL + reassembled query - del* = NULL + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = NULL +/?&& + query string = && + reassembled query = NULL + reassembled query - del* = NULL + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = NULL +/?&&& + query string = &&& + reassembled query = NULL + reassembled query - del* = NULL + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = NULL +/?field1=value1&&field2=value2 + query string = field1=value1&&field2=value2 + name = field1 + value = value1 + name = field2 + value = value2 + reassembled query = field1=value1&field2=value2 + reassembled query - del* = field1=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2 +/?&field1=value1&field2=value2 + query string = &field1=value1&field2=value2 + name = field1 + value = value1 + name = field2 + value = value2 + reassembled query = field1=value1&field2=value2 + reassembled query - del* = field1=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2 +/?&&field1=value1&field2=value2 + query string = &&field1=value1&field2=value2 + name = field1 + value = value1 + name = field2 + value = value2 + reassembled query = field1=value1&field2=value2 + reassembled query - del* = field1=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2 +/?field1=value1&field2=value2& + query string = field1=value1&field2=value2& + name = field1 + value = value1 + name = field2 + value = value2 + reassembled query = field1=value1&field2=value2 + reassembled query - del* = field1=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2 +/?field1=value1&field2=value2&& + query string = field1=value1&field2=value2&& + name = field1 + value = value1 + name = field2 + value = value2 + reassembled query = field1=value1&field2=value2 + reassembled query - del* = field1=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field2=value2 +/?field1=value1&delme=value2&field3=value3 + query string = field1=value1&delme=value2&field3=value3 + name = field1 + value = value1 + name = delme + value = value2 + name = field3 + value = value3 + reassembled query = field1=value1&delme=value2&field3=value3 + reassembled query - del* = field1=value1&field3=value3 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&delme=value2&field3=value3 +/?del=delete + query string = del=delete + name = del + value = delete + reassembled query = del=delete + reassembled query - del* = + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = del=delete +/?field1=del + query string = field1=del + name = field1 + value = del + reassembled query = field1=del + reassembled query - del* = field1=del + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=del +/?del1=value1&del2=value2&del3=value3 + query string = del1=value1&del2=value2&del3=value3 + name = del1 + value = value1 + name = del2 + value = value2 + name = del3 + value = value3 + reassembled query = del1=value1&del2=value2&del3=value3 + reassembled query - del* = + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = del1=value1&del2=value2&del3=value3 +/?field1=value1&del2=value2 + query string = field1=value1&del2=value2 + name = field1 + value = value1 + name = del2 + value = value2 + reassembled query = field1=value1&del2=value2 + reassembled query - del* = field1=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&del2=value2 +/?del1=value1&field2=value2 + query string = del1=value1&field2=value2 + name = del1 + value = value1 + name = field2 + value = value2 + reassembled query = del1=value1&field2=value2 + reassembled query - del* = field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = del1=value1&field2=value2 +/?field1=value1&del2=value2&del3=value3&del4=value4 + query string = field1=value1&del2=value2&del3=value3&del4=value4 + name = field1 + value = value1 + name = del2 + value = value2 + name = del3 + value = value3 + name = del4 + value = value4 + reassembled query = field1=value1&del2=value2&del3=value3&del4=value4 + reassembled query - del* = field1=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&del2=value2&del3=value3&del4=value4 +/?del1=value1&del2=value2&del3=value3&field4=value4 + query string = del1=value1&del2=value2&del3=value3&field4=value4 + name = del1 + value = value1 + name = del2 + value = value2 + name = del3 + value = value3 + name = field4 + value = value4 + reassembled query = del1=value1&del2=value2&del3=value3&field4=value4 + reassembled query - del* = field4=value4 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = del1=value1&del2=value2&del3=value3&field4=value4 +/?field1=value1&remove=value2&field3=value3 + query string = field1=value1&remove=value2&field3=value3 + name = field1 + value = value1 + name = remove + value = value2 + name = field3 + value = value3 + reassembled query = field1=value1&remove=value2&field3=value3 + reassembled query - del* = field1=value1&remove=value2&field3=value3 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field3=value3 +/?field1=remove + query string = field1=remove + name = field1 + value = remove + reassembled query = field1=remove + reassembled query - del* = field1=remove + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=remove +/?remove=value1 + query string = remove=value1 + name = remove + value = value1 + reassembled query = remove=value1 + reassembled query - del* = remove=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = +/?remove=value1&remove=value2 + query string = remove=value1&remove=value2 + name = remove + value = value1 + name = remove + value = value2 + reassembled query = remove=value1&remove=value2 + reassembled query - del* = remove=value1&remove=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = +/?remove=value1&remove=value2&remove=value3 + query string = remove=value1&remove=value2&remove=value3 + name = remove + value = value1 + name = remove + value = value2 + name = remove + value = value3 + reassembled query = remove=value1&remove=value2&remove=value3 + reassembled query - del* = remove=value1&remove=value2&remove=value3 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = +/?remove=value1&field2=value2 + query string = remove=value1&field2=value2 + name = remove + value = value1 + name = field2 + value = value2 + reassembled query = remove=value1&field2=value2 + reassembled query - del* = remove=value1&field2=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field2=value2 +/?field1=value1&remove=value2&remove=value3&remove=value4 + query string = field1=value1&remove=value2&remove=value3&remove=value4 + name = field1 + value = value1 + name = remove + value = value2 + name = remove + value = value3 + name = remove + value = value4 + reassembled query = field1=value1&remove=value2&remove=value3&remove=value4 + reassembled query - del* = field1=value1&remove=value2&remove=value3&remove=value4 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1 +/?remove=value1&remove=value2&remove=value3&field4=value4 + query string = remove=value1&remove=value2&remove=value3&field4=value4 + name = remove + value = value1 + name = remove + value = value2 + name = remove + value = value3 + name = field4 + value = value4 + reassembled query = remove=value1&remove=value2&remove=value3&field4=value4 + reassembled query - del* = remove=value1&remove=value2&remove=value3&field4=value4 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field4=value4 +/?field1=value1&remove=value2&remove=value3&field4=value4 + query string = field1=value1&remove=value2&remove=value3&field4=value4 + name = field1 + value = value1 + name = remove + value = value2 + name = remove + value = value3 + name = field4 + value = value4 + reassembled query = field1=value1&remove=value2&remove=value3&field4=value4 + reassembled query - del* = field1=value1&remove=value2&remove=value3&field4=value4 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=value1&field4=value4 +/?check=0 + query string = check=0 + name = check + value = 0 + reassembled query = check=0 + reassembled query - del* = check=0 + check field exists = true + check field is true = false + check field = 0 + check field name = check + value = 0 + reassembled query - remove = check=0 +/?check=0&check=0 + query string = check=0&check=0 + name = check + value = 0 + name = check + value = 0 + reassembled query = check=0&check=0 + reassembled query - del* = check=0&check=0 + check field exists = true + check field is true = false + check field = 0 + check field name = check + value = 0 + check field name = check + value = 0 + reassembled query - remove = check=0&check=0 +/?check=0&check=0&check=1 + query string = check=0&check=0&check=1 + name = check + value = 0 + name = check + value = 0 + name = check + value = 1 + reassembled query = check=0&check=0&check=1 + reassembled query - del* = check=0&check=0&check=1 + check field exists = true + check field is true = true + check field = 0 + check field name = check + value = 0 + check field name = check + value = 0 + check field name = check + value = 1 + reassembled query - remove = check=0&check=0&check=1 +/?check= + query string = check= + name = check + value = + reassembled query = check= + reassembled query - del* = check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = check= +/?check=&check= + query string = check=&check= + name = check + value = + name = check + value = + reassembled query = check=&check= + reassembled query - del* = check=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&check= +/?check=&check=&check=foo + query string = check=&check=&check=foo + name = check + value = + name = check + value = + name = check + value = foo + reassembled query = check=&check=&check=foo + reassembled query - del* = check=&check=&check=foo + check field exists = true + check field is true = true + check field = + check field name = check + value = + check field name = check + value = + check field name = check + value = foo + reassembled query - remove = check=&check=&check=foo +/?check + query string = check + name = check + value = + reassembled query = check= + reassembled query - del* = check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = check= +/?check&check + query string = check&check + name = check + value = + name = check + value = + reassembled query = check=&check= + reassembled query - del* = check=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&check= +/?check&check&check=BAR + query string = check&check&check=BAR + name = check + value = + name = check + value = + name = check + value = BAR + reassembled query = check=&check=&check=BAR + reassembled query - del* = check=&check=&check=BAR + check field exists = true + check field is true = true + check field = + check field name = check + value = + check field name = check + value = + check field name = check + value = BAR + reassembled query - remove = check=&check=&check=BAR +/?ChecK=0 + query string = ChecK=0 + name = ChecK + value = 0 + reassembled query = ChecK=0 + reassembled query - del* = ChecK=0 + check field exists = true + check field is true = false + check field = 0 + check field name = ChecK + value = 0 + reassembled query - remove = ChecK=0 +/?ChecK=0&ChecK=0 + query string = ChecK=0&ChecK=0 + name = ChecK + value = 0 + name = ChecK + value = 0 + reassembled query = ChecK=0&ChecK=0 + reassembled query - del* = ChecK=0&ChecK=0 + check field exists = true + check field is true = false + check field = 0 + check field name = ChecK + value = 0 + check field name = ChecK + value = 0 + reassembled query - remove = ChecK=0&ChecK=0 +/?ChecK=0&ChecK=0&ChecK=1 + query string = ChecK=0&ChecK=0&ChecK=1 + name = ChecK + value = 0 + name = ChecK + value = 0 + name = ChecK + value = 1 + reassembled query = ChecK=0&ChecK=0&ChecK=1 + reassembled query - del* = ChecK=0&ChecK=0&ChecK=1 + check field exists = true + check field is true = true + check field = 0 + check field name = ChecK + value = 0 + check field name = ChecK + value = 0 + check field name = ChecK + value = 1 + reassembled query - remove = ChecK=0&ChecK=0&ChecK=1 +/?ChecK= + query string = ChecK= + name = ChecK + value = + reassembled query = ChecK= + reassembled query - del* = ChecK= + check field exists = true + check field is true = false + check field = + check field name = ChecK + value = + reassembled query - remove = ChecK= +/?ChecK=&ChecK= + query string = ChecK=&ChecK= + name = ChecK + value = + name = ChecK + value = + reassembled query = ChecK=&ChecK= + reassembled query - del* = ChecK=&ChecK= + check field exists = true + check field is true = false + check field = + check field name = ChecK + value = + check field name = ChecK + value = + reassembled query - remove = ChecK=&ChecK= +/?ChecK=&ChecK=&ChecK=foo + query string = ChecK=&ChecK=&ChecK=foo + name = ChecK + value = + name = ChecK + value = + name = ChecK + value = foo + reassembled query = ChecK=&ChecK=&ChecK=foo + reassembled query - del* = ChecK=&ChecK=&ChecK=foo + check field exists = true + check field is true = true + check field = + check field name = ChecK + value = + check field name = ChecK + value = + check field name = ChecK + value = foo + reassembled query - remove = ChecK=&ChecK=&ChecK=foo +/?ChecK + query string = ChecK + name = ChecK + value = + reassembled query = ChecK= + reassembled query - del* = ChecK= + check field exists = true + check field is true = false + check field = + check field name = ChecK + value = + reassembled query - remove = ChecK= +/?ChecK&ChecK + query string = ChecK&ChecK + name = ChecK + value = + name = ChecK + value = + reassembled query = ChecK=&ChecK= + reassembled query - del* = ChecK=&ChecK= + check field exists = true + check field is true = false + check field = + check field name = ChecK + value = + check field name = ChecK + value = + reassembled query - remove = ChecK=&ChecK= +/?ChecK&ChecK&ChecK=BAR + query string = ChecK&ChecK&ChecK=BAR + name = ChecK + value = + name = ChecK + value = + name = ChecK + value = BAR + reassembled query = ChecK=&ChecK=&ChecK=BAR + reassembled query - del* = ChecK=&ChecK=&ChecK=BAR + check field exists = true + check field is true = true + check field = + check field name = ChecK + value = + check field name = ChecK + value = + check field name = ChecK + value = BAR + reassembled query - remove = ChecK=&ChecK=&ChecK=BAR +/?check + query string = check + name = check + value = + reassembled query = check= + reassembled query - del* = check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = check= +/?check=0 + query string = check=0 + name = check + value = 0 + reassembled query = check=0 + reassembled query - del* = check=0 + check field exists = true + check field is true = false + check field = 0 + check field name = check + value = 0 + reassembled query - remove = check=0 +/?check=1 + query string = check=1 + name = check + value = 1 + reassembled query = check=1 + reassembled query - del* = check=1 + check field exists = true + check field is true = true + check field = 1 + check field name = check + value = 1 + reassembled query - remove = check=1 +/?check=foo + query string = check=foo + name = check + value = foo + reassembled query = check=foo + reassembled query - del* = check=foo + check field exists = true + check field is true = true + check field = foo + check field name = check + value = foo + reassembled query - remove = check=foo +/?check&check=foo + query string = check&check=foo + name = check + value = + name = check + value = foo + reassembled query = check=&check=foo + reassembled query - del* = check=&check=foo + check field exists = true + check field is true = true + check field = + check field name = check + value = + check field name = check + value = foo + reassembled query - remove = check=&check=foo +/?check=&check=foo + query string = check=&check=foo + name = check + value = + name = check + value = foo + reassembled query = check=&check=foo + reassembled query - del* = check=&check=foo + check field exists = true + check field is true = true + check field = + check field name = check + value = + check field name = check + value = foo + reassembled query - remove = check=&check=foo +/?check=0&check=foo + query string = check=0&check=foo + name = check + value = 0 + name = check + value = foo + reassembled query = check=0&check=foo + reassembled query - del* = check=0&check=foo + check field exists = true + check field is true = true + check field = 0 + check field name = check + value = 0 + check field name = check + value = foo + reassembled query - remove = check=0&check=foo +/?check=1&check=foo + query string = check=1&check=foo + name = check + value = 1 + name = check + value = foo + reassembled query = check=1&check=foo + reassembled query - del* = check=1&check=foo + check field exists = true + check field is true = true + check field = 1 + check field name = check + value = 1 + check field name = check + value = foo + reassembled query - remove = check=1&check=foo +/?CHEck + query string = CHEck + name = CHEck + value = + reassembled query = CHEck= + reassembled query - del* = CHEck= + check field exists = true + check field is true = false + check field = + check field name = CHEck + value = + reassembled query - remove = CHEck= +/?CHEck=0 + query string = CHEck=0 + name = CHEck + value = 0 + reassembled query = CHEck=0 + reassembled query - del* = CHEck=0 + check field exists = true + check field is true = false + check field = 0 + check field name = CHEck + value = 0 + reassembled query - remove = CHEck=0 +/?CHEck=1 + query string = CHEck=1 + name = CHEck + value = 1 + reassembled query = CHEck=1 + reassembled query - del* = CHEck=1 + check field exists = true + check field is true = true + check field = 1 + check field name = CHEck + value = 1 + reassembled query - remove = CHEck=1 +/?CHEck=foo + query string = CHEck=foo + name = CHEck + value = foo + reassembled query = CHEck=foo + reassembled query - del* = CHEck=foo + check field exists = true + check field is true = true + check field = foo + check field name = CHEck + value = foo + reassembled query - remove = CHEck=foo +/?CHEck&CHEck=foo + query string = CHEck&CHEck=foo + name = CHEck + value = + name = CHEck + value = foo + reassembled query = CHEck=&CHEck=foo + reassembled query - del* = CHEck=&CHEck=foo + check field exists = true + check field is true = true + check field = + check field name = CHEck + value = + check field name = CHEck + value = foo + reassembled query - remove = CHEck=&CHEck=foo +/?CHEck=&CHEck=foo + query string = CHEck=&CHEck=foo + name = CHEck + value = + name = CHEck + value = foo + reassembled query = CHEck=&CHEck=foo + reassembled query - del* = CHEck=&CHEck=foo + check field exists = true + check field is true = true + check field = + check field name = CHEck + value = + check field name = CHEck + value = foo + reassembled query - remove = CHEck=&CHEck=foo +/?CHEck=0&CHEck=foo + query string = CHEck=0&CHEck=foo + name = CHEck + value = 0 + name = CHEck + value = foo + reassembled query = CHEck=0&CHEck=foo + reassembled query - del* = CHEck=0&CHEck=foo + check field exists = true + check field is true = true + check field = 0 + check field name = CHEck + value = 0 + check field name = CHEck + value = foo + reassembled query - remove = CHEck=0&CHEck=foo +/?CHEck=1&CHEck=foo + query string = CHEck=1&CHEck=foo + name = CHEck + value = 1 + name = CHEck + value = foo + reassembled query = CHEck=1&CHEck=foo + reassembled query - del* = CHEck=1&CHEck=foo + check field exists = true + check field is true = true + check field = 1 + check field name = CHEck + value = 1 + check field name = CHEck + value = foo + reassembled query - remove = CHEck=1&CHEck=foo +/?check + query string = check + name = check + value = + reassembled query = check= + reassembled query - del* = check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = check= +/?check&check + query string = check&check + name = check + value = + name = check + value = + reassembled query = check=&check= + reassembled query - del* = check=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&check= +/?check&check&check + query string = check&check&check + name = check + value = + name = check + value = + name = check + value = + reassembled query = check=&check=&check= + reassembled query - del* = check=&check=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&check=&check= +/?foo&check + query string = foo&check + name = foo + value = + name = check + value = + reassembled query = foo=&check= + reassembled query - del* = foo=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = foo=&check= +/?foo&check&check + query string = foo&check&check + name = foo + value = + name = check + value = + name = check + value = + reassembled query = foo=&check=&check= + reassembled query - del* = foo=&check=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = foo=&check=&check= +/?foo&check&check&check + query string = foo&check&check&check + name = foo + value = + name = check + value = + name = check + value = + name = check + value = + reassembled query = foo=&check=&check=&check= + reassembled query - del* = foo=&check=&check=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + check field name = check + value = + reassembled query - remove = foo=&check=&check=&check= +/?check&bar + query string = check&bar + name = check + value = + name = bar + value = + reassembled query = check=&bar= + reassembled query - del* = check=&bar= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = check=&bar= +/?check&check&bar + query string = check&check&bar + name = check + value = + name = check + value = + name = bar + value = + reassembled query = check=&check=&bar= + reassembled query - del* = check=&check=&bar= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&check=&bar= +/?check&check&check&bar + query string = check&check&check&bar + name = check + value = + name = check + value = + name = check + value = + name = bar + value = + reassembled query = check=&check=&check=&bar= + reassembled query - del* = check=&check=&check=&bar= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&check=&check=&bar= +/?foo&check&bar + query string = foo&check&bar + name = foo + value = + name = check + value = + name = bar + value = + reassembled query = foo=&check=&bar= + reassembled query - del* = foo=&check=&bar= + check field exists = true + check field is true = false + check field = + check field name = check + value = + reassembled query - remove = foo=&check=&bar= +/?foo&check&check&bar + query string = foo&check&check&bar + name = foo + value = + name = check + value = + name = check + value = + name = bar + value = + reassembled query = foo=&check=&check=&bar= + reassembled query - del* = foo=&check=&check=&bar= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = foo=&check=&check=&bar= +/?check&foo&check + query string = check&foo&check + name = check + value = + name = foo + value = + name = check + value = + reassembled query = check=&foo=&check= + reassembled query - del* = check=&foo=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&foo=&check= +/?check&foo&foo&check + query string = check&foo&foo&check + name = check + value = + name = foo + value = + name = foo + value = + name = check + value = + reassembled query = check=&foo=&foo=&check= + reassembled query - del* = check=&foo=&foo=&check= + check field exists = true + check field is true = false + check field = + check field name = check + value = + check field name = check + value = + reassembled query - remove = check=&foo=&foo=&check= +/?check=value1 + query string = check=value1 + name = check + value = value1 + reassembled query = check=value1 + reassembled query - del* = check=value1 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + reassembled query - remove = check=value1 +/?check=value1&check=value2 + query string = check=value1&check=value2 + name = check + value = value1 + name = check + value = value2 + reassembled query = check=value1&check=value2 + reassembled query - del* = check=value1&check=value2 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = check=value1&check=value2 +/?check&check=value1&check=value2 + query string = check&check=value1&check=value2 + name = check + value = + name = check + value = value1 + name = check + value = value2 + reassembled query = check=&check=value1&check=value2 + reassembled query - del* = check=&check=value1&check=value2 + check field exists = true + check field is true = true + check field = + check field name = check + value = + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = check=&check=value1&check=value2 +/?foo&check=value1 + query string = foo&check=value1 + name = foo + value = + name = check + value = value1 + reassembled query = foo=&check=value1 + reassembled query - del* = foo=&check=value1 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + reassembled query - remove = foo=&check=value1 +/?foo&check=value1&check=value2 + query string = foo&check=value1&check=value2 + name = foo + value = + name = check + value = value1 + name = check + value = value2 + reassembled query = foo=&check=value1&check=value2 + reassembled query - del* = foo=&check=value1&check=value2 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = foo=&check=value1&check=value2 +/?foo&check=value1&check=value2&check=value3 + query string = foo&check=value1&check=value2&check=value3 + name = foo + value = + name = check + value = value1 + name = check + value = value2 + name = check + value = value3 + reassembled query = foo=&check=value1&check=value2&check=value3 + reassembled query - del* = foo=&check=value1&check=value2&check=value3 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + check field name = check + value = value3 + reassembled query - remove = foo=&check=value1&check=value2&check=value3 +/?check=value1&bar + query string = check=value1&bar + name = check + value = value1 + name = bar + value = + reassembled query = check=value1&bar= + reassembled query - del* = check=value1&bar= + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + reassembled query - remove = check=value1&bar= +/?check=value1&check=value2&bar + query string = check=value1&check=value2&bar + name = check + value = value1 + name = check + value = value2 + name = bar + value = + reassembled query = check=value1&check=value2&bar= + reassembled query - del* = check=value1&check=value2&bar= + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = check=value1&check=value2&bar= +/?check=value1&check=value2&check=value3&bar + query string = check=value1&check=value2&check=value3&bar + name = check + value = value1 + name = check + value = value2 + name = check + value = value3 + name = bar + value = + reassembled query = check=value1&check=value2&check=value3&bar= + reassembled query - del* = check=value1&check=value2&check=value3&bar= + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + check field name = check + value = value3 + reassembled query - remove = check=value1&check=value2&check=value3&bar= +/?foo&check=value1&bar + query string = foo&check=value1&bar + name = foo + value = + name = check + value = value1 + name = bar + value = + reassembled query = foo=&check=value1&bar= + reassembled query - del* = foo=&check=value1&bar= + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + reassembled query - remove = foo=&check=value1&bar= +/?foo&check=value1&check=value2&bar + query string = foo&check=value1&check=value2&bar + name = foo + value = + name = check + value = value1 + name = check + value = value2 + name = bar + value = + reassembled query = foo=&check=value1&check=value2&bar= + reassembled query - del* = foo=&check=value1&check=value2&bar= + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = foo=&check=value1&check=value2&bar= +/?check=value1&foo&check=value2 + query string = check=value1&foo&check=value2 + name = check + value = value1 + name = foo + value = + name = check + value = value2 + reassembled query = check=value1&foo=&check=value2 + reassembled query - del* = check=value1&foo=&check=value2 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = check=value1&foo=&check=value2 +/?check=value1&foo&foo&check=value2 + query string = check=value1&foo&foo&check=value2 + name = check + value = value1 + name = foo + value = + name = foo + value = + name = check + value = value2 + reassembled query = check=value1&foo=&foo=&check=value2 + reassembled query - del* = check=value1&foo=&foo=&check=value2 + check field exists = true + check field is true = true + check field = value1 + check field name = check + value = value1 + check field name = check + value = value2 + reassembled query - remove = check=value1&foo=&foo=&check=value2 +/?field1=%26 + query string = field1=%26 + name = field1 + value = & + reassembled query = field1=%26 + reassembled query - del* = field1=%26 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=%26 +/?field1=%26&field2=%26 + query string = field1=%26&field2=%26 + name = field1 + value = & + name = field2 + value = & + reassembled query = field1=%26&field2=%26 + reassembled query - del* = field1=%26&field2=%26 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=%26&field2=%26 +/?field1=%3d + query string = field1=%3d + name = field1 + value = = + reassembled query = field1=%3D + reassembled query - del* = field1=%3D + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=%3D +/?field1=%3d&field2=%3d + query string = field1=%3d&field2=%3d + name = field1 + value = = + name = field2 + value = = + reassembled query = field1=%3D&field2=%3D + reassembled query - del* = field1=%3D&field2=%3D + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field1=%3D&field2=%3D +/?field%26=value1 + query string = field%26=value1 + name = field& + value = value1 + reassembled query = field%26=value1 + reassembled query - del* = field%26=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field%26=value1 +/?field%26=value1&field%26=value2 + query string = field%26=value1&field%26=value2 + name = field& + value = value1 + name = field& + value = value2 + reassembled query = field%26=value1&field%26=value2 + reassembled query - del* = field%26=value1&field%26=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field%26=value1&field%26=value2 +/?field%3d=value1 + query string = field%3d=value1 + name = field= + value = value1 + reassembled query = field%3D=value1 + reassembled query - del* = field%3D=value1 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field%3D=value1 +/?field%3d=value1&field%3d=value2 + query string = field%3d=value1&field%3d=value2 + name = field= + value = value1 + name = field= + value = value2 + reassembled query = field%3D=value1&field%3D=value2 + reassembled query - del* = field%3D=value1&field%3D=value2 + check field exists = false + check field is true = false + check field = not present + reassembled query - remove = field%3D=value1&field%3D=value2 Index: Makefile.am =================================================================== --- Makefile.am (revision 3604) +++ Makefile.am (working copy) @@ -6,7 +6,8 @@ INCLUDES = -I$(top_builddir)/include -I srcdir@/include @THREAD_CFLAGS@ @Z_CFLAGS@ -noinst_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath testURI \ +noinst_PROGRAMS=testSchemas testRelax testSAX testHTML testXPath \ + testURI testURIQuery \ testThreads testC14N testAutomata testRegexp \ testReader testapi testModule runtest runsuite @@ -100,6 +101,11 @@ testURI_DEPENDENCIES = $(DEPS) testURI_LDADD= $(LDADDS) +testURIQuery_SOURCES=testURIQuery.c +testURIQuery_LDFLAGS = +testURIQuery_DEPENDENCIES = $(DEPS) +testURIQuery_LDADD= $(LDADDS) + testRegexp_SOURCES=testRegexp.c testRegexp_LDFLAGS = testRegexp_DEPENDENCIES = $(DEPS) @@ -159,7 +165,7 @@ testall : tests SVGtests SAXtests -tests: XMLtests XMLenttests NStests IDtests Errtests APItests @READER_TEST@ @TEST_SAX@ @TEST_PUSH@ @TEST_HTML@ @TEST_PHTML@ @TEST_VALID@ URItests @TEST_PATTERN@ @TEST_XPATH@ @TEST_XPTR@ @TEST_XINCLUDE@ @TEST_C14N@ @TEST_DEBUG@ @TEST_CATALOG@ @TEST_REGEXPS@ @TEST_SCHEMAS@ @TEST_SCHEMATRON@ @TEST_THREADS@ Timingtests @TEST_VTIME@ @PYTHON_TESTS@ @TEST_MODULES@ +tests: XMLtests XMLenttests NStests IDtests Errtests APItests @READER_TEST@ @TEST_SAX@ @TEST_PUSH@ @TEST_HTML@ @TEST_PHTML@ @TEST_VALID@ URItests URIQuerytests @TEST_PATTERN@ @TEST_XPATH@ @TEST_XPTR@ @TEST_XINCLUDE@ @TEST_C14N@ @TEST_DEBUG@ @TEST_CATALOG@ @TEST_REGEXPS@ @TEST_SCHEMAS@ @TEST_SCHEMATRON@ @TEST_THREADS@ Timingtests @TEST_VTIME@ @PYTHON_TESTS@ @TEST_MODULES@ @(if [ "@PYTHON_SUBDIR@" != "" ] ; then cd python ; \ $(MAKE) MAKEFLAGS+=--silent tests ; fi) @(cd doc/examples ; $(MAKE) MAKEFLAGS+=--silent tests) @@ -437,6 +443,24 @@ rm result.$$name ; \ fi ; fi ; done) +URIQuerytests : testURIQuery$(EXEEXT) + @(echo > .memdump) + @echo "## URI query string parser regression tests" + -@(for i in $(srcdir)/test/URIQuery/*.data ; do \ + name=`basename $$i`; \ + if [ ! -d $$i ] ; then \ + if [ ! -f $(srcdir)/result/URIQuery/$$name ] ; then \ + echo New test file $$name ; \ + $(CHECKER) $(top_builddir)/testURIQuery < $$i > $(srcdir)/result/URIQuery/$$name ; \ + grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0"; \ + else \ + log=`$(CHECKER) $(top_builddir)/testURIQuery < $$i 2>&1 > result.$$name ; \ + grep "MORY ALLO" .memdump | grep -v "MEMORY ALLOCATED : 0";\ + diff $(srcdir)/result/URIQuery/$$name result.$$name` ; \ + if [ -n "$$log" ] ; then echo $$name result ; echo $$log ; fi ; \ + rm result.$$name ; \ + fi ; fi ; done) + XPathtests : testXPath$(EXEEXT) @(echo > .memdump) @echo "## XPath regression tests" Index: .cvsignore =================================================================== --- .cvsignore (revision 3604) +++ .cvsignore (working copy) @@ -34,6 +34,7 @@ xmlversion.h xmllint testURI +testURIQuery testDocbook testCatalog xmlcatalog Index: test/URIQuery/test1.data =================================================================== --- test/URIQuery/test1.data (revision 0) +++ test/URIQuery/test1.data (revision 0) @@ -0,0 +1,144 @@ +# List of tests URIs supplied to the testURIQuery.c program. +# That program takes each URL, extracts the query string (if any) +# and performs a series of xmlURIQuery* functions on that +# query string. You can find out more by looking at the test +# program and the result file (result/URIQuery/test1.data). + +# No query string: + +/ +/? + +# Some simple query strings just to test parsing: + +/?field1=value1 +/?field1=value1&field2=value2 +/?field1=value1&field2=value2&field3=value3 +/?field1=value1&field2=value2&field3=value3&field4=value4 + +# Test name= and =value + +/?field1= +/?=value1 +/?field1=&field2=value2 +/?=value1&field2=value2 +/?field1=value1&field2= +/?field1=value1&=value2 +/?field1=value1&field2=&field3=value3 +/?field1=value1&=value2&field3=value3 + +# Empty fields + +/?& +/?&& +/?&&& +/?field1=value1&&field2=value2 +/?&field1=value1&field2=value2 +/?&&field1=value1&field2=value2 +/?field1=value1&field2=value2& +/?field1=value1&field2=value2&& + +# Any field names matching "del*" should be removed (tests the +# "ignore" feature of xmlURIQueryCreate): + +/?field1=value1&delme=value2&field3=value3 +/?del=delete +/?field1=del +/?del1=value1&del2=value2&del3=value3 +/?field1=value1&del2=value2 +/?del1=value1&field2=value2 +/?field1=value1&del2=value2&del3=value3&del4=value4 +/?del1=value1&del2=value2&del3=value3&field4=value4 + +# Any field names called "remove" should be removed (tests +# xmlURIQueryRemove): + +/?field1=value1&remove=value2&field3=value3 +/?field1=remove +/?remove=value1 +/?remove=value1&remove=value2 +/?remove=value1&remove=value2&remove=value3 +/?remove=value1&field2=value2 +/?field1=value1&remove=value2&remove=value3&remove=value4 +/?remove=value1&remove=value2&remove=value3&field4=value4 +/?field1=value1&remove=value2&remove=value3&field4=value4 + +# Check Exists/IsTrue + +/?check=0 +/?check=0&check=0 +/?check=0&check=0&check=1 +/?check= +/?check=&check= +/?check=&check=&check=foo +/?check +/?check&check +/?check&check&check=BAR +/?ChecK=0 +/?ChecK=0&ChecK=0 +/?ChecK=0&ChecK=0&ChecK=1 +/?ChecK= +/?ChecK=&ChecK= +/?ChecK=&ChecK=&ChecK=foo +/?ChecK +/?ChecK&ChecK +/?ChecK&ChecK&ChecK=BAR + +# Check GetSingle + +/?check +/?check=0 +/?check=1 +/?check=foo +/?check&check=foo +/?check=&check=foo +/?check=0&check=foo +/?check=1&check=foo +/?CHEck +/?CHEck=0 +/?CHEck=1 +/?CHEck=foo +/?CHEck&CHEck=foo +/?CHEck=&CHEck=foo +/?CHEck=0&CHEck=foo +/?CHEck=1&CHEck=foo + +# Check GetMultiple + +/?check +/?check&check +/?check&check&check +/?foo&check +/?foo&check&check +/?foo&check&check&check +/?check&bar +/?check&check&bar +/?check&check&check&bar +/?foo&check&bar +/?foo&check&check&bar +/?check&foo&check +/?check&foo&foo&check +/?check=value1 +/?check=value1&check=value2 +/?check&check=value1&check=value2 +/?foo&check=value1 +/?foo&check=value1&check=value2 +/?foo&check=value1&check=value2&check=value3 +/?check=value1&bar +/?check=value1&check=value2&bar +/?check=value1&check=value2&check=value3&bar +/?foo&check=value1&bar +/?foo&check=value1&check=value2&bar +/?check=value1&foo&check=value2 +/?check=value1&foo&foo&check=value2 + +# %-sequences in URLs + +/?field1=%26 +/?field1=%26&field2=%26 +/?field1=%3d +/?field1=%3d&field2=%3d +/?field%26=value1 +/?field%26=value1&field%26=value2 +/?field%3d=value1 +/?field%3d=value1&field%3d=value2
Attachment:
smime.p7s
Description: S/MIME Cryptographic Signature