Welcome! Log In Create A New Profile

Advanced

[PATCH] Add support for HTTP 451 Return Code (RFC 7725)

Babak Farrokhi
November 23, 2016 02:50AM
Hello,

A recent RFC (7725) has introduced HTTP Return Code 451 to be returned when access to a resource is forbidden for legal reasons [1].
In addition to the return code, HTTP server may return an additional “Link” field in HTTP header. The new header should be formatted as below:

Link: https://spqr.example.org/legislatione; rel="blocked-by"

Please also note that the new Relation Name (blocked-by) is also added to IANA Link Relation Type Registry [2].

A user may simply return a 451 code based on a condition or additionally provide a link to a URL (usually pointed to the applicable legislation or regulation):

if ($http_user_agent !~ MSIE) {
return 451 https://spqr.example.org/legislatione;
}

if ($http_user_agent ~* (Wget) ) {
return 451;
}

Here is the proposed patch:

# HG changeset patch
# User Babak Farrokhi <babak@farrokhi.net>
# Date 1479886479 -12600
# Wed Nov 23 11:04:39 2016 +0330
# Node ID d56f78822c5bcaa8bde2d95c862d06491618154c
# Parent 2c7a2d75938a31044552b0a6cd6edaebdaf0bd69
Add support for HTTP 451 Return Code (RFC 7725)

RFC 7725 introduced HTTP 451 “Unavailable For Legal Reasons” return code,
to be returned when the user requests a resource which cannot be served
for legal reasons.
It also introduces an optional "Link" header field that should contain a
link to relevant webpage (e.g. legal documents) with following format:

Link: https://spqr.example.org/legislatione; rel="blocked-by"

A user can now configure nginx to return this code using a return clause
in configuration file:

if ($http_user_agent !~ MSIE) {
return 451 https://spqr.example.org/legislatione;
}

if ($http_user_agent ~* (Wget) ) {
return 451;
}

Please note that the URL is optional and if not specified, no "Link"
field will be added to header.

diff -r 2c7a2d75938a -r d56f78822c5b src/http/modules/perl/nginx.pm
--- a/src/http/modules/perl/nginx.pm Mon Nov 21 16:49:19 2016 +0300
+++ b/src/http/modules/perl/nginx.pm Wed Nov 23 11:04:39 2016 +0330
@@ -88,6 +88,7 @@
use constant HTTP_REQUEST_URI_TOO_LARGE => 414;
use constant HTTP_UNSUPPORTED_MEDIA_TYPE => 415;
use constant HTTP_RANGE_NOT_SATISFIABLE => 416;
+use constant HTTP_NOT_ALLOWED_LEGALLY => 451;

use constant HTTP_INTERNAL_SERVER_ERROR => 500;
use constant HTTP_SERVER_ERROR => 500;
diff -r 2c7a2d75938a -r d56f78822c5b src/http/ngx_http_core_module.c
--- a/src/http/ngx_http_core_module.c Mon Nov 21 16:49:19 2016 +0300
+++ b/src/http/ngx_http_core_module.c Wed Nov 23 11:04:39 2016 +0330
@@ -1862,6 +1862,7 @@
ngx_str_t val;
ngx_buf_t *b;
ngx_chain_t out;
+ ngx_str_t link;

if (ngx_http_discard_request_body(r) != NGX_OK) {
return NGX_HTTP_INTERNAL_SERVER_ERROR;
@@ -1873,6 +1874,32 @@
return NGX_HTTP_INTERNAL_SERVER_ERROR;
}

