清漆中的小写URL(内联C)

清漆中的小写URL(内联C),c,caching,lowercase,varnish,C,Caching,Lowercase,Varnish,在(3.0)中,URL以区分大小写的方式处理。我的意思是http://test.com/user/a4556与http://test.com/user/A4556。在我的web服务器上,它们被视为相同的url。我想做的是在所有请求URL进入时使用小写字母 我设法找到了,但Varnish的创建者表示我必须使用内联C来完成。我可以通过使用多个正则表达式以一种过于简单的方式实现这一点,但这似乎注定要失败 理想情况下,我想要的是一个VCL配置来实现这一点(可以是一个例子),但我愿意接受一个C函数,它接受

在(3.0)中,URL以区分大小写的方式处理。我的意思是
http://test.com/user/a4556
http://test.com/user/A4556
。在我的web服务器上,它们被视为相同的url。我想做的是在所有请求URL进入时使用小写字母

我设法找到了,但Varnish的创建者表示我必须使用内联C来完成。我可以通过使用多个正则表达式以一种过于简单的方式实现这一点,但这似乎注定要失败


理想情况下,我想要的是一个VCL配置来实现这一点(可以是一个例子),但我愿意接受一个C函数,它接受
const char*
并返回
const char*
(我不是C程序员,所以如果语法错误,请原谅我)

如果您正在寻找一个将大写字符串转换为小写的C函数,可以:

#include <ctype.h>

static char *
to_lower (char *str)
{
  char *s = str;  

  while (*s)
    {
      if (isupper (*s))
        *s = tolower (*s);
      s++;
    }
  return str;
}
#包括
静态字符*
至下(字符*str)
{
char*s=str;
而(*s)
{
如果(isupper(*s))
*s=tolower(*s);
s++;
}
返回str;
}

请注意,这会在适当的位置修改字符串。因此,您可能希望传递原始字符串的副本作为参数。

好的,我自己解决了这个问题。以下是VCL:

C{
    #include <ctype.h>
    //lovingly lifted from:
    //https://github.com/cosimo/varnish-accept-language/blob/master/examples/accept-language.vcl
    static void strtolower(const char *s) {
        register char *c;
        for (c=s; *c; c++) {
            if (isupper(*c)) {
                *c = tolower(*c);
            }
        }
        return;
    }
}C

sub vcl_recv {
   C{
        strtolower(VRT_r_req_url(sp));
   }C
}
C{
#包括
//可爱地从:
//https://github.com/cosimo/varnish-accept-language/blob/master/examples/accept-language.vcl
静态void strtolower(常量字符*s){
寄存器char*c;
对于(c=s;*c;c++){
如果(isupper(*c)){
*c=耐受力(*c);
}
}
返回;
}
}C
子vcl_recv{
C{
strtolower(VRT_r_req_url(sp));
}C
}

我把它放在一个单独的VCL文件中,然后为它添加了一个include。

我将分享我的解决方案,它将Richard的代码扩展为一个完整的解决方案

如果URL包含大写字母,我们将用户重定向到正确的URL,而不是在进入缓存机制之前简单地规范化URL。这可以防止搜索引擎将大小写URL与小写URL分开索引

# Define a function that converts a string to lower-case in-place.
# http://stackoverflow.com/questions/6857445
C{
    #include <ctype.h>

    static void strtolower(char *c) {
        for (; *c; c++) {
            if (isupper(*c)) {
                *c = tolower(*c);
            }
        }
    }
}C

sub vcl_recv {
    if (req.http.host ~ "[A-Z]" || req.url ~ "[A-Z]") {
        # Convert host and path to lowercase in-place.
        C{
            strtolower(VRT_GetHdr(sp, HDR_REQ, "\005host:"));
            strtolower((char *)VRT_r_req_url(sp));
        }C
        # Use req.http.location as a scratch register; any header will do.
        set req.http.location = "http://" req.http.host req.url;
        error 999 req.http.location;
    }

    # Fall-through to default
}

