How can I combine this into 1 block? - nginx

I am trying to set the $qualifies variable to 1 if both the path = "/" AND the query variable "band" != "". I've been able to figure out the separate sections below (I think) but wanted to know if there is an easier way. Seems like this could all be in 1 map:
map $request_uri $myvar {
~(?<captured_path>[^?]*) $captured_path;
}
map $arg_band $band{
"" 0;
default 1;
}
map "$myvar:$band" $qualifies{
default 0;
"/:1" 1;
}
Want to do it 'cause ugly and know there's probably a better way.

It seems like weren't aware that a query-less URL is already available within $uri, so, another potential solution is as follows:
map $uri:$arg_band $qualified {
default 0;
~^/:[^:]+$ 1;
}
Note both $uri and $arg_band can contain "weird" characters (e.g., both can contain ?, in case of $uri, through %3f), so, you gotta be sure in your regex to match your actual separator, and not a placeholder supplied by the user. This can either be done by making it random, long and secret, or by restricting the acceptable input from the user.
Note that without knowing what other logic is employed and how it makes use of the variables, most of the obvious and good-looking solutions would actually contain potential security vulnerabilities and be incorrect (e.g., the solution above may be incorrect if $arg_band does contain :).

Abstract
So, you're trying to set $qualifies to 1 if both $uri is / and $arg_band is not set to anything?
Basic Idea
The basic idea compared to your own code is that we have to do an inverse of the logical and operation to a logical or — (a && b) is always the same as !(!a || !b) — and once you know the theory, then the rest is simply a bit of coding.
And, indeed, it's very simple to do with a single http://nginx.org/r/map:
map $request_uri $qualifies {
default 1;
~^[^?]+[?]band=[^&] 0; # match if $arg_band set to .+, case 1
~^[^?]+[?].*&band=[^&] 0; # match if $arg_band set to .+, case 2
~^[/]+[^/?]+ 0; # match if $uri is set to "/"
}
Discussion
If you don't like the double cases for handling $arg_band, you can use the lookbehind operator of pcre, however, I believe that the above two cases might actually be more efficient and correct than the single one below:
^[^?]+[?].*(?<=[?&])band=[^&] # incorrect! will match /??band=a
A follow-up question I personally had was whether the above combined regex is actually correct, and would match the way nginx does its own parsing for $arg_band. This can be tested by running various strings against an nginx.conf that simply does something like return 200 $args\t$arg_band\t$uri\t$request_uri\n;; what I found out is that $uri is always cut at the first ?, whereas $args itself may contain the second ?, whereas the individual variable names must either start from the first ? of the request, or from & anytime after the first question mark, e.g., a question mark within $args is treated as a regular character, so, the above lookbehind code w/ (?<=[?&]) is incorrect due to the different matching of a string like /??band=t between the regex and actual $arg_band in nginx.
So, if you still want to combine the two expressions, then perhaps the following should be the most correct one:
^[^?]+[?](?:.*&)?band=[^&]
Summary
Making the overall solution:
map $request_uri $qualifies {
default 1;
~^[^?]+[?](.*&)?band=[^&] 0;
~^[/]+[^/?]+ 0;
}
However, you also have to consider how absolutely correct your solution has to be, and if a very high degree of correctness is required, then it may not be appropriate to do your own parsing of $request_uri (just as an example, when $request_uri is /a/../, the $uri will be just / due to URL normalisation, and your original solution already suffered from this).

Related

Regex to match for multiple strings anywhere within a string