+ if (status == NGX_HTTP_NOT_ALLOWED_LEGALLY) {
+ ngx_http_clear_link(r);
+
+ r->headers_out.link = ngx_list_push(&r->headers_out.headers);
+ if (r->headers_out.link == NULL) {
+ return NGX_HTTP_INTERNAL_SERVER_ERROR;
+ }
+
+ r->headers_out.link->hash = 1;
+ ngx_str_set(&r->headers_out.link->key, "Link");
+
+ link.data = ngx_pcalloc(r->pool, val.len +
+ ngx_strlen("<>; rel=\"blocked-by\""));
+ if (link.data == NULL) {
+ r->headers_out.link->hash = 0;
+ return NGX_ERROR;
+ }
+
+ link.len = ngx_sprintf(link.data, "<%s>; rel=\"blocked-by\"",
+ val.data) - link.data;
+
+ r->headers_out.link->value = link;
+
+ return status;
+ }
+
if (status == NGX_HTTP_MOVED_PERMANENTLY
|| status == NGX_HTTP_MOVED_TEMPORARILY
|| status == NGX_HTTP_SEE_OTHER
diff -r 2c7a2d75938a -r d56f78822c5b src/http/ngx_http_core_module.h
--- a/src/http/ngx_http_core_module.h Mon Nov 21 16:49:19 2016 +0300
+++ b/src/http/ngx_http_core_module.h Wed Nov 23 11:04:39 2016 +0330
@@ -570,6 +570,13 @@
r->headers_out.location = NULL; \
}

+#define ngx_http_clear_link(r) \
+ \
+ if (r->headers_out.link) { \
+ r->headers_out.link->hash = 0; \
+ r->headers_out.link = NULL; \
+ }
+
#define ngx_http_clear_etag(r) \
\
if (r->headers_out.etag) { \
diff -r 2c7a2d75938a -r d56f78822c5b src/http/ngx_http_header_filter_module.c
--- a/src/http/ngx_http_header_filter_module.c Mon Nov 21 16:49:19 2016 +0300
+++ b/src/http/ngx_http_header_filter_module.c Wed Nov 23 11:04:39 2016 +0330
@@ -100,12 +100,38 @@
ngx_null_string, /* "419 unused" */
ngx_null_string, /* "420 unused" */
ngx_string("421 Misdirected Request"),
+ ngx_null_string, /* "422 Unprocessable Entity" */
+ ngx_null_string, /* "423 Locked" */
+ ngx_null_string, /* "424 Failed Dependency" */
+ ngx_null_string, /* "425 unused" */
+ ngx_null_string, /* "426 Upgrade Required" */
+ ngx_null_string, /* "427 unused" */
+ ngx_null_string, /* "428 Precondition Required" */
+ ngx_null_string, /* "429 Too Many Requests" */
+ ngx_null_string, /* "430 unused" */
+ ngx_null_string, /* "431 Request Header Fields Too Large" */
+ ngx_null_string, /* "432 unused" */
+ ngx_null_string, /* "433 unused" */
+ ngx_null_string, /* "434 unused" */
+ ngx_null_string, /* "435 unused" */
+ ngx_null_string, /* "436 unused" */
+ ngx_null_string, /* "437 unused" */
+ ngx_null_string, /* "438 unused" */
+ ngx_null_string, /* "439 unused" */
+ ngx_null_string, /* "440 unused" */
+ ngx_null_string, /* "441 unused" */
+ ngx_null_string, /* "442 unused" */
+ ngx_null_string, /* "443 unused" */
+ ngx_null_string, /* "444 unused" */
+ ngx_null_string, /* "445 unused" */
+ ngx_null_string, /* "446 unused" */
+ ngx_null_string, /* "447 unused" */
+ ngx_null_string, /* "448 unused" */
+ ngx_null_string, /* "449 unused" */
+ ngx_null_string, /* "450 unused" */
+ ngx_string("451 Unavailable For Legal Reasons"),

- /* ngx_null_string, */ /* "422 Unprocessable Entity" */
- /* ngx_null_string, */ /* "423 Locked" */
- /* ngx_null_string, */ /* "424 Failed Dependency" */
-
-#define NGX_HTTP_LAST_4XX 422
+#define NGX_HTTP_LAST_4XX 452
#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

ngx_string("500 Internal Server Error"),
@@ -133,6 +159,7 @@
offsetof(ngx_http_headers_out_t, content_length) },
{ ngx_string("Content-Encoding"),
offsetof(ngx_http_headers_out_t, content_encoding) },
+ { ngx_string("Link"), offsetof(ngx_http_headers_out_t, link) },
{ ngx_string("Location"), offsetof(ngx_http_headers_out_t, location) },
{ ngx_string("Last-Modified"),
offsetof(ngx_http_headers_out_t, last_modified) },
diff -r 2c7a2d75938a -r d56f78822c5b src/http/ngx_http_request.h
--- a/src/http/ngx_http_request.h Mon Nov 21 16:49:19 2016 +0300
+++ b/src/http/ngx_http_request.h Wed Nov 23 11:04:39 2016 +0330
@@ -97,6 +97,7 @@
#define NGX_HTTP_RANGE_NOT_SATISFIABLE 416
#define NGX_HTTP_MISDIRECTED_REQUEST 421

