|
|
|
@ -3,7 +3,6 @@
|
|
|
|
|
#include "response.h" |
|
|
|
|
#include "request.h" |
|
|
|
|
#include "base.h" |
|
|
|
|
#include "burl.h" |
|
|
|
|
#include "fdevent.h" |
|
|
|
|
#include "http_header.h" |
|
|
|
|
#include "http_kv.h" |
|
|
|
@ -50,12 +49,21 @@ int http_response_write_header(request_st * const r) {
|
|
|
|
|
chunkqueue * const cq = r->write_queue; |
|
|
|
|
buffer * const b = chunkqueue_prepend_buffer_open(cq); |
|
|
|
|
|
|
|
|
|
if (r->http_version == HTTP_VERSION_1_1) { |
|
|
|
|
buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 ")); |
|
|
|
|
} else { |
|
|
|
|
buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 ")); |
|
|
|
|
/* future: might fork this routine and send headers directly to
|
|
|
|
|
* the HPACK encoder, rather than double-buffering in chunkqueue */ |
|
|
|
|
const int h1 = (r->http_version <= HTTP_VERSION_1_1); |
|
|
|
|
if (!h1) { |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(":status: ")); |
|
|
|
|
buffer_append_int(b, r->http_status); |
|
|
|
|
} |
|
|
|
|
else { |
|
|
|
|
if (r->http_version == HTTP_VERSION_1_1) { |
|
|
|
|
buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.1 ")); |
|
|
|
|
} else { |
|
|
|
|
buffer_copy_string_len(b, CONST_STR_LEN("HTTP/1.0 ")); |
|
|
|
|
} |
|
|
|
|
http_status_append(b, r->http_status); |
|
|
|
|
} |
|
|
|
|
http_status_append(b, r->http_status); |
|
|
|
|
|
|
|
|
|
/* disable keep-alive if requested */ |
|
|
|
|
|
|
|
|
@ -75,7 +83,7 @@ int http_response_write_header(request_st * const r) {
|
|
|
|
|
if ((r->resp_htags & HTTP_HEADER_UPGRADE) && r->http_version == HTTP_VERSION_1_1) { |
|
|
|
|
http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("upgrade")); |
|
|
|
|
} else if (0 == r->keep_alive) { |
|
|
|
|
if (r->http_version <= HTTP_VERSION_1_1) /*(e.g. not HTTP_VERSION_2)*/ |
|
|
|
|
if (h1) /*(e.g. not HTTP_VERSION_2)*/ |
|
|
|
|
http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("close")); |
|
|
|
|
} else if (r->http_version == HTTP_VERSION_1_0) {/*(&& r->keep_alive != 0)*/ |
|
|
|
|
http_header_response_set(r, HTTP_HEADER_CONNECTION, CONST_STR_LEN("Connection"), CONST_STR_LEN("keep-alive")); |
|
|
|
@ -95,7 +103,16 @@ int http_response_write_header(request_st * const r) {
|
|
|
|
|
continue; |
|
|
|
|
|
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("\r\n")); |
|
|
|
|
buffer_append_string_buffer(b, &ds->key); |
|
|
|
|
if (!h1) { /* HTTP/2 requires lowercase keys */ |
|
|
|
|
const size_t klen = buffer_string_length(&ds->key); |
|
|
|
|
char * const h = buffer_string_prepare_append(b, klen); |
|
|
|
|
const char * const k = ds->key.ptr; |
|
|
|
|
for (uint32_t j = 0; j < klen; ++j) |
|
|
|
|
h[j] = (k[j] < 'A' || k[j] > 'Z') ? k[j] : (k[j] | 0x20); |
|
|
|
|
buffer_commit(b, klen); |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
buffer_append_string_buffer(b, &ds->key); |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN(": ")); |
|
|
|
|
buffer_append_string_buffer(b, &ds->value); |
|
|
|
|
} |
|
|
|
@ -105,9 +122,6 @@ int http_response_write_header(request_st * const r) {
|
|
|
|
|
static char tstr[32]; /* 30-chars for "%a, %d %b %Y %H:%M:%S GMT" */ |
|
|
|
|
static size_t tlen; |
|
|
|
|
|
|
|
|
|
/* HTTP/1.1 requires a Date: header */ |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("\r\nDate: ")); |
|
|
|
|
|
|
|
|
|
/* cache the generated timestamp */ |
|
|
|
|
const time_t cur_ts = log_epoch_secs; |
|
|
|
|
if (tlast != cur_ts) { |
|
|
|
@ -116,12 +130,16 @@ int http_response_write_header(request_st * const r) {
|
|
|
|
|
"%a, %d %b %Y %H:%M:%S GMT", gmtime(&tlast)); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* HTTP/1.1 and later requires a Date: header */ |
|
|
|
|
buffer_append_string_len(b, !h1 ? "\r\ndate: " : "\r\nDate: ", |
|
|
|
|
sizeof("\r\ndate: ")-1); |
|
|
|
|
buffer_append_string_len(b, tstr, tlen); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (!(r->resp_htags & HTTP_HEADER_SERVER)) { |
|
|
|
|
if (!buffer_string_is_empty(r->conf.server_tag)) { |
|
|
|
|
buffer_append_string_len(b, CONST_STR_LEN("\r\nServer: ")); |
|
|
|
|
buffer_append_string_len(b, !h1 ? "\r\nserver: " : "\r\nServer: ", |
|
|
|
|
sizeof("\r\nserver: ")-1); |
|
|
|
|
buffer_append_string_len(b, CONST_BUF_LEN(r->conf.server_tag)); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|