Mercurial > hg > nginx-site
comparison xml/en/docs/dev/development_guide.xml @ 2765:5e3591372bf6
Development guide: request body filters section.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Wed, 01 Sep 2021 17:07:19 +0300 |
parents | 454af1d39021 |
children | b7ff3d1915a1 |
comparison
equal
deleted
inserted
replaced
2764:bc9c5d11b67c | 2765:5e3591372bf6 |
---|---|
5686 </para> | 5686 </para> |
5687 | 5687 |
5688 </section> | 5688 </section> |
5689 | 5689 |
5690 | 5690 |
5691 <section name="Request body filters" id="http_request_body_filters"> | |
5692 | |
5693 <para> | |
5694 After a request body part is read, it's passed to the request | |
5695 body filter chain by calling the first body filter handler stored in | |
5696 the <literal>ngx_http_top_request_body_filter</literal> variable. | |
5697 It's assumed that every body handler calls the next handler in the chain until | |
5698 the final handler <literal>ngx_http_request_body_save_filter(r, cl)</literal> | |
5699 is called. | |
5700 This handler collects the buffers in | |
5701 <literal>r->request_body->bufs</literal> | |
5702 and writes them to a file if necessary. | |
5703 The last request body buffer has nonzero <literal>last_buf</literal> flag. | |
5704 </para> | |
5705 | |
5706 <para> | |
5707 If a filter is planning to delay data buffers, it should set the flag | |
5708 <literal>r->request_body->filter_need_buffering</literal> to | |
5709 <literal>1</literal> when called for the first time. | |
5710 </para> | |
5711 | |
5712 <para> | |
5713 Following is an example of a simple request body filter that delays request | |
5714 body by one second. | |
5715 </para> | |
5716 | |
5717 <programlisting> | |
5718 #include <ngx_config.h> | |
5719 #include <ngx_core.h> | |
5720 #include <ngx_http.h> | |
5721 | |
5722 | |
5723 #define NGX_HTTP_DELAY_BODY 1000 | |
5724 | |
5725 | |
5726 typedef struct { | |
5727 ngx_event_t event; | |
5728 ngx_chain_t *out; | |
5729 } ngx_http_delay_body_ctx_t; | |
5730 | |
5731 | |
5732 static ngx_int_t ngx_http_delay_body_filter(ngx_http_request_t *r, | |
5733 ngx_chain_t *in); | |
5734 static void ngx_http_delay_body_cleanup(void *data); | |
5735 static void ngx_http_delay_body_event_handler(ngx_event_t *ev); | |
5736 static ngx_int_t ngx_http_delay_body_init(ngx_conf_t *cf); | |
5737 | |
5738 | |
5739 static ngx_http_module_t ngx_http_delay_body_module_ctx = { | |
5740 NULL, /* preconfiguration */ | |
5741 ngx_http_delay_body_init, /* postconfiguration */ | |
5742 | |
5743 NULL, /* create main configuration */ | |
5744 NULL, /* init main configuration */ | |
5745 | |
5746 NULL, /* create server configuration */ | |
5747 NULL, /* merge server configuration */ | |
5748 | |
5749 NULL, /* create location configuration */ | |
5750 NULL /* merge location configuration */ | |
5751 }; | |
5752 | |
5753 | |
5754 ngx_module_t ngx_http_delay_body_filter_module = { | |
5755 NGX_MODULE_V1, | |
5756 &ngx_http_delay_body_module_ctx, /* module context */ | |
5757 NULL, /* module directives */ | |
5758 NGX_HTTP_MODULE, /* module type */ | |
5759 NULL, /* init master */ | |
5760 NULL, /* init module */ | |
5761 NULL, /* init process */ | |
5762 NULL, /* init thread */ | |
5763 NULL, /* exit thread */ | |
5764 NULL, /* exit process */ | |
5765 NULL, /* exit master */ | |
5766 NGX_MODULE_V1_PADDING | |
5767 }; | |
5768 | |
5769 | |
5770 static ngx_http_request_body_filter_pt ngx_http_next_request_body_filter; | |
5771 | |
5772 | |
5773 static ngx_int_t | |
5774 ngx_http_delay_body_filter(ngx_http_request_t *r, ngx_chain_t *in) | |
5775 { | |
5776 ngx_int_t rc; | |
5777 ngx_chain_t *cl, *ln; | |
5778 ngx_http_cleanup_t *cln; | |
5779 ngx_http_delay_body_ctx_t *ctx; | |
5780 | |
5781 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
5782 "delay request body filter"); | |
5783 | |
5784 ctx = ngx_http_get_module_ctx(r, ngx_http_delay_body_filter_module); | |
5785 | |
5786 if (ctx == NULL) { | |
5787 ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_delay_body_ctx_t)); | |
5788 if (ctx == NULL) { | |
5789 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
5790 } | |
5791 | |
5792 ngx_http_set_ctx(r, ctx, ngx_http_delay_body_filter_module); | |
5793 | |
5794 r->request_body->filter_need_buffering = 1; | |
5795 } | |
5796 | |
5797 if (ngx_chain_add_copy(r->pool, &ctx->out, in) != NGX_OK) { | |
5798 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
5799 } | |
5800 | |
5801 if (!ctx->event.timedout) { | |
5802 if (!ctx->event.timer_set) { | |
5803 | |
5804 /* cleanup to remove the timer in case of abnormal termination */ | |
5805 | |
5806 cln = ngx_http_cleanup_add(r, 0); | |
5807 if (cln == NULL) { | |
5808 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
5809 } | |
5810 | |
5811 cln->handler = ngx_http_delay_body_cleanup; | |
5812 cln->data = ctx; | |
5813 | |
5814 /* add timer */ | |
5815 | |
5816 ctx->event.handler = ngx_http_delay_body_event_handler; | |
5817 ctx->event.data = r; | |
5818 ctx->event.log = r->connection->log; | |
5819 | |
5820 ngx_add_timer(&ctx->event, NGX_HTTP_DELAY_BODY); | |
5821 } | |
5822 | |
5823 return ngx_http_next_request_body_filter(r, NULL); | |
5824 } | |
5825 | |
5826 rc = ngx_http_next_request_body_filter(r, ctx->out); | |
5827 | |
5828 for (cl = ctx->out; cl; /* void */) { | |
5829 ln = cl; | |
5830 cl = cl->next; | |
5831 ngx_free_chain(r->pool, ln); | |
5832 } | |
5833 | |
5834 ctx->out = NULL; | |
5835 | |
5836 return rc; | |
5837 } | |
5838 | |
5839 | |
5840 static void | |
5841 ngx_http_delay_body_cleanup(void *data) | |
5842 { | |
5843 ngx_http_delay_body_ctx_t *ctx = data; | |
5844 | |
5845 if (ctx->event.timer_set) { | |
5846 ngx_del_timer(&ctx->event); | |
5847 } | |
5848 } | |
5849 | |
5850 | |
5851 static void | |
5852 ngx_http_delay_body_event_handler(ngx_event_t *ev) | |
5853 { | |
5854 ngx_connection_t *c; | |
5855 ngx_http_request_t *r; | |
5856 | |
5857 r = ev->data; | |
5858 c = r->connection; | |
5859 | |
5860 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, | |
5861 "delay request body event"); | |
5862 | |
5863 ngx_post_event(c->read, &ngx_posted_events); | |
5864 } | |
5865 | |
5866 | |
5867 static ngx_int_t | |
5868 ngx_http_delay_body_init(ngx_conf_t *cf) | |
5869 { | |
5870 ngx_http_next_request_body_filter = ngx_http_top_request_body_filter; | |
5871 ngx_http_top_request_body_filter = ngx_http_delay_body_filter; | |
5872 | |
5873 return NGX_OK; | |
5874 } | |
5875 </programlisting> | |
5876 | |
5877 </section> | |
5878 | |
5879 | |
5691 <section name="Response" id="http_response"> | 5880 <section name="Response" id="http_response"> |
5692 | 5881 |
5693 <para> | 5882 <para> |
5694 In nginx an HTTP response is produced by sending the response header followed by | 5883 In nginx an HTTP response is produced by sending the response header followed by |
5695 the optional response body. | 5884 the optional response body. |
5929 </programlisting> | 6118 </programlisting> |
5930 | 6119 |
5931 </section> | 6120 </section> |
5932 | 6121 |
5933 | 6122 |
5934 <section name="Body filters" id="http_body_filters"> | 6123 <section name="Response body filters" id="http_response_body_filters"> |
5935 | 6124 |
5936 <para> | 6125 <para> |
5937 The function <literal>ngx_http_output_filter(r, cl)</literal> invokes the | 6126 The function <literal>ngx_http_output_filter(r, cl)</literal> invokes the |
5938 body filter chain by calling the first body filter handler stored in | 6127 body filter chain by calling the first body filter handler stored in |
5939 the <literal>ngx_http_top_body_filter</literal> variable. | 6128 the <literal>ngx_http_top_body_filter</literal> variable. |