在Varnish(3.0)中,网址以区分大小写的方式处理。我的意思是http://test.com/user/a4556
与http://test.com/user/A4556
的处理方式不同。在我的网络服务器上,它们被视为相同的网址。我想做的是在它们进来时将varnish小写所有请求URL。
我设法找到this discussion但是Varnish的创建者表示我必须使用内联C来完成它。我可以使用多个正则表达式以一种简单的方式实现这一点,但看起来它肯定会失败。
理想情况下,我想要的是一个VCL配置来执行此操作(此示例可以是found here)但我会选择接受const char *
并返回的C函数const char *
(我不是C程序员,如果我的语法错误,请原谅我)。
答案 0 :(得分:2)
好的,我继续为自己解决了这个问题。这是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
}
我把它放在一个单独的VCL文件中,然后为它添加了一个包含。
答案 1 :(得分:2)
我将分享我的解决方案,将理查德的代码扩展为完整的解决方案。
如果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
}
在将const char *
转换为小写时,从char *
到req.url
有一个丑陋的演员......基本上,尽管Varnish告诉我们不要,我们正在修改字符串。 。它似乎工作。 : - )
答案 2 :(得分:2)
在提出原始问题近5年之后,我认为我们现在有了更清晰的答案。在搜索“小写清漆”时,这个SO问题仍然排在首位。
以下是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);
}
答案 3 :(得分:1)
必须提到的是,Varnish包含std vmod(https://www.varnish-cache.org/docs/trunk/reference/vmod_std.generated.html#func-tolower)中大写和小写字符串的能力
这比嵌入式C路由(在Varnish 4中默认禁用)要清晰得多。这是我用来规范化请求主机和网址的示例;
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));
....
}
答案 4 :(得分:0)
如果您正在寻找将大写字符串转换为小写字母的C函数,则会执行以下操作:
#include <ctype.h>
static char *
to_lower (char *str)
{
char *s = str;
while (*s)
{
if (isupper (*s))
*s = tolower (*s);
s++;
}
return str;
}
请注意,这会就地修改字符串。因此,您可能希望将原始字符串的副本作为参数传递。
答案 5 :(得分:0)
请注意,要设置来自C区块的网址并避免崩溃,请使用:
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
}