+#define NGX_HTTP_NOT_ALLOWED_LEGALLY 451

/* Our own HTTP codes */

@@ -253,6 +254,7 @@
ngx_table_elt_t *date;
ngx_table_elt_t *content_length;
ngx_table_elt_t *content_encoding;
+ ngx_table_elt_t *link;
ngx_table_elt_t *location;
ngx_table_elt_t *refresh;
ngx_table_elt_t *last_modified;
diff -r 2c7a2d75938a -r d56f78822c5b src/http/ngx_http_special_response.c
--- a/src/http/ngx_http_special_response.c Mon Nov 21 16:49:19 2016 +0300
+++ b/src/http/ngx_http_special_response.c Wed Nov 23 11:04:39 2016 +0330
@@ -217,6 +217,12 @@
"<center><h1>421 Misdirected Request</h1></center>" CRLF
;

+static char ngx_http_error_451_page[] =
+"<html>" CRLF
+"<head><title>451 Unavailable For Legal Reasons</title></head>" CRLF
+"<body bgcolor=\"white\">" CRLF
+"<center><h1>451 Unavailable For Legal Reasons</h1></center>" CRLF
+;

static char ngx_http_error_494_page[] =
"<html>" CRLF
@@ -347,8 +353,38 @@
ngx_null_string, /* 419 */
ngx_null_string, /* 420 */
ngx_string(ngx_http_error_421_page),
+ ngx_null_string, /* 422 */
+ ngx_null_string, /* 423 */
+ ngx_null_string, /* 424 */
+ ngx_null_string, /* 425 */
+ ngx_null_string, /* 426 */
+ ngx_null_string, /* 427 */
+ ngx_null_string, /* 428 */
+ ngx_null_string, /* 429 */
+ ngx_null_string, /* 430 */
+ ngx_null_string, /* 431 */
+ ngx_null_string, /* 432 */
+ ngx_null_string, /* 433 */
+ ngx_null_string, /* 434 */
+ ngx_null_string, /* 435 */
+ ngx_null_string, /* 436 */
+ ngx_null_string, /* 437 */
+ ngx_null_string, /* 438 */
+ ngx_null_string, /* 439 */
+ ngx_null_string, /* 440 */
+ ngx_null_string, /* 441 */
+ ngx_null_string, /* 442 */
+ ngx_null_string, /* 443 */
+ ngx_null_string, /* 444 */
+ ngx_null_string, /* 445 */
+ ngx_null_string, /* 446 */
+ ngx_null_string, /* 447 */
+ ngx_null_string, /* 448 */
+ ngx_null_string, /* 449 */
+ ngx_null_string, /* 450 */
+ ngx_string(ngx_http_error_451_page), /* 451, Unavailable For Legal Reasons */

-#define NGX_HTTP_LAST_4XX 422
+#define NGX_HTTP_LAST_4XX 452
#define NGX_HTTP_OFF_5XX (NGX_HTTP_LAST_4XX - 400 + NGX_HTTP_OFF_4XX)

ngx_string(ngx_http_error_494_page), /* 494, request header too large */




[1] https://datatracker.ietf.org/doc/rfc7725/?include_text=1
[2] http://www.iana.org/assignments/link-relations/link-relations.xhtml

Kind Regards,
--
Babak Farrokhi
https://github.com/farrokhi
_______________________________________________
nginx-devel mailing list
nginx-devel@nginx.org
http://mailman.nginx.org/mailman/listinfo/nginx-devel
Subject Author Views Posted

[PATCH] Add support for HTTP 451 Return Code (RFC 7725)

Babak Farrokhi 2287 November 23, 2016 02:50AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 239
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready