wandenberg / nginx-push-stream-module

A pure stream http push technology for your Nginx setup. Comet made easy and really scalable.
Other
2.22k stars 295 forks source link

Eventsource can't find channel ID when "if" block is present #127

Closed polpo closed 10 years ago

polpo commented 10 years ago

My configuration has a server running under multiple subdomains, for example *.example.com. I'd like to be able to change push_stream_allowed_origins to reflect that. Here's an example from nginx.conf:

location ~ /ev/(.*) {
    # activate event source mode for this location
    push_stream_subscriber eventsource;

    # positional channel path
    push_stream_channels_path                   $1;
    # message template
    push_stream_message_template                "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\"}";

    # ping frequency
    push_stream_ping_message_interval           10s;

    set $my_origin "";
    if ($http_origin ~* (https://.*\.example\.com(:[0-9]+)?)) {
      set $my_origin $http_origin;
    }
    push_stream_allowed_origins $my_origin;
}

But this does not seem to work. When the channel is opened, I get a 400 Bad Request error with the header X-Nginx-PushStream-Explain: No channel id provided. This is even though the GET request certainly has the channel ID right after /ev/ in the URL. If there is no if block, all works well, except I have to set push_stream_allowed_origins *; which I'd really rather not do.

polpo commented 10 years ago

Ok, I've found that if I put my if block outside of the location block, all works well.

set $my_origin "";
if ($http_origin ~* (https://.*\.example\.com(:[0-9]+)?)) {
  set $my_origin $http_origin;
}
location ~ /ev/(.*) {
    # activate event source mode for this location
    push_stream_subscriber eventsource;

    # positional channel path
    push_stream_channels_path                   $1;
    # message template
    push_stream_message_template                "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\"}";

    # ping frequency
    push_stream_ping_message_interval           10s;

    push_stream_allowed_origins $my_origin;
}
wandenberg commented 10 years ago

Hi @polpo

sorry for the long delay. The problem you had when used the if block inside the location is not related with the module itself. As you do not named the regular expression groups, the $1 variable assumes the last group matching. So when the $http_origin match with your pattern, $1 assumes the $http_origin, and connected in channels you do not desire. When the $http_origin does not match, $1 assumes an empty value, so the module complains about you do not sent a channel id.

An easy way to solve this is name the group like this below, pay attention on _$channelspath

  location ~ /ev/(?P<channels_path>.*) {
      # activate event source mode for this location
      push_stream_subscriber eventsource;

      # positional channel path
      push_stream_channels_path                   $channels_path;
      # message template
      push_stream_message_template                "{\"id\":~id~,\"channel\":\"~channel~\",\"text\":\"~text~\"}";

      # ping frequency
      push_stream_ping_message_interval           10s;

      set $my_origin "";
      if ($http_origin ~* (https://.*\.example\.com(:[0-9]+)?)) {
        set $my_origin $http_origin;
      }
      push_stream_allowed_origins $my_origin;
  }

One side note, the push_stream_allowed_origins directive will be removed on the next module version. I will put some instructions on README when this happens.