upstream nginx-0.7.31
[nginx.git] / nginx / src / http / ngx_http_postpone_filter_module.c
1
2 /*
3  * Copyright (C) Igor Sysoev
4  */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11
12 static ngx_int_t ngx_http_postpone_filter_add(ngx_http_request_t *r,
13     ngx_chain_t *in);
14 static ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf);
15
16
17 static ngx_http_module_t  ngx_http_postpone_filter_module_ctx = {
18     NULL,                                  /* preconfiguration */
19     ngx_http_postpone_filter_init,         /* postconfiguration */
20
21     NULL,                                  /* create main configuration */
22     NULL,                                  /* init main configuration */
23
24     NULL,                                  /* create server configuration */
25     NULL,                                  /* merge server configuration */
26
27     NULL,                                  /* create location configuration */
28     NULL                                   /* merge location configuration */
29 };
30
31
32 ngx_module_t  ngx_http_postpone_filter_module = {
33     NGX_MODULE_V1,
34     &ngx_http_postpone_filter_module_ctx,  /* module context */
35     NULL,                                  /* module directives */
36     NGX_HTTP_MODULE,                       /* module type */
37     NULL,                                  /* init master */
38     NULL,                                  /* init module */
39     NULL,                                  /* init process */
40     NULL,                                  /* init thread */
41     NULL,                                  /* exit thread */
42     NULL,                                  /* exit process */
43     NULL,                                  /* exit master */
44     NGX_MODULE_V1_PADDING
45 };
46
47
48 static ngx_http_output_body_filter_pt    ngx_http_next_filter;
49
50
51 static ngx_int_t
52 ngx_http_postpone_filter(ngx_http_request_t *r, ngx_chain_t *in)
53 {
54     ngx_connection_t              *c;
55     ngx_http_postponed_request_t  *pr;
56
57     c = r->connection;
58
59     ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
60                    "http postpone filter \"%V?%V\" %p", &r->uri, &r->args, in);
61
62     if (r != c->data) {
63
64         if (in) {
65             ngx_http_postpone_filter_add(r, in);
66             return NGX_OK;
67         }
68
69 #if 0
70         /* TODO: SSI may pass NULL */
71         ngx_log_error(NGX_LOG_ALERT, c->log, 0,
72                       "http postpone filter NULL inactive request",
73                       &r->uri, &r->args);
74 #endif
75
76         return NGX_OK;
77     }
78
79     if (r->postponed == NULL) {
80
81         if (in || c->buffered) {
82             return ngx_http_next_filter(r->main, in);
83         }
84
85         return NGX_OK;
86     }
87
88     if (in) {
89         ngx_http_postpone_filter_add(r, in);
90     }
91
92     do {
93         pr = r->postponed;
94
95         if (pr->request) {
96
97             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
98                            "http postpone filter wake \"%V?%V\"",
99                            &pr->request->uri, &pr->request->args);
100
101             r->postponed = pr->next;
102
103             c->data = pr->request;
104
105             return ngx_http_post_request(pr->request);
106         }
107
108         if (pr->out == NULL) {
109             ngx_log_error(NGX_LOG_ALERT, c->log, 0,
110                           "http postpone filter NULL output",
111                           &r->uri, &r->args);
112
113         } else {
114             ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
115                            "http postpone filter output \"%V?%V\"",
116                            &r->uri, &r->args);
117
118             if (ngx_http_next_filter(r->main, pr->out) == NGX_ERROR) {
119                 return NGX_ERROR;
120             }
121         }
122
123         r->postponed = pr->next;
124
125     } while (r->postponed);
126
127     return NGX_OK;
128 }
129
130
131 static ngx_int_t
132 ngx_http_postpone_filter_add(ngx_http_request_t *r, ngx_chain_t *in)
133 {
134     ngx_http_postponed_request_t  *pr, **ppr;
135
136     if (r->postponed) {
137         for (pr = r->postponed; pr->next; pr = pr->next) { /* void */ }
138
139         if (pr->request == NULL) {
140             goto found;
141         }
142
143         ppr = &pr->next;
144
145     } else {
146         ppr = &r->postponed;
147     }
148
149     pr = ngx_palloc(r->pool, sizeof(ngx_http_postponed_request_t));
150     if (pr == NULL) {
151         return NGX_ERROR;
152     }
153
154     *ppr = pr;
155
156     pr->request = NULL;
157     pr->out = NULL;
158     pr->next = NULL;
159
160 found:
161
162     if (ngx_chain_add_copy(r->pool, &pr->out, in) == NGX_OK) {
163         return NGX_OK;
164     }
165
166     return NGX_ERROR;
167 }
168
169
170 static ngx_int_t
171 ngx_http_postpone_filter_init(ngx_conf_t *cf)
172 {
173     ngx_http_next_filter = ngx_http_top_body_filter;
174     ngx_http_top_body_filter = ngx_http_postpone_filter;
175
176     return NGX_OK;
177 }