@@ -3267,6 +3267,195 @@ ngx_js_preload_object(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
32673267}
32683268
32693269
3270+ static ngx_int_t
3271+ ngx_js_build_proxy_auth_header (ngx_pool_t * pool , ngx_str_t * auth_header ,
3272+ ngx_str_t * user , ngx_str_t * pass )
3273+ {
3274+ u_char * p ;
3275+ size_t len ;
3276+ ngx_str_t userpass , b64 ;
3277+
3278+ userpass .len = user -> len + 1 + pass -> len ;
3279+ userpass .data = ngx_pnalloc (pool , userpass .len );
3280+ if (userpass .data == NULL ) {
3281+ return NGX_ERROR ;
3282+ }
3283+
3284+ p = ngx_cpymem (userpass .data , user -> data , user -> len );
3285+ * p ++ = ':' ;
3286+ ngx_memcpy (p , pass -> data , pass -> len );
3287+
3288+ b64 .len = ngx_base64_encoded_length (userpass .len );
3289+ b64 .data = ngx_pnalloc (pool , b64 .len );
3290+ if (b64 .data == NULL ) {
3291+ return NGX_ERROR ;
3292+ }
3293+
3294+ ngx_encode_base64 (& b64 , & userpass );
3295+
3296+ len = sizeof ("Proxy-Authorization: Basic \r\n" ) - 1 + b64 .len ;
3297+ p = ngx_pnalloc (pool , len );
3298+ if (p == NULL ) {
3299+ return NGX_ERROR ;
3300+ }
3301+
3302+ ngx_sprintf (p , "Proxy-Authorization: Basic %V\r\n" , & b64 );
3303+ auth_header -> data = p ;
3304+ auth_header -> len = len ;
3305+
3306+ return NGX_OK ;
3307+ }
3308+
3309+
3310+ ngx_int_t
3311+ ngx_js_parse_proxy_url (ngx_pool_t * pool , ngx_log_t * log , ngx_str_t * url ,
3312+ ngx_url_t * * url_out , ngx_str_t * auth_header_out )
3313+ {
3314+ u_char * p , * at , * colon , * host_start , * user_start , * pass_start ;
3315+ u_char * decoded_user , * decoded_pass , * decoded_end ;
3316+ size_t user_len , pass_len ;
3317+ ngx_url_t * u ;
3318+ ngx_str_t user , pass ;
3319+
3320+ if (url -> len == 0 ) {
3321+ * url_out = NULL ;
3322+ ngx_str_null (auth_header_out );
3323+ return NGX_OK ;
3324+ }
3325+
3326+ if (ngx_strncmp (url -> data , "http://" , sizeof ("http://" ) - 1 ) != 0 ) {
3327+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3328+ "js_fetch_proxy URL must use http:// scheme" );
3329+ return NGX_ERROR ;
3330+ }
3331+
3332+ host_start = url -> data + (sizeof ("http://" ) - 1 );
3333+ at = ngx_strlchr (host_start , url -> data + url -> len , '@' );
3334+
3335+ ngx_str_null (auth_header_out );
3336+
3337+ if (at != NULL ) {
3338+ colon = NULL ;
3339+
3340+ for (p = at - 1 ; p > host_start ; p -- ) {
3341+ if (* p == ':' ) {
3342+ colon = p ;
3343+ break ;
3344+ }
3345+ }
3346+
3347+ if (colon == NULL ) {
3348+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3349+ "js_fetch_proxy URL credentials must be in "
3350+ "user:password format" );
3351+ return NGX_ERROR ;
3352+ }
3353+
3354+ user_start = host_start ;
3355+ user_len = colon - host_start ;
3356+ pass_start = colon + 1 ;
3357+ pass_len = at - pass_start ;
3358+
3359+ decoded_user = ngx_pnalloc (pool , 128 );
3360+ if (decoded_user == NULL ) {
3361+ return NGX_ERROR ;
3362+ }
3363+
3364+ decoded_pass = ngx_pnalloc (pool , 128 );
3365+ if (decoded_pass == NULL ) {
3366+ return NGX_ERROR ;
3367+ }
3368+
3369+ p = user_start ;
3370+ decoded_end = decoded_user ;
3371+ ngx_unescape_uri (& decoded_end , & p , user_len , NGX_UNESCAPE_URI );
3372+
3373+ user_len = decoded_end - decoded_user ;
3374+ if (user_len == 0 || user_len > 127 ) {
3375+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3376+ "js_fetch_proxy username invalid or too long "
3377+ "(max 127 bytes after decoding)" );
3378+ return NGX_ERROR ;
3379+ }
3380+
3381+ p = pass_start ;
3382+ decoded_end = decoded_pass ;
3383+ ngx_unescape_uri (& decoded_end , & p , pass_len , NGX_UNESCAPE_URI );
3384+
3385+ pass_len = decoded_end - decoded_pass ;
3386+ if (pass_len == 0 || pass_len > 127 ) {
3387+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3388+ "js_fetch_proxy password invalid or too long "
3389+ "(max 127 bytes after decoding)" );
3390+ return NGX_ERROR ;
3391+ }
3392+
3393+ user .data = decoded_user ;
3394+ user .len = user_len ;
3395+ pass .data = decoded_pass ;
3396+ pass .len = pass_len ;
3397+
3398+ if (ngx_js_build_proxy_auth_header (pool , auth_header_out ,
3399+ & user , & pass )
3400+ != NGX_OK )
3401+ {
3402+ return NGX_ERROR ;
3403+ }
3404+
3405+ host_start = at + 1 ;
3406+ }
3407+
3408+ u = ngx_pcalloc (pool , sizeof (ngx_url_t ));
3409+ if (u == NULL ) {
3410+ return NGX_ERROR ;
3411+ }
3412+
3413+ u -> url .data = host_start ;
3414+ u -> url .len = url -> data + url -> len - host_start ;
3415+ u -> default_port = 3128 ;
3416+ u -> no_resolve = 1 ;
3417+
3418+ if (ngx_parse_url (pool , u ) != NGX_OK ) {
3419+ ngx_log_error (NGX_LOG_ERR , log , 0 , "invalid proxy URL: %V" , url );
3420+ return NGX_ERROR ;
3421+ }
3422+
3423+ * url_out = u ;
3424+
3425+ return NGX_OK ;
3426+ }
3427+
3428+
3429+ char *
3430+ ngx_js_fetch_proxy (ngx_conf_t * cf , ngx_command_t * cmd , void * conf )
3431+ {
3432+ ngx_str_t * value ;
3433+ ngx_js_loc_conf_t * jscf ;
3434+
3435+ jscf = conf ;
3436+
3437+ value = cf -> args -> elts ;
3438+
3439+ if (ngx_js_parse_proxy_url (cf -> pool , cf -> log , & value [1 ],
3440+ & jscf -> fetch_proxy_url ,
3441+ & jscf -> fetch_proxy_auth_header )
3442+ != NGX_OK )
3443+ {
3444+ ngx_conf_log_error (NGX_LOG_EMERG , cf , 0 ,
3445+ "invalid proxy URL: %V" , & value [1 ]);
3446+ return NGX_CONF_ERROR ;
3447+ }
3448+
3449+ if (jscf -> fetch_proxy_url == NULL ) {
3450+ ngx_conf_log_error (NGX_LOG_EMERG , cf , 0 ,
3451+ "proxy host is empty in URL: %V" , & value [1 ]);
3452+ return NGX_CONF_ERROR ;
3453+ }
3454+
3455+ return NGX_CONF_OK ;
3456+ }
3457+
3458+
32703459static ngx_int_t
32713460ngx_js_init_preload_vm (njs_vm_t * vm , ngx_js_loc_conf_t * conf )
32723461{
@@ -3946,6 +4135,7 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
39464135 * set by ngx_pcalloc():
39474136 *
39484137 * conf->reuse_queue = NULL;
4138+ * conf->fetch_proxy_auth_header = { 0, NULL };
39494139 */
39504140
39514141 conf -> paths = NGX_CONF_UNSET_PTR ;
@@ -3963,6 +4153,8 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
39634153 conf -> fetch_keepalive_requests = NGX_CONF_UNSET_UINT ;
39644154 conf -> fetch_keepalive_time = NGX_CONF_UNSET_MSEC ;
39654155 conf -> fetch_keepalive_timeout = NGX_CONF_UNSET_MSEC ;
4156+ conf -> fetch_proxy_url = NGX_CONF_UNSET_PTR ;
4157+ conf -> eval_proxy_url = NGX_CONF_UNSET_PTR ;
39664158
39674159 return conf ;
39684160}
@@ -4082,10 +4274,15 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
40824274 prev -> fetch_keepalive_time , 3600000 );
40834275 ngx_conf_merge_msec_value (conf -> fetch_keepalive_timeout ,
40844276 prev -> fetch_keepalive_timeout , 60000 );
4085-
40864277 ngx_queue_init (& conf -> fetch_keepalive_cache );
40874278 ngx_queue_init (& conf -> fetch_keepalive_free );
40884279
4280+ ngx_conf_merge_ptr_value (conf -> fetch_proxy_url , prev -> fetch_proxy_url ,
4281+ NULL );
4282+ ngx_conf_merge_ptr_value (conf -> eval_proxy_url , prev -> eval_proxy_url , NULL );
4283+ ngx_conf_merge_str_value (conf -> fetch_proxy_auth_header ,
4284+ prev -> fetch_proxy_auth_header , "" );
4285+
40894286 if (ngx_js_merge_vm (cf , (ngx_js_loc_conf_t * ) conf ,
40904287 (ngx_js_loc_conf_t * ) prev ,
40914288 init_vm )
0 commit comments