Commit 5bc59dcd authored by Wandenberg Peixoto's avatar Wandenberg Peixoto

adding some headers to allow cross domain requests

parent f6cf36f7
...@@ -102,6 +102,7 @@ typedef struct { ...@@ -102,6 +102,7 @@ typedef struct {
ngx_http_complex_value_t *user_agent; ngx_http_complex_value_t *user_agent;
ngx_str_t padding_by_user_agent; ngx_str_t padding_by_user_agent;
ngx_http_push_stream_padding_t *paddings; ngx_http_push_stream_padding_t *paddings;
ngx_str_t allowed_origins;
} ngx_http_push_stream_loc_conf_t; } ngx_http_push_stream_loc_conf_t;
// shared memory segment name // shared memory segment name
...@@ -276,6 +277,9 @@ static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_CONNECTION = ngx_string("Con ...@@ -276,6 +277,9 @@ static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_CONNECTION = ngx_string("Con
static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_SEC_WEBSOCKET_KEY = ngx_string("Sec-WebSocket-Key"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_SEC_WEBSOCKET_KEY = ngx_string("Sec-WebSocket-Key");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_SEC_WEBSOCKET_VERSION = ngx_string("Sec-WebSocket-Version"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_SEC_WEBSOCKET_VERSION = ngx_string("Sec-WebSocket-Version");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_SEC_WEBSOCKET_ACCEPT = ngx_string("Sec-WebSocket-Accept"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_SEC_WEBSOCKET_ACCEPT = ngx_string("Sec-WebSocket-Accept");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN = ngx_string("Access-Control-Allow-Origin");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_METHODS = ngx_string("Access-Control-Allow-Methods");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_HEADERS = ngx_string("Access-Control-Allow-Headers");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_WEBSOCKET_UPGRADE = ngx_string("WebSocket"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_WEBSOCKET_UPGRADE = ngx_string("WebSocket");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_WEBSOCKET_CONNECTION = ngx_string("Upgrade"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_WEBSOCKET_CONNECTION = ngx_string("Upgrade");
...@@ -326,6 +330,8 @@ static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_DELETE_METHODS = ngx ...@@ -326,6 +330,8 @@ static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_DELETE_METHODS = ngx
static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_METHODS = ngx_string("GET, POST"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_METHODS = ngx_string("GET, POST");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOW_GET = ngx_string("GET"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOW_GET = ngx_string("GET");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_ALLOWED_HEADERS = ngx_string("If-Modified-Since,If-None-Match");
#define NGX_HTTP_PUSH_STREAM_CHECK_AND_FINALIZE_REQUEST_ON_ERROR(val, fail, r, errormessage) \ #define NGX_HTTP_PUSH_STREAM_CHECK_AND_FINALIZE_REQUEST_ON_ERROR(val, fail, r, errormessage) \
if (val == fail) { \ if (val == fail) { \
ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, errormessage); \ ngx_log_error(NGX_LOG_ERR, (r)->connection->log, 0, errormessage); \
......
...@@ -41,6 +41,8 @@ static time_t NGX_HTTP_PUSH_STREAM_DEFAULT_SHM_MEMORY_CLEANUP_OBJECTS_TTL = 30; ...@@ -41,6 +41,8 @@ static time_t NGX_HTTP_PUSH_STREAM_DEFAULT_SHM_MEMORY_CLEANUP_OBJECTS_TTL = 30;
#define NGX_HTTP_PUSH_STREAM_DEFAULT_MESSAGE_TEMPLATE "~text~" #define NGX_HTTP_PUSH_STREAM_DEFAULT_MESSAGE_TEMPLATE "~text~"
#define NGX_HTTP_PUSH_STREAM_DEFAULT_FOOTER_TEMPLATE "" #define NGX_HTTP_PUSH_STREAM_DEFAULT_FOOTER_TEMPLATE ""
#define NGX_HTTP_PUSH_STREAM_DEFAULT_ALLOWED_ORIGINS "*"
#define NGX_HTTP_PUSH_STREAM_DEFAULT_PADDING_BY_USER_AGENT "[A|a]ndroid 2,4097,4097:[S|s]afari,1025,0" #define NGX_HTTP_PUSH_STREAM_DEFAULT_PADDING_BY_USER_AGENT "[A|a]ndroid 2,4097,4097:[S|s]afari,1025,0"
#define NGX_HTTP_PUSH_STREAM_DEFAULT_CONTENT_TYPE "text/plain" #define NGX_HTTP_PUSH_STREAM_DEFAULT_CONTENT_TYPE "text/plain"
......
...@@ -27,6 +27,6 @@ ...@@ -27,6 +27,6 @@
#define NGX_HTTP_PUSH_STREAM_MODULE_VERSION_H_ #define NGX_HTTP_PUSH_STREAM_MODULE_VERSION_H_
static const ngx_str_t NGX_HTTP_PUSH_STREAM_TAG = ngx_string("0.3.3"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_TAG = ngx_string("0.3.3");
static const ngx_str_t NGX_HTTP_PUSH_STREAM_COMMIT = ngx_string("bc4aeda8fa33e5806abe97cbee93f9fa045af834"); static const ngx_str_t NGX_HTTP_PUSH_STREAM_COMMIT = ngx_string("f6cf36f7d03be43f59d8f9d14b0f332d1ff7f3db");
#endif /* NGX_HTTP_PUSH_STREAM_MODULE_VERSION_H_ */ #endif /* NGX_HTTP_PUSH_STREAM_MODULE_VERSION_H_ */
...@@ -37,6 +37,8 @@ ngx_http_push_stream_publisher_handler(ngx_http_request_t *r) ...@@ -37,6 +37,8 @@ ngx_http_push_stream_publisher_handler(ngx_http_request_t *r)
r->keepalive = cf->keepalive; r->keepalive = cf->keepalive;
ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, &cf->allowed_origins);
// only accept GET, POST and DELETE methods if enable publisher administration // only accept GET, POST and DELETE methods if enable publisher administration
if ((cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && !(r->method & (NGX_HTTP_GET|NGX_HTTP_POST|NGX_HTTP_DELETE))) { if ((cf->location_type == NGX_HTTP_PUSH_STREAM_PUBLISHER_MODE_ADMIN) && !(r->method & (NGX_HTTP_GET|NGX_HTTP_POST|NGX_HTTP_DELETE))) {
ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_DELETE_METHODS); ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET_POST_DELETE_METHODS);
......
...@@ -224,6 +224,12 @@ static ngx_command_t ngx_http_push_stream_commands[] = { ...@@ -224,6 +224,12 @@ static ngx_command_t ngx_http_push_stream_commands[] = {
NGX_HTTP_LOC_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_push_stream_loc_conf_t, padding_by_user_agent), offsetof(ngx_http_push_stream_loc_conf_t, padding_by_user_agent),
NULL }, NULL },
{ ngx_string("push_stream_allowed_origins"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
ngx_conf_set_str_slot,
NGX_HTTP_LOC_CONF_OFFSET,
offsetof(ngx_http_push_stream_loc_conf_t, allowed_origins),
NULL },
ngx_null_command ngx_null_command
}; };
...@@ -501,7 +507,7 @@ ngx_http_push_stream_init_main_conf(ngx_conf_t *cf, void *parent) ...@@ -501,7 +507,7 @@ ngx_http_push_stream_init_main_conf(ngx_conf_t *cf, void *parent)
backtrack_parser->err.data = errstr; backtrack_parser->err.data = errstr;
if (ngx_regex_compile(backtrack_parser) != NGX_OK) { if (ngx_regex_compile(backtrack_parser) != NGX_OK) {
ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "push stream module: unable to compile backtrack parser pattern %V", &NGX_HTTP_PUSH_STREAM_BACKTRACK_PATTERN); ngx_conf_log_error(NGX_LOG_ERR, cf, 0, "push stream module: unable to compile backtrack parser pattern %V", &NGX_HTTP_PUSH_STREAM_BACKTRACK_PATTERN);
return NGX_CONF_ERROR; return NGX_CONF_ERROR;
} }
...@@ -541,6 +547,7 @@ ngx_http_push_stream_create_loc_conf(ngx_conf_t *cf) ...@@ -541,6 +547,7 @@ ngx_http_push_stream_create_loc_conf(ngx_conf_t *cf)
lcf->user_agent = NULL; lcf->user_agent = NULL;
lcf->padding_by_user_agent.data = NULL; lcf->padding_by_user_agent.data = NULL;
lcf->paddings = NULL; lcf->paddings = NULL;
lcf->allowed_origins.data = NULL;
return lcf; return lcf;
} }
...@@ -565,6 +572,7 @@ ngx_http_push_stream_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ...@@ -565,6 +572,7 @@ ngx_http_push_stream_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_msec_value(conf->longpolling_connection_ttl, prev->longpolling_connection_ttl, conf->subscriber_connection_ttl); ngx_conf_merge_msec_value(conf->longpolling_connection_ttl, prev->longpolling_connection_ttl, conf->subscriber_connection_ttl);
ngx_conf_merge_value(conf->websocket_allow_publish, prev->websocket_allow_publish, 0); ngx_conf_merge_value(conf->websocket_allow_publish, prev->websocket_allow_publish, 0);
ngx_conf_merge_str_value(conf->padding_by_user_agent, prev->padding_by_user_agent, NGX_HTTP_PUSH_STREAM_DEFAULT_PADDING_BY_USER_AGENT); ngx_conf_merge_str_value(conf->padding_by_user_agent, prev->padding_by_user_agent, NGX_HTTP_PUSH_STREAM_DEFAULT_PADDING_BY_USER_AGENT);
ngx_conf_merge_str_value(conf->allowed_origins, prev->allowed_origins, NGX_HTTP_PUSH_STREAM_DEFAULT_ALLOWED_ORIGINS);
if (conf->last_received_message_time == NULL) { if (conf->last_received_message_time == NULL) {
conf->last_received_message_time = prev->last_received_message_time; conf->last_received_message_time = prev->last_received_message_time;
......
...@@ -52,6 +52,15 @@ ngx_http_push_stream_subscriber_handler(ngx_http_request_t *r) ...@@ -52,6 +52,15 @@ ngx_http_push_stream_subscriber_handler(ngx_http_request_t *r)
ngx_int_t status_code; ngx_int_t status_code;
ngx_str_t *explain_error_message; ngx_str_t *explain_error_message;
// add headers to support cross domain requests
ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_ORIGIN, &cf->allowed_origins);
ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_METHODS, &NGX_HTTP_PUSH_STREAM_ALLOW_GET);
ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ACCESS_CONTROL_ALLOW_HEADERS, &NGX_HTTP_PUSH_STREAM_ALLOWED_HEADERS);
if (r->method & NGX_HTTP_OPTIONS) {
return ngx_http_push_stream_send_only_header_response(r, NGX_HTTP_OK, NULL);
}
// only accept GET method // only accept GET method
if (!(r->method & NGX_HTTP_GET)) { if (!(r->method & NGX_HTTP_GET)) {
ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET); ngx_http_push_stream_add_response_header(r, &NGX_HTTP_PUSH_STREAM_HEADER_ALLOW, &NGX_HTTP_PUSH_STREAM_ALLOW_GET);
......
...@@ -314,6 +314,8 @@ http { ...@@ -314,6 +314,8 @@ http {
<%= "push_stream_authorized_channels_only #{@authorized_channels_only};" unless @authorized_channels_only.nil? %> <%= "push_stream_authorized_channels_only #{@authorized_channels_only};" unless @authorized_channels_only.nil? %>
<%= "push_stream_broadcast_channel_max_qtd #{@broadcast_channel_max_qtd};" unless @broadcast_channel_max_qtd.nil? %> <%= "push_stream_broadcast_channel_max_qtd #{@broadcast_channel_max_qtd};" unless @broadcast_channel_max_qtd.nil? %>
<%= "push_stream_allowed_origins #{@allowed_origins};" unless @allowed_origins.nil? %>
server { server {
listen <%=nginx_port%>; listen <%=nginx_port%>;
server_name <%=nginx_host%>; server_name <%=nginx_host%>;
......
...@@ -380,4 +380,33 @@ class TestPublisher < Test::Unit::TestCase ...@@ -380,4 +380,33 @@ class TestPublisher < Test::Unit::TestCase
} }
end end
def test_default_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_default_access_control_allow_origin_header'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).get :head => headers, :timeout => 30
pub.callback {
assert_equal("*", pub.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
}
end
def config_test_custom_access_control_allow_origin_header
@allowed_origins = "custom.domain.com"
end
def test_custom_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_custom_access_control_allow_origin_header'
EventMachine.run {
pub = EventMachine::HttpRequest.new(nginx_address + '/pub?id=' + channel).get :head => headers, :timeout => 30
pub.callback {
assert_equal("custom.domain.com", pub.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
}
end
end end
...@@ -8,6 +8,13 @@ class TestSubscriber < Test::Unit::TestCase ...@@ -8,6 +8,13 @@ class TestSubscriber < Test::Unit::TestCase
end end
def test_accepted_methods def test_accepted_methods
# testing OPTIONS method, EventMachine::HttpRequest does not have support to it
socket = TCPSocket.open(nginx_host, nginx_port)
socket.print("OPTIONS /sub/ch_test_accepted_methods_0 HTTP/1.0\r\n\r\n")
headers, body = read_response(socket)
assert(headers.match(/HTTP\/1\.1 200 OK/), "Didn't receive right header")
assert(headers.match(/Content-Length: 0/), "Didn't receive right header")
EventMachine.run { EventMachine.run {
multi = EventMachine::MultiRequest.new multi = EventMachine::MultiRequest.new
...@@ -966,4 +973,55 @@ class TestSubscriber < Test::Unit::TestCase ...@@ -966,4 +973,55 @@ class TestSubscriber < Test::Unit::TestCase
add_test_timeout add_test_timeout
} }
end end
def test_access_control_allow_headers
headers = {'accept' => 'application/json'}
channel = 'test_access_control_allow_headers'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("*", sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
assert_equal("GET", sub_1.response_header['ACCESS_CONTROL_ALLOW_METHODS'], "Didn't receive the right header")
assert_equal("If-Modified-Since,If-None-Match", sub_1.response_header['ACCESS_CONTROL_ALLOW_HEADERS'], "Didn't receive the right header")
EventMachine.stop
}
add_test_timeout
}
end
def test_default_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_default_access_control_allow_origin_header'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("*", sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
add_test_timeout
}
end
def config_test_custom_access_control_allow_origin_header
@allowed_origins = "custom.domain.com"
end
def test_custom_access_control_allow_origin_header
headers = {'accept' => 'application/json'}
channel = 'test_custom_access_control_allow_origin_header'
EventMachine.run {
sub_1 = EventMachine::HttpRequest.new(nginx_address + '/sub/' + channel.to_s).get :head => headers, :timeout => 30
sub_1.stream { |chunk|
assert_equal("custom.domain.com", sub_1.response_header['ACCESS_CONTROL_ALLOW_ORIGIN'], "Didn't receive the right header")
EventMachine.stop
}
add_test_timeout
}
end
end end
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment