Add simple client side component
This commit is contained in:
@@ -6,4 +6,4 @@ CompileFlags:
|
|||||||
- "-I../nginx/objs"
|
- "-I../nginx/objs"
|
||||||
- "-I../nginx/src/os/unix"
|
- "-I../nginx/src/os/unix"
|
||||||
- "-I/opt/homebrew/Cellar/pcre2/10.47/include"
|
- "-I/opt/homebrew/Cellar/pcre2/10.47/include"
|
||||||
- "-I/opt/homebrew/Cellar/openssl@3/3.6.0/include"
|
- "-I/opt/homebrew/Cellar/openssl@3/3.6.1/include"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ build: ngx_http_pow.c
|
|||||||
|
|
||||||
.PHONY: configure
|
.PHONY: configure
|
||||||
configure:
|
configure:
|
||||||
|
cd ../nginx; \
|
||||||
../nginx/auto/configure \
|
../nginx/auto/configure \
|
||||||
--prefix=/Users/jona/repos/ngx-pow/nginx/install \
|
--prefix=/Users/jona/repos/ngx-pow/nginx/install \
|
||||||
--with-debug \
|
--with-debug \
|
||||||
@@ -12,4 +13,4 @@ configure:
|
|||||||
|
|
||||||
.PHONY: run
|
.PHONY: run
|
||||||
run: build
|
run: build
|
||||||
../nginx/objs/nginx -c "$(PWD)/ngx_http_pow.conf" -g "daemon off;"
|
../nginx/objs/nginx -c "$(PWD)/ngx_http_pow.conf"
|
||||||
|
|||||||
@@ -0,0 +1,95 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
||||||
|
<title>PoW Shield</title>
|
||||||
|
</head>
|
||||||
|
<script>
|
||||||
|
const SHA256_MD_LENGTH = 64;
|
||||||
|
const POW_RANDOM_LENGTH = 64;
|
||||||
|
|
||||||
|
function base64ToBytes(b64) {
|
||||||
|
return Uint8Array.from(atob(b64), c => c.charCodeAt(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
function deserializePowChallenge(b64) {
|
||||||
|
const bytes = base64ToBytes(b64);
|
||||||
|
const view = new DataView(bytes.buffer);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
|
||||||
|
const version = view.getUint32(offset, true); offset += 4;
|
||||||
|
const created = view.getUint32(offset, true); offset += 4;
|
||||||
|
const ttl = view.getUint32(offset, true); offset += 4;
|
||||||
|
const difficulty = view.getUint32(offset, true); offset += 4;
|
||||||
|
const random = view.buffer.slice(offset, offset + 64); offset += 64;
|
||||||
|
const digest = view.buffer.slice(offset);
|
||||||
|
|
||||||
|
return {
|
||||||
|
version,
|
||||||
|
created,
|
||||||
|
ttl,
|
||||||
|
difficulty,
|
||||||
|
random,
|
||||||
|
digest
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCookie(name) {
|
||||||
|
const cookies = document.cookie.split("; ");
|
||||||
|
|
||||||
|
for (const c of cookies) {
|
||||||
|
if (c.startsWith(name + "=")) {
|
||||||
|
return decodeURIComponent(c.substring(name.length + 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sha256(bytes) {
|
||||||
|
const hashBuffer = await crypto.subtle.digest("SHA-256", bytes);
|
||||||
|
return new Uint8Array(hashBuffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasLeadingBytes(buf, numBits) {
|
||||||
|
const zeroBytes = numBits / 8;
|
||||||
|
const remainingBits = numBits % 8;
|
||||||
|
const lut = Uint8Array([
|
||||||
|
0b11111111, 0b01111111, 0b00111111, 0b00011111,
|
||||||
|
0b00001111, 0b00000111, 0b00000011, 0b00000001
|
||||||
|
]);
|
||||||
|
|
||||||
|
for (let i = 0; i < zeroBytes; i++) {
|
||||||
|
if (buf[i] > 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buf[zeroBytes + 1] ^ lut[remainingBytes]) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function pow(challenge) {
|
||||||
|
const difficulty = deserializePowChallenge(challenge).difficulty
|
||||||
|
const pow = Uint32
|
||||||
|
|
||||||
|
let digest;
|
||||||
|
let nonce = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
sha256(challenge).then(d => digest = d);
|
||||||
|
} while (hasLeadingBytes(digest, difficulty))
|
||||||
|
|
||||||
|
console.log(digest)
|
||||||
|
}
|
||||||
|
|
||||||
|
const powChallengeCookie = getCookie("pow-challenge");
|
||||||
|
const powChallenge = deserializePowChallenge(powChallengeCookie);
|
||||||
|
console.log(powChallenge, powChallenge.length)
|
||||||
|
</script>
|
||||||
|
</html>
|
||||||
+115
-39
@@ -6,24 +6,24 @@
|
|||||||
|
|
||||||
#define NGX_HTTP_POW_CHALLENGE_RANDOM_LENGTH 64
|
#define NGX_HTTP_POW_CHALLENGE_RANDOM_LENGTH 64
|
||||||
#define NGX_HTTP_POW_HMAC_KEY "thisisaverysecretkey"
|
#define NGX_HTTP_POW_HMAC_KEY "thisisaverysecretkey"
|
||||||
#define NGX_HTTP_POW_CHALLENGE_HEADER_KEY "pow-challenge"
|
#define NGX_HTTP_POW_CHALLENGE_COOKIE_KEY "pow-challenge="
|
||||||
#define NGX_HTTP_POW_CHALLENGE_COOKIE_NAME "pow"
|
#define NGX_HTTP_POW_CHALLENGE_COOKIE_ATTRIBUTES "; Path=/; SameSite=Lax"
|
||||||
|
#define NGX_HTTP_POW_COOKIE_NAME "pow"
|
||||||
|
|
||||||
#define NGX_HTTP_POW_UNUSED __attribute__((unused))
|
#define NGX_HTTP_POW_UNUSED __attribute__((unused))
|
||||||
|
|
||||||
static ngx_int_t ngx_http_pow_init(ngx_conf_t *cf);
|
static ngx_int_t ngx_http_pow_init(ngx_conf_t *cf);
|
||||||
static ngx_int_t ngx_http_pow_handler(ngx_http_request_t *r);
|
static ngx_int_t ngx_http_pow_handler(ngx_http_request_t *r);
|
||||||
|
|
||||||
|
static ngx_str_t *pow_html;
|
||||||
|
|
||||||
static ngx_http_module_t ngx_http_pow_module_ctx = {
|
static ngx_http_module_t ngx_http_pow_module_ctx = {
|
||||||
NULL, /* preconfiguration */
|
NULL, /* preconfiguration */
|
||||||
ngx_http_pow_init, /* postconfiguration */
|
ngx_http_pow_init, /* postconfiguration */
|
||||||
|
|
||||||
NULL, /* create main configuration */
|
NULL, /* create main configuration */
|
||||||
NULL, /* init main configuration */
|
NULL, /* init main configuration */
|
||||||
|
|
||||||
NULL, /* create server configuration */
|
NULL, /* create server configuration */
|
||||||
NULL, /* merge server configuration */
|
NULL, /* merge server configuration */
|
||||||
|
|
||||||
NULL, /* create location configuration */
|
NULL, /* create location configuration */
|
||||||
NULL /* merge location configuration */
|
NULL /* merge location configuration */
|
||||||
};
|
};
|
||||||
@@ -43,8 +43,6 @@ ngx_module_t ngx_http_pow = {
|
|||||||
NGX_MODULE_V1_PADDING
|
NGX_MODULE_V1_PADDING
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NGX_HTTP_POW_CHALLENGE_SERIALIZED_LENGTH 256
|
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) ngx_http_pow_challenge_s {
|
typedef struct __attribute__((packed)) ngx_http_pow_challenge_s {
|
||||||
uint32_t version;
|
uint32_t version;
|
||||||
uint32_t created;
|
uint32_t created;
|
||||||
@@ -54,16 +52,23 @@ typedef struct __attribute__((packed)) ngx_http_pow_challenge_s {
|
|||||||
u_char digest[EVP_MAX_MD_SIZE];
|
u_char digest[EVP_MAX_MD_SIZE];
|
||||||
} ngx_http_pow_challenge_t;
|
} ngx_http_pow_challenge_t;
|
||||||
|
|
||||||
|
typedef struct __attribute__((packed)) ngx_http_pow_s {
|
||||||
|
ngx_http_pow_challenge_t challenge;
|
||||||
|
uint32_t nonce;
|
||||||
|
u_char hash[EVP_MAX_MD_SIZE];
|
||||||
|
} ngx_http_pow_t;
|
||||||
|
|
||||||
static ngx_http_pow_challenge_t
|
static ngx_http_pow_challenge_t
|
||||||
*ngx_http_pow_create_challenge(ngx_pool_t *pool)
|
*ngx_http_pow_create_challenge(ngx_pool_t *pool)
|
||||||
{
|
{
|
||||||
ngx_http_pow_challenge_t *challenge;
|
ngx_http_pow_challenge_t *challenge;
|
||||||
|
|
||||||
challenge = ngx_palloc(pool, sizeof(*challenge));
|
challenge = ngx_pcalloc(pool, sizeof(*challenge));
|
||||||
|
|
||||||
challenge->version = 1;
|
challenge->version = 1;
|
||||||
challenge->created = ngx_time();
|
challenge->created = ngx_time();
|
||||||
challenge->ttl = 30;
|
challenge->ttl = 30;
|
||||||
|
challenge->difficulty = 3;
|
||||||
|
|
||||||
RAND_bytes(challenge->random, NGX_HTTP_POW_CHALLENGE_RANDOM_LENGTH);
|
RAND_bytes(challenge->random, NGX_HTTP_POW_CHALLENGE_RANDOM_LENGTH);
|
||||||
|
|
||||||
@@ -87,8 +92,8 @@ static ngx_str_t
|
|||||||
challenge_string.len = sizeof(*challenge);
|
challenge_string.len = sizeof(*challenge);
|
||||||
|
|
||||||
encoded_length = ngx_base64_encoded_length(sizeof(*challenge));
|
encoded_length = ngx_base64_encoded_length(sizeof(*challenge));
|
||||||
buf = ngx_palloc(pool, encoded_length);
|
buf = ngx_pcalloc(pool, encoded_length);
|
||||||
marshalled = ngx_palloc(pool, sizeof(ngx_str_t));
|
marshalled = ngx_pcalloc(pool, sizeof(ngx_str_t));
|
||||||
|
|
||||||
marshalled->len = encoded_length;
|
marshalled->len = encoded_length;
|
||||||
marshalled->data = buf;
|
marshalled->data = buf;
|
||||||
@@ -104,8 +109,8 @@ static ngx_http_pow_challenge_t NGX_HTTP_POW_UNUSED
|
|||||||
ngx_http_pow_challenge_t *challenge;
|
ngx_http_pow_challenge_t *challenge;
|
||||||
ngx_str_t *unmarshalled;
|
ngx_str_t *unmarshalled;
|
||||||
|
|
||||||
challenge = ngx_palloc(pool, sizeof(*challenge));
|
challenge = ngx_pcalloc(pool, sizeof(*challenge));
|
||||||
unmarshalled = ngx_palloc(pool, sizeof(ngx_str_t));
|
unmarshalled = ngx_pcalloc(pool, sizeof(ngx_str_t));
|
||||||
|
|
||||||
unmarshalled->data = (u_char *)challenge;
|
unmarshalled->data = (u_char *)challenge;
|
||||||
unmarshalled->len = sizeof(*challenge);
|
unmarshalled->len = sizeof(*challenge);
|
||||||
@@ -120,32 +125,58 @@ ngx_http_pow_require_pow(ngx_http_request_t *r)
|
|||||||
{
|
{
|
||||||
ngx_http_pow_challenge_t *challenge;
|
ngx_http_pow_challenge_t *challenge;
|
||||||
ngx_table_elt_t *header;
|
ngx_table_elt_t *header;
|
||||||
|
ngx_chain_t out;
|
||||||
ngx_str_t *marshalled;
|
ngx_str_t *marshalled;
|
||||||
|
ngx_buf_t *body_buf;
|
||||||
|
u_char *p;
|
||||||
|
|
||||||
challenge = ngx_http_pow_create_challenge(r->pool);
|
challenge = ngx_http_pow_create_challenge(r->pool);
|
||||||
marshalled = ngx_http_pow_challenge_marshal(challenge, r->pool);
|
marshalled = ngx_http_pow_challenge_marshal(challenge, r->pool);
|
||||||
header = ngx_list_push(&r->headers_out.headers);
|
header = ngx_list_push(&r->headers_out.headers);
|
||||||
|
|
||||||
ngx_str_set(&header->key, NGX_HTTP_POW_CHALLENGE_HEADER_KEY);
|
ngx_str_set(&header->key, "Set-Cookie");
|
||||||
header->value = *marshalled;
|
|
||||||
header->hash = 1;
|
|
||||||
|
|
||||||
r->headers_out.status = NGX_HTTP_UNAUTHORIZED;
|
header->hash = 1;
|
||||||
r->headers_out.content_length = 0;
|
|
||||||
|
header->value.len = sizeof(NGX_HTTP_POW_CHALLENGE_COOKIE_KEY) - 1
|
||||||
|
+ marshalled->len
|
||||||
|
+ sizeof(NGX_HTTP_POW_CHALLENGE_COOKIE_ATTRIBUTES) - 1;
|
||||||
|
|
||||||
|
header->value.data = ngx_pcalloc(r->pool, header->value.len);
|
||||||
|
|
||||||
|
p = header->value.data;
|
||||||
|
|
||||||
|
p = ngx_cpymem(p, NGX_HTTP_POW_CHALLENGE_COOKIE_KEY,
|
||||||
|
sizeof(NGX_HTTP_POW_CHALLENGE_COOKIE_KEY) - 1);
|
||||||
|
p = ngx_cpymem(p, marshalled->data, marshalled->len);
|
||||||
|
p = ngx_cpymem(p, NGX_HTTP_POW_CHALLENGE_COOKIE_ATTRIBUTES,
|
||||||
|
sizeof(NGX_HTTP_POW_CHALLENGE_COOKIE_ATTRIBUTES) - 1);
|
||||||
|
|
||||||
|
r->headers_out.status = NGX_HTTP_UNAUTHORIZED;
|
||||||
|
r->headers_out.content_length_n = pow_html->len;
|
||||||
|
|
||||||
|
body_buf = ngx_calloc_buf(r->pool);
|
||||||
|
if (body_buf == NULL) {
|
||||||
|
/* We done fucked up */
|
||||||
|
}
|
||||||
|
|
||||||
|
body_buf->pos = pow_html->data;
|
||||||
|
body_buf->last = pow_html->data + pow_html->len;
|
||||||
|
body_buf->memory = 1;
|
||||||
|
body_buf->last_buf = 1;
|
||||||
|
body_buf->last_in_chain = 1;
|
||||||
|
body_buf->sync = 0;
|
||||||
|
|
||||||
|
out.buf = body_buf;
|
||||||
|
out.next = NULL;
|
||||||
|
|
||||||
ngx_http_send_header(r);
|
ngx_http_send_header(r);
|
||||||
|
ngx_http_output_filter(r, &out);
|
||||||
ngx_http_finalize_request(r, NGX_HTTP_UNAUTHORIZED);
|
ngx_http_finalize_request(r, NGX_HTTP_UNAUTHORIZED);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct __attribute__((packed)) ngx_http_pow_s {
|
|
||||||
ngx_http_pow_challenge_t challenge;
|
|
||||||
uint32_t nonce;
|
|
||||||
u_char hash[EVP_MAX_MD_SIZE];
|
|
||||||
} ngx_http_pow_t;
|
|
||||||
|
|
||||||
static ngx_str_t NGX_HTTP_POW_UNUSED
|
static ngx_str_t NGX_HTTP_POW_UNUSED
|
||||||
*ngx_http_pow_marshal(ngx_http_pow_t *pow,
|
*ngx_http_pow_marshal(ngx_http_pow_t *pow, ngx_pool_t *pool)
|
||||||
ngx_pool_t *pool)
|
|
||||||
{
|
{
|
||||||
ngx_str_t pow_string;
|
ngx_str_t pow_string;
|
||||||
ngx_str_t *marshalled;
|
ngx_str_t *marshalled;
|
||||||
@@ -156,8 +187,8 @@ static ngx_str_t NGX_HTTP_POW_UNUSED
|
|||||||
pow_string.len = sizeof(*pow);
|
pow_string.len = sizeof(*pow);
|
||||||
|
|
||||||
encoded_length = ngx_base64_encoded_length(sizeof(*pow));
|
encoded_length = ngx_base64_encoded_length(sizeof(*pow));
|
||||||
buf = ngx_palloc(pool, encoded_length);
|
buf = ngx_pcalloc(pool, encoded_length);
|
||||||
marshalled = ngx_palloc(pool, sizeof(ngx_str_t));
|
marshalled = ngx_pcalloc(pool, sizeof(ngx_str_t));
|
||||||
|
|
||||||
marshalled->len = encoded_length;
|
marshalled->len = encoded_length;
|
||||||
marshalled->data = buf;
|
marshalled->data = buf;
|
||||||
@@ -173,8 +204,8 @@ static ngx_http_pow_t
|
|||||||
ngx_http_pow_t *pow;
|
ngx_http_pow_t *pow;
|
||||||
ngx_str_t *unmarshalled;
|
ngx_str_t *unmarshalled;
|
||||||
|
|
||||||
pow = ngx_palloc(pool, sizeof(*pow));
|
pow = ngx_pcalloc(pool, sizeof(*pow));
|
||||||
unmarshalled = ngx_palloc(pool, sizeof(ngx_str_t));
|
unmarshalled = ngx_pcalloc(pool, sizeof(ngx_str_t));
|
||||||
|
|
||||||
unmarshalled->data = (u_char *)pow;
|
unmarshalled->data = (u_char *)pow;
|
||||||
unmarshalled->len = sizeof(*pow);
|
unmarshalled->len = sizeof(*pow);
|
||||||
@@ -232,7 +263,7 @@ ngx_http_pow_check_pow(ngx_http_request_t *r)
|
|||||||
ngx_http_pow_t *pow;
|
ngx_http_pow_t *pow;
|
||||||
ngx_str_t pow_cookie_value;
|
ngx_str_t pow_cookie_value;
|
||||||
|
|
||||||
ngx_str_t pow_cookie_name = ngx_string(NGX_HTTP_POW_CHALLENGE_COOKIE_NAME);
|
ngx_str_t pow_cookie_name = ngx_string(NGX_HTTP_POW_COOKIE_NAME);
|
||||||
|
|
||||||
/* No PoW cookie is present */
|
/* No PoW cookie is present */
|
||||||
if (!ngx_http_parse_multi_header_lines(r, r->headers_in.cookie,
|
if (!ngx_http_parse_multi_header_lines(r, r->headers_in.cookie,
|
||||||
@@ -245,8 +276,8 @@ ngx_http_pow_check_pow(ngx_http_request_t *r)
|
|||||||
|
|
||||||
/* Check digest matches */
|
/* Check digest matches */
|
||||||
if (!ngx_http_pow_check_digest(challenge,
|
if (!ngx_http_pow_check_digest(challenge,
|
||||||
sizeof(*challenge) - sizeof(challenge->digest),
|
sizeof(*challenge) - sizeof(challenge->digest),
|
||||||
challenge->digest)) {
|
challenge->digest)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,12 +287,13 @@ ngx_http_pow_check_pow(ngx_http_request_t *r)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Check pow difficulty */
|
/* Check pow difficulty */
|
||||||
ngx_http_pow_check_difficulty(pow, challenge->difficulty);
|
if (!ngx_http_pow_check_difficulty(pow, challenge->difficulty)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/* Check pow is correct */
|
/* Check pow is correct */
|
||||||
if (!ngx_http_pow_check_digest(pow,
|
if (!ngx_http_pow_check_digest(pow, sizeof(*pow) - sizeof(pow->hash),
|
||||||
sizeof(*pow) - sizeof(pow->hash),
|
pow->hash)) {
|
||||||
pow->hash)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,15 +313,59 @@ ngx_http_pow_handler(ngx_http_request_t *r)
|
|||||||
return NGX_DECLINED;
|
return NGX_DECLINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ngx_str_t
|
||||||
|
*ngx_http_pow_load_js(ngx_pool_t *pool, ngx_str_t *filename, ngx_log_t *log)
|
||||||
|
{
|
||||||
|
size_t filesize;
|
||||||
|
ngx_str_t *pow_html = NULL;
|
||||||
|
ngx_file_t file;
|
||||||
|
ngx_file_info_t file_info;
|
||||||
|
|
||||||
|
file.name = *filename;
|
||||||
|
file.log = log;
|
||||||
|
file.fd = ngx_open_file(filename->data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0);
|
||||||
|
|
||||||
|
if (file.fd == NGX_INVALID_FILE) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ngx_file_info(filename->data, &file_info) == NGX_FILE_ERROR) {
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
|
||||||
|
filesize = ngx_file_size(&file_info);
|
||||||
|
|
||||||
|
pow_html = ngx_pcalloc(pool, sizeof(ngx_str_t));
|
||||||
|
pow_html->data = ngx_pcalloc(pool, filesize);
|
||||||
|
pow_html->len = ngx_read_file(&file, pow_html->data, filesize, 0);
|
||||||
|
|
||||||
|
if (/* pow_html->len == NGX_ERROR || */ pow_html->len != filesize) {
|
||||||
|
pow_html = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
cleanup:
|
||||||
|
|
||||||
|
ngx_close_file(file.fd);
|
||||||
|
|
||||||
|
return pow_html;
|
||||||
|
}
|
||||||
|
|
||||||
static ngx_int_t
|
static ngx_int_t
|
||||||
ngx_http_pow_init(ngx_conf_t *cf)
|
ngx_http_pow_init(ngx_conf_t *cf)
|
||||||
{
|
{
|
||||||
|
ngx_str_t pow_html_path =
|
||||||
|
ngx_string("/Users/jona/repos/ngx-pow/ngx-http-pow/html/pow.html");
|
||||||
|
|
||||||
ngx_http_handler_pt *h;
|
ngx_http_handler_pt *h;
|
||||||
ngx_http_core_main_conf_t *cmcf;
|
ngx_http_core_main_conf_t *cmcf;
|
||||||
|
|
||||||
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
|
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
|
||||||
|
|
||||||
|
pow_html = ngx_http_pow_load_js(cf->pool, &pow_html_path, cf->log);
|
||||||
|
if (!pow_html) {
|
||||||
|
return NGX_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
|
h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers);
|
||||||
if (h == NULL) {
|
if (h == NULL) {
|
||||||
return NGX_ERROR;
|
return NGX_ERROR;
|
||||||
|
|||||||
+3
-1
@@ -1,4 +1,6 @@
|
|||||||
worker_processes 1;
|
worker_processes 1;
|
||||||
|
daemon off;
|
||||||
|
master_process off;
|
||||||
|
|
||||||
error_log stderr debug;
|
error_log stderr debug;
|
||||||
pid /tmp/nginx.pid;
|
pid /tmp/nginx.pid;
|
||||||
|
|||||||
Reference in New Issue
Block a user