1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Roman Arutyunyan
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_stream.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyevtypedef struct {
14e18a033bSKonstantin Ananyev    ngx_stream_complex_value_t   text;
15e18a033bSKonstantin Ananyev} ngx_stream_return_srv_conf_t;
16e18a033bSKonstantin Ananyev
17e18a033bSKonstantin Ananyev
18e18a033bSKonstantin Ananyevtypedef struct {
19e18a033bSKonstantin Ananyev    ngx_chain_t                 *out;
20e18a033bSKonstantin Ananyev} ngx_stream_return_ctx_t;
21e18a033bSKonstantin Ananyev
22e18a033bSKonstantin Ananyev
23e18a033bSKonstantin Ananyevstatic void ngx_stream_return_handler(ngx_stream_session_t *s);
24e18a033bSKonstantin Ananyevstatic void ngx_stream_return_write_handler(ngx_event_t *ev);
25e18a033bSKonstantin Ananyev
26e18a033bSKonstantin Ananyevstatic void *ngx_stream_return_create_srv_conf(ngx_conf_t *cf);
27e18a033bSKonstantin Ananyevstatic char *ngx_stream_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
28e18a033bSKonstantin Ananyev
29e18a033bSKonstantin Ananyev
30e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_stream_return_commands[] = {
31e18a033bSKonstantin Ananyev
32e18a033bSKonstantin Ananyev    { ngx_string("return"),
33e18a033bSKonstantin Ananyev      NGX_STREAM_SRV_CONF|NGX_CONF_TAKE1,
34e18a033bSKonstantin Ananyev      ngx_stream_return,
35e18a033bSKonstantin Ananyev      NGX_STREAM_SRV_CONF_OFFSET,
36e18a033bSKonstantin Ananyev      0,
37e18a033bSKonstantin Ananyev      NULL },
38e18a033bSKonstantin Ananyev
39e18a033bSKonstantin Ananyev      ngx_null_command
40e18a033bSKonstantin Ananyev};
41e18a033bSKonstantin Ananyev
42e18a033bSKonstantin Ananyev
43e18a033bSKonstantin Ananyevstatic ngx_stream_module_t  ngx_stream_return_module_ctx = {
44e18a033bSKonstantin Ananyev    NULL,                                  /* preconfiguration */
45e18a033bSKonstantin Ananyev    NULL,                                  /* postconfiguration */
46e18a033bSKonstantin Ananyev
47e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
48e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
49e18a033bSKonstantin Ananyev
50e18a033bSKonstantin Ananyev    ngx_stream_return_create_srv_conf,     /* create server configuration */
51e18a033bSKonstantin Ananyev    NULL                                   /* merge server configuration */
52e18a033bSKonstantin Ananyev};
53e18a033bSKonstantin Ananyev
54e18a033bSKonstantin Ananyev
55e18a033bSKonstantin Ananyevngx_module_t  ngx_stream_return_module = {
56e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
57e18a033bSKonstantin Ananyev    &ngx_stream_return_module_ctx,         /* module context */
58e18a033bSKonstantin Ananyev    ngx_stream_return_commands,            /* module directives */
59e18a033bSKonstantin Ananyev    NGX_STREAM_MODULE,                     /* module type */
60e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
61e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
62e18a033bSKonstantin Ananyev    NULL,                                  /* init process */
63e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
64e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
65e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
66e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
67e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
68e18a033bSKonstantin Ananyev};
69e18a033bSKonstantin Ananyev
70e18a033bSKonstantin Ananyev
71e18a033bSKonstantin Ananyevstatic void
72e18a033bSKonstantin Ananyevngx_stream_return_handler(ngx_stream_session_t *s)
73e18a033bSKonstantin Ananyev{
74e18a033bSKonstantin Ananyev    ngx_str_t                      text;
75e18a033bSKonstantin Ananyev    ngx_buf_t                     *b;
76e18a033bSKonstantin Ananyev    ngx_connection_t              *c;
77e18a033bSKonstantin Ananyev    ngx_stream_return_ctx_t       *ctx;
78e18a033bSKonstantin Ananyev    ngx_stream_return_srv_conf_t  *rscf;
79e18a033bSKonstantin Ananyev
80e18a033bSKonstantin Ananyev    c = s->connection;
81e18a033bSKonstantin Ananyev
82e18a033bSKonstantin Ananyev    c->log->action = "returning text";
83e18a033bSKonstantin Ananyev
84e18a033bSKonstantin Ananyev    rscf = ngx_stream_get_module_srv_conf(s, ngx_stream_return_module);
85e18a033bSKonstantin Ananyev
86e18a033bSKonstantin Ananyev    if (ngx_stream_complex_value(s, &rscf->text, &text) != NGX_OK) {
87e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
88e18a033bSKonstantin Ananyev        return;
89e18a033bSKonstantin Ananyev    }
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_STREAM, c->log, 0,
92e18a033bSKonstantin Ananyev                   "stream return text: \"%V\"", &text);
93e18a033bSKonstantin Ananyev
94e18a033bSKonstantin Ananyev    if (text.len == 0) {
95e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_OK);
96e18a033bSKonstantin Ananyev        return;
97e18a033bSKonstantin Ananyev    }
98e18a033bSKonstantin Ananyev
99e18a033bSKonstantin Ananyev    ctx = ngx_pcalloc(c->pool, sizeof(ngx_stream_return_ctx_t));
100e18a033bSKonstantin Ananyev    if (ctx == NULL) {
101e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
102e18a033bSKonstantin Ananyev        return;
103e18a033bSKonstantin Ananyev    }
104e18a033bSKonstantin Ananyev
105e18a033bSKonstantin Ananyev    ngx_stream_set_ctx(s, ctx, ngx_stream_return_module);
106e18a033bSKonstantin Ananyev
107e18a033bSKonstantin Ananyev    b = ngx_calloc_buf(c->pool);
108e18a033bSKonstantin Ananyev    if (b == NULL) {
109e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
110e18a033bSKonstantin Ananyev        return;
111e18a033bSKonstantin Ananyev    }
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev    b->memory = 1;
114e18a033bSKonstantin Ananyev    b->pos = text.data;
115e18a033bSKonstantin Ananyev    b->last = text.data + text.len;
116e18a033bSKonstantin Ananyev    b->last_buf = 1;
117e18a033bSKonstantin Ananyev
118e18a033bSKonstantin Ananyev    ctx->out = ngx_alloc_chain_link(c->pool);
119e18a033bSKonstantin Ananyev    if (ctx->out == NULL) {
120e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
121e18a033bSKonstantin Ananyev        return;
122e18a033bSKonstantin Ananyev    }
123e18a033bSKonstantin Ananyev
124e18a033bSKonstantin Ananyev    ctx->out->buf = b;
125e18a033bSKonstantin Ananyev    ctx->out->next = NULL;
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev    c->write->handler = ngx_stream_return_write_handler;
128e18a033bSKonstantin Ananyev
129e18a033bSKonstantin Ananyev    ngx_stream_return_write_handler(c->write);
130e18a033bSKonstantin Ananyev}
131e18a033bSKonstantin Ananyev
132e18a033bSKonstantin Ananyev
133e18a033bSKonstantin Ananyevstatic void
134e18a033bSKonstantin Ananyevngx_stream_return_write_handler(ngx_event_t *ev)
135e18a033bSKonstantin Ananyev{
136e18a033bSKonstantin Ananyev    ngx_connection_t         *c;
137e18a033bSKonstantin Ananyev    ngx_stream_session_t     *s;
138e18a033bSKonstantin Ananyev    ngx_stream_return_ctx_t  *ctx;
139e18a033bSKonstantin Ananyev
140e18a033bSKonstantin Ananyev    c = ev->data;
141e18a033bSKonstantin Ananyev    s = c->data;
142e18a033bSKonstantin Ananyev
143e18a033bSKonstantin Ananyev    if (ev->timedout) {
144e18a033bSKonstantin Ananyev        ngx_connection_error(c, NGX_ETIMEDOUT, "connection timed out");
145e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_OK);
146e18a033bSKonstantin Ananyev        return;
147e18a033bSKonstantin Ananyev    }
148e18a033bSKonstantin Ananyev
149e18a033bSKonstantin Ananyev    ctx = ngx_stream_get_module_ctx(s, ngx_stream_return_module);
150e18a033bSKonstantin Ananyev
151e18a033bSKonstantin Ananyev    if (ngx_stream_top_filter(s, ctx->out, 1) == NGX_ERROR) {
152e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
153e18a033bSKonstantin Ananyev        return;
154e18a033bSKonstantin Ananyev    }
155e18a033bSKonstantin Ananyev
156e18a033bSKonstantin Ananyev    ctx->out = NULL;
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev    if (!c->buffered) {
159e18a033bSKonstantin Ananyev        ngx_log_debug0(NGX_LOG_DEBUG_STREAM, c->log, 0,
160e18a033bSKonstantin Ananyev                       "stream return done sending");
161e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_OK);
162e18a033bSKonstantin Ananyev        return;
163e18a033bSKonstantin Ananyev    }
164e18a033bSKonstantin Ananyev
165e18a033bSKonstantin Ananyev    if (ngx_handle_write_event(ev, 0) != NGX_OK) {
166e18a033bSKonstantin Ananyev        ngx_stream_finalize_session(s, NGX_STREAM_INTERNAL_SERVER_ERROR);
167e18a033bSKonstantin Ananyev        return;
168e18a033bSKonstantin Ananyev    }
169e18a033bSKonstantin Ananyev
170e18a033bSKonstantin Ananyev    ngx_add_timer(ev, 5000);
171e18a033bSKonstantin Ananyev}
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyevstatic void *
175e18a033bSKonstantin Ananyevngx_stream_return_create_srv_conf(ngx_conf_t *cf)
176e18a033bSKonstantin Ananyev{
177e18a033bSKonstantin Ananyev    ngx_stream_return_srv_conf_t  *conf;
178e18a033bSKonstantin Ananyev
179e18a033bSKonstantin Ananyev    conf = ngx_pcalloc(cf->pool, sizeof(ngx_stream_return_srv_conf_t));
180e18a033bSKonstantin Ananyev    if (conf == NULL) {
181e18a033bSKonstantin Ananyev        return NULL;
182e18a033bSKonstantin Ananyev    }
183e18a033bSKonstantin Ananyev
184e18a033bSKonstantin Ananyev    return conf;
185e18a033bSKonstantin Ananyev}
186e18a033bSKonstantin Ananyev
187e18a033bSKonstantin Ananyev
188e18a033bSKonstantin Ananyevstatic char *
189e18a033bSKonstantin Ananyevngx_stream_return(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
190e18a033bSKonstantin Ananyev{
191e18a033bSKonstantin Ananyev    ngx_stream_return_srv_conf_t *rscf = conf;
192e18a033bSKonstantin Ananyev
193e18a033bSKonstantin Ananyev    ngx_str_t                           *value;
194e18a033bSKonstantin Ananyev    ngx_stream_core_srv_conf_t          *cscf;
195e18a033bSKonstantin Ananyev    ngx_stream_compile_complex_value_t   ccv;
196e18a033bSKonstantin Ananyev
197e18a033bSKonstantin Ananyev    if (rscf->text.value.data) {
198e18a033bSKonstantin Ananyev        return "is duplicate";
199e18a033bSKonstantin Ananyev    }
200e18a033bSKonstantin Ananyev
201e18a033bSKonstantin Ananyev    value = cf->args->elts;
202e18a033bSKonstantin Ananyev
203e18a033bSKonstantin Ananyev    ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t));
204e18a033bSKonstantin Ananyev
205e18a033bSKonstantin Ananyev    ccv.cf = cf;
206e18a033bSKonstantin Ananyev    ccv.value = &value[1];
207e18a033bSKonstantin Ananyev    ccv.complex_value = &rscf->text;
208e18a033bSKonstantin Ananyev
209e18a033bSKonstantin Ananyev    if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) {
210e18a033bSKonstantin Ananyev        return NGX_CONF_ERROR;
211e18a033bSKonstantin Ananyev    }
212e18a033bSKonstantin Ananyev
213e18a033bSKonstantin Ananyev    cscf = ngx_stream_conf_get_module_srv_conf(cf, ngx_stream_core_module);
214e18a033bSKonstantin Ananyev
215e18a033bSKonstantin Ananyev    cscf->handler = ngx_stream_return_handler;
216e18a033bSKonstantin Ananyev
217e18a033bSKonstantin Ananyev    return NGX_CONF_OK;
218e18a033bSKonstantin Ananyev}
219