I'm trying to add some validation in ASP.NET using Regex. Essentially I need to ensure a text box includes both ***ThisString*** and ***ThatString*** including the asterisks.
I can get it to work with one, or one or the other, just not both being present at the same time and at any part of the string.l it's validating.
Thanks
As nanhydrin correctly pointed out, my solution will not work if there are multiple of one of the strings but not the other. If that case may occur, you can check for each string separately for readability's sake
First regular expression- (?:\*{3}ThisString\*{3})
Second regular expression- (?:\*{3}ThatString\*{3})
If matches are found in both cases, you're good to go!
Original Answer:-
This is the regular expression you want: (?:\*{3}(?:ThisString|ThatString)\*{3})
Note: Make sure to have global match on and be sure to escape the asterisks correctly.
If the above expression finds 2 (or more) matches, it means you're good to go.
Explanation:-
The entire thing is in a non capturing group, this is to ensure, everything within does get matched fully
There are 3 stars on each side of the strings, having 3 stars on one side but not the other will not result in a match
Both ThisString and ThatString are in a grouped alternative, this is to reduce clutter, you could totally jam every possible positional pattern but this is just better as position doesn't matter here. ***ThatString*** can come before ***ThisString*** or vice versa.
MAKE SURE to check the length of the matches found, the length must be 2 for your
described condition to be satisfied.
Here's the live demo
Using #Chase's answer I was able to come up with the following:
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
Regex thisString = new Regex("(?:\*{3}ThisString\*{3})");
Regex thatString = new Regex("(?:\*{3}ThatString\*{3})");
if (!thisString.IsMatch(value.ToString()) || !thatString.IsMatch(value.ToString()))
{
return new ValidationResult("***ThisString*** and ***ThatString*** are used to generate the email text. Please ensure the text above has both ***ThisString*** and ***ThatString*** somewhere within the text."); }
return ValidationResult.Success;
}
Now if either regex patterns don't match anywhere, it'll return an error.

Creating a Regex to match "Body: Margin 0"

