diff --git a/doc/h2load.1 b/doc/h2load.1 index 16bfef4b..d226e6d5 100644 --- a/doc/h2load.1 +++ b/doc/h2load.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "H2LOAD" "1" "August 30, 2015" "1.3.0" "nghttp2" +.TH "H2LOAD" "1" "September 06, 2015" "1.3.1-DEV" "nghttp2" .SH NAME h2load \- HTTP/2 benchmarking tool . @@ -185,15 +185,15 @@ indefinitely, waiting for a response. Path of a file containing one or more lines separated by EOLs. Each script line is composed of two tab\-separated fields. The first field represents the time offset from -the start of execution, expressed as milliseconds with -microsecond resolution. The second field represents the -URI. This option will disable URIs getting from -command\-line. If \(aq\-\(aq is given as , script lines -will be read from stdin. Script lines are used in order -for each client. If \fI\%\-n\fP is given, it must be less than -or equal to the number of script lines, larger values are -clamped to the number of script lines. If \fI\%\-n\fP is -not given, the number of requests will default to the +the start of execution, expressed as a positive value of +milliseconds with microsecond resolution. The second +field represents the URI. This option will disable URIs +getting from command\-line. If \(aq\-\(aq is given as , +script lines will be read from stdin. Script lines are +used in order for each client. If \fI\%\-n\fP is given, it must be +less than or equal to the number of script lines, larger +values are clamped to the number of script lines. If \fI\%\-n\fP +is not given, the number of requests will default to the number of script lines. The scheme, host and port defined in the first URI are used solely. Values contained in other URIs, if present, are ignored. Definition of a diff --git a/doc/h2load.1.rst b/doc/h2load.1.rst index 08804352..f7e7b42b 100644 --- a/doc/h2load.1.rst +++ b/doc/h2load.1.rst @@ -150,15 +150,15 @@ OPTIONS Path of a file containing one or more lines separated by EOLs. Each script line is composed of two tab-separated fields. The first field represents the time offset from - the start of execution, expressed as milliseconds with - microsecond resolution. The second field represents the - URI. This option will disable URIs getting from - command-line. If '-' is given as , script lines - will be read from stdin. Script lines are used in order - for each client. If :option:`-n` is given, it must be less than - or equal to the number of script lines, larger values are - clamped to the number of script lines. If :option:`-n` is - not given, the number of requests will default to the + the start of execution, expressed as a positive value of + milliseconds with microsecond resolution. The second + field represents the URI. This option will disable URIs + getting from command-line. If '-' is given as , + script lines will be read from stdin. Script lines are + used in order for each client. If :option:`-n` is given, it must be + less than or equal to the number of script lines, larger + values are clamped to the number of script lines. If :option:`-n` + is not given, the number of requests will default to the number of script lines. The scheme, host and port defined in the first URI are used solely. Values contained in other URIs, if present, are ignored. Definition of a diff --git a/doc/nghttp.1 b/doc/nghttp.1 index 15d82481..de22bf0f 100644 --- a/doc/nghttp.1 +++ b/doc/nghttp.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "NGHTTP" "1" "August 30, 2015" "1.3.0" "nghttp2" +.TH "NGHTTP" "1" "September 06, 2015" "1.3.1-DEV" "nghttp2" .SH NAME nghttp \- HTTP/2 experimental client . diff --git a/doc/nghttpd.1 b/doc/nghttpd.1 index 0749e646..41b7d46d 100644 --- a/doc/nghttpd.1 +++ b/doc/nghttpd.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "NGHTTPD" "1" "August 30, 2015" "1.3.0" "nghttp2" +.TH "NGHTTPD" "1" "September 06, 2015" "1.3.1-DEV" "nghttp2" .SH NAME nghttpd \- HTTP/2 experimental server . diff --git a/doc/nghttpx.1 b/doc/nghttpx.1 index 52819ff3..2db514e9 100644 --- a/doc/nghttpx.1 +++ b/doc/nghttpx.1 @@ -1,6 +1,6 @@ .\" Man page generated from reStructuredText. . -.TH "NGHTTPX" "1" "August 30, 2015" "1.3.0" "nghttp2" +.TH "NGHTTPX" "1" "September 06, 2015" "1.3.1-DEV" "nghttp2" .SH NAME nghttpx \- HTTP/2 experimental proxy . @@ -905,6 +905,21 @@ Set path to save PID of this program. Run this program as . This option is intended to be used to drop root privileges. .UNINDENT +.SS Scripting +.INDENT 0.0 +.TP +.B \-\-request\-phase\-file= +Set mruby script file which will be executed when +request header fields are completely received from +frontend. This hook is called request phase hook. +.UNINDENT +.INDENT 0.0 +.TP +.B \-\-response\-phase\-file= +Set mruby script file which will be executed when +response header fields are completely received from +backend. This hook is called response phase hook. +.UNINDENT .SS Misc .INDENT 0.0 .TP @@ -1003,19 +1018,14 @@ Link: ; rel=preload .UNINDENT .UNINDENT .sp -Currently, the following restrictions are applied for server push: +Currently, the following restriction is applied for server push: .INDENT 0.0 .IP 1. 3 -URI\-reference must not contain authority. If it exists, it is not -pushed. \fB/fonts/font.woff\fP and \fBcss/theme.css\fP are eligible to -be pushed. \fBhttps://example.org/fonts/font.woff\fP and -\fB//example.org/css/theme.css\fP are not. -.IP 2. 3 The associated stream must have method "GET" or "POST". The associated stream\(aqs status code must be 200. .UNINDENT .sp -These limitations may be loosened in the future release. +This limitation may be loosened in the future release. .SH UNIX DOMAIN SOCKET .sp nghttpx supports UNIX domain socket with a filename for both frontend @@ -1101,6 +1111,278 @@ If \fI\%\-\-tls\-ticket\-key\-file\fP is given, encryption key is read from the given file. In this case, nghttpx does not rotate key automatically. To rotate key, one has to restart nghttpx (see SIGNALS). +.SH MRUBY SCRIPTING +.sp +\fBWARNING:\fP +.INDENT 0.0 +.INDENT 3.5 +The current mruby extension API is experimental and not frozen. The +API is subject to change in the future release. +.UNINDENT +.UNINDENT +.sp +nghttpx allows users to extend its capability using mruby scripts. +nghttpx has 2 hook points to execute mruby script: request phase and +response phase. The request phase hook is invoked after all request +header fields are received from client. The response phase hook is +invoked after all response header fields are received from backend +server. These hooks allows users to modify header fields, or common +HTTP variables, like authority or request path, and even return custom +response without forwarding request to backend servers. +.sp +To set request phase hook, use \fI\%\-\-request\-phase\-file\fP option. +To set response phase hook, use \fI\%\-\-response\-phase\-file\fP +option. +.sp +For request and response phase hook, user calls \fI\%Nghttpx.run\fP +with block. The \fI\%Nghttpx::Env\fP is passed to the block. +User can can access \fI\%Nghttpx::Request\fP and +\fI\%Nghttpx::Response\fP objects via \fI\%Nghttpx::Env#req\fP +and \fI\%Nghttpx::Env#resp\fP respectively. +.INDENT 0.0 +.TP +.B classmethod .Nghttpx.run(&block) +Run request or response phase hook with given \fIblock\fP\&. +\fI\%Nghttpx::Env\fP object is passed to the given block. +.UNINDENT +.INDENT 0.0 +.TP +.B Nghttpx::REQUEST_PHASE +Constant to represent request phase. +.UNINDENT +.INDENT 0.0 +.TP +.B Nghttpx::RESPONSE_PHASE +Constant to represent response phase. +.UNINDENT +.INDENT 0.0 +.TP +.B class Nghttpx::Env +Object to represent current request specific context. +.INDENT 7.0 +.TP +.B attribute [R] req +Return \fI\%Request\fP object. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] resp +Return \fI\%Response\fP object. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] ctx +Return Ruby hash object. It persists until request finishes. +So values set in request phase hoo can be retrieved in +response phase hook. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] phase +Return the current phase. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] remote_addr +Return IP address of a remote client. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B class Nghttpx::Request +Object to represent request from client. The modification to +Request object is allowed only in request phase hook. +.INDENT 7.0 +.TP +.B attribute [R] http_version_major +Return HTTP major version. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] http_version_minor +Return HTTP minor version. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R/W] method +HTTP method. On assignment, copy of given value is assigned. +We don\(aqt accept arbitrary method name. We will document them +later, but well known methods, like GET, PUT and POST, are all +supported. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R/W] authority +Authority (i.e., example.org), including optional port +component . On assignment, copy of given value is assigned. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R/W] scheme +Scheme (i.e., http, https). On assignment, copy of given +value is assigned. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R/W] path +Request path, including query component (i.e., /index.html). +On assignment, copy of given value is assigned. The path does +not include authority component of URI. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] headers +Return Ruby hash containing copy of request header fields. +Changing values in returned hash does not change request +header fields actually used in request processing. Use +\fI\%Nghttpx::Request#add_header\fP or +\fI\%Nghttpx::Request#set_header\fP to change request +header fields. +.UNINDENT +.INDENT 7.0 +.TP +.B add_header(key, value) +Add header entry associated with key. The value can be single +string or array of string. It does not replace any existing +values associated with key. +.UNINDENT +.INDENT 7.0 +.TP +.B set_header(key, value) +Set header entry associated with key. The value can be single +string or array of string. It replaces any existing values +associated with key. +.UNINDENT +.INDENT 7.0 +.TP +.B clear_headers() +Clear all existing request header fields. +.UNINDENT +.INDENT 7.0 +.TP +.B push uri +Initiate to push resource identified by \fIuri\fP\&. Only HTTP/2 +protocol supports this feature. For the other protocols, this +method is noop. \fIuri\fP can be absolute URI, absolute path or +relative path to the current request. For absolute or +relative path, scheme and authority are inherited from the +current request. Currently, method is always GET. nghttpx +will issue request to backend servers to fulfill this request. +The request and response phase hooks will be called for pushed +resource as well. +.UNINDENT +.UNINDENT +.INDENT 0.0 +.TP +.B class Nghttpx::Response +Object to represent response from backend server. +.INDENT 7.0 +.TP +.B attribute [R] http_version_major +Return HTTP major version. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] http_version_minor +Return HTTP minor version. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R/W] status +HTTP status code. It must be in the range [200, 999], +inclusive. The non\-final status code is not supported in +mruby scripting at the moment. +.UNINDENT +.INDENT 7.0 +.TP +.B attribute [R] headers +Return Ruby hash containing copy of response header fields. +Changing values in returned hash does not change response +header fields actually used in response processing. Use +\fI\%Nghttpx::Response#add_header\fP or +\fI\%Nghttpx::Response#set_header\fP to change response +header fields. +.UNINDENT +.INDENT 7.0 +.TP +.B add_header(key, value) +Add header entry associated with key. The value can be single +string or array of string. It does not replace any existing +values associated with key. +.UNINDENT +.INDENT 7.0 +.TP +.B set_header(key, value) +Set header entry associated with key. The value can be single +string or array of string. It replaces any existing values +associated with key. +.UNINDENT +.INDENT 7.0 +.TP +.B clear_headers() +Clear all existing response header fields. +.UNINDENT +.INDENT 7.0 +.TP +.B return(body) +Return custom response \fIbody\fP to a client. When this method +is called in request phase hook, the request is not forwarded +to the backend, and response phase hook for this request will +not be invoked. When this method is called in resonse phase +hook, response from backend server is canceled and discarded. +The status code and response header fields should be set +before using this method. To set status code, use :rb:meth To +set response header fields, use +\fI\%Nghttpx::Response#status\fP\&. If status code is not +set, 200 is used. \fI\%Nghttpx::Response#add_header\fP and +\fI\%Nghttpx::Response#set_header\fP\&. When this method is +invoked in response phase hook, the response headers are +filled with the ones received from backend server. To send +completely custom header fields, first call +\fI\%Nghttpx::Response#clear_headers\fP to erase all +existing header fields, and then add required header fields. +It is an error to call this method twice for a given request. +.UNINDENT +.UNINDENT +.SS MRUBY EXAMPLES +.sp +Modify requet path: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +Nghttpx.run do |env| + env.req.path = "/apps#{env.req.path}" +end +.ft P +.fi +.UNINDENT +.UNINDENT +.sp +Note that the file containing the above script must be set with +\fI\%\-\-request\-phase\-file\fP option since we modify request path. +.sp +Restrict permission of viewing a content to a specific client +addresses: +.INDENT 0.0 +.INDENT 3.5 +.sp +.nf +.ft C +Nghttpx.run do |env| + allowed_clients = ["127.0.0.1", "::1"] + + if env.req.path.start_with?("/log/") && + !allowed_clients.include?(env.remote_addr) then + env.resp.status = 404 + env.resp.return "permission denied" + end +end +.ft P +.fi +.UNINDENT +.UNINDENT .SH SEE ALSO .sp \fInghttp(1)\fP, \fInghttpd(1)\fP, \fIh2load(1)\fP diff --git a/doc/nghttpx.1.rst b/doc/nghttpx.1.rst index beeb0916..9f8558f2 100644 --- a/doc/nghttpx.1.rst +++ b/doc/nghttpx.1.rst @@ -811,6 +811,22 @@ Process be used to drop root privileges. +Scripting +~~~~~~~~~ + +.. option:: --request-phase-file= + + Set mruby script file which will be executed when + request header fields are completely received from + frontend. This hook is called request phase hook. + +.. option:: --response-phase-file= + + Set mruby script file which will be executed when + response header fields are completely received from + backend. This hook is called response phase hook. + + Misc ~~~~ @@ -906,17 +922,12 @@ header field to initiate server push: Link: ; rel=preload Link: ; rel=preload -Currently, the following restrictions are applied for server push: +Currently, the following restriction is applied for server push: -1. URI-reference must not contain authority. If it exists, it is not - pushed. ``/fonts/font.woff`` and ``css/theme.css`` are eligible to - be pushed. ``https://example.org/fonts/font.woff`` and - ``//example.org/css/theme.css`` are not. - -2. The associated stream must have method "GET" or "POST". The +1. The associated stream must have method "GET" or "POST". The associated stream's status code must be 200. -These limitations may be loosened in the future release. +This limitation may be loosened in the future release. UNIX DOMAIN SOCKET ------------------ @@ -1005,6 +1016,239 @@ from the given file. In this case, nghttpx does not rotate key automatically. To rotate key, one has to restart nghttpx (see SIGNALS). +MRUBY SCRIPTING +--------------- + +.. warning:: + + The current mruby extension API is experimental and not frozen. The + API is subject to change in the future release. + +nghttpx allows users to extend its capability using mruby scripts. +nghttpx has 2 hook points to execute mruby script: request phase and +response phase. The request phase hook is invoked after all request +header fields are received from client. The response phase hook is +invoked after all response header fields are received from backend +server. These hooks allows users to modify header fields, or common +HTTP variables, like authority or request path, and even return custom +response without forwarding request to backend servers. + +To set request phase hook, use :option:`--request-phase-file` option. +To set response phase hook, use :option:`--response-phase-file` +option. + +For request and response phase hook, user calls :rb:meth:`Nghttpx.run` +with block. The :rb:class:`Nghttpx::Env` is passed to the block. +User can can access :rb:class:`Nghttpx::Request` and +:rb:class:`Nghttpx::Response` objects via :rb:attr:`Nghttpx::Env#req` +and :rb:attr:`Nghttpx::Env#resp` respectively. + +.. rb:module:: Nghttpx + +.. rb:classmethod:: run(&block) + + Run request or response phase hook with given *block*. + :rb:class:`Nghttpx::Env` object is passed to the given block. + +.. rb:const:: REQUEST_PHASE + + Constant to represent request phase. + +.. rb:const:: RESPONSE_PHASE + + Constant to represent response phase. + +.. rb:class:: Env + + Object to represent current request specific context. + + .. rb:attr_reader:: req + + Return :rb:class:`Request` object. + + .. rb:attr_reader:: resp + + Return :rb:class:`Response` object. + + .. rb:attr_reader:: ctx + + Return Ruby hash object. It persists until request finishes. + So values set in request phase hoo can be retrieved in + response phase hook. + + .. rb:attr_reader:: phase + + Return the current phase. + + .. rb:attr_reader:: remote_addr + + Return IP address of a remote client. + +.. rb:class:: Request + + Object to represent request from client. The modification to + Request object is allowed only in request phase hook. + + .. rb:attr_reader:: http_version_major + + Return HTTP major version. + + .. rb:attr_reader:: http_version_minor + + Return HTTP minor version. + + .. rb:attr_accessor:: method + + HTTP method. On assignment, copy of given value is assigned. + We don't accept arbitrary method name. We will document them + later, but well known methods, like GET, PUT and POST, are all + supported. + + .. rb:attr_accessor:: authority + + Authority (i.e., example.org), including optional port + component . On assignment, copy of given value is assigned. + + .. rb:attr_accessor:: scheme + + Scheme (i.e., http, https). On assignment, copy of given + value is assigned. + + .. rb:attr_accessor:: path + + Request path, including query component (i.e., /index.html). + On assignment, copy of given value is assigned. The path does + not include authority component of URI. + + .. rb:attr_reader:: headers + + Return Ruby hash containing copy of request header fields. + Changing values in returned hash does not change request + header fields actually used in request processing. Use + :rb:meth:`Nghttpx::Request#add_header` or + :rb:meth:`Nghttpx::Request#set_header` to change request + header fields. + + .. rb:method:: add_header(key, value) + + Add header entry associated with key. The value can be single + string or array of string. It does not replace any existing + values associated with key. + + .. rb:method:: set_header(key, value) + + Set header entry associated with key. The value can be single + string or array of string. It replaces any existing values + associated with key. + + .. rb:method:: clear_headers + + Clear all existing request header fields. + + .. rb:method:: push uri + + Initiate to push resource identified by *uri*. Only HTTP/2 + protocol supports this feature. For the other protocols, this + method is noop. *uri* can be absolute URI, absolute path or + relative path to the current request. For absolute or + relative path, scheme and authority are inherited from the + current request. Currently, method is always GET. nghttpx + will issue request to backend servers to fulfill this request. + The request and response phase hooks will be called for pushed + resource as well. + +.. rb:class:: Response + + Object to represent response from backend server. + + .. rb:attr_reader:: http_version_major + + Return HTTP major version. + + .. rb:attr_reader:: http_version_minor + + Return HTTP minor version. + + .. rb:attr_accessor:: status + + HTTP status code. It must be in the range [200, 999], + inclusive. The non-final status code is not supported in + mruby scripting at the moment. + + .. rb:attr_reader:: headers + + Return Ruby hash containing copy of response header fields. + Changing values in returned hash does not change response + header fields actually used in response processing. Use + :rb:meth:`Nghttpx::Response#add_header` or + :rb:meth:`Nghttpx::Response#set_header` to change response + header fields. + + .. rb:method:: add_header(key, value) + + Add header entry associated with key. The value can be single + string or array of string. It does not replace any existing + values associated with key. + + .. rb:method:: set_header(key, value) + + Set header entry associated with key. The value can be single + string or array of string. It replaces any existing values + associated with key. + + .. rb:method:: clear_headers + + Clear all existing response header fields. + + .. rb:method:: return(body) + + Return custom response *body* to a client. When this method + is called in request phase hook, the request is not forwarded + to the backend, and response phase hook for this request will + not be invoked. When this method is called in resonse phase + hook, response from backend server is canceled and discarded. + The status code and response header fields should be set + before using this method. To set status code, use :rb:meth To + set response header fields, use + :rb:attr:`Nghttpx::Response#status`. If status code is not + set, 200 is used. :rb:meth:`Nghttpx::Response#add_header` and + :rb:meth:`Nghttpx::Response#set_header`. When this method is + invoked in response phase hook, the response headers are + filled with the ones received from backend server. To send + completely custom header fields, first call + :rb:meth:`Nghttpx::Response#clear_headers` to erase all + existing header fields, and then add required header fields. + It is an error to call this method twice for a given request. + +MRUBY EXAMPLES +~~~~~~~~~~~~~~ + +Modify requet path: + +.. code-block:: ruby + + Nghttpx.run do |env| + env.req.path = "/apps#{env.req.path}" + end + +Note that the file containing the above script must be set with +:option:`--request-phase-file` option since we modify request path. + +Restrict permission of viewing a content to a specific client +addresses: + +.. code-block:: ruby + + Nghttpx.run do |env| + allowed_clients = ["127.0.0.1", "::1"] + + if env.req.path.start_with?("/log/") && + !allowed_clients.include?(env.remote_addr) then + env.resp.status = 404 + env.resp.return "permission denied" + end + end + SEE ALSO --------