@@ -3305,6 +3305,196 @@ ngx_js_preload_object(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
33053305}
33063306
33073307
3308+ static ngx_int_t
3309+ ngx_js_build_proxy_auth_header (ngx_pool_t * pool , ngx_str_t * auth_header ,
3310+ ngx_str_t * user , ngx_str_t * pass )
3311+ {
3312+ u_char * p ;
3313+ size_t len ;
3314+ ngx_str_t userpass , b64 ;
3315+
3316+ userpass .len = user -> len + 1 + pass -> len ;
3317+ userpass .data = ngx_pnalloc (pool , userpass .len );
3318+ if (userpass .data == NULL ) {
3319+ return NGX_ERROR ;
3320+ }
3321+
3322+ p = ngx_cpymem (userpass .data , user -> data , user -> len );
3323+ * p ++ = ':' ;
3324+ ngx_memcpy (p , pass -> data , pass -> len );
3325+
3326+ b64 .len = ngx_base64_encoded_length (userpass .len );
3327+ b64 .data = ngx_pnalloc (pool , b64 .len );
3328+ if (b64 .data == NULL ) {
3329+ return NGX_ERROR ;
3330+ }
3331+
3332+ ngx_encode_base64 (& b64 , & userpass );
3333+
3334+ len = sizeof ("Proxy-Authorization: Basic \r\n" ) - 1 + b64 .len ;
3335+ p = ngx_pnalloc (pool , len );
3336+ if (p == NULL ) {
3337+ return NGX_ERROR ;
3338+ }
3339+
3340+ ngx_sprintf (p , "Proxy-Authorization: Basic %V\r\n" , & b64 );
3341+ auth_header -> data = p ;
3342+ auth_header -> len = len ;
3343+
3344+ return NGX_OK ;
3345+ }
3346+
3347+
3348+ ngx_int_t
3349+ ngx_js_parse_proxy_url (ngx_pool_t * pool , ngx_log_t * log , ngx_str_t * url_str ,
3350+ ngx_url_t * * url_out , ngx_str_t * auth_header_out )
3351+ {
3352+ u_char * p , * at , * colon , * host_start , * user_start , * pass_start ;
3353+ u_char * decoded_user , * decoded_pass , * decoded_end ;
3354+ size_t user_len , pass_len ;
3355+ ngx_url_t * u ;
3356+ ngx_str_t user , pass ;
3357+
3358+ if (url_str -> len == 0 ) {
3359+ * url_out = NULL ;
3360+ ngx_str_null (auth_header_out );
3361+ return NGX_OK ;
3362+ }
3363+
3364+ if (ngx_strncmp (url_str -> data , "http://" , sizeof ("http://" ) - 1 ) != 0 ) {
3365+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3366+ "js_fetch_proxy URL must use http:// scheme" );
3367+ return NGX_ERROR ;
3368+ }
3369+
3370+ host_start = url_str -> data + (sizeof ("http://" ) - 1 );
3371+ at = ngx_strlchr (host_start , url_str -> data + url_str -> len , '@' );
3372+
3373+ ngx_str_null (auth_header_out );
3374+
3375+ if (at != NULL ) {
3376+ colon = NULL ;
3377+
3378+ for (p = at - 1 ; p > host_start ; p -- ) {
3379+ if (* p == ':' ) {
3380+ colon = p ;
3381+ break ;
3382+ }
3383+ }
3384+
3385+ if (colon == NULL ) {
3386+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3387+ "js_fetch_proxy URL credentials must be in "
3388+ "user:password format" );
3389+ return NGX_ERROR ;
3390+ }
3391+
3392+ user_start = host_start ;
3393+ user_len = colon - host_start ;
3394+ pass_start = colon + 1 ;
3395+ pass_len = at - pass_start ;
3396+
3397+ decoded_user = ngx_pnalloc (pool , 128 );
3398+ if (decoded_user == NULL ) {
3399+ return NGX_ERROR ;
3400+ }
3401+
3402+ decoded_pass = ngx_pnalloc (pool , 128 );
3403+ if (decoded_pass == NULL ) {
3404+ return NGX_ERROR ;
3405+ }
3406+
3407+ p = user_start ;
3408+ decoded_end = decoded_user ;
3409+ ngx_unescape_uri (& decoded_end , & p , user_len , NGX_UNESCAPE_URI );
3410+
3411+ user_len = decoded_end - decoded_user ;
3412+ if (user_len == 0 || user_len > 127 ) {
3413+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3414+ "js_fetch_proxy username invalid or too long "
3415+ "(max 127 bytes after decoding)" );
3416+ return NGX_ERROR ;
3417+ }
3418+
3419+ p = pass_start ;
3420+ decoded_end = decoded_pass ;
3421+ ngx_unescape_uri (& decoded_end , & p , pass_len , NGX_UNESCAPE_URI );
3422+
3423+ pass_len = decoded_end - decoded_pass ;
3424+ if (pass_len == 0 || pass_len > 127 ) {
3425+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3426+ "js_fetch_proxy password invalid or too long "
3427+ "(max 127 bytes after decoding)" );
3428+ return NGX_ERROR ;
3429+ }
3430+
3431+ user .data = decoded_user ;
3432+ user .len = user_len ;
3433+ pass .data = decoded_pass ;
3434+ pass .len = pass_len ;
3435+
3436+ if (ngx_js_build_proxy_auth_header (pool , auth_header_out ,
3437+ & user , & pass )
3438+ != NGX_OK )
3439+ {
3440+ return NGX_ERROR ;
3441+ }
3442+
3443+ host_start = at + 1 ;
3444+ }
3445+
3446+ u = ngx_pcalloc (pool , sizeof (ngx_url_t ));
3447+ if (u == NULL ) {
3448+ return NGX_ERROR ;
3449+ }
3450+
3451+ u -> url .data = host_start ;
3452+ u -> url .len = url_str -> data + url_str -> len - host_start ;
3453+ u -> default_port = 3128 ;
3454+ u -> no_resolve = 1 ;
3455+
3456+ if (ngx_parse_url (pool , u ) != NGX_OK ) {
3457+ ngx_log_error (NGX_LOG_ERR , log , 0 ,
3458+ "invalid proxy URL: %V" , url_str );
3459+ return NGX_ERROR ;
3460+ }
3461+
3462+ * url_out = u ;
3463+
3464+ return NGX_OK ;
3465+ }
3466+
3467+
3468+ char *
3469+ ngx_js_fetch_proxy (ngx_conf_t * cf , ngx_command_t * cmd , void * conf )
3470+ {
3471+ ngx_str_t * value ;
3472+ ngx_js_loc_conf_t * jscf ;
3473+
3474+ jscf = conf ;
3475+
3476+ value = cf -> args -> elts ;
3477+
3478+ if (ngx_js_parse_proxy_url (cf -> pool , cf -> log , & value [1 ],
3479+ & jscf -> fetch_proxy_url ,
3480+ & jscf -> fetch_proxy_auth_header )
3481+ != NGX_OK )
3482+ {
3483+ ngx_conf_log_error (NGX_LOG_EMERG , cf , 0 ,
3484+ "invalid proxy URL: %V" , & value [1 ]);
3485+ return NGX_CONF_ERROR ;
3486+ }
3487+
3488+ if (jscf -> fetch_proxy_url == NULL ) {
3489+ ngx_conf_log_error (NGX_LOG_EMERG , cf , 0 ,
3490+ "proxy host is empty in URL: %V" , & value [1 ]);
3491+ return NGX_CONF_ERROR ;
3492+ }
3493+
3494+ return NGX_CONF_OK ;
3495+ }
3496+
3497+
33083498static ngx_int_t
33093499ngx_js_init_preload_vm (njs_vm_t * vm , ngx_js_loc_conf_t * conf )
33103500{
@@ -3984,6 +4174,7 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
39844174 * set by ngx_pcalloc():
39854175 *
39864176 * conf->reuse_queue = NULL;
4177+ * conf->fetch_proxy_auth_header = { 0, NULL };
39874178 */
39884179
39894180 conf -> paths = NGX_CONF_UNSET_PTR ;
@@ -4001,6 +4192,8 @@ ngx_js_create_conf(ngx_conf_t *cf, size_t size)
40014192 conf -> fetch_keepalive_requests = NGX_CONF_UNSET_UINT ;
40024193 conf -> fetch_keepalive_time = NGX_CONF_UNSET_MSEC ;
40034194 conf -> fetch_keepalive_timeout = NGX_CONF_UNSET_MSEC ;
4195+ conf -> fetch_proxy_url = NGX_CONF_UNSET_PTR ;
4196+ conf -> eval_proxy_url = NGX_CONF_UNSET_PTR ;
40044197
40054198 return conf ;
40064199}
@@ -4120,10 +4313,15 @@ ngx_js_merge_conf(ngx_conf_t *cf, void *parent, void *child,
41204313 prev -> fetch_keepalive_time , 3600000 );
41214314 ngx_conf_merge_msec_value (conf -> fetch_keepalive_timeout ,
41224315 prev -> fetch_keepalive_timeout , 60000 );
4123-
41244316 ngx_queue_init (& conf -> fetch_keepalive_cache );
41254317 ngx_queue_init (& conf -> fetch_keepalive_free );
41264318
4319+ ngx_conf_merge_ptr_value (conf -> fetch_proxy_url , prev -> fetch_proxy_url ,
4320+ NULL );
4321+ ngx_conf_merge_ptr_value (conf -> eval_proxy_url , prev -> eval_proxy_url , NULL );
4322+ ngx_conf_merge_str_value (conf -> fetch_proxy_auth_header ,
4323+ prev -> fetch_proxy_auth_header , "" );
4324+
41274325 if (ngx_js_merge_vm (cf , (ngx_js_loc_conf_t * ) conf ,
41284326 (ngx_js_loc_conf_t * ) prev ,
41294327 init_vm )
0 commit comments