I want to create a regex, in order to find out if an entry exists.
The Entry is in a CSS File.
Unfortunately different developers tend to write them in different manners, so I want to create a regex, that matches all this individualities.
I hope somebody can help me.
body {
margin: 0; }
body
{
margin: 0;
}
body{margin:0;}
There are too many variables that could makes your regexp fails: body could have an id, a class, and/or be part of a bigger list. You could have comments, the ";" could be missing, you could have multiple rules inside.
Unless you want to match exactly the three strings above, I strongly suggest to use a css parser that returns an AST. Something like: https://github.com/csstree/csstree
Something like this seems to work for your examples, as well as any other valid synthax I can think of :
^\s*[\.\#]{0}body(\s|\n)*\{[^\}]*(\s|\n)*margin(\s|\n)*\:\s*0\s*\;[^\}]*\}
Try here : https://regex101.com/r/GbIbdE/1

How can I prevent SQLite from treating a string as a number?

I would like to query an SQLite table that contains directory paths to find all the paths under some hierarchy. Here's an example of the contents of the column:
/alpha/papa/
/alpha/papa/tango/
/alpha/quebec/
/bravo/papa/
/bravo/papa/uniform/
/charlie/quebec/tango/
If I search for everything under /bravo/papa/, I would like to get:
/bravo/papa/
/bravo/papa/uniform/
I am currently trying to do this like so (see below for the long story of why I can't use more simple methods):
SELECT * FROM Files WHERE Path >= '/bravo/papa/' AND Path < '/bravo/papa0';
This works. It looks a bit weird, but it works for this example. '0' is the unicode code point 1 greater than '/'. When ordered lexicographically, all the paths starting with '/bravo/papa/' compare greater than it and less than 'bravo/papa0'. However, in my tests, I find that this breaks down when we try this:
SELECT * FROM Files WHERE Path >= '/' AND Path < '0';
This returns no results, but it should return every row. As far as I can tell, the problem is that SQLite is treating '0' as a number, not a string. If I use '0Z' instead of '0', for example, I do get results, but I introduce a risk of getting false positives. (For example, if there actually was an entry '0'.)
The simple version of my question is: is there some way to get SQLite to treat '0' in such a query as the length-1 string containing the unicode character '0' (which should sort strings such as '!', '*' and '/', but before '1', '=' and 'A') instead of the integer 0 (which SQLite sorts before all strings)?
I think in this case I can actually get away with special-casing a search for everything under '/', since all my entries will always start with '/', but I'd really like to know how to avoid this sort of thing in general, as it's unpleasantly surprising in all the same ways as Javascript's "==" operator.
First approach
A more natural approach would be to use the LIKE or GLOB operator. For example:
SELECT * FROM Files WHERE Path LIKE #prefix || '%';
But I want to support all valid path characters, so I would need to use ESCAPE for the '_' and '%' symbols. Apparently this prevents SQLite from using an index on Path. (See http://www.sqlite.org/optoverview.html#like_opt ) I really want to be able to benefit from an index here, and it sounds like that's impossible using either LIKE or GLOB unless I can guarantee that none of their special characters will occur in the directory name, and POSIX allows anything other than NUL and '/', even GLOB's '*' and '?' characters.
I'm providing this for context. I'm interested in other approaches to solve the underlying problem, but I'd prefer to accept an answer that directly addresses the ambiguity of strings-that-look-like-numbers in SQLite.
Similar questions
How do I prevent sqlite from evaluating a string as a math expression?
In that question, the values weren't quoted. I get these results even when the values are quoted or passed in as parameters.
EDIT - See my answer below. The column was created with the invalid type "STRING", which SQLite treated as NUMERIC.
* Groan *. The column had NUMERIC affinity because it had accidentally been specified as "STRING" instead of "TEXT". Since SQLite didn't recognize the type name, it made it NUMERIC, and because SQLite doesn't enforce column types, everything else worked as expected, except that any time a number-like string is inserted into that column it is converted into a numeric type.

ASP.NET Routing Regex to match specific pattern

I am trying to write a regular expression for ASP.NET MapPageRoute that matches a specific type of path.
I do not want to match anything with a file extension so I used this regex ^[^.]*$ which worked fine except it also picked up if the default document was requested. I do not want it to pick up the default document so I have been trying to change it to require at least one character. I tried adding .{1,} or .+ to the beginning of the working regex but it stopped working alltogether.
routes.MapPageRoute("content", "{*contentpath}", "~/Content.aspx", true, new RouteValueDictionary { }, new RouteValueDictionary { { "contentpath", #"^[^.]*$" } });
How can I change my regex to accomplish this?
Unfortunately my brain does not seem capable of learning regular expressions properly.
You want to change your * quantifier to +. * matches zero or more times, whereas + matches one or more. So, what you are asking for is this:
^[^.]+$
The regex is accomplishing this: "At the beginning of the string, match all characters that are not ., at least one time, up to the end of the string."
^[^.]+$
zero is to * as one is to +

Regex for ASP.NET url rewrite

Sample text =
legacycard.ashx?save=false&iNo=3&No=555
Sample pattern =
^legacycard.ashx(.*)No=(\d+)
Want to grab group #2 value of "555" (the value of "No=" in the sample text)
In Expresso, this works, but in ASP.NET UrlRewrite, it is not catching.
Am I missing something?
Thanks!
I would do something along these lines:
^legacycard.ashx\?(?:.+&)*No=(\d+)
The \? will escape the question mark that normally separates the URL and the parameters, then you make sure that it will capture every parameter key/value pair (anything that ends on &) before the parameter you actually care about. Using ?: lets you specify that the set of brackets is non capturing (I'm assuming you won't need any of the data, has the potential to slightly speeds up your regex) and leaves you just 555 captured. The added benefit of this approach is that it'll work regardless of parameter order.
Just use this regex:
^legacycard\.ashx\?save=(false|true)&iNo=(?<ino>\d+)&No=(?<no>\d+)
Then Regex Replace with
${no}
Looks fine to me, your regex should match the entire string
legacycard.ashx?save=false&iNo=3&No=555
not sure why you have groups, but groups should also return
?save=false&iNo=3&
and
555
For good measure you should know that the . in legacycard.ashx is also interpreted by regex and you would normally escape it, in this case it dosen't matter because a single dot matches everything, also a dot. :)
Try this
^legacycard.ashx(\?No=|.*?&No=)(\d+)
this should work.

Resources