0

I have cookies in my HTTP header like so:

Set-Cookie: frontend=ovsu0p8khivgvp29samlago1q0; adminhtml=6df3s767g199d7mmk49dgni4t7; external_no_cache=1; ZDEDebuggerPresent=php,phtml,php3

and I need to extract the 26 character string that comes after frontend (e.g. ovsu0p8khivgvp29samlago1q0). The following regular expression matches that for me:

(?<=frontend=)(.*)(?=;)

However, I am using Varnish Cache and can only use a regex replace. Therefore, to extract that cookie value (26 character frontend string) I need to match all characters that do not match that pattern (so I can replace them with '').

I've done a fair bit of Googling but so far have drawn a blank. I've tried the following

  • Match characters that do not match the pattern I want: [^((?<=frontend=)[A-Za-z0-9]{26}(?=;))] which matches random characters, including the ones I want to preserve

I'd be grateful if someone could point me in the right direction, or note where I might have gone wrong.

james
  • 792
  • 7
  • 15

3 Answers3

2

The Set-Cookie response header is a bit magical in Varnish, since the backends tend to send multiple headers with the same name. This is prohibited by the RFC, but the defacto way to do it.

If you are using Varnish 3.0 you can use the Header VMOD, it can parse the response and extract what you need:

https://github.com/varnish/libvmod-header

lkarsten
  • 2,971
  • 1
  • 15
  • 11
1

Use regex pattern

^Set-Cookie:.*?\bfrontend=([^;]*)

and the "26 character string that comes after frontend" will be in group 1 (usually referred to in the replacement string as $1)

Martin Ender
  • 43,427
  • 11
  • 90
  • 130
Ωmega
  • 42,614
  • 34
  • 134
  • 203
  • @m.buettner - Thank you for optimizing my solution. – Ωmega Nov 24 '12 at 01:24
  • This gets me the 26 character value I am after, but I am still stuck on how I select anything that does not match that pattern – james Nov 25 '12 at 00:36
  • @james :: Use more groups then: `^(Set-Cookie:\s)(.*?)(\bfrontend=)([^;]*)(.*)$` – Ωmega Nov 25 '12 at 01:06
  • I needed to select everything not matching that pattern as I can only do replace. lkarsten pointed me to a module that enables me to select what I need – james Nov 27 '12 at 16:52
1

Do you have control over the replacement string? If so, you can go with Ωmega's answer, and use $1 in your replacement string to write the frontend value back.

Otherwise, you could use this:

^Set-Cookie:.*(?!frontend=)|(?<=frontend=.{26}).*$

This will match everything from the start of the string, until frontend= is encountered. Or it will match everything that has frontend= exactly 26 characters to the left of it and up until the end of the string. If those 26 characters are a variable length, it would get signigicantly more complicated, because only .NET supports variable-length lookbehinds.

For your last question. Let's have a look at your regex:

[^((?<=frontend=)[A-Za-z0-9]{26}(?=;))]

Well, firstly the negative character class [^...] you tried to surround you pattern with, doesn't really work like this. It is still a character class, so it matches only a single character that is not inside that class. But it gets even more complicated (and I wonder why it matches at all). So firstly the character class should be closed by the first ]. This character class matches anything that is not (, ?, <, =, ), a letter or a digit. Then the {26} is applied to that, so we are trying to find 26 of those characters. Then the (?=;) which asserts that those 26 characters are followed by ;. Now comes what should not work. The closing ) should actually throw and error. And the final ] would just be interpreted as a literal ].

There are some regex flavors which allow for nesting of character classes (Java does). In this case, you would simply have a character class equivalent to [^a-zA-Z0-9(){}?<=;]. But as far as I could google it, Varnish uses PCRE, and in PCRE your regex should simply not compile.

Martin Ender
  • 43,427
  • 11
  • 90
  • 130