[core] http_response_304(), http_response_412()

adjustments for RFC9110 handling of Content-Length with 304 Not Modified

x-ref:
  https://www.rfc-editor.org/rfc/rfc9110#name-content-length
This commit is contained in:
Glenn Strauss 2023-08-11 21:42:15 -04:00
parent 73f3c7f2d4
commit 0fdf13a268
3 changed files with 46 additions and 20 deletions

View File

@ -236,6 +236,38 @@ static int http_response_maybe_cachable (const request_st * const r) {
}
static handler_t http_response_304 (request_st * const r) {
#if 0 /* option: could set Content-Length with 304 if content known */
/* RFC9110
* https://www.rfc-editor.org/rfc/rfc9110#name-content-length */
/*assert(r->resp_body_finished);*/
off_t qlen = chunkqueue_length(&r->write_queue);
if (qlen > 0)
buffer_append_int(
http_header_response_set_ptr(r, HTTP_HEADER_CONTENT_LENGTH,
CONST_STR_LEN("Content-Length")),
qlen);
#endif
#if 0 /* performed in http_response_write_prepare() */
http_response_body_clear(r, 1);
r->resp_body_finished = 1;
#endif
r->http_status = 304;
return HANDLER_FINISHED;
}
__attribute_cold__
static handler_t http_response_412 (request_st * const r) {
/* http_response_reqbody_read_error() without setting r->keep_alive = 0 */
http_response_body_clear(r, 0);
r->handler_module = NULL;
r->http_status = 412;
return HANDLER_FINISHED;
}
int http_response_handle_cachable(request_st * const r, const buffer *lmod, const unix_time64_t lmtime) {
if (!http_response_maybe_cachable(r))
return HANDLER_GO_ON;
@ -259,14 +291,9 @@ int http_response_handle_cachable(request_st * const r, const buffer *lmod, cons
/*(weak etag comparison must not be used for ranged requests)*/
int range_request = (0 != light_btst(r->rqst_htags, HTTP_HEADER_RANGE));
if (http_etag_matches(etag, vb->ptr, !range_request)) {
if (http_method_get_head_query(r->http_method)) {
r->http_status = 304;
return HANDLER_FINISHED;
} else {
r->http_status = 412;
r->handler_module = NULL;
return HANDLER_FINISHED;
}
return http_method_get_head_query(r->http_method)
? http_response_304(r)
: http_response_412(r);
}
} else if (http_method_get_head_query(r->http_method)
&& (vb = http_header_request_get(r, HTTP_HEADER_IF_MODIFIED_SINCE,
@ -277,8 +304,7 @@ int http_response_handle_cachable(request_st * const r, const buffer *lmod, cons
/* last-modified handling */
if (buffer_is_equal(lmod, vb)
|| !http_date_if_modified_since(BUF_PTR_LEN(vb), lmtime)) {
r->http_status = 304;
return HANDLER_FINISHED;
return http_response_304(r);
}
}

View File

@ -1601,12 +1601,7 @@ static int mod_ssi_handle_request(request_st * const r, handler_ctx * const p) {
http_header_response_set(r, HTTP_HEADER_ETAG, CONST_STR_LEN("ETag"), BUF_PTR_LEN(r->tmp_buf));
const buffer * const mtime = http_response_set_last_modified(r, st.st_mtime);
if (HANDLER_FINISHED == http_response_handle_cachable(r, mtime, st.st_mtime)) {
/* ok, the client already has our content,
* no need to send it again */
chunkqueue_reset(&r->write_queue);
}
http_response_handle_cachable(r, mtime, st.st_mtime);
}
/* Reset the modified time of included files */

View File

@ -607,12 +607,17 @@ http_response_write_prepare(request_st * const r)
break;
case 204: /* class: header only */
case 205:
case 304:
/* disable chunked encoding again as we have no body */
http_response_body_clear(r, 1);
/* no Content-Body, no Content-Length */
/* RFC9110
* https://www.rfc-editor.org/rfc/rfc9110#name-content-length
* A server MUST NOT send a Content-Length header field in any response
* with a status code of 1xx (Informational) or 204 (No Content)
* (done for 205, too, only as sanity check; 205 has no content.
* Content-Length: 0 will subsequently be set for 205 further below) */
http_header_response_unset(r, HTTP_HEADER_CONTENT_LENGTH,
CONST_STR_LEN("Content-Length"));
__attribute_fallthrough__
case 304: /* cooperate with http_response_304() */
http_response_body_clear(r, 1);
r->resp_body_finished = 1;
break;
default: /* class: header + body */