1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208
|
/*
* Copyright (C) Yichun Zhang (agentzh)
*/
#ifndef DDEBUG
#define DDEBUG 0
#endif
#include "ddebug.h"
#include "ngx_http_echo_sleep.h"
#include "ngx_http_echo_handler.h"
#include <nginx.h>
#include <ngx_log.h>
/* event handler for echo_sleep */
static void ngx_http_echo_post_sleep(ngx_http_request_t *r);
static void ngx_http_echo_sleep_cleanup(void *data);
ngx_int_t
ngx_http_echo_exec_echo_sleep(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_str_t *computed_arg;
ngx_str_t *computed_arg_elts;
ngx_int_t delay; /* in msec */
ngx_http_cleanup_t *cln;
computed_arg_elts = computed_args->elts;
computed_arg = &computed_arg_elts[0];
delay = ngx_atofp(computed_arg->data, computed_arg->len, 3);
if (delay == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid sleep duration \"%V\"", &computed_arg_elts[0]);
return NGX_HTTP_BAD_REQUEST;
}
dd("adding timer with delay %lu ms, r:%.*s", (unsigned long) delay,
(int) r->uri.len, r->uri.data);
ngx_add_timer(&ctx->sleep, (ngx_msec_t) delay);
/* we don't check broken downstream connections
* ourselves so even if the client shuts down
* the connection prematurely, nginx will still
* go on waiting for our timers to get properly
* expired. However, we'd still register a
* cleanup handler for completeness. */
cln = ngx_http_cleanup_add(r, 0);
if (cln == NULL) {
return NGX_ERROR;
}
cln->handler = ngx_http_echo_sleep_cleanup;
cln->data = r;
return NGX_AGAIN;
}
static void
ngx_http_echo_post_sleep(ngx_http_request_t *r)
{
ngx_http_echo_ctx_t *ctx;
/* ngx_int_t rc; */
dd("post sleep, r:%.*s", (int) r->uri.len, r->uri.data);
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (ctx == NULL) {
return;
}
ctx->waiting = 0;
ctx->done = 1;
dd("sleep: after get module ctx");
dd("timed out? %d", ctx->sleep.timedout);
dd("timer set? %d", ctx->sleep.timer_set);
if (!ctx->sleep.timedout) {
dd("HERE reached!");
return;
}
ctx->sleep.timedout = 0;
if (ctx->sleep.timer_set) {
dd("deleting timer for echo_sleep");
ngx_del_timer(&ctx->sleep);
}
/* r->write_event_handler = ngx_http_request_empty_handler; */
ngx_http_echo_wev_handler(r);
}
void
ngx_http_echo_sleep_event_handler(ngx_event_t *ev)
{
ngx_connection_t *c;
ngx_http_request_t *r;
ngx_http_log_ctx_t *ctx;
r = ev->data;
c = r->connection;
if (c->destroyed) {
return;
}
if (c->error) {
ngx_http_finalize_request(r, NGX_ERROR);
return;
}
ctx = c->log->data;
ctx->current_request = r;
/* XXX when r->done == 1 we should do cleaning immediately
* and delete our timer and then quit. */
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, c->log, 0,
"echo sleep event handler: \"%V?%V\"", &r->uri, &r->args);
/*
if (r->done) {
return;
}
*/
ngx_http_echo_post_sleep(r);
#if defined(nginx_version)
dd("before run posted requests");
ngx_http_run_posted_requests(c);
dd("after run posted requests");
#endif
}
ngx_int_t
ngx_http_echo_exec_echo_blocking_sleep(ngx_http_request_t *r,
ngx_http_echo_ctx_t *ctx, ngx_array_t *computed_args)
{
ngx_str_t *computed_arg;
ngx_str_t *computed_arg_elts;
ngx_int_t delay; /* in msec */
computed_arg_elts = computed_args->elts;
computed_arg = &computed_arg_elts[0];
delay = ngx_atofp(computed_arg->data, computed_arg->len, 3);
if (delay == NGX_ERROR) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid sleep duration \"%V\"", &computed_arg_elts[0]);
return NGX_HTTP_BAD_REQUEST;
}
dd("blocking delay: %lu ms", (unsigned long) delay);
ngx_msleep((ngx_msec_t) delay);
return NGX_OK;
}
static void
ngx_http_echo_sleep_cleanup(void *data)
{
ngx_http_request_t *r = data;
ngx_http_echo_ctx_t *ctx;
dd("echo sleep cleanup");
ctx = ngx_http_get_module_ctx(r, ngx_http_echo_module);
if (ctx == NULL) {
return;
}
if (ctx->sleep.timer_set) {
dd("cleanup: deleting timer for echo_sleep");
ngx_del_timer(&ctx->sleep);
return;
}
dd("cleanup: timer not set");
}
|