1 
2 /*
3  * Copyright (C) Nginx, Inc.
4  * Copyright (C) Valentin V. Bartenev
5  */
6 
7 
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11 #include <ngx_http_v2_module.h>
12 
13 
14 static ngx_int_t ngx_http_v2_add_variables(ngx_conf_t *cf);
15 
16 static ngx_int_t ngx_http_v2_variable(ngx_http_request_t *r,
17     ngx_http_variable_value_t *v, uintptr_t data);
18 
19 static ngx_int_t ngx_http_v2_module_init(ngx_cycle_t *cycle);
20 
21 static void *ngx_http_v2_create_main_conf(ngx_conf_t *cf);
22 static char *ngx_http_v2_init_main_conf(ngx_conf_t *cf, void *conf);
23 static void *ngx_http_v2_create_srv_conf(ngx_conf_t *cf);
24 static char *ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent,
25     void *child);
26 static void *ngx_http_v2_create_loc_conf(ngx_conf_t *cf);
27 static char *ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent,
28     void *child);
29 
30 static char *ngx_http_v2_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
31 
32 static char *ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post,
33     void *data);
34 static char *ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data);
35 static char *ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data);
36 static char *ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post,
37     void *data);
38 static char *ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data);
39 static char *ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd,
40     void *conf);
41 
42 
43 static ngx_conf_post_t  ngx_http_v2_recv_buffer_size_post =
44     { ngx_http_v2_recv_buffer_size };
45 static ngx_conf_post_t  ngx_http_v2_pool_size_post =
46     { ngx_http_v2_pool_size };
47 static ngx_conf_post_t  ngx_http_v2_preread_size_post =
48     { ngx_http_v2_preread_size };
49 static ngx_conf_post_t  ngx_http_v2_streams_index_mask_post =
50     { ngx_http_v2_streams_index_mask };
51 static ngx_conf_post_t  ngx_http_v2_chunk_size_post =
52     { ngx_http_v2_chunk_size };
53 
54 
55 static ngx_command_t  ngx_http_v2_commands[] = {
56 
57     { ngx_string("http2_recv_buffer_size"),
58       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
59       ngx_conf_set_size_slot,
60       NGX_HTTP_MAIN_CONF_OFFSET,
61       offsetof(ngx_http_v2_main_conf_t, recv_buffer_size),
62       &ngx_http_v2_recv_buffer_size_post },
63 
64     { ngx_string("http2_pool_size"),
65       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
66       ngx_conf_set_size_slot,
67       NGX_HTTP_SRV_CONF_OFFSET,
68       offsetof(ngx_http_v2_srv_conf_t, pool_size),
69       &ngx_http_v2_pool_size_post },
70 
71     { ngx_string("http2_max_concurrent_streams"),
72       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
73       ngx_conf_set_num_slot,
74       NGX_HTTP_SRV_CONF_OFFSET,
75       offsetof(ngx_http_v2_srv_conf_t, concurrent_streams),
76       NULL },
77 
78     { ngx_string("http2_max_concurrent_pushes"),
79       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
80       ngx_conf_set_num_slot,
81       NGX_HTTP_SRV_CONF_OFFSET,
82       offsetof(ngx_http_v2_srv_conf_t, concurrent_pushes),
83       NULL },
84 
85     { ngx_string("http2_max_requests"),
86       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
87       ngx_conf_set_num_slot,
88       NGX_HTTP_SRV_CONF_OFFSET,
89       offsetof(ngx_http_v2_srv_conf_t, max_requests),
90       NULL },
91 
92     { ngx_string("http2_max_field_size"),
93       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
94       ngx_conf_set_size_slot,
95       NGX_HTTP_SRV_CONF_OFFSET,
96       offsetof(ngx_http_v2_srv_conf_t, max_field_size),
97       NULL },
98 
99     { ngx_string("http2_max_header_size"),
100       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
101       ngx_conf_set_size_slot,
102       NGX_HTTP_SRV_CONF_OFFSET,
103       offsetof(ngx_http_v2_srv_conf_t, max_header_size),
104       NULL },
105 
106     { ngx_string("http2_body_preread_size"),
107       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
108       ngx_conf_set_size_slot,
109       NGX_HTTP_SRV_CONF_OFFSET,
110       offsetof(ngx_http_v2_srv_conf_t, preread_size),
111       &ngx_http_v2_preread_size_post },
112 
113     { ngx_string("http2_streams_index_size"),
114       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
115       ngx_conf_set_num_slot,
116       NGX_HTTP_SRV_CONF_OFFSET,
117       offsetof(ngx_http_v2_srv_conf_t, streams_index_mask),
118       &ngx_http_v2_streams_index_mask_post },
119 
120     { ngx_string("http2_recv_timeout"),
121       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
122       ngx_conf_set_msec_slot,
123       NGX_HTTP_SRV_CONF_OFFSET,
124       offsetof(ngx_http_v2_srv_conf_t, recv_timeout),
125       NULL },
126 
127     { ngx_string("http2_idle_timeout"),
128       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
129       ngx_conf_set_msec_slot,
130       NGX_HTTP_SRV_CONF_OFFSET,
131       offsetof(ngx_http_v2_srv_conf_t, idle_timeout),
132       NULL },
133 
134     { ngx_string("http2_chunk_size"),
135       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
136       ngx_conf_set_size_slot,
137       NGX_HTTP_LOC_CONF_OFFSET,
138       offsetof(ngx_http_v2_loc_conf_t, chunk_size),
139       &ngx_http_v2_chunk_size_post },
140 
141     { ngx_string("http2_push_preload"),
142       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
143       ngx_conf_set_flag_slot,
144       NGX_HTTP_LOC_CONF_OFFSET,
145       offsetof(ngx_http_v2_loc_conf_t, push_preload),
146       NULL },
147 
148     { ngx_string("http2_push"),
149       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
150       ngx_http_v2_push,
151       NGX_HTTP_LOC_CONF_OFFSET,
152       0,
153       NULL },
154 
155     { ngx_string("spdy_recv_buffer_size"),
156       NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
157       ngx_http_v2_spdy_deprecated,
158       NGX_HTTP_MAIN_CONF_OFFSET,
159       0,
160       NULL },
161 
162     { ngx_string("spdy_pool_size"),
163       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
164       ngx_http_v2_spdy_deprecated,
165       NGX_HTTP_SRV_CONF_OFFSET,
166       0,
167       NULL },
168 
169     { ngx_string("spdy_max_concurrent_streams"),
170       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
171       ngx_http_v2_spdy_deprecated,
172       NGX_HTTP_SRV_CONF_OFFSET,
173       0,
174       NULL },
175 
176     { ngx_string("spdy_streams_index_size"),
177       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
178       ngx_http_v2_spdy_deprecated,
179       NGX_HTTP_SRV_CONF_OFFSET,
180       0,
181       NULL },
182 
183     { ngx_string("spdy_recv_timeout"),
184       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
185       ngx_http_v2_spdy_deprecated,
186       NGX_HTTP_SRV_CONF_OFFSET,
187       0,
188       NULL },
189 
190     { ngx_string("spdy_keepalive_timeout"),
191       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
192       ngx_http_v2_spdy_deprecated,
193       NGX_HTTP_SRV_CONF_OFFSET,
194       0,
195       NULL },
196 
197     { ngx_string("spdy_headers_comp"),
198       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1,
199       ngx_http_v2_spdy_deprecated,
200       NGX_HTTP_SRV_CONF_OFFSET,
201       0,
202       NULL },
203 
204     { ngx_string("spdy_chunk_size"),
205       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
206       ngx_http_v2_spdy_deprecated,
207       NGX_HTTP_LOC_CONF_OFFSET,
208       0,
209       NULL },
210 
211       ngx_null_command
212 };
213 
214 
215 static ngx_http_module_t  ngx_http_v2_module_ctx = {
216     ngx_http_v2_add_variables,             /* preconfiguration */
217     NULL,                                  /* postconfiguration */
218 
219     ngx_http_v2_create_main_conf,          /* create main configuration */
220     ngx_http_v2_init_main_conf,            /* init main configuration */
221 
222     ngx_http_v2_create_srv_conf,           /* create server configuration */
223     ngx_http_v2_merge_srv_conf,            /* merge server configuration */
224 
225     ngx_http_v2_create_loc_conf,           /* create location configuration */
226     ngx_http_v2_merge_loc_conf             /* merge location configuration */
227 };
228 
229 
230 ngx_module_t  ngx_http_v2_module = {
231     NGX_MODULE_V1,
232     &ngx_http_v2_module_ctx,               /* module context */
233     ngx_http_v2_commands,                  /* module directives */
234     NGX_HTTP_MODULE,                       /* module type */
235     NULL,                                  /* init master */
236     ngx_http_v2_module_init,               /* init module */
237     NULL,                                  /* init process */
238     NULL,                                  /* init thread */
239     NULL,                                  /* exit thread */
240     NULL,                                  /* exit process */
241     NULL,                                  /* exit master */
242     NGX_MODULE_V1_PADDING
243 };
244 
245 
246 static ngx_http_variable_t  ngx_http_v2_vars[] = {
247 
248     { ngx_string("http2"), NULL,
249       ngx_http_v2_variable, 0, 0, 0 },
250 
251       ngx_http_null_variable
252 };
253 
254 
255 static ngx_int_t
ngx_http_v2_add_variables(ngx_conf_t * cf)256 ngx_http_v2_add_variables(ngx_conf_t *cf)
257 {
258     ngx_http_variable_t  *var, *v;
259 
260     for (v = ngx_http_v2_vars; v->name.len; v++) {
261         var = ngx_http_add_variable(cf, &v->name, v->flags);
262         if (var == NULL) {
263             return NGX_ERROR;
264         }
265 
266         var->get_handler = v->get_handler;
267         var->data = v->data;
268     }
269 
270     return NGX_OK;
271 }
272 
273 
274 static ngx_int_t
ngx_http_v2_variable(ngx_http_request_t * r,ngx_http_variable_value_t * v,uintptr_t data)275 ngx_http_v2_variable(ngx_http_request_t *r,
276     ngx_http_variable_value_t *v, uintptr_t data)
277 {
278 
279     if (r->stream) {
280 #if (NGX_HTTP_SSL)
281 
282         if (r->connection->ssl) {
283             v->len = sizeof("h2") - 1;
284             v->valid = 1;
285             v->no_cacheable = 0;
286             v->not_found = 0;
287             v->data = (u_char *) "h2";
288 
289             return NGX_OK;
290         }
291 
292 #endif
293         v->len = sizeof("h2c") - 1;
294         v->valid = 1;
295         v->no_cacheable = 0;
296         v->not_found = 0;
297         v->data = (u_char *) "h2c";
298 
299         return NGX_OK;
300     }
301 
302     *v = ngx_http_variable_null_value;
303 
304     return NGX_OK;
305 }
306 
307 
308 static ngx_int_t
ngx_http_v2_module_init(ngx_cycle_t * cycle)309 ngx_http_v2_module_init(ngx_cycle_t *cycle)
310 {
311     return NGX_OK;
312 }
313 
314 
315 static void *
ngx_http_v2_create_main_conf(ngx_conf_t * cf)316 ngx_http_v2_create_main_conf(ngx_conf_t *cf)
317 {
318     ngx_http_v2_main_conf_t  *h2mcf;
319 
320     h2mcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_main_conf_t));
321     if (h2mcf == NULL) {
322         return NULL;
323     }
324 
325     h2mcf->recv_buffer_size = NGX_CONF_UNSET_SIZE;
326 
327     return h2mcf;
328 }
329 
330 
331 static char *
ngx_http_v2_init_main_conf(ngx_conf_t * cf,void * conf)332 ngx_http_v2_init_main_conf(ngx_conf_t *cf, void *conf)
333 {
334     ngx_http_v2_main_conf_t *h2mcf = conf;
335 
336     ngx_conf_init_size_value(h2mcf->recv_buffer_size, 256 * 1024);
337 
338     return NGX_CONF_OK;
339 }
340 
341 
342 static void *
ngx_http_v2_create_srv_conf(ngx_conf_t * cf)343 ngx_http_v2_create_srv_conf(ngx_conf_t *cf)
344 {
345     ngx_http_v2_srv_conf_t  *h2scf;
346 
347     h2scf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_srv_conf_t));
348     if (h2scf == NULL) {
349         return NULL;
350     }
351 
352     h2scf->pool_size = NGX_CONF_UNSET_SIZE;
353 
354     h2scf->concurrent_streams = NGX_CONF_UNSET_UINT;
355     h2scf->concurrent_pushes = NGX_CONF_UNSET_UINT;
356     h2scf->max_requests = NGX_CONF_UNSET_UINT;
357 
358     h2scf->max_field_size = NGX_CONF_UNSET_SIZE;
359     h2scf->max_header_size = NGX_CONF_UNSET_SIZE;
360 
361     h2scf->preread_size = NGX_CONF_UNSET_SIZE;
362 
363     h2scf->streams_index_mask = NGX_CONF_UNSET_UINT;
364 
365     h2scf->recv_timeout = NGX_CONF_UNSET_MSEC;
366     h2scf->idle_timeout = NGX_CONF_UNSET_MSEC;
367 
368     return h2scf;
369 }
370 
371 
372 static char *
ngx_http_v2_merge_srv_conf(ngx_conf_t * cf,void * parent,void * child)373 ngx_http_v2_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child)
374 {
375     ngx_http_v2_srv_conf_t *prev = parent;
376     ngx_http_v2_srv_conf_t *conf = child;
377 
378     ngx_conf_merge_size_value(conf->pool_size, prev->pool_size, 4096);
379 
380     ngx_conf_merge_uint_value(conf->concurrent_streams,
381                               prev->concurrent_streams, 128);
382     ngx_conf_merge_uint_value(conf->concurrent_pushes,
383                               prev->concurrent_pushes, 10);
384     ngx_conf_merge_uint_value(conf->max_requests, prev->max_requests, 1000);
385 
386     ngx_conf_merge_size_value(conf->max_field_size, prev->max_field_size,
387                               4096);
388     ngx_conf_merge_size_value(conf->max_header_size, prev->max_header_size,
389                               16384);
390 
391     ngx_conf_merge_size_value(conf->preread_size, prev->preread_size, 65536);
392 
393     ngx_conf_merge_uint_value(conf->streams_index_mask,
394                               prev->streams_index_mask, 32 - 1);
395 
396     ngx_conf_merge_msec_value(conf->recv_timeout,
397                               prev->recv_timeout, 30000);
398     ngx_conf_merge_msec_value(conf->idle_timeout,
399                               prev->idle_timeout, 180000);
400 
401     return NGX_CONF_OK;
402 }
403 
404 
405 static void *
ngx_http_v2_create_loc_conf(ngx_conf_t * cf)406 ngx_http_v2_create_loc_conf(ngx_conf_t *cf)
407 {
408     ngx_http_v2_loc_conf_t  *h2lcf;
409 
410     h2lcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_v2_loc_conf_t));
411     if (h2lcf == NULL) {
412         return NULL;
413     }
414 
415     /*
416      * set by ngx_pcalloc():
417      *
418      *     h2lcf->pushes = NULL;
419      */
420 
421     h2lcf->chunk_size = NGX_CONF_UNSET_SIZE;
422 
423     h2lcf->push_preload = NGX_CONF_UNSET;
424     h2lcf->push = NGX_CONF_UNSET;
425 
426     return h2lcf;
427 }
428 
429 
430 static char *
ngx_http_v2_merge_loc_conf(ngx_conf_t * cf,void * parent,void * child)431 ngx_http_v2_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
432 {
433     ngx_http_v2_loc_conf_t *prev = parent;
434     ngx_http_v2_loc_conf_t *conf = child;
435 
436     ngx_conf_merge_size_value(conf->chunk_size, prev->chunk_size, 8 * 1024);
437 
438     ngx_conf_merge_value(conf->push, prev->push, 1);
439 
440     if (conf->push && conf->pushes == NULL) {
441         conf->pushes = prev->pushes;
442     }
443 
444     ngx_conf_merge_value(conf->push_preload, prev->push_preload, 0);
445 
446     return NGX_CONF_OK;
447 }
448 
449 
450 static char *
ngx_http_v2_push(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)451 ngx_http_v2_push(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
452 {
453     ngx_http_v2_loc_conf_t *h2lcf = conf;
454 
455     ngx_str_t                         *value;
456     ngx_http_complex_value_t          *cv;
457     ngx_http_compile_complex_value_t   ccv;
458 
459     value = cf->args->elts;
460 
461     if (ngx_strcmp(value[1].data, "off") == 0) {
462 
463         if (h2lcf->pushes) {
464             return "\"off\" parameter cannot be used with URI";
465         }
466 
467         if (h2lcf->push == 0) {
468             return "is duplicate";
469         }
470 
471         h2lcf->push = 0;
472         return NGX_CONF_OK;
473     }
474 
475     if (h2lcf->push == 0) {
476         return "URI cannot be used with \"off\" parameter";
477     }
478 
479     h2lcf->push = 1;
480 
481     if (h2lcf->pushes == NULL) {
482         h2lcf->pushes = ngx_array_create(cf->pool, 1,
483                                          sizeof(ngx_http_complex_value_t));
484         if (h2lcf->pushes == NULL) {
485             return NGX_CONF_ERROR;
486         }
487     }
488 
489     cv = ngx_array_push(h2lcf->pushes);
490     if (cv == NULL) {
491         return NGX_CONF_ERROR;
492     }
493 
494     ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
495 
496     ccv.cf = cf;
497     ccv.value = &value[1];
498     ccv.complex_value = cv;
499 
500     if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
501         return NGX_CONF_ERROR;
502     }
503 
504     return NGX_CONF_OK;
505 }
506 
507 
508 static char *
ngx_http_v2_recv_buffer_size(ngx_conf_t * cf,void * post,void * data)509 ngx_http_v2_recv_buffer_size(ngx_conf_t *cf, void *post, void *data)
510 {
511     size_t *sp = data;
512 
513     if (*sp <= 2 * NGX_HTTP_V2_STATE_BUFFER_SIZE) {
514         return "value is too small";
515     }
516 
517     return NGX_CONF_OK;
518 }
519 
520 
521 static char *
ngx_http_v2_pool_size(ngx_conf_t * cf,void * post,void * data)522 ngx_http_v2_pool_size(ngx_conf_t *cf, void *post, void *data)
523 {
524     size_t *sp = data;
525 
526     if (*sp < NGX_MIN_POOL_SIZE) {
527         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
528                            "the pool size must be no less than %uz",
529                            NGX_MIN_POOL_SIZE);
530 
531         return NGX_CONF_ERROR;
532     }
533 
534     if (*sp % NGX_POOL_ALIGNMENT) {
535         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
536                            "the pool size must be a multiple of %uz",
537                            NGX_POOL_ALIGNMENT);
538 
539         return NGX_CONF_ERROR;
540     }
541 
542     return NGX_CONF_OK;
543 }
544 
545 
546 static char *
ngx_http_v2_preread_size(ngx_conf_t * cf,void * post,void * data)547 ngx_http_v2_preread_size(ngx_conf_t *cf, void *post, void *data)
548 {
549     size_t *sp = data;
550 
551     if (*sp > NGX_HTTP_V2_MAX_WINDOW) {
552         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
553                            "the maximum body preread buffer size is %uz",
554                            NGX_HTTP_V2_MAX_WINDOW);
555 
556         return NGX_CONF_ERROR;
557     }
558 
559     return NGX_CONF_OK;
560 }
561 
562 
563 static char *
ngx_http_v2_streams_index_mask(ngx_conf_t * cf,void * post,void * data)564 ngx_http_v2_streams_index_mask(ngx_conf_t *cf, void *post, void *data)
565 {
566     ngx_uint_t *np = data;
567 
568     ngx_uint_t  mask;
569 
570     mask = *np - 1;
571 
572     if (*np == 0 || (*np & mask)) {
573         return "must be a power of two";
574     }
575 
576     *np = mask;
577 
578     return NGX_CONF_OK;
579 }
580 
581 
582 static char *
ngx_http_v2_chunk_size(ngx_conf_t * cf,void * post,void * data)583 ngx_http_v2_chunk_size(ngx_conf_t *cf, void *post, void *data)
584 {
585     size_t *sp = data;
586 
587     if (*sp == 0) {
588         ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
589                            "the http2 chunk size cannot be zero");
590 
591         return NGX_CONF_ERROR;
592     }
593 
594     if (*sp > NGX_HTTP_V2_MAX_FRAME_SIZE) {
595         *sp = NGX_HTTP_V2_MAX_FRAME_SIZE;
596     }
597 
598     return NGX_CONF_OK;
599 }
600 
601 
602 static char *
ngx_http_v2_spdy_deprecated(ngx_conf_t * cf,ngx_command_t * cmd,void * conf)603 ngx_http_v2_spdy_deprecated(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
604 {
605     ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
606                        "invalid directive \"%V\": ngx_http_spdy_module "
607                        "was superseded by ngx_http_v2_module", &cmd->name);
608 
609     return NGX_CONF_OK;
610 }
611