HTTP参数未在Apache 2.4中断功能中发送

时间:2014-07-13 16:40:30

标签: apache http ubuntu apache2 apache2.4

所以让我们从一些背景开始吧。我有一个3层系统,在Apache的服务器上用mod_wsgi运行的django中实现了API。

今天我决定将运行在DigitalOcean的服务器从Ubuntu 12.04升级到Ubuntu 14.04。没什么特别的,只有Apache2也更新到版本 2.4.7 。在浪费了当天的大部分时间来查明they actually changed the default folder from /var/www to /var/www/html,破坏功能之后,我决定测试我的API。在没有触及任何一行代码的情况下,我的一些功能无法正常工作。

我将使用其中一个较小的函数作为示例:

# Returns the location information for the specified animal, within the specified period.
@csrf_exempt # Prevents Cross Site Request Forgery errors.
def get_animal_location_reports_in_time_frame(request):
    start_date = request.META.get('HTTP_START_DATE')
    end_date = request.META.get('HTTP_END_DATE')
    reports = ur_animal_location_reports.objects.select_related('species').filter(date__range=(start_date, end_date), species__localizable=True).order_by('-date')
    # Filter by animal if parameter sent.
    if request.META.get('HTTP_SPECIES') is not None:
        reports = reports.filter(species=request.META.get('HTTP_SPECIES'))

    # Add each information to the result object.
    response = []
    for rep in reports:
        response.append(dict(
            ID=rep.id,
            Species=rep.species.ai_species_species,
            Species_slug=rep.species.ai_species_species_slug,
            Date=str(rep.date),
            Lat=rep.latitude,
            Lon=rep.longitude,
            Verified=(rep.tracker is not None),
        ))
    # Return the object as a JSON string.
    return HttpResponse(json.dumps(response, indent = 4))

经过一些调试后,我发现request.META.get('HTTP_START_DATE')request.META.get('HTTP_END_DATE')正在返回None。我尝试了很多客户端,从REST客户端(例如PyCharm和RestConsole for Chrome中的客户端)到通常与API通信的Android应用程序,但结果是相同的,这两个参数没有被发送。

然后我决定测试是否正在发送其他参数,而我感到非常恐怖。在上面的函数中,request.META.get('HTTP_SPECIES')将具有正确的值。

在对名称进行了一些摆弄之后,我发现 ALL 标题中包含_字符的参数不会进入API。

所以我想,很酷,我只会使用-代替_,这应该有效,对吧?错误。 -_

的身份到达API

此时我完全不解,所以我决定找到罪魁祸首。我使用django开发服务器运行API,运行:

sudo python manage.py runserver 0.0.0.0:8000

使用相同的客户端发送相同的参数时,API可以很好地选择它们!因此,django不会造成这种情况,Ubuntu 14.04不会造成这种情况,唯一可能导致它的是Apache 2.4.7!

现在将默认文件夹从/var/www移动到/var/www/html,从而打破了功能,一切(在我看来)非常愚蠢的原因已经够糟了,但这太多了。

有没有人知道这里发生了什么以及为什么?

2 个答案:

答案 0 :(得分:3)

这是Apache 2.4的变化。

这是Apache HTTP Server Documentation Version 2.4

  

MOD CGI,MOD INCLUDE,MOD ISAPI,...标题到环境变量的翻译比以前更严格   通过标头注入缓解一些可能的跨站点脚本攻击。包含无效字符的标头    (包括下划线) 现在以静默方式删除。 Apache中的环境变量(p.81)有一些指针   关于如何解决需要此类标头的损坏的旧客户端。 (这会影响所有使用的模块   这些环境变量。)

- 第11页

  

出于可移植性的原因,环境变量的名称可能只包含字母,数字和下划线字符。另外,第一个字符可能不是数字。 当传递给CGI脚本和SSI页面时,与此限制不匹配的字符将被下划线替换。

- Page 86

换句话说,这是一个非常重要的变化。所以你需要重写你的应用程序,所以发送破折号而不是下划线,而Apache又将替换下划线。

修改

这似乎有办法解决这个问题。如果您在apache.org上查看this document,可以看到您可以通过将.htaccess的值放入名为foo_bar的新变量中,在foo-bar中修复它而后者又将由Apache转回foo_bar。见下面的例子:

SetEnvIfNoCase ^foo.bar$ ^(.*)$ fix_accept_encoding=$1
RequestHeader set foo-bar %{fix_accept_encoding}e env=fix_accept_encoding

唯一的缺点是你必须为每个标题制定一个规则,但你不必对客户端或服务器端的代码进行任何更改。

答案 1 :(得分:0)

你确定Django也没有升级吗?

https://docs.djangoproject.com/en/dev/ref/request-response/

  

除了CONTENT_LENGTH和CONTENT_TYPE之外,如上所述,请求中的任何HTTP头都将转换为META密钥,方法是将所有字符转换为大写,用下划线替换任何连字符,并在名称中添加HTTP_前缀。因此,例如,名为X-Bender的标头将映射到META密钥HTTP_X_BENDER。

关键部分是:Django正在转换' - '强调并预先设置HTTP _'它。如果您在调用 api时已经添加了HTTP_前缀,则可能会增加一倍。例如' HTTP_HTTP_SPECIES'