为什么 Perl 的 CGI::cookie 能够在 IE 中设置 cookie,但不能在 Firefox 中设置 cookie?

发布于 2024-09-29 07:57:13 字数 3532 浏览 5 评论 0原文

我有一些 Perl CGI 代码,我试图在 SourceForge 帐户的项目 Web 空间中运行它。该代码在与 IE 通信时能够很好地设置浏览器 cookie,但在与 Firefox 通信时无法设置 cookie。当我在“localhost”上使用 Apache 进行测试时,两个浏览器都工作正常。 Firefox 仅在远程 SourceForge URL 上显示错误。

搜索发现了数十个几乎重复的问题,但通常人们有完全相反的问题! (Firefox 很好,IE 有问题)

这是我调用来设置 cookie 的实用子程序:

sub setCookie {
    my $name = shift;
    my $value = shift;
    my $expires = shift;
    my $path = shift;
    my $domain = shift;
    if( !defined( $expires ) ) {
        $expires = '+4h';
    }
    if( !defined( $path ) ) {
        $path = '/';
    }
    if( !defined( $domain ) ) {
        $domain = 'steveperkins.sourceforge.net';
    }
    my $cookie = CGI::cookie(
        -name    => $name,
        -value   => $value,
        -domain   => $domain,
        -expies => $expires,
        -path    => $path
    );
    $r->header_out('Set-cookie' => $cookie);
}

有什么想法吗?我的第一个想法是某种子域问题,因为我的 SourceForge 项目 URL 中有一个子域,而“localhost”则没有。我尝试过将 cookie 域设置为我的特定子域,或者仅设置为基本“sourceforge.net”。无论如何,这似乎都没有什么区别。

更新:下面的评论中有人询问有关 HTTP 响应标头的问题。我使用网络流量分析工具 Wireshark 来监控 IE 和 Firefox 的请求和响应标头,它们的外观如下:

IE(有效)

请求

GET http://myproject.sourceforge.net/cgi-bin/myscript.cgi?page=user&userID=1 HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Referer: http://myproject.sourceforge.net/cgi-bin/myscript.cgi
Accept-Language: en-us
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.5.30729; InfoPath.1; .NET CLR 3.0.30618)
Proxy-Connection: Keep-Alive
Host: myproject.sourceforge.net
Authorization: Basic [password omitted]

响应

HTTP/1.1 200 OK
Server: nginx/0.7.63
Date: Tue, 26 Oct 2010 18:23:49 GMT
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 28 Oct 2010 18:23:49 GMT
Cache-Control: max-age=172800, proxy-revalidate
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Set-Cookie: USER=1; domain=myproject.sourceforge.net; path=/

Firefox(无效)

请求

GET http://myproject.sourceforge.net/cgi-bin/myscript.cgi HTTP/1.1
Host: myproject.sourceforge.net
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Proxy-Connection: keep-alive
Cookie: __utma=191645736.1501259260.1287701281.1288028150.1288100562.10; __utmz=191645736.1288101011.10.10.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=sourceforge%20project%20web%20space%20basic%20auth; _jsuid=4215309712123065236
Authorization: Basic [password omitted]

响应

HTTP/1.1 200 OK
Server: nginx/0.7.63
Date: Tue, 26 Oct 2010 18:17:58 GMT
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 28 Oct 2010 18:17:58 GMT
Cache-Control: max-age=172800, proxy-revalidate
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Age: 0

I have a bit of Perl CGI code which I'm trying to run in the project web space of a SourceForge account. The code is able to set a browser cookie just fine when talking to IE, but the cookie is not set when talking to Firefox. When I test with Apache on "localhost", both browsers work fine. It's only on the remote SourceForge URL that Firefox craps out.

A search has turned up dozens of near-duplicate questions, but usually people have the exact opposite problem! (Firefox being fine and IE having the problem)

Here is the utility sub I'm calling to set cookies:

sub setCookie {
    my $name = shift;
    my $value = shift;
    my $expires = shift;
    my $path = shift;
    my $domain = shift;
    if( !defined( $expires ) ) {
        $expires = '+4h';
    }
    if( !defined( $path ) ) {
        $path = '/';
    }
    if( !defined( $domain ) ) {
        $domain = 'steveperkins.sourceforge.net';
    }
    my $cookie = CGI::cookie(
        -name    => $name,
        -value   => $value,
        -domain   => $domain,
        -expies => $expires,
        -path    => $path
    );
    $r->header_out('Set-cookie' => $cookie);
}

Any ideas? My first thought was some kind of subdomain issue, because my SourceForge project URL has a subdomain in it while "localhost" does not. I've experimented with setting the cookie domain to my specific subdomain, or to just the base "sourceforge.net". It doesn't seem to make a difference either way.

UPDATE: Someone in the comments below asked about the HTTP response headers. I've used the network traffic analyzer tool Wireshark to monitor the request and response headers for both IE and Firefox, and here's what they look like:

IE (works)

Request