sub vcl_error {
    # Check for redirects - redirects are performed using: error 999 "http://target-url/"
    # Thus we piggyback the redirect target in the error response variable.
    if (obj.status == 999) {
        set obj.http.location = obj.response;
        set obj.status = 301;
        set obj.response = "Moved permanently";
        return(deliver);
    }

    # Fall-through to default
}
#定义一个将字符串转换为小写的函数。
# http://stackoverflow.com/questions/6857445
C{
#包括
静态void strtolower(字符*c){
对于(;*c;c++){
如果(isupper(*c)){
*c=耐受力(*c);
}
}
}
}C
子vcl_recv{
if(req.http.host~“[A-Z]”| | req.url~“[A-Z]”){
#就地将主机和路径转换为小写。
C{
strtolower(VRT_GetHdr(sp,HDR_请求,“\005host:”);
strtolower((char*)VRT_r_req_url(sp));
}C
#使用req.http.location作为临时寄存器;任何头都可以。
设置req.http.location=“http://”req.http.host req.url;
错误999 req.http.location;
}
#违约
}
子vcl_错误{
#检查重定向-使用以下命令执行重定向:错误999“http://target-url/"
#因此,我们将重定向目标放在错误响应变量中。
如果(对象状态==999){
设置obj.http.location=obj.response;
设置obj.status=301;
设置obj.response=“永久移动”;
归还(交付);
}
#违约
}

req.url
转换为小写时,会出现从
const char*
char*
的难看转换。。。基本上,我们正在修改字符串,尽管Varnish告诉我们不要这样做。它似乎起作用了。:-)

请注意,要从C块设置URL并避免崩溃,请使用:

VRT_l_req_url(sp,"new-string", vrt_magic_string_end);
(从“varnishd-C”输出中提取此细节。)以下是对第一个答案的未经测试的修订:

C{
    #include <ctype.h>
    //lovingly lifted from:
    //https://github.com/cosimo/varnish-accept-language/blob/master/examples/accept-language.vcl
    static void strtolower(const char *s) {
        register char *c;
        for (c=s; *c; c++) {
            if (isupper(*c)) {
                *c = tolower(*c);
            }
        }
        return;
    }
}C

sub vcl_recv {
   C{
        const char *url = VRT_r_req_url(sp);
        char urlRewritten[1000];
        strcat(urlRewritten, url);
        strtolower(urlRewritten);
        VRT_l_req_url(sp, urlRewritten, vrt_magic_string_end);
   }C
}
C{
#包括
//可爱地从:
//https://github.com/cosimo/varnish-accept-language/blob/master/examples/accept-language.vcl
静态void strtolower(常量字符*s){
寄存器char*c;
对于(c=s;*c;c++){
如果(isupper(*c)){
*c=耐受力(*c);
}
}
返回;
}
}C
子vcl_recv{
C{
const char*url=VRT_r_req_url(sp);
重写字符[1000];
strcat(url重写,url);
strtolower(URL重写);
VRT_l_req_url(sp、url重写、VRT_magic_string_end);
}C
}

必须提到的是,Varnish包括在std vmod()中使用大小写字符串的功能

这比嵌入式C路由(在Varnish 4中默认禁用)干净得多。下面是一个用于规范请求主机和url的示例

    import std;

    sub vcl_recv {

      # normalize Host header
      set req.http.Host = std.tolower(regsub(req.http.Host, ":[0-9]+", ""));
      ....

    }

    sub vcl_hash {
      # set cache key to lowercased req.url 
      hash_data(std.tolower(req.url));
      ....
    }

在最初的问题被提出近5年后,我认为我们现在有了一个更清晰的答案。在寻找“小写清漆”的过程中,这个问题仍然排在首位

下面是Fastly推荐的示例的简化变体:

# at the top of your VCL
import std;

sub vcl_recv {
  # Lowercase all incoming URLs. It will also be lowercase by the time the hash is computed.
  set req.url = std.tolower(req.url);
}

当我将其放入原型控制台应用程序中时,我得到一个“to_lower”的冲突类型错误。如果我将函数名更改为stou lower,我会得到错误:“stou lower”的类型冲突。避免崩溃,是吗?当请求带有1000个字符的URL时会发生什么情况?:)我认为这可能只在Varnish 4.0中可用,但在v3.0()中似乎确实存在。希望我当时就知道了。有趣的是,Firefox44和Chrome48都会在你按下enter键时将主机请求头小写。不完全确定主机上的tolower()是否有必要。我想这没什么。Varnish文档确认浏览器将主机小写。“值得指出的是,Varnish在对主机名或URL进行散列之前不会将其小写,因此理论上使用“Varnish.org/”和“Varnish.org/”会导致不同的缓存条目。然而,浏览器倾向于将主机名小写。”-