Re: [PATCH] HTTP/2: expose function to push single resource to modules

2018-02-14 Thread Ruslan Ermilov
On Tue, Feb 13, 2018 at 04:31:17PM +0300, Maxim Dounin wrote:
> Hello!
> 
> On Tue, Feb 13, 2018 at 12:21:36PM +, Alessandro Ghedini wrote:
> 
> > On Fri, Feb 09, 2018 at 10:35:59AM +0300, Ruslan Ermilov wrote:
> > > On Thu, Feb 08, 2018 at 07:48:25PM +, Alessandro Ghedini wrote:
> > > > On Thu, Feb 08, 2018 at 10:00:27PM +0300, Maxim Dounin wrote:
> > > > > On Thu, Feb 08, 2018 at 04:52:59PM +, Alessandro Ghedini wrote:
> > > > > 
> > > > > > # HG changeset patch
> > > > > > # User Alessandro Ghedini 
> > > > > > # Date 1518108716 0
> > > > > > #  Thu Feb 08 16:51:56 2018 +
> > > > > > # Branch expose-push
> > > > > > # Node ID 1bb98b06d5536dfc80a407aabd8d06f9309f8df6
> > > > > > # Parent  a49af443656f2b65ca5de9d8cad5594f44e18ff7
> > > > > > HTTP/2: expose function to push single resource to modules.
> > > > > > 
> > > > > > This makes it possible for 3rd party modules to implement 
> > > > > > alternative
> > > > > > methods for deciding which resources to push to clients on a 
> > > > > > per-request
> > > > > > basis (e.g. by parsing HTML from the response body, by using a 
> > > > > > custom
> > > > > > Link header parser, ...).
> > > > > > 
> > > > > > No functional changes.
> > > > > 
> > > > > Not sure this is a good idea.
> > > > > 
> > > > > You may consider exposing a variable to be used in http2_push 
> > > > > instead.
> > > > 
> > > > Right, the problem is that as far as I can tell http2_push only 
> > > > supports a
> > > > single resource, even when a variable is used, so it wouldn't be 
> > > > possible to
> > > > push multiple resources without specifying multiple http2_push 
> > > > directives,
> > > > each with its own variable, and even then you'd only have a fixed 
> > > > number of
> > > > resources that can be pushed, which wouldn't work well when the number 
> > > > of
> > > > resources changes depending on each request/response.
> > > > 
> > > > So in the end exposing the internal functions to modules seemed better 
> > > > than
> > > > just trying to make http2_push support multiple resources per directive,
> > > > which would add complexity to NGINX itself rather than the external 
> > > > modules
> > > > (though I can do that if you think it would be a better solution).
> > > 
> > > We've also considered adding support for the X-Accel-Push header, but
> > > decided not to implement it at this time.  If implemented, there could
> > > be multiple X-Accel-Push headers in the proxied response.
> > 
> > That might work for us, but it's a somewhat awkward interface to use from
> > inside a module, so I'd still prefer something more direct, and as I said,
> > exposing the function to modules seemed the least invasive change to NGINX.
> > 
> > Could you please expand a bit on why you think this might be a bad idea?
> > 
> > In any case I can look into implementing X-Accel-Push support if you don't
> > plan on doing it yourself.
> 
> I presonally think that X-Accel-Push is not needed and should not 
> be added given we already have http2_push.  Also, HTTP/2 push as a 
> technology has enough design problems to introduce additional 
> interfaces.
> 
> If you want to use HTTP2 pushes from a module, consider either 
> using http2_push with variables as previously suggested (right now 
> you can use multiple http2_push directives if you want to push 
> multiple resources), or adding "Link: rel=preload" headers and 
> using http2_push_preload. 

The latter was made programmatically available in 6ba68ad8b24c,
"Basic support of the Link response header."
___
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel


Re: [PATCH] HTTP/2: added support for setting custom push request headers

2018-02-14 Thread Ruslan Ermilov
On Tue, Feb 13, 2018 at 11:58:40AM +, Alessandro Ghedini wrote:
> If it's of any help, I merged your patch and mine into one, which copies the
> headers (excluding Accept) into PUSH_PROMISE and r->headers_in like my 
> original
> patch did, as well as HPACK encode them into PUSH_PROMISE instead of writing
> them as literal strings, as your patch did. This fixes the problems I 
> mentioned
> in my previous email.

To keep you updated, we're cultivating these patches:

# HG changeset patch
# User Ruslan Ermilov 
# Date 1518609549 -10800
#  Wed Feb 14 14:59:09 2018 +0300
# Node ID 9cd08f096c366771ffbebd2872883be04903d425
# Parent  8b0553239592f5d0fd419e5116b9d343838685cf
Expose more headers with NGX_HTTP_HEADERS.

diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -140,7 +140,7 @@ ngx_http_header_t  ngx_http_headers_in[]
  offsetof(ngx_http_headers_in_t, upgrade),
  ngx_http_process_header_line },
 
