# HG changeset patch # User Maxim Dounin # Date 1386183687 -14400 # Node ID c82b2e020b9f55aff4135747ca228af8851598dd # Parent 692afcea9d0d05c10b1dd7f2bd095dd014665f4c SSL support in the uwsgi module. Based on patch by Roberto De Ioris. diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -34,6 +34,12 @@ typedef struct { ngx_uint_t modifier1; ngx_uint_t modifier2; + +#if (NGX_HTTP_SSL) + ngx_uint_t ssl; + ngx_uint_t ssl_protocols; + ngx_str_t ssl_ciphers; +#endif } ngx_http_uwsgi_loc_conf_t; @@ -66,6 +72,11 @@ static char *ngx_http_uwsgi_cache_key(ng void *conf); #endif +#if (NGX_HTTP_SSL) +static ngx_int_t ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, + ngx_http_uwsgi_loc_conf_t *uwcf); +#endif + static ngx_conf_num_bounds_t ngx_http_uwsgi_modifier_bounds = { ngx_conf_check_num_bounds, 0, 255 @@ -86,6 +97,20 @@ static ngx_conf_bitmask_t ngx_http_uwsgi }; +#if (NGX_HTTP_SSL) + +static ngx_conf_bitmask_t ngx_http_uwsgi_ssl_protocols[] = { + { ngx_string("SSLv2"), NGX_SSL_SSLv2 }, + { ngx_string("SSLv3"), NGX_SSL_SSLv3 }, + { ngx_string("TLSv1"), NGX_SSL_TLSv1 }, + { ngx_string("TLSv1.1"), NGX_SSL_TLSv1_1 }, + { ngx_string("TLSv1.2"), NGX_SSL_TLSv1_2 }, + { ngx_null_string, 0 } +}; + +#endif + + ngx_module_t ngx_http_uwsgi_module; @@ -361,6 +386,31 @@ static ngx_command_t ngx_http_uwsgi_comm offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ignore_headers), &ngx_http_upstream_ignore_headers_masks }, +#if (NGX_HTTP_SSL) + + { ngx_string("uwsgi_ssl_session_reuse"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, upstream.ssl_session_reuse), + NULL }, + + { ngx_string("uwsgi_ssl_protocols"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_uwsgi_loc_conf_t, ssl_protocols), + &ngx_http_uwsgi_ssl_protocols }, + + { ngx_string("uwsgi_ssl_ciphers"), + 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_uwsgi_loc_conf_t, ssl_ciphers), + NULL }, + +#endif + ngx_null_command }; @@ -448,15 +498,29 @@ ngx_http_uwsgi_handler(ngx_http_request_ uwcf = ngx_http_get_module_loc_conf(r, ngx_http_uwsgi_module); - if (uwcf->uwsgi_lengths) { + u = r->upstream; + + if (uwcf->uwsgi_lengths == NULL) { + +#if (NGX_HTTP_SSL) + u->ssl = (uwcf->upstream.ssl != NULL); + + if (u->ssl) { + ngx_str_set(&u->schema, "suwsgi://"); + + } else { + ngx_str_set(&u->schema, "uwsgi://"); + } +#else + ngx_str_set(&u->schema, "uwsgi://"); +#endif + + } else { if (ngx_http_uwsgi_eval(r, uwcf) != NGX_OK) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } } - u = r->upstream; - - ngx_str_set(&u->schema, "uwsgi://"); u->output.tag = (ngx_buf_tag_t) &ngx_http_uwsgi_module; u->conf = &uwcf->upstream; @@ -494,6 +558,7 @@ ngx_http_uwsgi_handler(ngx_http_request_ static ngx_int_t ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) { + size_t add; ngx_url_t url; ngx_http_upstream_t *u; @@ -506,6 +571,41 @@ ngx_http_uwsgi_eval(ngx_http_request_t * return NGX_ERROR; } + if (url.url.len > 8 + && ngx_strncasecmp(url.url.data, (u_char *) "uwsgi://", 8) == 0) + { + add = 8; + + } else if (url.url.len > 9 + && ngx_strncasecmp(url.url.data, (u_char *) "suwsgi://", 9) == 0) + { + +#if (NGX_HTTP_SSL) + add = 9; + r->upstream->ssl = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "suwsgi protocol requires SSL support"); + return NGX_CONF_ERROR; +#endif + + } else { + add = 0; + } + + u = r->upstream; + + if (add) { + u->schema.len = add; + u->schema.data = url.url.data; + + url.url.data += add; + url.url.len -= add; + + } else { + ngx_str_set(&u->schema, (u_char *) "uwsgi://"); + } + url.no_resolve = 1; if (ngx_parse_url(r->pool, &url) != NGX_OK) { @@ -517,8 +617,6 @@ ngx_http_uwsgi_eval(ngx_http_request_t * return NGX_ERROR; } - u = r->upstream; - u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); if (u->resolved == NULL) { return NGX_ERROR; @@ -1145,6 +1243,9 @@ ngx_http_uwsgi_create_loc_conf(ngx_conf_ conf->upstream.pass_headers = NGX_CONF_UNSET_PTR; conf->upstream.intercept_errors = NGX_CONF_UNSET; +#if (NGX_HTTP_SSL) + conf->upstream.ssl_session_reuse = NGX_CONF_UNSET; +#endif /* "uwsgi_cyclic_temp_file" is disabled */ conf->upstream.cyclic_temp_file = 0; @@ -1392,6 +1493,27 @@ ngx_http_uwsgi_merge_loc_conf(ngx_conf_t ngx_conf_merge_value(conf->upstream.intercept_errors, prev->upstream.intercept_errors, 0); +#if (NGX_HTTP_SSL) + ngx_conf_merge_value(conf->upstream.ssl_session_reuse, + prev->upstream.ssl_session_reuse, 1); + + ngx_conf_merge_bitmask_value(conf->ssl_protocols, prev->ssl_protocols, + (NGX_CONF_BITMASK_SET|NGX_SSL_SSLv3 + |NGX_SSL_TLSv1|NGX_SSL_TLSv1_1 + |NGX_SSL_TLSv1_2)); + + ngx_conf_merge_str_value(conf->ssl_ciphers, prev->ssl_ciphers, + "DEFAULT"); + + if (conf->ssl && ngx_http_uwsgi_set_ssl(cf, conf) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (conf->upstream.ssl == NULL) { + conf->upstream.ssl = prev->upstream.ssl; + } +#endif + ngx_conf_merge_str_value(conf->uwsgi_string, prev->uwsgi_string, ""); hash.max_size = 512; @@ -1670,6 +1792,7 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ { ngx_http_uwsgi_loc_conf_t *uwcf = conf; + size_t add; ngx_url_t u; ngx_str_t *value, *url; ngx_uint_t n; @@ -1705,12 +1828,35 @@ ngx_http_uwsgi_pass(ngx_conf_t *cf, ngx_ return NGX_CONF_ERROR; } +#if (NGX_HTTP_SSL) + uwcf->ssl = 1; +#endif + return NGX_CONF_OK; } + if (ngx_strncasecmp(url->data, (u_char *) "uwsgi://", 8) == 0) { + add = 8; + + } else if (ngx_strncasecmp(url->data, (u_char *) "suwsgi://", 9) == 0) { + +#if (NGX_HTTP_SSL) + add = 9; + uwcf->ssl = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "suwsgi protocol requires SSL support"); + return NGX_CONF_ERROR; +#endif + + } else { + add = 0; + } + ngx_memzero(&u, sizeof(ngx_url_t)); - u.url = value[1]; + u.url.len = url->len - add; + u.url.data = url->data + add; u.no_resolve = 1; uwcf->upstream.upstream = ngx_http_upstream_add(cf, &u, 0); @@ -1844,3 +1990,47 @@ ngx_http_uwsgi_cache_key(ngx_conf_t *cf, } #endif + + +#if (NGX_HTTP_SSL) + +static ngx_int_t +ngx_http_uwsgi_set_ssl(ngx_conf_t *cf, ngx_http_uwsgi_loc_conf_t *uwcf) +{ + ngx_pool_cleanup_t *cln; + + uwcf->upstream.ssl = ngx_pcalloc(cf->pool, sizeof(ngx_ssl_t)); + if (uwcf->upstream.ssl == NULL) { + return NGX_ERROR; + } + + uwcf->upstream.ssl->log = cf->log; + + if (ngx_ssl_create(uwcf->upstream.ssl, uwcf->ssl_protocols, NULL) + != NGX_OK) + { + return NGX_ERROR; + } + + if (SSL_CTX_set_cipher_list(uwcf->upstream.ssl->ctx, + (const char *) uwcf->ssl_ciphers.data) + == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &uwcf->ssl_ciphers); + return NGX_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + return NGX_ERROR; + } + + cln->handler = ngx_ssl_cleanup_ctx; + cln->data = uwcf->upstream.ssl; + + return NGX_OK; +} + +#endif