GET http://myproject.sourceforge.net/cgi-bin/myscript.cgi?page=user&userID=1 HTTP/1.1
Accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/x-ms-application, application/vnd.ms-xpsdocument, application/xaml+xml, application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, application/x-shockwave-flash, */*
Referer: http://myproject.sourceforge.net/cgi-bin/myscript.cgi
Accept-Language: en-us
UA-CPU: x86
Accept-Encoding: gzip, deflate
User-Agent: Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 1.1.4322; .NET CLR 3.5.30729; InfoPath.1; .NET CLR 3.0.30618)
Proxy-Connection: Keep-Alive
Host: myproject.sourceforge.net
Authorization: Basic [password omitted]

Response

HTTP/1.1 200 OK
Server: nginx/0.7.63
Date: Tue, 26 Oct 2010 18:23:49 GMT
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 28 Oct 2010 18:23:49 GMT
Cache-Control: max-age=172800, proxy-revalidate
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Set-Cookie: USER=1; domain=myproject.sourceforge.net; path=/

Firefox (doesn't work)

Request

GET http://myproject.sourceforge.net/cgi-bin/myscript.cgi HTTP/1.1
Host: myproject.sourceforge.net
User-Agent: Mozilla/5.0 (Windows; U; Windows NT 6.0; en-US; rv:1.9.2.11) Gecko/20101012 Firefox/3.6.11
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7
Keep-Alive: 115
Proxy-Connection: keep-alive
Cookie: __utma=191645736.1501259260.1287701281.1288028150.1288100562.10; __utmz=191645736.1288101011.10.10.utmcsr=google|utmccn=(organic)|utmcmd=organic|utmctr=sourceforge%20project%20web%20space%20basic%20auth; _jsuid=4215309712123065236
Authorization: Basic [password omitted]

Response

HTTP/1.1 200 OK
Server: nginx/0.7.63
Date: Tue, 26 Oct 2010 18:17:58 GMT
Content-Type: text/html; charset=ISO-8859-1
Expires: Thu, 28 Oct 2010 18:17:58 GMT
Cache-Control: max-age=172800, proxy-revalidate
Transfer-Encoding: chunked
Proxy-Connection: Keep-Alive
Connection: Keep-Alive
Content-Encoding: gzip
Age: 0

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

濫情▎り 2024-10-06 07:57:13

我想说的是,您在设置过期时间时遇到了一个错误,

if( !defined( $path ) ) {
    $expires = '/';
}

应该

if( !defined( $path ) ) {
    $path = '/';
}

更新:根据您上面使用wireshark提供的信息,我将检查当Firefox进入时是否实际调用了setCookie。(两者都顺便说一句,URL 不同,这可能表明代码中的逻辑根据 URL 跳过了 setCookie 调用)。还可以尝试在两个浏览器中使用相同的 URL,看看会发生什么。

I would say that you've got a bug in setting your expiration

if( !defined( $path ) ) {
    $expires = '/';
}

should be

if( !defined( $path ) ) {
    $path = '/';
}

Updated: Based on the information you provide above using wireshark I would check if the setCookie is actually called when Firefox comes in. (both URL are different btw, it could be an indication that the logic in your code skips the setCookie call based on the URL). Also try to use the same URL with both browser and see what happens.

旧话新听 2024-10-06 07:57:13

啊!事实证明,问题在于,当在“localhost”上运行时,只有一个 cookie 正在运行,但在 SourceForge 的服务器上托管时,却有多个 cookie 正在运行。

如果您查看上面问题中剪切粘贴的 Firefox 请求标头,您会注意到有几个 cookie 名称-值对...每对都用分号分隔。 我的代码未能解释这一点,所以它看到的只是一个巨大的格式错误的 cookie。

我仍然不是 100% 确定为什么它在 IE 中部分工作,我将来可能会重新审视这个,看看是否可以学到更多。但目前这基本上是一个有争议的问题。我将代码更改为按分号拆分,然后按等号拆分,我现在处理 cookie 得很好。

感谢大家的见解和建议!皮埃尔-吕克,出于对下面所有评论的感激之情,我确实给你的答案投了赞成票。

    sub getCookie {
    my $cookieName = shift;
    my %headers = $r->headers_in;
    my @keys = keys( %headers );
    foreach my $name ( @keys ) {
        if( $name eq 'Cookie') {
        my @semicolontokens = split( ';', $headers{$name} );
        foreach my $splitname ( @semicolontokens ) {
           $splitname =~ s/^\s+//;
           $splitname =~ s/\s+$//;
           my @pair = split( '=', $splitname );
               if( $pair[0] eq $cookieName ) {
               return $pair[1];
               }
           }
       }
   }

Argh! It turns out the issue is that there is only one cookie in play when running on "localhost", but there are multiple cookies in play when hosted on SourceForge's servers.

If you look at the Firefox request headers cut-n-pasted in the question above, you'll notice that there are several cookie name-value pairs... with each pair separated by semicolons. My code was failing to account for this, so all it saw was one giant mal-formed cookie.

I'm still not 100% sure why it was partially working in IE, and I may revisit this in the future to see if more can be learned. But it's basically a moot point for now. I altered the code to split on semicolons AND then split on equals signs, I'm processing cookies just fine now.

Thanks to everyone for your insight and suggestions! Pierre-Luc, I did give your answer an upvote out of gratitude for all the comments beneath it.

    sub getCookie {
    my $cookieName = shift;
    my %headers = $r->headers_in;
    my @keys = keys( %headers );
    foreach my $name ( @keys ) {
        if( $name eq 'Cookie') {
        my @semicolontokens = split( ';', $headers{$name} );
        foreach my $splitname ( @semicolontokens ) {
           $splitname =~ s/^\s+//;
           $splitname =~ s/\s+$//;
           my @pair = split( '=', $splitname );
               if( $pair[0] eq $cookieName ) {
               return $pair[1];
               }
           }
       }
   }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文