-#if (NGX_HTTP_GZIP)
+#if (NGX_HTTP_GZIP || NGX_HTTP_HEADERS)
 { ngx_string("Accept-Encoding"),
  offsetof(ngx_http_headers_in_t, accept_encoding),
  ngx_http_process_header_line },
diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h
+++ b/src/http/ngx_http_request.h
@@ -200,7 +200,7 @@ typedef struct {
 ngx_table_elt_t  *expect;
 ngx_table_elt_t  *upgrade;
 
-#if (NGX_HTTP_GZIP)
+#if (NGX_HTTP_GZIP || NGX_HTTP_HEADERS)
 ngx_table_elt_t  *accept_encoding;
 ngx_table_elt_t  *via;
 #endif
# HG changeset patch
# User Ruslan Ermilov 
# Date 1518634812 -10800
#  Wed Feb 14 22:00:12 2018 +0300
# Node ID cd54884b375b70ecd358358e5e78f43e70b6163a
# Parent  9cd08f096c366771ffbebd2872883be04903d425
HTTP/2: push additional request headers (closes #1478).

The Accept-Encoding, Accept-Language, and User-Agent header fields
are now copied from the original request to pushed requests.

diff --git a/auto/modules b/auto/modules
--- a/auto/modules
+++ b/auto/modules
@@ -420,6 +420,7 @@ if [ $HTTP = YES ]; then
 
 if [ $HTTP_V2 = YES ]; then
 have=NGX_HTTP_V2 . auto/have
+have=NGX_HTTP_HEADERS . auto/have
 
 ngx_module_name=ngx_http_v2_module
 ngx_module_incs=src/http/v2
diff --git a/src/http/v2/ngx_http_v2.c b/src/http/v2/ngx_http_v2.c
--- a/src/http/v2/ngx_http_v2.c
+++ b/src/http/v2/ngx_http_v2.c
@@ -11,6 +11,14 @@
 #include 
 
 
+typedef struct {
+ngx_str_t   name;
+ngx_uint_t  offset;
+ngx_uint_t  hash;
+ngx_http_header_t  *hh;
+} ngx_http_v2_parse_header_t;
+
+
 /* errors */
 #define NGX_HTTP_V2_NO_ERROR 0x0
 #define NGX_HTTP_V2_PROTOCOL_ERROR   0x1
@@ -156,6 +164,8 @@ static ngx_int_t ngx_http_v2_parse_schem
 ngx_str_t *value);
 static ngx_int_t ngx_http_v2_parse_authority(ngx_http_request_t *r,
 ngx_str_t *value);
+static ngx_int_t ngx_http_v2_parse_header(ngx_http_request_t *r,
+ngx_http_v2_parse_header_t *header, ngx_str_t *value);
 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
 ngx_http_v2_header_t *header);
@@ -201,6 +211,23 @@ static ngx_http_v2_handler_pt ngx_http_v
 (sizeof(ngx_http_v2_frame_states) / sizeof(ngx_http_v2_handler_pt))
 
 
+static ngx_http_v2_parse_header_t  ngx_http_v2_parse_headers[] = {
+{ ngx_string("host"),
+  offsetof(ngx_http_headers_in_t, host), 0, NULL },
+
+{ ngx_string("accept-encoding"),
+  offsetof(ngx_http_headers_in_t, accept_encoding), 0, NULL },
+
+{ ngx_string("accept-language"),
+  offsetof(ngx_http_headers_in_t, accept_language), 0, NULL },
+
+{ ngx_string("user-agent"),
+  offsetof(ngx_http_headers_in_t, user_agent), 0, NULL },
+
+{ ngx_null_string, 0, 0, NULL }
+};
+
+
 void
 ngx_http_v2_init(ngx_event_t *rev)
 {
@@ -2514,21 +2541,25 @@ ngx_http_v2_parse_int(ngx_http_v2_connec
 }
 
 
-ngx_int_t
-ngx_http_v2_push_stream(ngx_http_v2_connection_t *h2c, ngx_uint_t depend,
-size_t request_length, ngx_str_t *path, ngx_str_t *authority)
+ngx_http_v2_stream_t *
+ngx_http_v2_push_stream(ngx_http_v2_stream_t *parent, ngx_str_t *path)
 {
-ngx_int_t  rc;
-ngx_str_t  value;
-ngx_connection_t  *fc;
-ngx_http_request_t*r;
-ngx_http_v2_node_t*node;
-ngx_http_v2_stream_t  *stream;
+ngx_int_t rc;
+ngx_str_t value;
+ngx_table_elt_t **h;
+ngx_connection_t *fc;
+ngx_http_request_t   *r;
+ngx_http_v2_node_t   *node;
+ngx_http_v2_stream_t *stream;
+ngx_http_v2_connection_t *h2c;
+ngx_http_v2_parse_header_t   *header;
+
+h2c = parent->connection;
 
 node = ngx_htt