mirror of
https://gitee.com/openharmony/third_party_nghttp2
synced 2025-02-12 11:59:25 +00:00
Reformat lines with clang-format-3.5
This commit is contained in:
parent
2c830a4698
commit
b1f807abd1
@ -42,8 +42,7 @@
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 3) {
|
||||
@ -59,19 +58,16 @@ int main(int argc, char* argv[])
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
if(argc >= 5) {
|
||||
if (argc >= 5) {
|
||||
server.tls(argv[3], argv[4]);
|
||||
}
|
||||
|
||||
server.listen
|
||||
("*", port,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
res->write_head(200, { header{ "foo", "bar" } });
|
||||
res->end("hello, world");
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
server.listen("*", port, [](const std::shared_ptr<request> &req,
|
||||
const std::shared_ptr<response> &res) {
|
||||
res->write_head(200, {header{"foo", "bar"}});
|
||||
res->end("hello, world");
|
||||
});
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
|
@ -45,8 +45,7 @@
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 4) {
|
||||
@ -63,47 +62,44 @@ int main(int argc, char* argv[])
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
if(argc >= 6) {
|
||||
if (argc >= 6) {
|
||||
server.tls(argv[4], argv[5]);
|
||||
}
|
||||
|
||||
server.listen
|
||||
("*", port,
|
||||
[&docroot](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
auto path = percent_decode(req->path());
|
||||
if(!check_path(path)) {
|
||||
res->write_head(404);
|
||||
res->end();
|
||||
return;
|
||||
}
|
||||
server.listen("*", port, [&docroot](const std::shared_ptr<request> &req,
|
||||
const std::shared_ptr<response> &res) {
|
||||
auto path = percent_decode(req->path());
|
||||
if (!check_path(path)) {
|
||||
res->write_head(404);
|
||||
res->end();
|
||||
return;
|
||||
}
|
||||
|
||||
if(path == "/") {
|
||||
path = "/index.html";
|
||||
}
|
||||
if (path == "/") {
|
||||
path = "/index.html";
|
||||
}
|
||||
|
||||
path = docroot + path;
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if(fd == -1) {
|
||||
res->write_head(404);
|
||||
res->end();
|
||||
return;
|
||||
}
|
||||
path = docroot + path;
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if (fd == -1) {
|
||||
res->write_head(404);
|
||||
res->end();
|
||||
return;
|
||||
}
|
||||
|
||||
auto headers = std::vector<header>();
|
||||
auto headers = std::vector<header>();
|
||||
|
||||
struct stat stbuf;
|
||||
if(stat(path.c_str(), &stbuf) == 0) {
|
||||
headers.push_back
|
||||
(header{"content-length", std::to_string(stbuf.st_size)});
|
||||
headers.push_back
|
||||
(header{"last-modified", http_date(stbuf.st_mtim.tv_sec)});
|
||||
}
|
||||
res->write_head(200, std::move(headers));
|
||||
res->end(file_reader_from_fd(fd));
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
struct stat stbuf;
|
||||
if (stat(path.c_str(), &stbuf) == 0) {
|
||||
headers.push_back(
|
||||
header{"content-length", std::to_string(stbuf.st_size)});
|
||||
headers.push_back(
|
||||
header{"last-modified", http_date(stbuf.st_mtim.tv_sec)});
|
||||
}
|
||||
res->write_head(200, std::move(headers));
|
||||
res->end(file_reader_from_fd(fd));
|
||||
});
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
|
@ -43,8 +43,7 @@
|
||||
using namespace nghttp2::asio_http2;
|
||||
using namespace nghttp2::asio_http2::server;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
int main(int argc, char *argv[]) {
|
||||
try {
|
||||
// Check command line arguments.
|
||||
if (argc < 4) {
|
||||
@ -61,89 +60,81 @@ int main(int argc, char* argv[])
|
||||
|
||||
server.num_threads(num_threads);
|
||||
|
||||
if(argc >= 5) {
|
||||
if (argc >= 5) {
|
||||
server.tls(argv[4], argv[5]);
|
||||
}
|
||||
|
||||
server.num_concurrent_tasks(num_concurrent_tasks);
|
||||
|
||||
server.listen
|
||||
("*", port,
|
||||
[](const std::shared_ptr<request>& req,
|
||||
const std::shared_ptr<response>& res)
|
||||
{
|
||||
res->write_head(200);
|
||||
server.listen("*", port, [](const std::shared_ptr<request> &req,
|
||||
const std::shared_ptr<response> &res) {
|
||||
res->write_head(200);
|
||||
|
||||
auto msgq = std::make_shared<std::deque<std::string>>();
|
||||
auto msgq = std::make_shared<std::deque<std::string>>();
|
||||
|
||||
res->end
|
||||
([msgq](uint8_t *buf, std::size_t len) -> std::pair<ssize_t, bool>
|
||||
{
|
||||
if(msgq->empty()) {
|
||||
// if msgq is empty, tells the library that don't call
|
||||
// this callback until we call res->resume(). This is
|
||||
// done by returing std::make_pair(0, false).
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
auto msg = std::move(msgq->front());
|
||||
msgq->pop_front();
|
||||
res->end([msgq](uint8_t * buf, std::size_t len)
|
||||
-> std::pair<ssize_t, bool> {
|
||||
if (msgq->empty()) {
|
||||
// if msgq is empty, tells the library that don't call
|
||||
// this callback until we call res->resume(). This is
|
||||
// done by returing std::make_pair(0, false).
|
||||
return std::make_pair(0, false);
|
||||
}
|
||||
auto msg = std::move(msgq->front());
|
||||
msgq->pop_front();
|
||||
|
||||
if(msg.empty()) {
|
||||
// The empty message signals the end of response in
|
||||
// this simple protocol.
|
||||
return std::make_pair(0, true);
|
||||
}
|
||||
if (msg.empty()) {
|
||||
// The empty message signals the end of response in
|
||||
// this simple protocol.
|
||||
return std::make_pair(0, true);
|
||||
}
|
||||
|
||||
auto nwrite = std::min(len, msg.size());
|
||||
std::copy(std::begin(msg), std::begin(msg) + nwrite, buf);
|
||||
if(msg.size() > nwrite) {
|
||||
msgq->push_front(msg.substr(nwrite));
|
||||
}
|
||||
return std::make_pair(nwrite, false);
|
||||
});
|
||||
auto nwrite = std::min(len, msg.size());
|
||||
std::copy(std::begin(msg), std::begin(msg) + nwrite, buf);
|
||||
if (msg.size() > nwrite) {
|
||||
msgq->push_front(msg.substr(nwrite));
|
||||
}
|
||||
return std::make_pair(nwrite, false);
|
||||
});
|
||||
|
||||
req->run_task
|
||||
([res, msgq](channel& channel)
|
||||
{
|
||||
// executed in different thread from request callback
|
||||
// was called.
|
||||
req->run_task([res, msgq](channel &channel) {
|
||||
// executed in different thread from request callback
|
||||
// was called.
|
||||
|
||||
// Using res and msgq is not safe inside this callback.
|
||||
// But using them in callback passed to channel::post is
|
||||
// safe.
|
||||
// Using res and msgq is not safe inside this callback.
|
||||
// But using them in callback passed to channel::post is
|
||||
// safe.
|
||||
|
||||
// We just emit simple message "message N\n" in every 1
|
||||
// second and 3 times in total.
|
||||
for(std::size_t i = 0; i < 3; ++i) {
|
||||
msgq->push_back("message " + std::to_string(i + 1) + "\n");
|
||||
// We just emit simple message "message N\n" in every 1
|
||||
// second and 3 times in total.
|
||||
for (std::size_t i = 0; i < 3; ++i) {
|
||||
msgq->push_back("message " + std::to_string(i + 1) + "\n");
|
||||
|
||||
channel.post([res]()
|
||||
{
|
||||
// executed in same thread where
|
||||
// request callback was called.
|
||||
channel.post([res]() {
|
||||
// executed in same thread where
|
||||
// request callback was called.
|
||||
|
||||
// Tells library we have new message.
|
||||
res->resume();
|
||||
});
|
||||
// Tells library we have new message.
|
||||
res->resume();
|
||||
});
|
||||
|
||||
sleep(1);
|
||||
}
|
||||
sleep(1);
|
||||
}
|
||||
|
||||
// Send empty message to signal the end of response
|
||||
// body.
|
||||
msgq->push_back("");
|
||||
// Send empty message to signal the end of response
|
||||
// body.
|
||||
msgq->push_back("");
|
||||
|
||||
channel.post([res]()
|
||||
{
|
||||
// executed in same thread where request
|
||||
// callback was called.
|
||||
res->resume();
|
||||
});
|
||||
channel.post([res]() {
|
||||
// executed in same thread where request
|
||||
// callback was called.
|
||||
res->resume();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
} catch (std::exception& e) {
|
||||
});
|
||||
} catch (std::exception &e) {
|
||||
std::cerr << "exception: " << e.what() << "\n";
|
||||
}
|
||||
|
||||
|
@ -50,19 +50,19 @@
|
||||
#include <openssl/err.h>
|
||||
#include <openssl/conf.h>
|
||||
|
||||
enum {
|
||||
IO_NONE,
|
||||
WANT_READ,
|
||||
WANT_WRITE
|
||||
};
|
||||
enum { IO_NONE, WANT_READ, WANT_WRITE };
|
||||
|
||||
#define MAKE_NV(NAME, VALUE) \
|
||||
{(uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE}
|
||||
#define MAKE_NV(NAME, VALUE) \
|
||||
{ \
|
||||
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
#define MAKE_NV_CS(NAME, VALUE) \
|
||||
{(uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, strlen(VALUE), \
|
||||
NGHTTP2_NV_FLAG_NONE}
|
||||
#define MAKE_NV_CS(NAME, VALUE) \
|
||||
{ \
|
||||
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, strlen(VALUE), \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
struct Connection {
|
||||
SSL *ssl;
|
||||
@ -103,10 +103,9 @@ struct URI {
|
||||
* Returns copy of string |s| with the length |len|. The returned
|
||||
* string is NULL-terminated.
|
||||
*/
|
||||
static char* strcopy(const char *s, size_t len)
|
||||
{
|
||||
static char *strcopy(const char *s, size_t len) {
|
||||
char *dst;
|
||||
dst = malloc(len+1);
|
||||
dst = malloc(len + 1);
|
||||
memcpy(dst, s, len);
|
||||
dst[len] = '\0';
|
||||
return dst;
|
||||
@ -115,8 +114,7 @@ static char* strcopy(const char *s, size_t len)
|
||||
/*
|
||||
* Prints error message |msg| and exit.
|
||||
*/
|
||||
static void die(const char *msg)
|
||||
{
|
||||
static void die(const char *msg) {
|
||||
fprintf(stderr, "FATAL: %s\n", msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -125,8 +123,7 @@ static void die(const char *msg)
|
||||
* Prints error containing the function name |func| and message |msg|
|
||||
* and exit.
|
||||
*/
|
||||
static void dief(const char *func, const char *msg)
|
||||
{
|
||||
static void dief(const char *func, const char *msg) {
|
||||
fprintf(stderr, "FATAL: %s: %s\n", func, msg);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -135,8 +132,7 @@ static void dief(const char *func, const char *msg)
|
||||
* Prints error containing the function name |func| and error code
|
||||
* |error_code| and exit.
|
||||
*/
|
||||
static void diec(const char *func, int error_code)
|
||||
{
|
||||
static void diec(const char *func, int error_code) {
|
||||
fprintf(stderr, "FATAL: %s: error_code=%d, msg=%s\n", func, error_code,
|
||||
nghttp2_strerror(error_code));
|
||||
exit(EXIT_FAILURE);
|
||||
@ -148,21 +144,19 @@ static void diec(const char *func, int error_code)
|
||||
* bytes actually written. See the documentation of
|
||||
* nghttp2_send_callback for the details.
|
||||
*/
|
||||
static ssize_t send_callback(nghttp2_session *session _U_,
|
||||
const uint8_t *data, size_t length, int flags _U_,
|
||||
void *user_data)
|
||||
{
|
||||
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
||||
size_t length, int flags _U_, void *user_data) {
|
||||
struct Connection *connection;
|
||||
int rv;
|
||||
connection = (struct Connection*)user_data;
|
||||
connection = (struct Connection *)user_data;
|
||||
connection->want_io = IO_NONE;
|
||||
ERR_clear_error();
|
||||
rv = SSL_write(connection->ssl, data, (int)length);
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
int err = SSL_get_error(connection->ssl, rv);
|
||||
if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
|
||||
connection->want_io = (err == SSL_ERROR_WANT_READ ?
|
||||
WANT_READ : WANT_WRITE);
|
||||
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
|
||||
connection->want_io =
|
||||
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
|
||||
rv = NGHTTP2_ERR_WOULDBLOCK;
|
||||
} else {
|
||||
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
@ -177,41 +171,39 @@ static ssize_t send_callback(nghttp2_session *session _U_,
|
||||
* |length| bytes. Returns the number of bytes stored in |buf|. See
|
||||
* the documentation of nghttp2_recv_callback for the details.
|
||||
*/
|
||||
static ssize_t recv_callback(nghttp2_session *session _U_,
|
||||
uint8_t *buf, size_t length, int flags _U_,
|
||||
void *user_data)
|
||||
{
|
||||
static ssize_t recv_callback(nghttp2_session *session _U_, uint8_t *buf,
|
||||
size_t length, int flags _U_, void *user_data) {
|
||||
struct Connection *connection;
|
||||
int rv;
|
||||
connection = (struct Connection*)user_data;
|
||||
connection = (struct Connection *)user_data;
|
||||
connection->want_io = IO_NONE;
|
||||
ERR_clear_error();
|
||||
rv = SSL_read(connection->ssl, buf, (int)length);
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
int err = SSL_get_error(connection->ssl, rv);
|
||||
if(err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
|
||||
connection->want_io = (err == SSL_ERROR_WANT_READ ?
|
||||
WANT_READ : WANT_WRITE);
|
||||
if (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ) {
|
||||
connection->want_io =
|
||||
(err == SSL_ERROR_WANT_READ ? WANT_READ : WANT_WRITE);
|
||||
rv = NGHTTP2_ERR_WOULDBLOCK;
|
||||
} else {
|
||||
rv = NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
} else if(rv == 0) {
|
||||
} else if (rv == 0) {
|
||||
rv = NGHTTP2_ERR_EOF;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
static int on_frame_send_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data _U_)
|
||||
{
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data _U_) {
|
||||
size_t i;
|
||||
switch(frame->hd.type) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
|
||||
if (nghttp2_session_get_stream_user_data(session, frame->hd.stream_id)) {
|
||||
const nghttp2_nv *nva = frame->headers.nva;
|
||||
printf("[INFO] C ----------------------------> S (HEADERS)\n");
|
||||
for(i = 0; i < frame->headers.nvlen; ++i) {
|
||||
for (i = 0; i < frame->headers.nvlen; ++i) {
|
||||
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
|
||||
printf(": ");
|
||||
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
|
||||
@ -230,18 +222,18 @@ static int on_frame_send_callback(nghttp2_session *session,
|
||||
}
|
||||
|
||||
static int on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data _U_)
|
||||
{
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data _U_) {
|
||||
size_t i;
|
||||
switch(frame->hd.type) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE) {
|
||||
const nghttp2_nv *nva = frame->headers.nva;
|
||||
struct Request *req;
|
||||
req = nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
if(req) {
|
||||
if (req) {
|
||||
printf("[INFO] C <---------------------------- S (HEADERS)\n");
|
||||
for(i = 0; i < frame->headers.nvlen; ++i) {
|
||||
for (i = 0; i < frame->headers.nvlen; ++i) {
|
||||
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
|
||||
printf(": ");
|
||||
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
|
||||
@ -266,18 +258,16 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
||||
* fetch 1 resource in this program, after reception of the response,
|
||||
* we submit GOAWAY and close the session.
|
||||
*/
|
||||
static int on_stream_close_callback(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code _U_,
|
||||
void *user_data _U_)
|
||||
{
|
||||
void *user_data _U_) {
|
||||
struct Request *req;
|
||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||
if(req) {
|
||||
if (req) {
|
||||
int rv;
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
diec("nghttp2_session_terminate_session", rv);
|
||||
}
|
||||
}
|
||||
@ -290,16 +280,16 @@ static int on_stream_close_callback(nghttp2_session *session,
|
||||
* The implementation of nghttp2_on_data_chunk_recv_callback type. We
|
||||
* use this function to print the received response body.
|
||||
*/
|
||||
static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t stream_id,
|
||||
static int on_data_chunk_recv_callback(nghttp2_session *session,
|
||||
uint8_t flags _U_, int32_t stream_id,
|
||||
const uint8_t *data, size_t len,
|
||||
void *user_data _U_)
|
||||
{
|
||||
void *user_data _U_) {
|
||||
struct Request *req;
|
||||
req = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||
if(req) {
|
||||
if (req) {
|
||||
printf("[INFO] C <---------------------------- S (DATA chunk)\n"
|
||||
"%lu bytes\n", (unsigned long int)len);
|
||||
"%lu bytes\n",
|
||||
(unsigned long int)len);
|
||||
fwrite(data, 1, len, stdout);
|
||||
printf("\n");
|
||||
}
|
||||
@ -312,23 +302,22 @@ static int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags _
|
||||
* always required. Since we use nghttp2_session_recv(), the
|
||||
* recv_callback is also required.
|
||||
*/
|
||||
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
|
||||
{
|
||||
static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks) {
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_recv_callback(callbacks, recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(callbacks, on_frame_send_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_send_callback(callbacks,
|
||||
on_frame_send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -336,16 +325,14 @@ static void setup_nghttp2_callbacks(nghttp2_session_callbacks *callbacks)
|
||||
* HTTP/2 protocol, if server does not offer HTTP/2 the nghttp2
|
||||
* library supports, we terminate program.
|
||||
*/
|
||||
static int select_next_proto_cb(SSL* ssl _U_,
|
||||
unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg _U_)
|
||||
{
|
||||
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg _U_) {
|
||||
int rv;
|
||||
/* nghttp2_select_next_protocol() selects HTTP/2 protocol the
|
||||
nghttp2 library supports. */
|
||||
rv = nghttp2_select_next_protocol(out, outlen, in, inlen);
|
||||
if(rv <= 0) {
|
||||
if (rv <= 0) {
|
||||
die("Server did not advertise HTTP/2 protocol");
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
@ -354,25 +341,23 @@ static int select_next_proto_cb(SSL* ssl _U_,
|
||||
/*
|
||||
* Setup SSL/TLS context.
|
||||
*/
|
||||
static void init_ssl_ctx(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
static void init_ssl_ctx(SSL_CTX *ssl_ctx) {
|
||||
/* Disable SSLv2 and enable all workarounds for buggy servers */
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
|
||||
SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
/* Set NPN callback */
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
}
|
||||
|
||||
static void ssl_handshake(SSL *ssl, int fd)
|
||||
{
|
||||
static void ssl_handshake(SSL *ssl, int fd) {
|
||||
int rv;
|
||||
if(SSL_set_fd(ssl, fd) == 0) {
|
||||
if (SSL_set_fd(ssl, fd) == 0) {
|
||||
dief("SSL_set_fd", ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
ERR_clear_error();
|
||||
rv = SSL_connect(ssl);
|
||||
if(rv <= 0) {
|
||||
if (rv <= 0) {
|
||||
dief("SSL_connect", ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
}
|
||||
@ -381,8 +366,7 @@ static void ssl_handshake(SSL *ssl, int fd)
|
||||
* Connects to the host |host| and port |port|. This function returns
|
||||
* the file descriptor of the client socket.
|
||||
*/
|
||||
static int connect_to(const char *host, uint16_t port)
|
||||
{
|
||||
static int connect_to(const char *host, uint16_t port) {
|
||||
struct addrinfo hints;
|
||||
int fd = -1;
|
||||
int rv;
|
||||
@ -393,17 +377,18 @@ static int connect_to(const char *host, uint16_t port)
|
||||
hints.ai_family = AF_UNSPEC;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
rv = getaddrinfo(host, service, &hints, &res);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
dief("getaddrinfo", gai_strerror(rv));
|
||||
}
|
||||
for(rp = res; rp; rp = rp->ai_next) {
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||
if(fd == -1) {
|
||||
if (fd == -1) {
|
||||
continue;
|
||||
}
|
||||
while((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
|
||||
errno == EINTR);
|
||||
if(rv == 0) {
|
||||
while ((rv = connect(fd, rp->ai_addr, rp->ai_addrlen)) == -1 &&
|
||||
errno == EINTR)
|
||||
;
|
||||
if (rv == 0) {
|
||||
break;
|
||||
}
|
||||
close(fd);
|
||||
@ -413,25 +398,25 @@ static int connect_to(const char *host, uint16_t port)
|
||||
return fd;
|
||||
}
|
||||
|
||||
static void make_non_block(int fd)
|
||||
{
|
||||
static void make_non_block(int fd) {
|
||||
int flags, rv;
|
||||
while((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR);
|
||||
if(flags == -1) {
|
||||
while ((flags = fcntl(fd, F_GETFL, 0)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (flags == -1) {
|
||||
dief("fcntl", strerror(errno));
|
||||
}
|
||||
while((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR);
|
||||
if(rv == -1) {
|
||||
while ((rv = fcntl(fd, F_SETFL, flags | O_NONBLOCK)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (rv == -1) {
|
||||
dief("fcntl", strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
static void set_tcp_nodelay(int fd)
|
||||
{
|
||||
static void set_tcp_nodelay(int fd) {
|
||||
int val = 1;
|
||||
int rv;
|
||||
rv = setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &val, (socklen_t)sizeof(val));
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
dief("setsockopt", strerror(errno));
|
||||
}
|
||||
}
|
||||
@ -439,15 +424,14 @@ static void set_tcp_nodelay(int fd)
|
||||
/*
|
||||
* Update |pollfd| based on the state of |connection|.
|
||||
*/
|
||||
static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
|
||||
{
|
||||
static void ctl_poll(struct pollfd *pollfd, struct Connection *connection) {
|
||||
pollfd->events = 0;
|
||||
if(nghttp2_session_want_read(connection->session) ||
|
||||
connection->want_io == WANT_READ) {
|
||||
if (nghttp2_session_want_read(connection->session) ||
|
||||
connection->want_io == WANT_READ) {
|
||||
pollfd->events |= POLLIN;
|
||||
}
|
||||
if(nghttp2_session_want_write(connection->session) ||
|
||||
connection->want_io == WANT_WRITE) {
|
||||
if (nghttp2_session_want_write(connection->session) ||
|
||||
connection->want_io == WANT_WRITE) {
|
||||
pollfd->events |= POLLOUT;
|
||||
}
|
||||
}
|
||||
@ -457,24 +441,20 @@ static void ctl_poll(struct pollfd *pollfd, struct Connection *connection)
|
||||
* function does not send packets; just append the request to the
|
||||
* internal queue in |connection->session|.
|
||||
*/
|
||||
static void submit_request(struct Connection *connection, struct Request *req)
|
||||
{
|
||||
static void submit_request(struct Connection *connection, struct Request *req) {
|
||||
int32_t stream_id;
|
||||
const nghttp2_nv nva[] = {
|
||||
/* Make sure that the last item is NULL */
|
||||
MAKE_NV(":method", "GET"),
|
||||
MAKE_NV_CS(":path", req->path),
|
||||
MAKE_NV(":scheme", "https"),
|
||||
MAKE_NV_CS(":authority", req->hostport),
|
||||
MAKE_NV("accept", "*/*"),
|
||||
MAKE_NV("user-agent", "nghttp2/"NGHTTP2_VERSION)
|
||||
};
|
||||
/* Make sure that the last item is NULL */
|
||||
const nghttp2_nv nva[] = {MAKE_NV(":method", "GET"),
|
||||
MAKE_NV_CS(":path", req->path),
|
||||
MAKE_NV(":scheme", "https"),
|
||||
MAKE_NV_CS(":authority", req->hostport),
|
||||
MAKE_NV("accept", "*/*"),
|
||||
MAKE_NV("user-agent", "nghttp2/" NGHTTP2_VERSION)};
|
||||
|
||||
stream_id = nghttp2_submit_request(connection->session, NULL,
|
||||
nva, sizeof(nva)/sizeof(nva[0]),
|
||||
NULL, req);
|
||||
stream_id = nghttp2_submit_request(connection->session, NULL, nva,
|
||||
sizeof(nva) / sizeof(nva[0]), NULL, req);
|
||||
|
||||
if(stream_id < 0) {
|
||||
if (stream_id < 0) {
|
||||
diec("nghttp2_submit_request", stream_id);
|
||||
}
|
||||
|
||||
@ -485,21 +465,19 @@ static void submit_request(struct Connection *connection, struct Request *req)
|
||||
/*
|
||||
* Performs the network I/O.
|
||||
*/
|
||||
static void exec_io(struct Connection *connection)
|
||||
{
|
||||
static void exec_io(struct Connection *connection) {
|
||||
int rv;
|
||||
rv = nghttp2_session_recv(connection->session);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
diec("nghttp2_session_recv", rv);
|
||||
}
|
||||
rv = nghttp2_session_send(connection->session);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
diec("nghttp2_session_send", rv);
|
||||
}
|
||||
}
|
||||
|
||||
static void request_init(struct Request *req, const struct URI *uri)
|
||||
{
|
||||
static void request_init(struct Request *req, const struct URI *uri) {
|
||||
req->host = strcopy(uri->host, uri->hostlen);
|
||||
req->port = uri->port;
|
||||
req->path = strcopy(uri->path, uri->pathlen);
|
||||
@ -507,8 +485,7 @@ static void request_init(struct Request *req, const struct URI *uri)
|
||||
req->stream_id = -1;
|
||||
}
|
||||
|
||||
static void request_free(struct Request *req)
|
||||
{
|
||||
static void request_free(struct Request *req) {
|
||||
free(req->host);
|
||||
free(req->path);
|
||||
free(req->hostport);
|
||||
@ -517,8 +494,7 @@ static void request_free(struct Request *req)
|
||||
/*
|
||||
* Fetches the resource denoted by |uri|.
|
||||
*/
|
||||
static void fetch_uri(const struct URI *uri)
|
||||
{
|
||||
static void fetch_uri(const struct URI *uri) {
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
int fd;
|
||||
SSL_CTX *ssl_ctx;
|
||||
@ -533,16 +509,16 @@ static void fetch_uri(const struct URI *uri)
|
||||
|
||||
/* Establish connection and setup SSL */
|
||||
fd = connect_to(req.host, req.port);
|
||||
if(fd == -1) {
|
||||
if (fd == -1) {
|
||||
die("Could not open file descriptor");
|
||||
}
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if(ssl_ctx == NULL) {
|
||||
if (ssl_ctx == NULL) {
|
||||
dief("SSL_CTX_new", ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
init_ssl_ctx(ssl_ctx);
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
if(ssl == NULL) {
|
||||
if (ssl == NULL) {
|
||||
dief("SSL_new", ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
/* To simplify the program, we perform SSL/TLS handshake in blocking
|
||||
@ -564,18 +540,17 @@ static void fetch_uri(const struct URI *uri)
|
||||
|
||||
rv = nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
diec("nghttp2_session_callbacks_new", rv);
|
||||
}
|
||||
|
||||
setup_nghttp2_callbacks(callbacks);
|
||||
|
||||
rv = nghttp2_session_client_new(&connection.session, callbacks,
|
||||
&connection);
|
||||
rv = nghttp2_session_client_new(&connection.session, callbacks, &connection);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
diec("nghttp2_session_client_new", rv);
|
||||
}
|
||||
|
||||
@ -586,16 +561,16 @@ static void fetch_uri(const struct URI *uri)
|
||||
ctl_poll(pollfds, &connection);
|
||||
|
||||
/* Event loop */
|
||||
while(nghttp2_session_want_read(connection.session) ||
|
||||
nghttp2_session_want_write(connection.session)) {
|
||||
while (nghttp2_session_want_read(connection.session) ||
|
||||
nghttp2_session_want_write(connection.session)) {
|
||||
int nfds = poll(pollfds, npollfds, -1);
|
||||
if(nfds == -1) {
|
||||
if (nfds == -1) {
|
||||
dief("poll", strerror(errno));
|
||||
}
|
||||
if(pollfds[0].revents & (POLLIN | POLLOUT)) {
|
||||
if (pollfds[0].revents & (POLLIN | POLLOUT)) {
|
||||
exec_io(&connection);
|
||||
}
|
||||
if((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
|
||||
if ((pollfds[0].revents & POLLHUP) || (pollfds[0].revents & POLLERR)) {
|
||||
die("Connection error");
|
||||
}
|
||||
ctl_poll(pollfds, &connection);
|
||||
@ -611,96 +586,94 @@ static void fetch_uri(const struct URI *uri)
|
||||
request_free(&req);
|
||||
}
|
||||
|
||||
static int parse_uri(struct URI *res, const char *uri)
|
||||
{
|
||||
static int parse_uri(struct URI *res, const char *uri) {
|
||||
/* We only interested in https */
|
||||
size_t len, i, offset;
|
||||
int ipv6addr = 0;
|
||||
memset(res, 0, sizeof(struct URI));
|
||||
len = strlen(uri);
|
||||
if(len < 9 || memcmp("https://", uri, 8) != 0) {
|
||||
if (len < 9 || memcmp("https://", uri, 8) != 0) {
|
||||
return -1;
|
||||
}
|
||||
offset = 8;
|
||||
res->host = res->hostport = &uri[offset];
|
||||
res->hostlen = 0;
|
||||
if(uri[offset] == '[') {
|
||||
if (uri[offset] == '[') {
|
||||
/* IPv6 literal address */
|
||||
++offset;
|
||||
++res->host;
|
||||
ipv6addr = 1;
|
||||
for(i = offset; i < len; ++i) {
|
||||
if(uri[i] == ']') {
|
||||
res->hostlen = i-offset;
|
||||
offset = i+1;
|
||||
for (i = offset; i < len; ++i) {
|
||||
if (uri[i] == ']') {
|
||||
res->hostlen = i - offset;
|
||||
offset = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const char delims[] = ":/?#";
|
||||
for(i = offset; i < len; ++i) {
|
||||
if(strchr(delims, uri[i]) != NULL) {
|
||||
for (i = offset; i < len; ++i) {
|
||||
if (strchr(delims, uri[i]) != NULL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
res->hostlen = i-offset;
|
||||
res->hostlen = i - offset;
|
||||
offset = i;
|
||||
}
|
||||
if(res->hostlen == 0) {
|
||||
if (res->hostlen == 0) {
|
||||
return -1;
|
||||
}
|
||||
/* Assuming https */
|
||||
res->port = 443;
|
||||
if(offset < len) {
|
||||
if(uri[offset] == ':') {
|
||||
if (offset < len) {
|
||||
if (uri[offset] == ':') {
|
||||
/* port */
|
||||
const char delims[] = "/?#";
|
||||
int port = 0;
|
||||
++offset;
|
||||
for(i = offset; i < len; ++i) {
|
||||
if(strchr(delims, uri[i]) != NULL) {
|
||||
for (i = offset; i < len; ++i) {
|
||||
if (strchr(delims, uri[i]) != NULL) {
|
||||
break;
|
||||
}
|
||||
if('0' <= uri[i] && uri[i] <= '9') {
|
||||
if ('0' <= uri[i] && uri[i] <= '9') {
|
||||
port *= 10;
|
||||
port += uri[i]-'0';
|
||||
if(port > 65535) {
|
||||
port += uri[i] - '0';
|
||||
if (port > 65535) {
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(port == 0) {
|
||||
if (port == 0) {
|
||||
return -1;
|
||||
}
|
||||
offset = i;
|
||||
res->port = port;
|
||||
}
|
||||
}
|
||||
res->hostportlen = uri+offset+ipv6addr-res->host;
|
||||
for(i = offset; i < len; ++i) {
|
||||
if(uri[i] == '#') {
|
||||
res->hostportlen = uri + offset + ipv6addr - res->host;
|
||||
for (i = offset; i < len; ++i) {
|
||||
if (uri[i] == '#') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(i-offset == 0) {
|
||||
if (i - offset == 0) {
|
||||
res->path = "/";
|
||||
res->pathlen = 1;
|
||||
} else {
|
||||
res->path = &uri[offset];
|
||||
res->pathlen = i-offset;
|
||||
res->pathlen = i - offset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
struct URI uri;
|
||||
struct sigaction act;
|
||||
int rv;
|
||||
|
||||
if(argc < 2) {
|
||||
if (argc < 2) {
|
||||
die("Specify a https URI");
|
||||
}
|
||||
|
||||
@ -714,7 +687,7 @@ int main(int argc, char **argv)
|
||||
SSL_library_init();
|
||||
|
||||
rv = parse_uri(&uri, argv[1]);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
die("parse_uri failed");
|
||||
}
|
||||
fetch_uri(&uri);
|
||||
|
@ -31,43 +31,39 @@
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#define MAKE_NV(K, V) \
|
||||
{ (uint8_t*)K, (uint8_t*)V, sizeof(K) - 1, sizeof(V) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE }
|
||||
#define MAKE_NV(K, V) \
|
||||
{ \
|
||||
(uint8_t *) K, (uint8_t *)V, sizeof(K) - 1, sizeof(V) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
static void deflate(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_hd_inflater *inflater,
|
||||
const nghttp2_nv * const nva, size_t nvlen);
|
||||
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
|
||||
size_t nvlen);
|
||||
|
||||
static int inflate_header_block(nghttp2_hd_inflater *inflater,
|
||||
uint8_t *in, size_t inlen, int final);
|
||||
static int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
|
||||
size_t inlen, int final);
|
||||
|
||||
int main(int argc _U_, char **argv _U_)
|
||||
{
|
||||
int main(int argc _U_, char **argv _U_) {
|
||||
int rv;
|
||||
nghttp2_hd_deflater *deflater;
|
||||
nghttp2_hd_inflater *inflater;
|
||||
/* Define 1st header set. This is looks like a HTTP request. */
|
||||
nghttp2_nv nva1[] = {
|
||||
MAKE_NV(":scheme", "https"),
|
||||
MAKE_NV(":authority", "example.org"),
|
||||
MAKE_NV(":path", "/"),
|
||||
MAKE_NV("user-agent", "libnghttp2"),
|
||||
MAKE_NV("accept-encoding", "gzip, deflate")
|
||||
};
|
||||
MAKE_NV(":scheme", "https"), MAKE_NV(":authority", "example.org"),
|
||||
MAKE_NV(":path", "/"), MAKE_NV("user-agent", "libnghttp2"),
|
||||
MAKE_NV("accept-encoding", "gzip, deflate")};
|
||||
/* Define 2nd header set */
|
||||
nghttp2_nv nva2[] = {
|
||||
MAKE_NV(":scheme", "https"),
|
||||
MAKE_NV(":authority", "example.org"),
|
||||
MAKE_NV(":path", "/stylesheet/style.css"),
|
||||
MAKE_NV("user-agent", "libnghttp2"),
|
||||
MAKE_NV("accept-encoding", "gzip, deflate"),
|
||||
MAKE_NV("referer", "https://example.org")
|
||||
};
|
||||
nghttp2_nv nva2[] = {MAKE_NV(":scheme", "https"),
|
||||
MAKE_NV(":authority", "example.org"),
|
||||
MAKE_NV(":path", "/stylesheet/style.css"),
|
||||
MAKE_NV("user-agent", "libnghttp2"),
|
||||
MAKE_NV("accept-encoding", "gzip, deflate"),
|
||||
MAKE_NV("referer", "https://example.org")};
|
||||
|
||||
rv = nghttp2_hd_deflate_new(&deflater, 4096);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "nghttp2_hd_deflate_init failed with error: %s\n",
|
||||
nghttp2_strerror(rv));
|
||||
exit(EXIT_FAILURE);
|
||||
@ -75,7 +71,7 @@ int main(int argc _U_, char **argv _U_)
|
||||
|
||||
rv = nghttp2_hd_inflate_new(&inflater);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
fprintf(stderr, "nghttp2_hd_inflate_init failed with error: %s\n",
|
||||
nghttp2_strerror(rv));
|
||||
exit(EXIT_FAILURE);
|
||||
@ -95,9 +91,8 @@ int main(int argc _U_, char **argv _U_)
|
||||
}
|
||||
|
||||
static void deflate(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_hd_inflater *inflater,
|
||||
const nghttp2_nv * const nva, size_t nvlen)
|
||||
{
|
||||
nghttp2_hd_inflater *inflater, const nghttp2_nv *const nva,
|
||||
size_t nvlen) {
|
||||
ssize_t rv;
|
||||
uint8_t *buf;
|
||||
size_t buflen;
|
||||
@ -107,13 +102,13 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
||||
|
||||
sum = 0;
|
||||
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
sum += nva[i].namelen + nva[i].valuelen;
|
||||
}
|
||||
|
||||
printf("Input (%zu byte(s)):\n\n", sum);
|
||||
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
fwrite(nva[i].name, nva[i].namelen, 1, stdout);
|
||||
printf(": ");
|
||||
fwrite(nva[i].value, nva[i].valuelen, 1, stdout);
|
||||
@ -125,7 +120,7 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
||||
|
||||
rv = nghttp2_hd_deflate_hd(deflater, buf, buflen, nva, nvlen);
|
||||
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "nghttp2_hd_deflate_hd() failed with error: %s\n",
|
||||
nghttp2_strerror((int)rv));
|
||||
|
||||
@ -136,17 +131,17 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
||||
|
||||
outlen = rv;
|
||||
|
||||
printf("\nDeflate (%zu byte(s), ratio %.02f):\n\n",
|
||||
outlen, sum == 0 ? 0 : (double)outlen / sum);
|
||||
printf("\nDeflate (%zu byte(s), ratio %.02f):\n\n", outlen,
|
||||
sum == 0 ? 0 : (double)outlen / sum);
|
||||
|
||||
for(i = 0; i < outlen; ++i) {
|
||||
if((i & 0x0fu) == 0) {
|
||||
for (i = 0; i < outlen; ++i) {
|
||||
if ((i & 0x0fu) == 0) {
|
||||
printf("%08zX: ", i);
|
||||
}
|
||||
|
||||
printf("%02X ", buf[i]);
|
||||
|
||||
if(((i + 1) & 0x0fu) == 0) {
|
||||
if (((i + 1) & 0x0fu) == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
@ -157,7 +152,7 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
||||
header data. */
|
||||
rv = inflate_header_block(inflater, buf, outlen, 1);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
free(buf);
|
||||
|
||||
exit(EXIT_FAILURE);
|
||||
@ -169,20 +164,18 @@ static void deflate(nghttp2_hd_deflater *deflater,
|
||||
free(buf);
|
||||
}
|
||||
|
||||
int inflate_header_block(nghttp2_hd_inflater *inflater,
|
||||
uint8_t *in, size_t inlen, int final)
|
||||
{
|
||||
int inflate_header_block(nghttp2_hd_inflater *inflater, uint8_t *in,
|
||||
size_t inlen, int final) {
|
||||
ssize_t rv;
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
nghttp2_nv nv;
|
||||
int inflate_flags = 0;
|
||||
size_t proclen;
|
||||
|
||||
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags,
|
||||
in, inlen, final);
|
||||
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, in, inlen, final);
|
||||
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "inflate failed with error code %zd", rv);
|
||||
return -1;
|
||||
}
|
||||
@ -192,20 +185,19 @@ int inflate_header_block(nghttp2_hd_inflater *inflater,
|
||||
in += proclen;
|
||||
inlen -= proclen;
|
||||
|
||||
if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
|
||||
if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
|
||||
fwrite(nv.name, nv.namelen, 1, stderr);
|
||||
fprintf(stderr, ": ");
|
||||
fwrite(nv.value, nv.valuelen, 1, stderr);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
|
||||
if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
|
||||
nghttp2_hd_inflate_end_headers(inflater);
|
||||
break;
|
||||
}
|
||||
|
||||
if((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 &&
|
||||
inlen == 0) {
|
||||
if ((inflate_flags & NGHTTP2_HD_INFLATE_EMIT) == 0 && inlen == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -47,7 +47,7 @@
|
||||
|
||||
#include "http-parser/http_parser.h"
|
||||
|
||||
#define ARRLEN(x) (sizeof(x)/sizeof(x[0]))
|
||||
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
typedef struct {
|
||||
/* The NULL-terminated URI string to retreive. */
|
||||
@ -74,9 +74,8 @@ typedef struct {
|
||||
http2_stream_data *stream_data;
|
||||
} http2_session_data;
|
||||
|
||||
static http2_stream_data* create_http2_stream_data(const char *uri,
|
||||
struct http_parser_url *u)
|
||||
{
|
||||
static http2_stream_data *create_http2_stream_data(const char *uri,
|
||||
struct http_parser_url *u) {
|
||||
/* MAX 5 digits (max 65535) + 1 ':' + 1 NULL (because of snprintf) */
|
||||
size_t extra = 7;
|
||||
http2_stream_data *stream_data = malloc(sizeof(http2_stream_data));
|
||||
@ -87,29 +86,29 @@ static http2_stream_data* create_http2_stream_data(const char *uri,
|
||||
|
||||
stream_data->authoritylen = u->field_data[UF_HOST].len;
|
||||
stream_data->authority = malloc(stream_data->authoritylen + extra);
|
||||
memcpy(stream_data->authority,
|
||||
&uri[u->field_data[UF_HOST].off], u->field_data[UF_HOST].len);
|
||||
if(u->field_set & (1 << UF_PORT)) {
|
||||
memcpy(stream_data->authority, &uri[u->field_data[UF_HOST].off],
|
||||
u->field_data[UF_HOST].len);
|
||||
if (u->field_set & (1 << UF_PORT)) {
|
||||
stream_data->authoritylen +=
|
||||
snprintf(stream_data->authority + u->field_data[UF_HOST].len, extra,
|
||||
":%u", u->port);
|
||||
snprintf(stream_data->authority + u->field_data[UF_HOST].len, extra,
|
||||
":%u", u->port);
|
||||
}
|
||||
|
||||
stream_data->pathlen = 0;
|
||||
if(u->field_set & (1 << UF_PATH)) {
|
||||
if (u->field_set & (1 << UF_PATH)) {
|
||||
stream_data->pathlen = u->field_data[UF_PATH].len;
|
||||
}
|
||||
if(u->field_set & (1 << UF_QUERY)) {
|
||||
if (u->field_set & (1 << UF_QUERY)) {
|
||||
/* +1 for '?' character */
|
||||
stream_data->pathlen += u->field_data[UF_QUERY].len + 1;
|
||||
}
|
||||
if(stream_data->pathlen > 0) {
|
||||
if (stream_data->pathlen > 0) {
|
||||
stream_data->path = malloc(stream_data->pathlen);
|
||||
if(u->field_set & (1 << UF_PATH)) {
|
||||
memcpy(stream_data->path,
|
||||
&uri[u->field_data[UF_PATH].off], u->field_data[UF_PATH].len);
|
||||
if (u->field_set & (1 << UF_PATH)) {
|
||||
memcpy(stream_data->path, &uri[u->field_data[UF_PATH].off],
|
||||
u->field_data[UF_PATH].len);
|
||||
}
|
||||
if(u->field_set & (1 << UF_QUERY)) {
|
||||
if (u->field_set & (1 << UF_QUERY)) {
|
||||
memcpy(stream_data->path + u->field_data[UF_PATH].len + 1,
|
||||
&uri[u->field_data[UF_QUERY].off], u->field_data[UF_QUERY].len);
|
||||
}
|
||||
@ -119,16 +118,15 @@ static http2_stream_data* create_http2_stream_data(const char *uri,
|
||||
return stream_data;
|
||||
}
|
||||
|
||||
static void delete_http2_stream_data(http2_stream_data *stream_data)
|
||||
{
|
||||
static void delete_http2_stream_data(http2_stream_data *stream_data) {
|
||||
free(stream_data->path);
|
||||
free(stream_data->authority);
|
||||
free(stream_data);
|
||||
}
|
||||
|
||||
/* Initializes |session_data| */
|
||||
static http2_session_data *create_http2_session_data(struct event_base *evbase)
|
||||
{
|
||||
static http2_session_data *
|
||||
create_http2_session_data(struct event_base *evbase) {
|
||||
http2_session_data *session_data = malloc(sizeof(http2_session_data));
|
||||
|
||||
memset(session_data, 0, sizeof(http2_session_data));
|
||||
@ -136,11 +134,10 @@ static http2_session_data *create_http2_session_data(struct event_base *evbase)
|
||||
return session_data;
|
||||
}
|
||||
|
||||
static void delete_http2_session_data(http2_session_data *session_data)
|
||||
{
|
||||
static void delete_http2_session_data(http2_session_data *session_data) {
|
||||
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
|
||||
if(ssl) {
|
||||
if (ssl) {
|
||||
SSL_shutdown(ssl);
|
||||
}
|
||||
bufferevent_free(session_data->bev);
|
||||
@ -149,17 +146,15 @@ static void delete_http2_session_data(http2_session_data *session_data)
|
||||
session_data->dnsbase = NULL;
|
||||
nghttp2_session_del(session_data->session);
|
||||
session_data->session = NULL;
|
||||
if(session_data->stream_data) {
|
||||
if (session_data->stream_data) {
|
||||
delete_http2_stream_data(session_data->stream_data);
|
||||
session_data->stream_data = NULL;
|
||||
}
|
||||
free(session_data);
|
||||
}
|
||||
|
||||
static void print_header(FILE *f,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen)
|
||||
{
|
||||
static void print_header(FILE *f, const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen) {
|
||||
fwrite(name, namelen, 1, f);
|
||||
fprintf(f, ": ");
|
||||
fwrite(value, valuelen, 1, f);
|
||||
@ -169,13 +164,10 @@ static void print_header(FILE *f,
|
||||
/* Print HTTP headers to |f|. Please note that this function does not
|
||||
take into account that header name and value are sequence of
|
||||
octets, therefore they may contain non-printable characters. */
|
||||
static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen) {
|
||||
size_t i;
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
print_header(f,
|
||||
nva[i].name, nva[i].namelen,
|
||||
nva[i].value, nva[i].valuelen);
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
print_header(f, nva[i].name, nva[i].namelen, nva[i].value, nva[i].valuelen);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
}
|
||||
@ -183,11 +175,9 @@ static void print_headers(FILE *f, nghttp2_nv *nva, size_t nvlen)
|
||||
/* nghttp2_send_callback. Here we transmit the |data|, |length| bytes,
|
||||
to the network. Because we are using libevent bufferevent, we just
|
||||
write those bytes into bufferevent buffer. */
|
||||
static ssize_t send_callback(nghttp2_session *session _U_,
|
||||
const uint8_t *data, size_t length,
|
||||
int flags _U_, void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
||||
size_t length, int flags _U_, void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
struct bufferevent *bev = session_data->bev;
|
||||
bufferevent_write(bev, data, length);
|
||||
return length;
|
||||
@ -196,17 +186,15 @@ static ssize_t send_callback(nghttp2_session *session _U_,
|
||||
/* nghttp2_on_header_callback: Called when nghttp2 library emits
|
||||
single header name/value pair. */
|
||||
static int on_header_callback(nghttp2_session *session _U_,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags _U_,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
const nghttp2_frame *frame, const uint8_t *name,
|
||||
size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, uint8_t flags _U_,
|
||||
void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
/* Print response headers for the initiated request. */
|
||||
print_header(stderr, name, namelen, value, valuelen);
|
||||
break;
|
||||
@ -219,13 +207,12 @@ static int on_header_callback(nghttp2_session *session _U_,
|
||||
started to receive header block. */
|
||||
static int on_begin_headers_callback(nghttp2_session *session _U_,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
fprintf(stderr, "Response headers for stream ID=%d:\n",
|
||||
frame->hd.stream_id);
|
||||
}
|
||||
@ -237,13 +224,12 @@ static int on_begin_headers_callback(nghttp2_session *session _U_,
|
||||
/* nghttp2_on_frame_recv_callback: Called when nghttp2 library
|
||||
received a complete frame from the remote peer. */
|
||||
static int on_frame_recv_callback(nghttp2_session *session _U_,
|
||||
const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
switch(frame->hd.type) {
|
||||
const nghttp2_frame *frame, void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
if (frame->headers.cat == NGHTTP2_HCAT_RESPONSE &&
|
||||
session_data->stream_data->stream_id == frame->hd.stream_id) {
|
||||
fprintf(stderr, "All headers received\n");
|
||||
}
|
||||
break;
|
||||
@ -256,13 +242,12 @@ static int on_frame_recv_callback(nghttp2_session *session _U_,
|
||||
is meant to the stream we initiated, print the received data in
|
||||
stdout, so that the user can redirect its output to the file
|
||||
easily. */
|
||||
static int on_data_chunk_recv_callback(nghttp2_session *session _U_, uint8_t flags _U_,
|
||||
int32_t stream_id,
|
||||
static int on_data_chunk_recv_callback(nghttp2_session *session _U_,
|
||||
uint8_t flags _U_, int32_t stream_id,
|
||||
const uint8_t *data, size_t len,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
if(session_data->stream_data->stream_id == stream_id) {
|
||||
void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
if (session_data->stream_data->stream_id == stream_id) {
|
||||
fwrite(data, len, 1, stdout);
|
||||
}
|
||||
return 0;
|
||||
@ -272,19 +257,17 @@ static int on_data_chunk_recv_callback(nghttp2_session *session _U_, uint8_t fla
|
||||
closed. This example program only deals with 1 HTTP request (1
|
||||
stream), if it is closed, we send GOAWAY and tear down the
|
||||
session */
|
||||
static int on_stream_close_callback(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
nghttp2_error_code error_code,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
int rv;
|
||||
|
||||
if(session_data->stream_data->stream_id == stream_id) {
|
||||
fprintf(stderr, "Stream %d closed with error_code=%d\n",
|
||||
stream_id, error_code);
|
||||
if (session_data->stream_data->stream_id == stream_id) {
|
||||
fprintf(stderr, "Stream %d closed with error_code=%d\n", stream_id,
|
||||
error_code);
|
||||
rv = nghttp2_session_terminate_session(session, NGHTTP2_NO_ERROR);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
}
|
||||
@ -294,117 +277,111 @@ static int on_stream_close_callback(nghttp2_session *session,
|
||||
/* NPN TLS extension client callback. We check that server advertised
|
||||
the HTTP/2 protocol the nghttp2 library supports. If not, exit
|
||||
the program. */
|
||||
static int select_next_proto_cb(SSL* ssl _U_,
|
||||
unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen,
|
||||
void *arg _U_)
|
||||
{
|
||||
if(nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
static int select_next_proto_cb(SSL *ssl _U_, unsigned char **out,
|
||||
unsigned char *outlen, const unsigned char *in,
|
||||
unsigned int inlen, void *arg _U_) {
|
||||
if (nghttp2_select_next_protocol(out, outlen, in, inlen) <= 0) {
|
||||
errx(1, "Server did not advertise " NGHTTP2_PROTO_VERSION_ID);
|
||||
}
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
/* Create SSL_CTX. */
|
||||
static SSL_CTX* create_ssl_ctx(void)
|
||||
{
|
||||
static SSL_CTX *create_ssl_ctx(void) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_client_method());
|
||||
if(!ssl_ctx) {
|
||||
if (!ssl_ctx) {
|
||||
errx(1, "Could not create SSL/TLS context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
SSL_CTX_set_options(ssl_ctx,
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_CTX_set_next_proto_select_cb(ssl_ctx, select_next_proto_cb, NULL);
|
||||
return ssl_ctx;
|
||||
}
|
||||
|
||||
/* Create SSL object */
|
||||
static SSL* create_ssl(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
|
||||
SSL *ssl;
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
if(!ssl) {
|
||||
if (!ssl) {
|
||||
errx(1, "Could not create SSL/TLS session object: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
return ssl;
|
||||
}
|
||||
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
{
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data) {
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
|
||||
nghttp2_session_client_new(&session_data->session, callbacks, session_data);
|
||||
|
||||
nghttp2_session_callbacks_del(callbacks);
|
||||
}
|
||||
|
||||
static void send_client_connection_header(http2_session_data *session_data)
|
||||
{
|
||||
static void send_client_connection_header(http2_session_data *session_data) {
|
||||
nghttp2_settings_entry iv[1] = {
|
||||
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
|
||||
};
|
||||
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
|
||||
int rv;
|
||||
|
||||
bufferevent_write(session_data->bev,
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE,
|
||||
bufferevent_write(session_data->bev, NGHTTP2_CLIENT_CONNECTION_PREFACE,
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
|
||||
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
|
||||
iv, ARRLEN(iv));
|
||||
if(rv != 0) {
|
||||
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
|
||||
ARRLEN(iv));
|
||||
if (rv != 0) {
|
||||
errx(1, "Could not submit SETTINGS: %s", nghttp2_strerror(rv));
|
||||
}
|
||||
}
|
||||
|
||||
#define MAKE_NV(NAME, VALUE, VALUELEN) \
|
||||
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, VALUELEN, \
|
||||
NGHTTP2_NV_FLAG_NONE }
|
||||
#define MAKE_NV(NAME, VALUE, VALUELEN) \
|
||||
{ \
|
||||
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, VALUELEN, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
#define MAKE_NV2(NAME, VALUE) \
|
||||
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE }
|
||||
#define MAKE_NV2(NAME, VALUE) \
|
||||
{ \
|
||||
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
/* Send HTTP request to the remote peer */
|
||||
static void submit_request(http2_session_data *session_data)
|
||||
{
|
||||
static void submit_request(http2_session_data *session_data) {
|
||||
int32_t stream_id;
|
||||
http2_stream_data *stream_data = session_data->stream_data;
|
||||
const char *uri = stream_data->uri;
|
||||
const struct http_parser_url *u = stream_data->u;
|
||||
nghttp2_nv hdrs[] = {
|
||||
MAKE_NV2(":method", "GET"),
|
||||
MAKE_NV(":scheme",
|
||||
&uri[u->field_data[UF_SCHEMA].off], u->field_data[UF_SCHEMA].len),
|
||||
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
|
||||
MAKE_NV(":path", stream_data->path, stream_data->pathlen)
|
||||
};
|
||||
MAKE_NV2(":method", "GET"),
|
||||
MAKE_NV(":scheme", &uri[u->field_data[UF_SCHEMA].off],
|
||||
u->field_data[UF_SCHEMA].len),
|
||||
MAKE_NV(":authority", stream_data->authority, stream_data->authoritylen),
|
||||
MAKE_NV(":path", stream_data->path, stream_data->pathlen)};
|
||||
fprintf(stderr, "Request headers:\n");
|
||||
print_headers(stderr, hdrs, ARRLEN(hdrs));
|
||||
stream_id = nghttp2_submit_request(session_data->session, NULL,
|
||||
hdrs, ARRLEN(hdrs), NULL, stream_data);
|
||||
if(stream_id < 0) {
|
||||
stream_id = nghttp2_submit_request(session_data->session, NULL, hdrs,
|
||||
ARRLEN(hdrs), NULL, stream_data);
|
||||
if (stream_id < 0) {
|
||||
errx(1, "Could not submit HTTP request: %s", nghttp2_strerror(stream_id));
|
||||
}
|
||||
|
||||
@ -413,12 +390,11 @@ static void submit_request(http2_session_data *session_data)
|
||||
|
||||
/* Serialize the frame and send (or buffer) the data to
|
||||
bufferevent. */
|
||||
static int session_send(http2_session_data *session_data)
|
||||
{
|
||||
static int session_send(http2_session_data *session_data) {
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_session_send(session_data->session);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
@ -429,26 +405,25 @@ static int session_send(http2_session_data *session_data)
|
||||
of bufferevent and feed them to nghttp2 library. This may invoke
|
||||
nghttp2 callbacks. It may also queues the frame in nghttp2 session
|
||||
context. To send them, we call session_send() in the end. */
|
||||
static void readcb(struct bufferevent *bev, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
static void readcb(struct bufferevent *bev, void *ptr) {
|
||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||
ssize_t readlen;
|
||||
struct evbuffer *input = bufferevent_get_input(bev);
|
||||
size_t datalen = evbuffer_get_length(input);
|
||||
unsigned char *data = evbuffer_pullup(input, -1);
|
||||
|
||||
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
|
||||
if(readlen < 0) {
|
||||
if (readlen < 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
if(evbuffer_drain(input, readlen) != 0) {
|
||||
if (evbuffer_drain(input, readlen) != 0) {
|
||||
warnx("Fatal error: evbuffer_drain failed");
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
if(session_send(session_data) != 0) {
|
||||
if (session_send(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
@ -458,12 +433,11 @@ static void readcb(struct bufferevent *bev, void *ptr)
|
||||
receiving GOAWAY, we check the some conditions on the nghttp2
|
||||
library and output buffer of bufferevent. If it indicates we have
|
||||
no business to this session, tear down the connection. */
|
||||
static void writecb(struct bufferevent *bev _U_, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(nghttp2_session_want_read(session_data->session) == 0 &&
|
||||
nghttp2_session_want_write(session_data->session) == 0 &&
|
||||
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
|
||||
static void writecb(struct bufferevent *bev _U_, void *ptr) {
|
||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||
if (nghttp2_session_want_read(session_data->session) == 0 &&
|
||||
nghttp2_session_want_write(session_data->session) == 0 &&
|
||||
evbuffer_get_length(bufferevent_get_output(session_data->bev)) == 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
}
|
||||
}
|
||||
@ -473,10 +447,9 @@ static void writecb(struct bufferevent *bev _U_, void *ptr)
|
||||
peer verification. After SSL/TLS handshake is over, initialize
|
||||
nghttp2 library session, and send client connection header. Then
|
||||
send HTTP request. */
|
||||
static void eventcb(struct bufferevent *bev, short events, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(events & BEV_EVENT_CONNECTED) {
|
||||
static void eventcb(struct bufferevent *bev, short events, void *ptr) {
|
||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||
if (events & BEV_EVENT_CONNECTED) {
|
||||
int fd = bufferevent_getfd(bev);
|
||||
int val = 1;
|
||||
fprintf(stderr, "Connected\n");
|
||||
@ -484,41 +457,38 @@ static void eventcb(struct bufferevent *bev, short events, void *ptr)
|
||||
initialize_nghttp2_session(session_data);
|
||||
send_client_connection_header(session_data);
|
||||
submit_request(session_data);
|
||||
if(session_send(session_data) != 0) {
|
||||
if (session_send(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(events & BEV_EVENT_EOF) {
|
||||
if (events & BEV_EVENT_EOF) {
|
||||
warnx("Disconnected from the remote host");
|
||||
} else if(events & BEV_EVENT_ERROR) {
|
||||
} else if (events & BEV_EVENT_ERROR) {
|
||||
warnx("Network error");
|
||||
} else if(events & BEV_EVENT_TIMEOUT) {
|
||||
} else if (events & BEV_EVENT_TIMEOUT) {
|
||||
warnx("Timeout");
|
||||
}
|
||||
delete_http2_session_data(session_data);
|
||||
}
|
||||
|
||||
/* Start connecting to the remote peer |host:port| */
|
||||
static void initiate_connection(struct event_base *evbase,
|
||||
SSL_CTX *ssl_ctx,
|
||||
static void initiate_connection(struct event_base *evbase, SSL_CTX *ssl_ctx,
|
||||
const char *host, uint16_t port,
|
||||
http2_session_data *session_data)
|
||||
{
|
||||
http2_session_data *session_data) {
|
||||
int rv;
|
||||
struct bufferevent *bev;
|
||||
SSL *ssl;
|
||||
|
||||
ssl = create_ssl(ssl_ctx);
|
||||
bev = bufferevent_openssl_socket_new(evbase, -1, ssl,
|
||||
BUFFEREVENT_SSL_CONNECTING,
|
||||
BEV_OPT_DEFER_CALLBACKS |
|
||||
BEV_OPT_CLOSE_ON_FREE);
|
||||
bev = bufferevent_openssl_socket_new(
|
||||
evbase, -1, ssl, BUFFEREVENT_SSL_CONNECTING,
|
||||
BEV_OPT_DEFER_CALLBACKS | BEV_OPT_CLOSE_ON_FREE);
|
||||
bufferevent_setcb(bev, readcb, writecb, eventcb, session_data);
|
||||
rv = bufferevent_socket_connect_hostname(bev, session_data->dnsbase,
|
||||
AF_UNSPEC, host, port);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
errx(1, "Could not connect to the remote host %s", host);
|
||||
}
|
||||
session_data->bev = bev;
|
||||
@ -526,8 +496,7 @@ static void initiate_connection(struct event_base *evbase,
|
||||
|
||||
/* Get resource denoted by the |uri|. The debug and error messages are
|
||||
printed in stderr, while the response body is printed in stdout. */
|
||||
static void run(const char *uri)
|
||||
{
|
||||
static void run(const char *uri) {
|
||||
struct http_parser_url u;
|
||||
char *host;
|
||||
uint16_t port;
|
||||
@ -538,11 +507,11 @@ static void run(const char *uri)
|
||||
|
||||
/* Parse the |uri| and stores its components in |u| */
|
||||
rv = http_parser_parse_url(uri, strlen(uri), 0, &u);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
errx(1, "Could not parse URI %s", uri);
|
||||
}
|
||||
host = strndup(&uri[u.field_data[UF_HOST].off], u.field_data[UF_HOST].len);
|
||||
if(!(u.field_set & (1 << UF_PORT))) {
|
||||
if (!(u.field_set & (1 << UF_PORT))) {
|
||||
port = 443;
|
||||
} else {
|
||||
port = u.port;
|
||||
@ -565,11 +534,10 @@ static void run(const char *uri)
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
struct sigaction act;
|
||||
|
||||
if(argc < 2) {
|
||||
if (argc < 2) {
|
||||
fprintf(stderr, "Usage: libevent-client HTTPS_URI\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
@ -51,11 +51,13 @@
|
||||
|
||||
#define OUTPUT_WOULDBLOCK_THRESHOLD (1 << 16)
|
||||
|
||||
#define ARRLEN(x) (sizeof(x)/sizeof(x[0]))
|
||||
#define ARRLEN(x) (sizeof(x) / sizeof(x[0]))
|
||||
|
||||
#define MAKE_NV(NAME, VALUE) \
|
||||
{ (uint8_t*)NAME, (uint8_t*)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE }
|
||||
#define MAKE_NV(NAME, VALUE) \
|
||||
{ \
|
||||
(uint8_t *) NAME, (uint8_t *)VALUE, sizeof(NAME) - 1, sizeof(VALUE) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
struct app_context;
|
||||
typedef struct app_context app_context;
|
||||
@ -83,43 +85,40 @@ struct app_context {
|
||||
static unsigned char next_proto_list[256];
|
||||
static size_t next_proto_list_len;
|
||||
|
||||
static int next_proto_cb(SSL *s _U_, const unsigned char **data, unsigned int *len,
|
||||
void *arg _U_)
|
||||
{
|
||||
static int next_proto_cb(SSL *s _U_, const unsigned char **data,
|
||||
unsigned int *len, void *arg _U_) {
|
||||
*data = next_proto_list;
|
||||
*len = (unsigned int)next_proto_list_len;
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}
|
||||
|
||||
/* Create SSL_CTX. */
|
||||
static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
|
||||
{
|
||||
static SSL_CTX *create_ssl_ctx(const char *key_file, const char *cert_file) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
EC_KEY *ecdh;
|
||||
|
||||
ssl_ctx = SSL_CTX_new(SSLv23_server_method());
|
||||
if(!ssl_ctx) {
|
||||
if (!ssl_ctx) {
|
||||
errx(1, "Could not create SSL/TLS context: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
SSL_CTX_set_options(ssl_ctx,
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
|
||||
|
||||
ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if(!ecdh) {
|
||||
if (!ecdh) {
|
||||
errx(1, "EC_KEY_new_by_curv_name failed: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
SSL_CTX_set_tmp_ecdh(ssl_ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
|
||||
if(SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file,
|
||||
SSL_FILETYPE_PEM) != 1) {
|
||||
if (SSL_CTX_use_PrivateKey_file(ssl_ctx, key_file, SSL_FILETYPE_PEM) != 1) {
|
||||
errx(1, "Could not read private key file %s", key_file);
|
||||
}
|
||||
if(SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
|
||||
if (SSL_CTX_use_certificate_chain_file(ssl_ctx, cert_file) != 1) {
|
||||
errx(1, "Could not read certificate file %s", cert_file);
|
||||
}
|
||||
|
||||
@ -133,11 +132,10 @@ static SSL_CTX* create_ssl_ctx(const char *key_file, const char *cert_file)
|
||||
}
|
||||
|
||||
/* Create SSL object */
|
||||
static SSL* create_ssl(SSL_CTX *ssl_ctx)
|
||||
{
|
||||
static SSL *create_ssl(SSL_CTX *ssl_ctx) {
|
||||
SSL *ssl;
|
||||
ssl = SSL_new(ssl_ctx);
|
||||
if(!ssl) {
|
||||
if (!ssl) {
|
||||
errx(1, "Could not create SSL/TLS session object: %s",
|
||||
ERR_error_string(ERR_get_error(), NULL));
|
||||
}
|
||||
@ -145,28 +143,25 @@ static SSL* create_ssl(SSL_CTX *ssl_ctx)
|
||||
}
|
||||
|
||||
static void add_stream(http2_session_data *session_data,
|
||||
http2_stream_data *stream_data)
|
||||
{
|
||||
http2_stream_data *stream_data) {
|
||||
stream_data->next = session_data->root.next;
|
||||
session_data->root.next = stream_data;
|
||||
stream_data->prev = &session_data->root;
|
||||
if(stream_data->next) {
|
||||
if (stream_data->next) {
|
||||
stream_data->next->prev = stream_data;
|
||||
}
|
||||
}
|
||||
|
||||
static void remove_stream(http2_session_data *session_data _U_,
|
||||
http2_stream_data *stream_data)
|
||||
{
|
||||
http2_stream_data *stream_data) {
|
||||
stream_data->prev->next = stream_data->next;
|
||||
if(stream_data->next) {
|
||||
if (stream_data->next) {
|
||||
stream_data->next->prev = stream_data->prev;
|
||||
}
|
||||
}
|
||||
|
||||
static http2_stream_data* create_http2_stream_data
|
||||
(http2_session_data *session_data, int32_t stream_id)
|
||||
{
|
||||
static http2_stream_data *
|
||||
create_http2_stream_data(http2_session_data *session_data, int32_t stream_id) {
|
||||
http2_stream_data *stream_data;
|
||||
stream_data = malloc(sizeof(http2_stream_data));
|
||||
memset(stream_data, 0, sizeof(http2_stream_data));
|
||||
@ -177,20 +172,18 @@ static http2_stream_data* create_http2_stream_data
|
||||
return stream_data;
|
||||
}
|
||||
|
||||
static void delete_http2_stream_data(http2_stream_data *stream_data)
|
||||
{
|
||||
if(stream_data->fd != -1) {
|
||||
static void delete_http2_stream_data(http2_stream_data *stream_data) {
|
||||
if (stream_data->fd != -1) {
|
||||
close(stream_data->fd);
|
||||
}
|
||||
free(stream_data->request_path);
|
||||
free(stream_data);
|
||||
}
|
||||
|
||||
static http2_session_data* create_http2_session_data(app_context *app_ctx,
|
||||
static http2_session_data *create_http2_session_data(app_context *app_ctx,
|
||||
int fd,
|
||||
struct sockaddr *addr,
|
||||
int addrlen)
|
||||
{
|
||||
int addrlen) {
|
||||
int rv;
|
||||
http2_session_data *session_data;
|
||||
SSL *ssl;
|
||||
@ -202,12 +195,11 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
|
||||
memset(session_data, 0, sizeof(http2_session_data));
|
||||
session_data->app_ctx = app_ctx;
|
||||
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char *)&val, sizeof(val));
|
||||
session_data->bev = bufferevent_openssl_socket_new
|
||||
(app_ctx->evbase, fd, ssl,
|
||||
BUFFEREVENT_SSL_ACCEPTING,
|
||||
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
||||
session_data->bev = bufferevent_openssl_socket_new(
|
||||
app_ctx->evbase, fd, ssl, BUFFEREVENT_SSL_ACCEPTING,
|
||||
BEV_OPT_CLOSE_ON_FREE | BEV_OPT_DEFER_CALLBACKS);
|
||||
rv = getnameinfo(addr, addrlen, host, sizeof(host), NULL, 0, NI_NUMERICHOST);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
session_data->client_addr = strdup("(unknown)");
|
||||
} else {
|
||||
session_data->client_addr = strdup(host);
|
||||
@ -216,17 +208,16 @@ static http2_session_data* create_http2_session_data(app_context *app_ctx,
|
||||
return session_data;
|
||||
}
|
||||
|
||||
static void delete_http2_session_data(http2_session_data *session_data)
|
||||
{
|
||||
static void delete_http2_session_data(http2_session_data *session_data) {
|
||||
http2_stream_data *stream_data;
|
||||
SSL *ssl = bufferevent_openssl_get_ssl(session_data->bev);
|
||||
fprintf(stderr, "%s disconnected\n", session_data->client_addr);
|
||||
if(ssl) {
|
||||
if (ssl) {
|
||||
SSL_shutdown(ssl);
|
||||
}
|
||||
bufferevent_free(session_data->bev);
|
||||
nghttp2_session_del(session_data->session);
|
||||
for(stream_data = session_data->root.next; stream_data;) {
|
||||
for (stream_data = session_data->root.next; stream_data;) {
|
||||
http2_stream_data *next = stream_data->next;
|
||||
delete_http2_stream_data(stream_data);
|
||||
stream_data = next;
|
||||
@ -237,11 +228,10 @@ static void delete_http2_session_data(http2_session_data *session_data)
|
||||
|
||||
/* Serialize the frame and send (or buffer) the data to
|
||||
bufferevent. */
|
||||
static int session_send(http2_session_data *session_data)
|
||||
{
|
||||
static int session_send(http2_session_data *session_data) {
|
||||
int rv;
|
||||
rv = nghttp2_session_send(session_data->session);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
@ -252,37 +242,34 @@ static int session_send(http2_session_data *session_data)
|
||||
function. Invocation of nghttp2_session_mem_recv() may make
|
||||
additional pending frames, so call session_send() at the end of the
|
||||
function. */
|
||||
static int session_recv(http2_session_data *session_data)
|
||||
{
|
||||
static int session_recv(http2_session_data *session_data) {
|
||||
ssize_t readlen;
|
||||
struct evbuffer *input = bufferevent_get_input(session_data->bev);
|
||||
size_t datalen = evbuffer_get_length(input);
|
||||
unsigned char *data = evbuffer_pullup(input, -1);
|
||||
|
||||
readlen = nghttp2_session_mem_recv(session_data->session, data, datalen);
|
||||
if(readlen < 0) {
|
||||
if (readlen < 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror((int)readlen));
|
||||
return -1;
|
||||
}
|
||||
if(evbuffer_drain(input, readlen) != 0) {
|
||||
if (evbuffer_drain(input, readlen) != 0) {
|
||||
warnx("Fatal error: evbuffer_drain failed");
|
||||
return -1;
|
||||
}
|
||||
if(session_send(session_data) != 0) {
|
||||
if (session_send(session_data) != 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t send_callback(nghttp2_session *session _U_,
|
||||
const uint8_t *data, size_t length,
|
||||
int flags _U_, void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
static ssize_t send_callback(nghttp2_session *session _U_, const uint8_t *data,
|
||||
size_t length, int flags _U_, void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
struct bufferevent *bev = session_data->bev;
|
||||
/* Avoid excessive buffering in server side. */
|
||||
if(evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
|
||||
OUTPUT_WOULDBLOCK_THRESHOLD) {
|
||||
if (evbuffer_get_length(bufferevent_get_output(session_data->bev)) >=
|
||||
OUTPUT_WOULDBLOCK_THRESHOLD) {
|
||||
return NGHTTP2_ERR_WOULDBLOCK;
|
||||
}
|
||||
bufferevent_write(bev, data, length);
|
||||
@ -290,26 +277,24 @@ static ssize_t send_callback(nghttp2_session *session _U_,
|
||||
}
|
||||
|
||||
/* Returns nonzero if the string |s| ends with the substring |sub| */
|
||||
static int ends_with(const char *s, const char *sub)
|
||||
{
|
||||
static int ends_with(const char *s, const char *sub) {
|
||||
size_t slen = strlen(s);
|
||||
size_t sublen = strlen(sub);
|
||||
if(slen < sublen) {
|
||||
if (slen < sublen) {
|
||||
return 0;
|
||||
}
|
||||
return memcmp(s + slen - sublen, sub, sublen) == 0;
|
||||
}
|
||||
|
||||
/* Returns int value of hex string character |c| */
|
||||
static uint8_t hex_to_uint(uint8_t c)
|
||||
{
|
||||
if('0' <= c && c <= '9') {
|
||||
static uint8_t hex_to_uint(uint8_t c) {
|
||||
if ('0' <= c && c <= '9') {
|
||||
return c - '0';
|
||||
}
|
||||
if('A' <= c && c <= 'F') {
|
||||
if ('A' <= c && c <= 'F') {
|
||||
return c - 'A' + 10;
|
||||
}
|
||||
if('a' <= c && c <= 'f') {
|
||||
if ('a' <= c && c <= 'f') {
|
||||
return c - 'a' + 10;
|
||||
}
|
||||
return 0;
|
||||
@ -319,16 +304,15 @@ static uint8_t hex_to_uint(uint8_t c)
|
||||
and returns the decoded byte string in allocated buffer. The return
|
||||
value is NULL terminated. The caller must free the returned
|
||||
string. */
|
||||
static char* percent_decode(const uint8_t *value, size_t valuelen)
|
||||
{
|
||||
static char *percent_decode(const uint8_t *value, size_t valuelen) {
|
||||
char *res;
|
||||
|
||||
res = malloc(valuelen + 1);
|
||||
if(valuelen > 3) {
|
||||
if (valuelen > 3) {
|
||||
size_t i, j;
|
||||
for(i = 0, j = 0; i < valuelen - 2;) {
|
||||
if(value[i] != '%' ||
|
||||
!isxdigit(value[i + 1]) || !isxdigit(value[i + 2])) {
|
||||
for (i = 0, j = 0; i < valuelen - 2;) {
|
||||
if (value[i] != '%' || !isxdigit(value[i + 1]) ||
|
||||
!isxdigit(value[i + 2])) {
|
||||
res[j++] = value[i++];
|
||||
continue;
|
||||
}
|
||||
@ -344,33 +328,33 @@ static char* percent_decode(const uint8_t *value, size_t valuelen)
|
||||
return res;
|
||||
}
|
||||
|
||||
static ssize_t file_read_callback
|
||||
(nghttp2_session *session _U_, int32_t stream_id _U_,
|
||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source, void *user_data _U_)
|
||||
{
|
||||
static ssize_t file_read_callback(nghttp2_session *session _U_,
|
||||
int32_t stream_id _U_, uint8_t *buf,
|
||||
size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source,
|
||||
void *user_data _U_) {
|
||||
int fd = source->fd;
|
||||
ssize_t r;
|
||||
while((r = read(fd, buf, length)) == -1 && errno == EINTR);
|
||||
if(r == -1) {
|
||||
while ((r = read(fd, buf, length)) == -1 && errno == EINTR)
|
||||
;
|
||||
if (r == -1) {
|
||||
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
|
||||
}
|
||||
if(r == 0) {
|
||||
if (r == 0) {
|
||||
*data_flags |= NGHTTP2_DATA_FLAG_EOF;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
static int send_response(nghttp2_session *session, int32_t stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen, int fd)
|
||||
{
|
||||
nghttp2_nv *nva, size_t nvlen, int fd) {
|
||||
int rv;
|
||||
nghttp2_data_provider data_prd;
|
||||
data_prd.source.fd = fd;
|
||||
data_prd.read_callback = file_read_callback;
|
||||
|
||||
rv = nghttp2_submit_response(session, stream_id, nva, nvlen, &data_prd);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
@ -378,25 +362,22 @@ static int send_response(nghttp2_session *session, int32_t stream_id,
|
||||
}
|
||||
|
||||
const char ERROR_HTML[] = "<html><head><title>404</title></head>"
|
||||
"<body><h1>404 Not Found</h1></body></html>";
|
||||
"<body><h1>404 Not Found</h1></body></html>";
|
||||
|
||||
static int error_reply(nghttp2_session *session,
|
||||
http2_stream_data *stream_data)
|
||||
{
|
||||
http2_stream_data *stream_data) {
|
||||
int rv;
|
||||
ssize_t writelen;
|
||||
int pipefd[2];
|
||||
nghttp2_nv hdrs[] = {
|
||||
MAKE_NV(":status", "404")
|
||||
};
|
||||
nghttp2_nv hdrs[] = {MAKE_NV(":status", "404")};
|
||||
|
||||
rv = pipe(pipefd);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
warn("Could not create pipe");
|
||||
rv = nghttp2_submit_rst_stream(session, NGHTTP2_FLAG_NONE,
|
||||
stream_data->stream_id,
|
||||
NGHTTP2_INTERNAL_ERROR);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
@ -406,15 +387,15 @@ static int error_reply(nghttp2_session *session,
|
||||
writelen = write(pipefd[1], ERROR_HTML, sizeof(ERROR_HTML) - 1);
|
||||
close(pipefd[1]);
|
||||
|
||||
if(writelen != sizeof(ERROR_HTML) - 1) {
|
||||
if (writelen != sizeof(ERROR_HTML) - 1) {
|
||||
close(pipefd[0]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
stream_data->fd = pipefd[0];
|
||||
|
||||
if(send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
|
||||
pipefd[0]) != 0) {
|
||||
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs),
|
||||
pipefd[0]) != 0) {
|
||||
close(pipefd[0]);
|
||||
return -1;
|
||||
}
|
||||
@ -424,27 +405,26 @@ static int error_reply(nghttp2_session *session,
|
||||
/* nghttp2_on_header_callback: Called when nghttp2 library emits
|
||||
single header name/value pair. */
|
||||
static int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags _U_,
|
||||
void *user_data _U_)
|
||||
{
|
||||
const nghttp2_frame *frame, const uint8_t *name,
|
||||
size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, uint8_t flags _U_,
|
||||
void *user_data _U_) {
|
||||
http2_stream_data *stream_data;
|
||||
const char PATH[] = ":path";
|
||||
switch(frame->hd.type) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_HEADERS:
|
||||
if(frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
if (frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
break;
|
||||
}
|
||||
stream_data = nghttp2_session_get_stream_user_data(session,
|
||||
frame->hd.stream_id);
|
||||
if(!stream_data || stream_data->request_path) {
|
||||
stream_data =
|
||||
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
if (!stream_data || stream_data->request_path) {
|
||||
break;
|
||||
}
|
||||
if(namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
|
||||
if (namelen == sizeof(PATH) - 1 && memcmp(PATH, name, namelen) == 0) {
|
||||
size_t j;
|
||||
for(j = 0; j < valuelen && value[j] != '?'; ++j);
|
||||
for (j = 0; j < valuelen && value[j] != '?'; ++j)
|
||||
;
|
||||
stream_data->request_path = percent_decode(value, j);
|
||||
}
|
||||
break;
|
||||
@ -454,13 +434,12 @@ static int on_header_callback(nghttp2_session *session,
|
||||
|
||||
static int on_begin_headers_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
http2_stream_data *stream_data;
|
||||
|
||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
if (frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
|
||||
return 0;
|
||||
}
|
||||
stream_data = create_http2_stream_data(session_data, frame->hd.stream_id);
|
||||
@ -471,52 +450,47 @@ static int on_begin_headers_callback(nghttp2_session *session,
|
||||
|
||||
/* Minimum check for directory traversal. Returns nonzero if it is
|
||||
safe. */
|
||||
static int check_path(const char *path)
|
||||
{
|
||||
static int check_path(const char *path) {
|
||||
/* We don't like '\' in url. */
|
||||
return path[0] && path[0] == '/' &&
|
||||
strchr(path, '\\') == NULL &&
|
||||
strstr(path, "/../") == NULL &&
|
||||
strstr(path, "/./") == NULL &&
|
||||
!ends_with(path, "/..") && !ends_with(path, "/.");
|
||||
return path[0] && path[0] == '/' && strchr(path, '\\') == NULL &&
|
||||
strstr(path, "/../") == NULL && strstr(path, "/./") == NULL &&
|
||||
!ends_with(path, "/..") && !ends_with(path, "/.");
|
||||
}
|
||||
|
||||
static int on_request_recv(nghttp2_session *session,
|
||||
http2_session_data *session_data,
|
||||
http2_stream_data *stream_data)
|
||||
{
|
||||
http2_stream_data *stream_data) {
|
||||
int fd;
|
||||
nghttp2_nv hdrs[] = {
|
||||
MAKE_NV(":status", "200")
|
||||
};
|
||||
nghttp2_nv hdrs[] = {MAKE_NV(":status", "200")};
|
||||
char *rel_path;
|
||||
|
||||
if(!stream_data->request_path) {
|
||||
if(error_reply(session, stream_data) != 0) {
|
||||
if (!stream_data->request_path) {
|
||||
if (error_reply(session, stream_data) != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
fprintf(stderr, "%s GET %s\n", session_data->client_addr,
|
||||
stream_data->request_path);
|
||||
if(!check_path(stream_data->request_path)) {
|
||||
if(error_reply(session, stream_data) != 0) {
|
||||
if (!check_path(stream_data->request_path)) {
|
||||
if (error_reply(session, stream_data) != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
for(rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path);
|
||||
for (rel_path = stream_data->request_path; *rel_path == '/'; ++rel_path)
|
||||
;
|
||||
fd = open(rel_path, O_RDONLY);
|
||||
if(fd == -1) {
|
||||
if(error_reply(session, stream_data) != 0) {
|
||||
if (fd == -1) {
|
||||
if (error_reply(session, stream_data) != 0) {
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
stream_data->fd = fd;
|
||||
|
||||
if(send_response(session, stream_data->stream_id, hdrs,
|
||||
ARRLEN(hdrs), fd) != 0) {
|
||||
if (send_response(session, stream_data->stream_id, hdrs, ARRLEN(hdrs), fd) !=
|
||||
0) {
|
||||
close(fd);
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
@ -524,20 +498,19 @@ static int on_request_recv(nghttp2_session *session,
|
||||
}
|
||||
|
||||
static int on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
const nghttp2_frame *frame, void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
http2_stream_data *stream_data;
|
||||
switch(frame->hd.type) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
case NGHTTP2_HEADERS:
|
||||
/* Check that the client request has finished */
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
stream_data = nghttp2_session_get_stream_user_data(session,
|
||||
frame->hd.stream_id);
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
stream_data =
|
||||
nghttp2_session_get_stream_user_data(session, frame->hd.stream_id);
|
||||
/* For DATA and HEADERS frame, this callback may be called after
|
||||
on_stream_close_callback. Check that stream still alive. */
|
||||
if(!stream_data) {
|
||||
if (!stream_data) {
|
||||
return 0;
|
||||
}
|
||||
return on_request_recv(session, session_data, stream_data);
|
||||
@ -549,16 +522,13 @@ static int on_frame_recv_callback(nghttp2_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int on_stream_close_callback(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code _U_,
|
||||
void *user_data)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)user_data;
|
||||
static int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code _U_, void *user_data) {
|
||||
http2_session_data *session_data = (http2_session_data *)user_data;
|
||||
http2_stream_data *stream_data;
|
||||
|
||||
stream_data = nghttp2_session_get_stream_user_data(session, stream_id);
|
||||
if(!stream_data) {
|
||||
if (!stream_data) {
|
||||
return 0;
|
||||
}
|
||||
remove_stream(session_data, stream_data);
|
||||
@ -566,8 +536,7 @@ static int on_stream_close_callback(nghttp2_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
{
|
||||
static void initialize_nghttp2_session(http2_session_data *session_data) {
|
||||
nghttp2_option *option;
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
|
||||
@ -581,19 +550,17 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
|
||||
nghttp2_session_callbacks_set_send_callback(callbacks, send_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(callbacks, on_begin_headers_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
callbacks, on_begin_headers_callback);
|
||||
|
||||
nghttp2_session_server_new2(&session_data->session, callbacks, session_data,
|
||||
option);
|
||||
@ -604,16 +571,14 @@ static void initialize_nghttp2_session(http2_session_data *session_data)
|
||||
|
||||
/* Send HTTP/2 client connection header, which includes 24 bytes
|
||||
magic octets and SETTINGS frame */
|
||||
static int send_server_connection_header(http2_session_data *session_data)
|
||||
{
|
||||
static int send_server_connection_header(http2_session_data *session_data) {
|
||||
nghttp2_settings_entry iv[1] = {
|
||||
{ NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100 }
|
||||
};
|
||||
{NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS, 100}};
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE,
|
||||
iv, ARRLEN(iv));
|
||||
if(rv != 0) {
|
||||
rv = nghttp2_submit_settings(session_data->session, NGHTTP2_FLAG_NONE, iv,
|
||||
ARRLEN(iv));
|
||||
if (rv != 0) {
|
||||
warnx("Fatal error: %s", nghttp2_strerror(rv));
|
||||
return -1;
|
||||
}
|
||||
@ -622,10 +587,9 @@ static int send_server_connection_header(http2_session_data *session_data)
|
||||
|
||||
/* readcb for bufferevent after client connection header was
|
||||
checked. */
|
||||
static void readcb(struct bufferevent *bev _U_, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(session_recv(session_data) != 0) {
|
||||
static void readcb(struct bufferevent *bev _U_, void *ptr) {
|
||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||
if (session_recv(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
@ -639,44 +603,42 @@ static void readcb(struct bufferevent *bev _U_, void *ptr)
|
||||
process pending data in the output buffer. This is necessary
|
||||
because we have a threshold on the buffer size to avoid too much
|
||||
buffering. See send_callback(). */
|
||||
static void writecb(struct bufferevent *bev, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
|
||||
static void writecb(struct bufferevent *bev, void *ptr) {
|
||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||
if (evbuffer_get_length(bufferevent_get_output(bev)) > 0) {
|
||||
return;
|
||||
}
|
||||
if(nghttp2_session_want_read(session_data->session) == 0 &&
|
||||
nghttp2_session_want_write(session_data->session) == 0) {
|
||||
if (nghttp2_session_want_read(session_data->session) == 0 &&
|
||||
nghttp2_session_want_write(session_data->session) == 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
if(session_send(session_data) != 0) {
|
||||
if (session_send(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* eventcb for bufferevent */
|
||||
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr)
|
||||
{
|
||||
http2_session_data *session_data = (http2_session_data*)ptr;
|
||||
if(events & BEV_EVENT_CONNECTED) {
|
||||
static void eventcb(struct bufferevent *bev _U_, short events, void *ptr) {
|
||||
http2_session_data *session_data = (http2_session_data *)ptr;
|
||||
if (events & BEV_EVENT_CONNECTED) {
|
||||
fprintf(stderr, "%s connected\n", session_data->client_addr);
|
||||
|
||||
initialize_nghttp2_session(session_data);
|
||||
|
||||
if(send_server_connection_header(session_data) != 0) {
|
||||
if (send_server_connection_header(session_data) != 0) {
|
||||
delete_http2_session_data(session_data);
|
||||
return;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
if(events & BEV_EVENT_EOF) {
|
||||
if (events & BEV_EVENT_EOF) {
|
||||
fprintf(stderr, "%s EOF\n", session_data->client_addr);
|
||||
} else if(events & BEV_EVENT_ERROR) {
|
||||
} else if (events & BEV_EVENT_ERROR) {
|
||||
fprintf(stderr, "%s network error\n", session_data->client_addr);
|
||||
} else if(events & BEV_EVENT_TIMEOUT) {
|
||||
} else if (events & BEV_EVENT_TIMEOUT) {
|
||||
fprintf(stderr, "%s timeout\n", session_data->client_addr);
|
||||
}
|
||||
delete_http2_session_data(session_data);
|
||||
@ -684,9 +646,8 @@ static void eventcb(struct bufferevent *bev _U_, short events, void *ptr)
|
||||
|
||||
/* callback for evconnlistener */
|
||||
static void acceptcb(struct evconnlistener *listener _U_, int fd,
|
||||
struct sockaddr *addr, int addrlen, void *arg)
|
||||
{
|
||||
app_context *app_ctx = (app_context*)arg;
|
||||
struct sockaddr *addr, int addrlen, void *arg) {
|
||||
app_context *app_ctx = (app_context *)arg;
|
||||
http2_session_data *session_data;
|
||||
|
||||
session_data = create_http2_session_data(app_ctx, fd, addr, addrlen);
|
||||
@ -695,8 +656,7 @@ static void acceptcb(struct evconnlistener *listener _U_, int fd,
|
||||
}
|
||||
|
||||
static void start_listen(struct event_base *evbase, const char *service,
|
||||
app_context *app_ctx)
|
||||
{
|
||||
app_context *app_ctx) {
|
||||
int rv;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *res, *rp;
|
||||
@ -710,16 +670,15 @@ static void start_listen(struct event_base *evbase, const char *service,
|
||||
#endif /* AI_ADDRCONFIG */
|
||||
|
||||
rv = getaddrinfo(NULL, service, &hints, &res);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
errx(1, NULL);
|
||||
}
|
||||
for(rp = res; rp; rp = rp->ai_next) {
|
||||
for (rp = res; rp; rp = rp->ai_next) {
|
||||
struct evconnlistener *listener;
|
||||
listener = evconnlistener_new_bind(evbase, acceptcb, app_ctx,
|
||||
LEV_OPT_CLOSE_ON_FREE |
|
||||
LEV_OPT_REUSEABLE, 16,
|
||||
rp->ai_addr, rp->ai_addrlen);
|
||||
if(listener) {
|
||||
listener = evconnlistener_new_bind(
|
||||
evbase, acceptcb, app_ctx, LEV_OPT_CLOSE_ON_FREE | LEV_OPT_REUSEABLE,
|
||||
16, rp->ai_addr, rp->ai_addrlen);
|
||||
if (listener) {
|
||||
freeaddrinfo(res);
|
||||
|
||||
return;
|
||||
@ -729,16 +688,14 @@ static void start_listen(struct event_base *evbase, const char *service,
|
||||
}
|
||||
|
||||
static void initialize_app_context(app_context *app_ctx, SSL_CTX *ssl_ctx,
|
||||
struct event_base *evbase)
|
||||
{
|
||||
struct event_base *evbase) {
|
||||
memset(app_ctx, 0, sizeof(app_context));
|
||||
app_ctx->ssl_ctx = ssl_ctx;
|
||||
app_ctx->evbase = evbase;
|
||||
}
|
||||
|
||||
static void run(const char *service,
|
||||
const char *key_file, const char *cert_file)
|
||||
{
|
||||
static void run(const char *service, const char *key_file,
|
||||
const char *cert_file) {
|
||||
SSL_CTX *ssl_ctx;
|
||||
app_context app_ctx;
|
||||
struct event_base *evbase;
|
||||
@ -754,11 +711,10 @@ static void run(const char *service,
|
||||
SSL_CTX_free(ssl_ctx);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
struct sigaction act;
|
||||
|
||||
if(argc < 4) {
|
||||
if (argc < 4) {
|
||||
fprintf(stderr, "Usage: libevent-server PORT KEY_FILE CERT_FILE\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -25,7 +25,7 @@
|
||||
#ifndef NGHTTP2_H
|
||||
#define NGHTTP2_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -186,7 +186,7 @@ typedef struct {
|
||||
*
|
||||
* The length of :macro:`NGHTTP2_CLIENT_CONNECTION_HEADER`.
|
||||
*/
|
||||
#define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN \
|
||||
#define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN \
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN
|
||||
|
||||
/**
|
||||
@ -621,7 +621,6 @@ typedef struct {
|
||||
uint8_t reserved;
|
||||
} nghttp2_frame_hd;
|
||||
|
||||
|
||||
/**
|
||||
* @union
|
||||
*
|
||||
@ -681,10 +680,9 @@ typedef enum {
|
||||
* :enum:`NGHTTP2_ERR_CALLBACK_FAILURE` will signal the entire session
|
||||
* failure.
|
||||
*/
|
||||
typedef ssize_t (*nghttp2_data_source_read_callback)
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, uint32_t *data_flags,
|
||||
nghttp2_data_source *source, void *user_data);
|
||||
typedef ssize_t (*nghttp2_data_source_read_callback)(
|
||||
nghttp2_session *session, int32_t stream_id, uint8_t *buf, size_t length,
|
||||
uint32_t *data_flags, nghttp2_data_source *source, void *user_data);
|
||||
|
||||
/**
|
||||
* @struct
|
||||
@ -1113,9 +1111,9 @@ typedef union {
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_send_callback()`.
|
||||
*/
|
||||
typedef ssize_t (*nghttp2_send_callback)
|
||||
(nghttp2_session *session,
|
||||
const uint8_t *data, size_t length, int flags, void *user_data);
|
||||
typedef ssize_t (*nghttp2_send_callback)(nghttp2_session *session,
|
||||
const uint8_t *data, size_t length,
|
||||
int flags, void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1141,9 +1139,9 @@ typedef ssize_t (*nghttp2_send_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_recv_callback()`.
|
||||
*/
|
||||
typedef ssize_t (*nghttp2_recv_callback)
|
||||
(nghttp2_session *session,
|
||||
uint8_t *buf, size_t length, int flags, void *user_data);
|
||||
typedef ssize_t (*nghttp2_recv_callback)(nghttp2_session *session, uint8_t *buf,
|
||||
size_t length, int flags,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1179,8 +1177,9 @@ typedef ssize_t (*nghttp2_recv_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_frame_recv_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_frame_recv_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
typedef int (*nghttp2_on_frame_recv_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1206,9 +1205,9 @@ typedef int (*nghttp2_on_frame_recv_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_invalid_frame_recv_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_invalid_frame_recv_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
uint32_t error_code, void *user_data);
|
||||
typedef int (*nghttp2_on_invalid_frame_recv_callback)(
|
||||
nghttp2_session *session, const nghttp2_frame *frame, uint32_t error_code,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1240,9 +1239,11 @@ typedef int (*nghttp2_on_invalid_frame_recv_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_data_chunk_recv_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_data_chunk_recv_callback)
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data);
|
||||
typedef int (*nghttp2_on_data_chunk_recv_callback)(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const uint8_t *data,
|
||||
size_t len, void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1260,8 +1261,9 @@ typedef int (*nghttp2_on_data_chunk_recv_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_before_frame_send_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_before_frame_send_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
typedef int (*nghttp2_before_frame_send_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1278,8 +1280,9 @@ typedef int (*nghttp2_before_frame_send_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_frame_send_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_frame_send_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
typedef int (*nghttp2_on_frame_send_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1299,9 +1302,10 @@ typedef int (*nghttp2_on_frame_send_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_frame_not_send_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_frame_not_send_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, int lib_error_code,
|
||||
void *user_data);
|
||||
typedef int (*nghttp2_on_frame_not_send_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
int lib_error_code,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1325,9 +1329,10 @@ typedef int (*nghttp2_on_frame_not_send_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_stream_close_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_stream_close_callback)
|
||||
(nghttp2_session *session, int32_t stream_id, uint32_t error_code,
|
||||
void *user_data);
|
||||
typedef int (*nghttp2_on_stream_close_callback)(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1353,8 +1358,9 @@ typedef int (*nghttp2_on_stream_close_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_begin_headers_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_begin_headers_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
typedef int (*nghttp2_on_begin_headers_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1417,13 +1423,11 @@ typedef int (*nghttp2_on_begin_headers_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_header_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_header_callback)
|
||||
(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *user_data);
|
||||
typedef int (*nghttp2_on_header_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags, void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1442,11 +1446,10 @@ typedef int (*nghttp2_on_header_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_select_padding_callback()`.
|
||||
*/
|
||||
typedef ssize_t (*nghttp2_select_padding_callback)
|
||||
(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
size_t max_payloadlen,
|
||||
void *user_data);
|
||||
typedef ssize_t (*nghttp2_select_padding_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
size_t max_payloadlen,
|
||||
void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1472,12 +1475,10 @@ typedef ssize_t (*nghttp2_select_padding_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_data_source_read_length_callback()`.
|
||||
*/
|
||||
typedef ssize_t (*nghttp2_data_source_read_length_callback)
|
||||
(nghttp2_session *session, uint8_t frame_type, int32_t stream_id,
|
||||
int32_t session_remote_window_size,
|
||||
int32_t stream_remote_window_size,
|
||||
uint32_t remote_max_frame_size,
|
||||
void *user_data);
|
||||
typedef ssize_t (*nghttp2_data_source_read_length_callback)(
|
||||
nghttp2_session *session, uint8_t frame_type, int32_t stream_id,
|
||||
int32_t session_remote_window_size, int32_t stream_remote_window_size,
|
||||
uint32_t remote_max_frame_size, void *user_data);
|
||||
|
||||
/**
|
||||
* @functypedef
|
||||
@ -1501,8 +1502,9 @@ typedef ssize_t (*nghttp2_data_source_read_length_callback)
|
||||
* To set this callback to :type:`nghttp2_session_callbacks`, use
|
||||
* `nghttp2_session_callbacks_set_on_begin_frame_callback()`.
|
||||
*/
|
||||
typedef int (*nghttp2_on_begin_frame_callback)
|
||||
(nghttp2_session *session, const nghttp2_frame_hd *hd, void *user_data);
|
||||
typedef int (*nghttp2_on_begin_frame_callback)(nghttp2_session *session,
|
||||
const nghttp2_frame_hd *hd,
|
||||
void *user_data);
|
||||
|
||||
struct nghttp2_session_callbacks;
|
||||
|
||||
@ -1541,7 +1543,6 @@ int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr);
|
||||
*/
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
@ -1550,8 +1551,8 @@ void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks);
|
||||
* uses solely `nghttp2_session_mem_send()` to serialize data to
|
||||
* transmit.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_send_callback
|
||||
(nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback);
|
||||
void nghttp2_session_callbacks_set_send_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1561,8 +1562,8 @@ void nghttp2_session_callbacks_set_send_callback
|
||||
* application uses solely `nghttp2_session_mem_recv()` to process
|
||||
* received data.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_recv_callback
|
||||
(nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback);
|
||||
void nghttp2_session_callbacks_set_recv_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1570,9 +1571,9 @@ void nghttp2_session_callbacks_set_recv_callback
|
||||
* Sets callback function invoked by `nghttp2_session_recv()` when a
|
||||
* frame is received.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback);
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1580,9 +1581,9 @@ void nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
* Sets callback function invoked by `nghttp2_session_recv()` when an
|
||||
* invalid non-DATA frame is received.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback);
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1590,27 +1591,27 @@ void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
|
||||
* Sets callback function invoked when a chunk of data in DATA frame
|
||||
* is received.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback);
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked before a non-DATA frame is sent.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback);
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked after a frame is sent.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback);
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1618,18 +1619,18 @@ void nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
* Sets callback function invoked when a non-DATA frame is not sent
|
||||
* because of an error.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback);
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked when the stream is closed.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback);
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1637,9 +1638,9 @@ void nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
* Sets callback function invoked when the reception of header block
|
||||
* in HEADERS or PUSH_PROMISE is started.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback);
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1647,9 +1648,9 @@ void nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
* Sets callback function invoked when a header name/value pair is
|
||||
* received.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_header_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback);
|
||||
void nghttp2_session_callbacks_set_on_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1658,9 +1659,9 @@ void nghttp2_session_callbacks_set_on_header_callback
|
||||
* how many padding bytes are required for the transmission of the
|
||||
* given frame.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_select_padding_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback);
|
||||
void nghttp2_session_callbacks_set_select_padding_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1668,18 +1669,18 @@ void nghttp2_session_callbacks_set_select_padding_callback
|
||||
* Sets callback function determine the length allowed in
|
||||
* :type:`nghttp2_data_source_read_callback`.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback);
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback);
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
* Sets callback function invoked when a frame header is received.
|
||||
*/
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback);
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback);
|
||||
|
||||
struct nghttp2_option;
|
||||
|
||||
@ -1836,8 +1837,7 @@ int nghttp2_session_server_new(nghttp2_session **session_ptr,
|
||||
*/
|
||||
int nghttp2_session_client_new2(nghttp2_session **session_ptr,
|
||||
const nghttp2_session_callbacks *callbacks,
|
||||
void *user_data,
|
||||
const nghttp2_option *option);
|
||||
void *user_data, const nghttp2_option *option);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -1862,8 +1862,7 @@ int nghttp2_session_client_new2(nghttp2_session **session_ptr,
|
||||
*/
|
||||
int nghttp2_session_server_new2(nghttp2_session **session_ptr,
|
||||
const nghttp2_session_callbacks *callbacks,
|
||||
void *user_data,
|
||||
const nghttp2_option *option);
|
||||
void *user_data, const nghttp2_option *option);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2053,8 +2052,8 @@ int nghttp2_session_recv(nghttp2_session *session);
|
||||
* when |session| was configured as server and
|
||||
* `nghttp2_option_set_recv_client_preface()` is used.
|
||||
*/
|
||||
ssize_t nghttp2_session_mem_recv(nghttp2_session *session,
|
||||
const uint8_t *in, size_t inlen);
|
||||
ssize_t nghttp2_session_mem_recv(nghttp2_session *session, const uint8_t *in,
|
||||
size_t inlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2108,7 +2107,7 @@ int nghttp2_session_want_write(nghttp2_session *session);
|
||||
* ``NULL``. If the stream does not exist, this function returns
|
||||
* ``NULL``.
|
||||
*/
|
||||
void* nghttp2_session_get_stream_user_data(nghttp2_session *session,
|
||||
void *nghttp2_session_get_stream_user_data(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
@ -2155,8 +2154,9 @@ size_t nghttp2_session_get_outbound_queue_size(nghttp2_session *session);
|
||||
*
|
||||
* This function returns -1 if it fails.
|
||||
*/
|
||||
int32_t nghttp2_session_get_stream_effective_recv_data_length
|
||||
(nghttp2_session *session, int32_t stream_id);
|
||||
int32_t
|
||||
nghttp2_session_get_stream_effective_recv_data_length(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2168,8 +2168,9 @@ int32_t nghttp2_session_get_stream_effective_recv_data_length
|
||||
*
|
||||
* This function returns -1 if it fails.
|
||||
*/
|
||||
int32_t nghttp2_session_get_stream_effective_local_window_size
|
||||
(nghttp2_session *session, int32_t stream_id);
|
||||
int32_t
|
||||
nghttp2_session_get_stream_effective_local_window_size(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2185,8 +2186,8 @@ int32_t nghttp2_session_get_stream_effective_local_window_size
|
||||
*
|
||||
* This function returns -1 if it fails.
|
||||
*/
|
||||
int32_t nghttp2_session_get_effective_recv_data_length
|
||||
(nghttp2_session *session);
|
||||
int32_t
|
||||
nghttp2_session_get_effective_recv_data_length(nghttp2_session *session);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2198,8 +2199,8 @@ int32_t nghttp2_session_get_effective_recv_data_length
|
||||
*
|
||||
* This function returns -1 if it fails.
|
||||
*/
|
||||
int32_t nghttp2_session_get_effective_local_window_size
|
||||
(nghttp2_session *session);
|
||||
int32_t
|
||||
nghttp2_session_get_effective_local_window_size(nghttp2_session *session);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2215,7 +2216,7 @@ int32_t nghttp2_session_get_effective_local_window_size
|
||||
*
|
||||
* This function returns -1 if it fails.
|
||||
*/
|
||||
int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session* session,
|
||||
int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
@ -2225,7 +2226,7 @@ int32_t nghttp2_session_get_stream_remote_window_size(nghttp2_session* session,
|
||||
*
|
||||
* This function always succeeds.
|
||||
*/
|
||||
int32_t nghttp2_session_get_remote_window_size(nghttp2_session* session);
|
||||
int32_t nghttp2_session_get_remote_window_size(nghttp2_session *session);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2233,7 +2234,7 @@ int32_t nghttp2_session_get_remote_window_size(nghttp2_session* session);
|
||||
* Returns 1 if local peer half closed the given stream |stream_id|.
|
||||
* Returns 0 if it did not. Returns -1 if no such stream exists.
|
||||
*/
|
||||
int nghttp2_session_get_stream_local_close(nghttp2_session* session,
|
||||
int nghttp2_session_get_stream_local_close(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
@ -2242,7 +2243,7 @@ int nghttp2_session_get_stream_local_close(nghttp2_session* session,
|
||||
* Returns 1 if remote peer half closed the given stream |stream_id|.
|
||||
* Returns 0 if it did not. Returns -1 if no such stream exists.
|
||||
*/
|
||||
int nghttp2_session_get_stream_remote_close(nghttp2_session* session,
|
||||
int nghttp2_session_get_stream_remote_close(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/**
|
||||
@ -2361,8 +2362,7 @@ int nghttp2_session_consume(nghttp2_session *session, int32_t stream_id,
|
||||
*/
|
||||
int nghttp2_session_upgrade(nghttp2_session *session,
|
||||
const uint8_t *settings_payload,
|
||||
size_t settings_payloadlen,
|
||||
void *stream_user_data);
|
||||
size_t settings_payloadlen, void *stream_user_data);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2385,8 +2385,7 @@ int nghttp2_session_upgrade(nghttp2_session *session,
|
||||
* :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
|
||||
* The provided |buflen| size is too small to hold the output.
|
||||
*/
|
||||
ssize_t nghttp2_pack_settings_payload(uint8_t *buf,
|
||||
size_t buflen,
|
||||
ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
@ -2396,7 +2395,7 @@ ssize_t nghttp2_pack_settings_payload(uint8_t *buf,
|
||||
* Returns string describing the |lib_error_code|. The
|
||||
* |lib_error_code| must be one of the :enum:`nghttp2_error`.
|
||||
*/
|
||||
const char* nghttp2_strerror(int lib_error_code);
|
||||
const char *nghttp2_strerror(int lib_error_code);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2537,8 +2536,7 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
|
||||
* :enum:`NGHTTP2_ERR_INVALID_ARGUMENT`
|
||||
* The |stream_id| is 0.
|
||||
*/
|
||||
int nghttp2_submit_response(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd);
|
||||
|
||||
@ -2711,8 +2709,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags,
|
||||
* The |stream_id| is 0.
|
||||
*/
|
||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
int32_t stream_id, uint32_t error_code);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -2750,7 +2747,6 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags,
|
||||
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
||||
const nghttp2_settings_entry *iv, size_t niv);
|
||||
|
||||
|
||||
/**
|
||||
* @function
|
||||
*
|
||||
@ -2805,8 +2801,8 @@ int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags,
|
||||
*
|
||||
*/
|
||||
int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
int32_t stream_id, const nghttp2_nv *nva,
|
||||
size_t nvlen,
|
||||
void *promised_stream_user_data);
|
||||
|
||||
/**
|
||||
@ -2866,8 +2862,7 @@ int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags,
|
||||
* The |opaque_data_len| is too large.
|
||||
*/
|
||||
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags,
|
||||
int32_t last_stream_id,
|
||||
uint32_t error_code,
|
||||
int32_t last_stream_id, uint32_t error_code,
|
||||
const uint8_t *opaque_data, size_t opaque_data_len);
|
||||
|
||||
/**
|
||||
@ -2937,8 +2932,7 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
* |origin_len| is is too large.
|
||||
*/
|
||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
uint32_t max_age, uint16_t port,
|
||||
int32_t stream_id, uint32_t max_age, uint16_t port,
|
||||
const uint8_t *protocol_id, size_t protocol_id_len,
|
||||
const uint8_t *host, size_t host_len,
|
||||
const uint8_t *origin, size_t origin_len);
|
||||
@ -3143,9 +3137,9 @@ int nghttp2_hd_deflate_change_table_size(nghttp2_hd_deflater *deflater,
|
||||
* :enum:`NGHTTP2_ERR_INSUFF_BUFSIZE`
|
||||
* The provided |buflen| size is too small to hold the output.
|
||||
*/
|
||||
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater,
|
||||
uint8_t *buf, size_t buflen,
|
||||
const nghttp2_nv *nva, size_t nvlen);
|
||||
ssize_t nghttp2_hd_deflate_hd(nghttp2_hd_deflater *deflater, uint8_t *buf,
|
||||
size_t buflen, const nghttp2_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
/**
|
||||
* @function
|
||||
@ -3302,9 +3296,9 @@ typedef enum {
|
||||
* }
|
||||
*
|
||||
*/
|
||||
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater,
|
||||
nghttp2_nv *nv_out, int *inflate_flags,
|
||||
uint8_t *in, size_t inlen, int in_final);
|
||||
ssize_t nghttp2_hd_inflate_hd(nghttp2_hd_inflater *inflater, nghttp2_nv *nv_out,
|
||||
int *inflate_flags, uint8_t *in, size_t inlen,
|
||||
int in_final);
|
||||
|
||||
/**
|
||||
* @function
|
||||
|
@ -28,8 +28,7 @@
|
||||
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
void nghttp2_buf_init(nghttp2_buf *buf)
|
||||
{
|
||||
void nghttp2_buf_init(nghttp2_buf *buf) {
|
||||
buf->begin = NULL;
|
||||
buf->end = NULL;
|
||||
buf->pos = NULL;
|
||||
@ -37,15 +36,13 @@ void nghttp2_buf_init(nghttp2_buf *buf)
|
||||
buf->mark = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial)
|
||||
{
|
||||
int nghttp2_buf_init2(nghttp2_buf *buf, size_t initial) {
|
||||
nghttp2_buf_init(buf);
|
||||
return nghttp2_buf_reserve(buf, initial);
|
||||
}
|
||||
|
||||
void nghttp2_buf_free(nghttp2_buf *buf)
|
||||
{
|
||||
if(buf == NULL) {
|
||||
void nghttp2_buf_free(nghttp2_buf *buf) {
|
||||
if (buf == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -53,21 +50,20 @@ void nghttp2_buf_free(nghttp2_buf *buf)
|
||||
buf->begin = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
|
||||
{
|
||||
int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap) {
|
||||
uint8_t *ptr;
|
||||
size_t cap;
|
||||
|
||||
cap = nghttp2_buf_cap(buf);
|
||||
|
||||
if(cap >= new_cap) {
|
||||
if (cap >= new_cap) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
new_cap = nghttp2_max(new_cap, cap * 2);
|
||||
|
||||
ptr = realloc(buf->begin, new_cap);
|
||||
if(ptr == NULL) {
|
||||
if (ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -80,30 +76,27 @@ int nghttp2_buf_reserve(nghttp2_buf *buf, size_t new_cap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_buf_reset(nghttp2_buf *buf)
|
||||
{
|
||||
void nghttp2_buf_reset(nghttp2_buf *buf) {
|
||||
buf->pos = buf->last = buf->mark = buf->begin;
|
||||
}
|
||||
|
||||
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len)
|
||||
{
|
||||
void nghttp2_buf_wrap_init(nghttp2_buf *buf, uint8_t *begin, size_t len) {
|
||||
buf->begin = buf->pos = buf->last = buf->mark = begin;
|
||||
buf->end = begin + len;
|
||||
}
|
||||
|
||||
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length)
|
||||
{
|
||||
static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length) {
|
||||
int rv;
|
||||
|
||||
*chain = malloc(sizeof(nghttp2_buf_chain));
|
||||
if(*chain == NULL) {
|
||||
if (*chain == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
(*chain)->next = NULL;
|
||||
|
||||
rv = nghttp2_buf_init2(&(*chain)->buf, chunk_length);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
free(*chain);
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
@ -111,36 +104,32 @@ static int buf_chain_new(nghttp2_buf_chain **chain, size_t chunk_length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void buf_chain_del(nghttp2_buf_chain *chain)
|
||||
{
|
||||
static void buf_chain_del(nghttp2_buf_chain *chain) {
|
||||
nghttp2_buf_free(&chain->buf);
|
||||
free(chain);
|
||||
}
|
||||
|
||||
int nghttp2_bufs_init(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk)
|
||||
{
|
||||
size_t max_chunk) {
|
||||
return nghttp2_bufs_init2(bufs, chunk_length, max_chunk, 0);
|
||||
}
|
||||
|
||||
int nghttp2_bufs_init2(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk, size_t offset)
|
||||
{
|
||||
size_t max_chunk, size_t offset) {
|
||||
return nghttp2_bufs_init3(bufs, chunk_length, max_chunk, max_chunk, offset);
|
||||
}
|
||||
|
||||
int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
size_t max_chunk, size_t chunk_keep, size_t offset)
|
||||
{
|
||||
size_t max_chunk, size_t chunk_keep, size_t offset) {
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if(chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
|
||||
if (chunk_keep == 0 || max_chunk < chunk_keep || chunk_length < offset) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, chunk_length);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -159,17 +148,16 @@ int nghttp2_bufs_init3(nghttp2_bufs *bufs, size_t chunk_length,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
|
||||
{
|
||||
int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length) {
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if(chunk_length < bufs->offset) {
|
||||
if (chunk_length < bufs->offset) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, chunk_length);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -186,15 +174,14 @@ int nghttp2_bufs_realloc(nghttp2_bufs *bufs, size_t chunk_length)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_free(nghttp2_bufs *bufs)
|
||||
{
|
||||
void nghttp2_bufs_free(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain, *next_chain;
|
||||
|
||||
if(bufs == NULL) {
|
||||
if (bufs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(chain = bufs->head; chain;) {
|
||||
for (chain = bufs->head; chain;) {
|
||||
next_chain = chain->next;
|
||||
|
||||
buf_chain_del(chain);
|
||||
@ -205,12 +192,11 @@ void nghttp2_bufs_free(nghttp2_bufs *bufs)
|
||||
bufs->head = NULL;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
|
||||
{
|
||||
int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len) {
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
chain = malloc(sizeof(nghttp2_buf_chain));
|
||||
if(chain == NULL) {
|
||||
if (chain == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -231,9 +217,8 @@ int nghttp2_bufs_wrap_init(nghttp2_bufs *bufs, uint8_t *begin, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs)
|
||||
{
|
||||
if(bufs == NULL) {
|
||||
void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs) {
|
||||
if (bufs == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -241,12 +226,11 @@ void nghttp2_bufs_wrap_free(nghttp2_bufs *bufs)
|
||||
bufs->head = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
|
||||
{
|
||||
void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *ci;
|
||||
|
||||
for(ci = bufs->cur; ci; ci = ci->next) {
|
||||
if(nghttp2_buf_len(&ci->buf) == 0) {
|
||||
for (ci = bufs->cur; ci; ci = ci->next) {
|
||||
if (nghttp2_buf_len(&ci->buf) == 0) {
|
||||
return;
|
||||
} else {
|
||||
bufs->cur = ci;
|
||||
@ -254,42 +238,40 @@ void nghttp2_bufs_seek_last_present(nghttp2_bufs *bufs)
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs)
|
||||
{
|
||||
ssize_t nghttp2_bufs_len(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *ci;
|
||||
ssize_t len;
|
||||
|
||||
len = 0;
|
||||
for(ci = bufs->head; ci; ci = ci->next) {
|
||||
for (ci = bufs->head; ci; ci = ci->next) {
|
||||
len += nghttp2_buf_len(&ci->buf);
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
static ssize_t bufs_avail(nghttp2_bufs *bufs)
|
||||
{
|
||||
static ssize_t bufs_avail(nghttp2_bufs *bufs) {
|
||||
return (ssize_t)(nghttp2_buf_avail(&bufs->cur->buf) +
|
||||
(bufs->chunk_length - bufs->offset) * (bufs->max_chunk - bufs->chunk_used));
|
||||
(bufs->chunk_length - bufs->offset) *
|
||||
(bufs->max_chunk - bufs->chunk_used));
|
||||
}
|
||||
|
||||
static int bufs_alloc_chain(nghttp2_bufs *bufs)
|
||||
{
|
||||
static int bufs_alloc_chain(nghttp2_bufs *bufs) {
|
||||
int rv;
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
if(bufs->cur->next) {
|
||||
if (bufs->cur->next) {
|
||||
bufs->cur = bufs->cur->next;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(bufs->max_chunk == bufs->chunk_used) {
|
||||
if (bufs->max_chunk == bufs->chunk_used) {
|
||||
return NGHTTP2_ERR_BUFFER_ERROR;
|
||||
}
|
||||
|
||||
rv = buf_chain_new(&chain, bufs->chunk_length);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -307,26 +289,25 @@ static int bufs_alloc_chain(nghttp2_bufs *bufs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
|
||||
{
|
||||
int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len) {
|
||||
int rv;
|
||||
size_t nwrite;
|
||||
nghttp2_buf *buf;
|
||||
const uint8_t *p;
|
||||
|
||||
if(bufs_avail(bufs) < (ssize_t)len) {
|
||||
if (bufs_avail(bufs) < (ssize_t)len) {
|
||||
return NGHTTP2_ERR_BUFFER_ERROR;
|
||||
}
|
||||
|
||||
p = data;
|
||||
|
||||
while(len) {
|
||||
while (len) {
|
||||
buf = &bufs->cur->buf;
|
||||
|
||||
nwrite = nghttp2_min((size_t)nghttp2_buf_avail(buf), len);
|
||||
if(nwrite == 0) {
|
||||
if (nwrite == 0) {
|
||||
rv = bufs_alloc_chain(bufs);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
continue;
|
||||
@ -340,31 +321,29 @@ int nghttp2_bufs_add(nghttp2_bufs *bufs, const void *data, size_t len)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bufs_ensure_addb(nghttp2_bufs *bufs)
|
||||
{
|
||||
static int bufs_ensure_addb(nghttp2_bufs *bufs) {
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
|
||||
buf = &bufs->cur->buf;
|
||||
|
||||
if(nghttp2_buf_avail(buf) > 0) {
|
||||
if (nghttp2_buf_avail(buf) > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = bufs_alloc_chain(bufs);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
|
||||
{
|
||||
int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -373,12 +352,11 @@ int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b)
|
||||
{
|
||||
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -387,12 +365,11 @@ int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b)
|
||||
{
|
||||
int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -401,12 +378,11 @@ int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b)
|
||||
{
|
||||
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b) {
|
||||
int rv;
|
||||
|
||||
rv = bufs_ensure_addb(bufs);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -415,8 +391,7 @@ int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
|
||||
{
|
||||
ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out) {
|
||||
size_t len;
|
||||
nghttp2_buf_chain *chain;
|
||||
nghttp2_buf *buf;
|
||||
@ -425,28 +400,27 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
|
||||
|
||||
len = 0;
|
||||
|
||||
for(chain = bufs->head; chain; chain = chain->next) {
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
len += nghttp2_buf_len(&chain->buf);
|
||||
}
|
||||
|
||||
if(!len) {
|
||||
if (!len) {
|
||||
res = NULL;
|
||||
} else {
|
||||
res = malloc(len);
|
||||
|
||||
if(res == NULL) {
|
||||
if (res == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
nghttp2_buf_wrap_init(&resbuf, res, len);
|
||||
|
||||
for(chain = bufs->head; chain; chain = chain->next) {
|
||||
for (chain = bufs->head; chain; chain = chain->next) {
|
||||
buf = &chain->buf;
|
||||
|
||||
if(resbuf.last) {
|
||||
resbuf.last = nghttp2_cpymem(resbuf.last,
|
||||
buf->pos, nghttp2_buf_len(buf));
|
||||
if (resbuf.last) {
|
||||
resbuf.last = nghttp2_cpymem(resbuf.last, buf->pos, nghttp2_buf_len(buf));
|
||||
}
|
||||
|
||||
nghttp2_buf_reset(buf);
|
||||
@ -460,27 +434,26 @@ ssize_t nghttp2_bufs_remove(nghttp2_bufs *bufs, uint8_t **out)
|
||||
return (ssize_t)len;
|
||||
}
|
||||
|
||||
void nghttp2_bufs_reset(nghttp2_bufs *bufs)
|
||||
{
|
||||
void nghttp2_bufs_reset(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain, *ci;
|
||||
size_t k;
|
||||
|
||||
k = bufs->chunk_keep;
|
||||
|
||||
for(ci = bufs->head; ci; ci = ci->next) {
|
||||
for (ci = bufs->head; ci; ci = ci->next) {
|
||||
nghttp2_buf_reset(&ci->buf);
|
||||
nghttp2_buf_shift_right(&ci->buf, bufs->offset);
|
||||
|
||||
if(--k == 0) {
|
||||
if (--k == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(ci) {
|
||||
if (ci) {
|
||||
chain = ci->next;
|
||||
ci->next = NULL;
|
||||
|
||||
for(ci = chain; ci;) {
|
||||
for (ci = chain; ci;) {
|
||||
chain = ci->next;
|
||||
|
||||
buf_chain_del(ci);
|
||||
@ -494,17 +467,12 @@ void nghttp2_bufs_reset(nghttp2_bufs *bufs)
|
||||
bufs->cur = bufs->head;
|
||||
}
|
||||
|
||||
int nghttp2_bufs_advance(nghttp2_bufs *bufs)
|
||||
{
|
||||
return bufs_alloc_chain(bufs);
|
||||
}
|
||||
int nghttp2_bufs_advance(nghttp2_bufs *bufs) { return bufs_alloc_chain(bufs); }
|
||||
|
||||
int nghttp2_bufs_next_present(nghttp2_bufs *bufs)
|
||||
{
|
||||
int nghttp2_bufs_next_present(nghttp2_bufs *bufs) {
|
||||
nghttp2_buf_chain *chain;
|
||||
|
||||
chain = bufs->cur->next;
|
||||
|
||||
return chain && nghttp2_buf_len(&chain->buf);
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_BUF_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -58,17 +58,17 @@ typedef struct {
|
||||
#define nghttp2_buf_pos_offset(BUF) ((ssize_t)((BUF)->pos - (BUF)->begin))
|
||||
#define nghttp2_buf_last_offset(BUF) ((ssize_t)((BUF)->last - (BUF)->begin))
|
||||
|
||||
#define nghttp2_buf_shift_right(BUF, AMT) \
|
||||
do { \
|
||||
(BUF)->pos += AMT; \
|
||||
(BUF)->last += AMT; \
|
||||
} while(0)
|
||||
#define nghttp2_buf_shift_right(BUF, AMT) \
|
||||
do { \
|
||||
(BUF)->pos += AMT; \
|
||||
(BUF)->last += AMT; \
|
||||
} while (0)
|
||||
|
||||
#define nghttp2_buf_shift_left(BUF, AMT) \
|
||||
do { \
|
||||
(BUF)->pos -= AMT; \
|
||||
(BUF)->last -= AMT; \
|
||||
} while(0)
|
||||
#define nghttp2_buf_shift_left(BUF, AMT) \
|
||||
do { \
|
||||
(BUF)->pos -= AMT; \
|
||||
(BUF)->last -= AMT; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Initializes the |buf|. No memory is allocated in this function. Use
|
||||
@ -76,7 +76,6 @@ typedef struct {
|
||||
*/
|
||||
void nghttp2_buf_init(nghttp2_buf *buf);
|
||||
|
||||
|
||||
/*
|
||||
* Initializes the |buf| and allocates at least |initial| bytes of
|
||||
* memory.
|
||||
@ -264,15 +263,15 @@ int nghttp2_bufs_addb(nghttp2_bufs *bufs, uint8_t b);
|
||||
*/
|
||||
int nghttp2_bufs_addb_hold(nghttp2_bufs *bufs, uint8_t b);
|
||||
|
||||
#define nghttp2_bufs_fast_addb(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last++ = B; \
|
||||
} while(0)
|
||||
#define nghttp2_bufs_fast_addb(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last++ = B; \
|
||||
} while (0)
|
||||
|
||||
#define nghttp2_bufs_fast_addb_hold(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last = B; \
|
||||
} while(0)
|
||||
#define nghttp2_bufs_fast_addb_hold(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last = B; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Performs bitwise-OR of |b| at bufs->cur->buf.last. A new buffers
|
||||
@ -294,15 +293,15 @@ int nghttp2_bufs_orb(nghttp2_bufs *bufs, uint8_t b);
|
||||
*/
|
||||
int nghttp2_bufs_orb_hold(nghttp2_bufs *bufs, uint8_t b);
|
||||
|
||||
#define nghttp2_bufs_fast_orb(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last++ |= B; \
|
||||
} while(0)
|
||||
#define nghttp2_bufs_fast_orb(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last++ |= B; \
|
||||
} while (0)
|
||||
|
||||
#define nghttp2_bufs_fast_orb_hold(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last |= B; \
|
||||
} while(0)
|
||||
#define nghttp2_bufs_fast_orb_hold(BUFS, B) \
|
||||
do { \
|
||||
*(BUFS)->cur->buf.last |= B; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Copies all data stored in |bufs| to the contagious buffer. This
|
||||
@ -342,10 +341,10 @@ void nghttp2_bufs_reset(nghttp2_bufs *bufs);
|
||||
int nghttp2_bufs_advance(nghttp2_bufs *bufs);
|
||||
|
||||
/* Sets bufs->cur to bufs->head */
|
||||
#define nghttp2_bufs_rewind(BUFS) \
|
||||
do { \
|
||||
(BUFS)->cur = (BUFS)->head; \
|
||||
} while(0)
|
||||
#define nghttp2_bufs_rewind(BUFS) \
|
||||
do { \
|
||||
(BUFS)->cur = (BUFS)->head; \
|
||||
} while (0)
|
||||
|
||||
/*
|
||||
* Move bufs->cur, from the current position, using next member, to
|
||||
|
@ -26,114 +26,98 @@
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr)
|
||||
{
|
||||
int nghttp2_session_callbacks_new(nghttp2_session_callbacks **callbacks_ptr) {
|
||||
*callbacks_ptr = calloc(1, sizeof(nghttp2_session_callbacks));
|
||||
|
||||
if(*callbacks_ptr == NULL) {
|
||||
if (*callbacks_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks)
|
||||
{
|
||||
void nghttp2_session_callbacks_del(nghttp2_session_callbacks *callbacks) {
|
||||
free(callbacks);
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_send_callback
|
||||
(nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_send_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_send_callback send_callback) {
|
||||
cbs->send_callback = send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_recv_callback
|
||||
(nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_recv_callback(
|
||||
nghttp2_session_callbacks *cbs, nghttp2_recv_callback recv_callback) {
|
||||
cbs->recv_callback = recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_recv_callback on_frame_recv_callback) {
|
||||
cbs->on_frame_recv_callback = on_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_invalid_frame_recv_callback on_invalid_frame_recv_callback) {
|
||||
cbs->on_invalid_frame_recv_callback = on_invalid_frame_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_data_chunk_recv_callback on_data_chunk_recv_callback) {
|
||||
cbs->on_data_chunk_recv_callback = on_data_chunk_recv_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_before_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_before_frame_send_callback before_frame_send_callback) {
|
||||
cbs->before_frame_send_callback = before_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_frame_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_send_callback on_frame_send_callback) {
|
||||
cbs->on_frame_send_callback = on_frame_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_frame_not_send_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_frame_not_send_callback on_frame_not_send_callback) {
|
||||
cbs->on_frame_not_send_callback = on_frame_not_send_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_stream_close_callback on_stream_close_callback) {
|
||||
cbs->on_stream_close_callback = on_stream_close_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_begin_headers_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_headers_callback on_begin_headers_callback) {
|
||||
cbs->on_begin_headers_callback = on_begin_headers_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_header_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_header_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_header_callback on_header_callback) {
|
||||
cbs->on_header_callback = on_header_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_select_padding_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_select_padding_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_select_padding_callback select_padding_callback) {
|
||||
cbs->select_padding_callback = select_padding_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_data_source_read_length_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_data_source_read_length_callback data_source_read_length_callback) {
|
||||
cbs->read_length_callback = data_source_read_length_callback;
|
||||
}
|
||||
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback
|
||||
(nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback)
|
||||
{
|
||||
void nghttp2_session_callbacks_set_on_begin_frame_callback(
|
||||
nghttp2_session_callbacks *cbs,
|
||||
nghttp2_on_begin_frame_callback on_begin_frame_callback) {
|
||||
cbs->on_begin_frame_callback = on_begin_frame_callback;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_CALLBACKS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
@ -33,17 +33,15 @@
|
||||
#include "nghttp2_net.h"
|
||||
#include "nghttp2_priority_spec.h"
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t* buf, const nghttp2_frame_hd *hd)
|
||||
{
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd) {
|
||||
nghttp2_put_uint32be(&buf[0], (uint32_t)(hd->length << 8));
|
||||
buf[3]= hd->type;
|
||||
buf[3] = hd->type;
|
||||
buf[4] = hd->flags;
|
||||
nghttp2_put_uint32be(&buf[5], hd->stream_id);
|
||||
/* ignore hd->reserved for now */
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf)
|
||||
{
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf) {
|
||||
hd->length = nghttp2_get_uint32(&buf[0]) >> 8;
|
||||
hd->type = buf[3];
|
||||
hd->flags = buf[4];
|
||||
@ -51,10 +49,8 @@ void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf)
|
||||
hd->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
|
||||
uint8_t type, uint8_t flags,
|
||||
int32_t stream_id)
|
||||
{
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id) {
|
||||
hd->length = length;
|
||||
hd->type = type;
|
||||
hd->flags = flags;
|
||||
@ -62,73 +58,59 @@ void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
|
||||
hd->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
nghttp2_headers_category cat,
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
|
||||
int32_t stream_id, nghttp2_headers_category cat,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
nghttp2_nv *nva, size_t nvlen) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_HEADERS, flags, stream_id);
|
||||
frame->padlen = 0;
|
||||
frame->nva = nva;
|
||||
frame->nvlen = nvlen;
|
||||
frame->cat = cat;
|
||||
|
||||
if(pri_spec) {
|
||||
if (pri_spec) {
|
||||
frame->pri_spec = *pri_spec;
|
||||
} else {
|
||||
nghttp2_priority_spec_default_init(&frame->pri_spec);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame)
|
||||
{
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame) {
|
||||
nghttp2_nv_array_del(frame->nva);
|
||||
}
|
||||
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
const nghttp2_priority_spec *pri_spec) {
|
||||
nghttp2_frame_hd_init(&frame->hd, NGHTTP2_PRIORITY_SPECLEN, NGHTTP2_PRIORITY,
|
||||
NGHTTP2_FLAG_NONE, stream_id);
|
||||
frame->pri_spec = *pri_spec;
|
||||
}
|
||||
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame _U_)
|
||||
{}
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame _U_) {}
|
||||
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code)
|
||||
{
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
||||
uint32_t error_code) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_RST_STREAM, NGHTTP2_FLAG_NONE,
|
||||
stream_id);
|
||||
frame->error_code = error_code;
|
||||
}
|
||||
|
||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame _U_)
|
||||
{}
|
||||
|
||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame _U_) {}
|
||||
|
||||
void nghttp2_frame_settings_init(nghttp2_settings *frame, uint8_t flags,
|
||||
nghttp2_settings_entry *iv, size_t niv)
|
||||
{
|
||||
nghttp2_settings_entry *iv, size_t niv) {
|
||||
nghttp2_frame_hd_init(&frame->hd, niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH,
|
||||
NGHTTP2_SETTINGS, flags, 0);
|
||||
frame->niv = niv;
|
||||
frame->iv = iv;
|
||||
}
|
||||
|
||||
void nghttp2_frame_settings_free(nghttp2_settings *frame)
|
||||
{
|
||||
free(frame->iv);
|
||||
}
|
||||
void nghttp2_frame_settings_free(nghttp2_settings *frame) { free(frame->iv); }
|
||||
|
||||
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t promised_stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
nghttp2_nv *nva, size_t nvlen) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_PUSH_PROMISE, flags, stream_id);
|
||||
frame->padlen = 0;
|
||||
frame->nva = nva;
|
||||
@ -137,30 +119,26 @@ void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame,
|
||||
frame->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame)
|
||||
{
|
||||
void nghttp2_frame_push_promise_free(nghttp2_push_promise *frame) {
|
||||
nghttp2_nv_array_del(frame->nva);
|
||||
}
|
||||
|
||||
void nghttp2_frame_ping_init(nghttp2_ping *frame, uint8_t flags,
|
||||
const uint8_t *opaque_data)
|
||||
{
|
||||
const uint8_t *opaque_data) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 8, NGHTTP2_PING, flags, 0);
|
||||
if(opaque_data) {
|
||||
if (opaque_data) {
|
||||
memcpy(frame->opaque_data, opaque_data, sizeof(frame->opaque_data));
|
||||
} else {
|
||||
memset(frame->opaque_data, 0, sizeof(frame->opaque_data));
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_frame_ping_free(nghttp2_ping *frame _U_)
|
||||
{}
|
||||
void nghttp2_frame_ping_free(nghttp2_ping *frame _U_) {}
|
||||
|
||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
uint32_t error_code,
|
||||
uint8_t *opaque_data, size_t opaque_data_len)
|
||||
{
|
||||
nghttp2_frame_hd_init(&frame->hd, 8+opaque_data_len, NGHTTP2_GOAWAY,
|
||||
uint32_t error_code, uint8_t *opaque_data,
|
||||
size_t opaque_data_len) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 8 + opaque_data_len, NGHTTP2_GOAWAY,
|
||||
NGHTTP2_FLAG_NONE, 0);
|
||||
frame->last_stream_id = last_stream_id;
|
||||
frame->error_code = error_code;
|
||||
@ -169,33 +147,25 @@ void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
frame->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame)
|
||||
{
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame) {
|
||||
free(frame->opaque_data);
|
||||
}
|
||||
|
||||
void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t window_size_increment)
|
||||
{
|
||||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags,
|
||||
stream_id);
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t window_size_increment) {
|
||||
nghttp2_frame_hd_init(&frame->hd, 4, NGHTTP2_WINDOW_UPDATE, flags, stream_id);
|
||||
frame->window_size_increment = window_size_increment;
|
||||
frame->reserved = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame _U_)
|
||||
{}
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame _U_) {}
|
||||
|
||||
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
uint32_t max_age,
|
||||
uint16_t port,
|
||||
uint8_t *protocol_id,
|
||||
size_t protocol_id_len,
|
||||
uint8_t *host, size_t host_len,
|
||||
uint8_t *origin, size_t origin_len)
|
||||
{
|
||||
uint32_t max_age, uint16_t port,
|
||||
uint8_t *protocol_id, size_t protocol_id_len,
|
||||
uint8_t *host, size_t host_len, uint8_t *origin,
|
||||
size_t origin_len) {
|
||||
size_t payloadlen;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
|
||||
@ -216,46 +186,40 @@ void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
altsvc->origin_len = origin_len;
|
||||
}
|
||||
|
||||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame)
|
||||
{
|
||||
void nghttp2_frame_altsvc_free(nghttp2_extension *frame) {
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
|
||||
altsvc = frame->payload;
|
||||
|
||||
if(altsvc == NULL) {
|
||||
if (altsvc == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
free(altsvc->protocol_id);
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen)
|
||||
{
|
||||
size_t nghttp2_frame_trail_padlen(nghttp2_frame *frame, size_t padlen) {
|
||||
return padlen - ((frame->hd.flags & NGHTTP2_FLAG_PADDED) > 0);
|
||||
}
|
||||
|
||||
void nghttp2_frame_data_init(nghttp2_data *frame, uint8_t flags,
|
||||
int32_t stream_id)
|
||||
{
|
||||
int32_t stream_id) {
|
||||
/* At this moment, the length of DATA frame is unknown */
|
||||
nghttp2_frame_hd_init(&frame->hd, 0, NGHTTP2_DATA, flags, stream_id);
|
||||
frame->padlen = 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame _U_)
|
||||
{}
|
||||
void nghttp2_frame_data_free(nghttp2_data *frame _U_) {}
|
||||
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags)
|
||||
{
|
||||
if(flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
size_t nghttp2_frame_priority_len(uint8_t flags) {
|
||||
if (flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
return NGHTTP2_PRIORITY_SPECLEN;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
|
||||
{
|
||||
size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame) {
|
||||
return nghttp2_frame_priority_len(frame->hd.flags);
|
||||
}
|
||||
|
||||
@ -272,8 +236,7 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame)
|
||||
* We don't process any padding here.
|
||||
*/
|
||||
static int frame_pack_headers_shared(nghttp2_bufs *bufs,
|
||||
nghttp2_frame_hd *frame_hd)
|
||||
{
|
||||
nghttp2_frame_hd *frame_hd) {
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_buf_chain *ci, *ce;
|
||||
nghttp2_frame_hd hd;
|
||||
@ -283,20 +246,20 @@ static int frame_pack_headers_shared(nghttp2_bufs *bufs,
|
||||
hd = *frame_hd;
|
||||
hd.length = nghttp2_buf_len(buf);
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n", hd.length));
|
||||
DEBUGF(fprintf(stderr, "send: HEADERS/PUSH_PROMISE, payloadlen=%zu\n",
|
||||
hd.length));
|
||||
|
||||
/* We have multiple frame buffers, which means one or more
|
||||
CONTINUATION frame is involved. Remove END_HEADERS flag from the
|
||||
first frame. */
|
||||
if(bufs->head != bufs->cur) {
|
||||
if (bufs->head != bufs->cur) {
|
||||
hd.flags &= ~NGHTTP2_FLAG_END_HEADERS;
|
||||
}
|
||||
|
||||
buf->pos -= NGHTTP2_FRAME_HDLEN;
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
|
||||
|
||||
if(bufs->head != bufs->cur) {
|
||||
if (bufs->head != bufs->cur) {
|
||||
/* 2nd and later frames are CONTINUATION frames. */
|
||||
hd.type = NGHTTP2_CONTINUATION;
|
||||
/* We don't have no flags except for last CONTINUATION */
|
||||
@ -304,13 +267,13 @@ static int frame_pack_headers_shared(nghttp2_bufs *bufs,
|
||||
|
||||
ce = bufs->cur;
|
||||
|
||||
for(ci = bufs->head->next; ci != ce; ci = ci->next) {
|
||||
for (ci = bufs->head->next; ci != ce; ci = ci->next) {
|
||||
buf = &ci->buf;
|
||||
|
||||
hd.length = nghttp2_buf_len(buf);
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"send: int CONTINUATION, payloadlen=%zu\n", hd.length));
|
||||
DEBUGF(fprintf(stderr, "send: int CONTINUATION, payloadlen=%zu\n",
|
||||
hd.length));
|
||||
|
||||
buf->pos -= NGHTTP2_FRAME_HDLEN;
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
|
||||
@ -321,8 +284,8 @@ static int frame_pack_headers_shared(nghttp2_bufs *bufs,
|
||||
/* Set END_HEADERS flag for last CONTINUATION */
|
||||
hd.flags = NGHTTP2_FLAG_END_HEADERS;
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"send: last CONTINUATION, payloadlen=%zu\n", hd.length));
|
||||
DEBUGF(fprintf(stderr, "send: last CONTINUATION, payloadlen=%zu\n",
|
||||
hd.length));
|
||||
|
||||
buf->pos -= NGHTTP2_FRAME_HDLEN;
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &hd);
|
||||
@ -331,10 +294,8 @@ static int frame_pack_headers_shared(nghttp2_bufs *bufs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
|
||||
nghttp2_headers *frame,
|
||||
nghttp2_hd_deflater *deflater)
|
||||
{
|
||||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
|
||||
nghttp2_hd_deflater *deflater) {
|
||||
size_t nv_offset;
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
@ -351,17 +312,17 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
|
||||
/* This call will adjust buf->last to the correct position */
|
||||
rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
|
||||
|
||||
if(rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
buf->pos -= nv_offset;
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_frame_pack_priority_spec(buf->pos, &frame->pri_spec);
|
||||
}
|
||||
|
||||
@ -372,10 +333,9 @@ int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
|
||||
}
|
||||
|
||||
void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
const nghttp2_priority_spec *pri_spec) {
|
||||
nghttp2_put_uint32be(buf, pri_spec->stream_id);
|
||||
if(pri_spec->exclusive) {
|
||||
if (pri_spec->exclusive) {
|
||||
buf[0] |= 0x80;
|
||||
}
|
||||
buf[4] = pri_spec->weight - 1;
|
||||
@ -384,8 +344,7 @@ void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
uint8_t flags _U_,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_)
|
||||
{
|
||||
size_t payloadlen _U_) {
|
||||
int32_t dep_stream_id;
|
||||
uint8_t exclusive;
|
||||
int32_t weight;
|
||||
@ -399,9 +358,8 @@ void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
|
||||
int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
size_t payloadlen) {
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags,
|
||||
payload, payloadlen);
|
||||
} else {
|
||||
@ -414,8 +372,7 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame)
|
||||
{
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@ -437,15 +394,13 @@ int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame)
|
||||
|
||||
void nghttp2_frame_unpack_priority_payload(nghttp2_priority *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags,
|
||||
payload, payloadlen);
|
||||
size_t payloadlen) {
|
||||
nghttp2_frame_unpack_priority_spec(&frame->pri_spec, frame->hd.flags, payload,
|
||||
payloadlen);
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
nghttp2_rst_stream *frame)
|
||||
{
|
||||
nghttp2_rst_stream *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@ -466,20 +421,18 @@ int nghttp2_frame_pack_rst_stream(nghttp2_bufs *bufs,
|
||||
|
||||
void nghttp2_frame_unpack_rst_stream_payload(nghttp2_rst_stream *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_)
|
||||
{
|
||||
size_t payloadlen _U_) {
|
||||
frame->error_code = nghttp2_get_uint32(payload);
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame)
|
||||
{
|
||||
int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
|
||||
buf = &bufs->head->buf;
|
||||
|
||||
if(nghttp2_buf_avail(buf) < (ssize_t)frame->hd.length) {
|
||||
if (nghttp2_buf_avail(buf) < (ssize_t)frame->hd.length) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
@ -487,18 +440,17 @@ int nghttp2_frame_pack_settings(nghttp2_bufs *bufs, nghttp2_settings *frame)
|
||||
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||
|
||||
buf->last += nghttp2_frame_pack_settings_payload(buf->last,
|
||||
frame->iv, frame->niv);
|
||||
buf->last +=
|
||||
nghttp2_frame_pack_settings_payload(buf->last, frame->iv, frame->niv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv)
|
||||
{
|
||||
size_t niv) {
|
||||
size_t i;
|
||||
for(i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
|
||||
for (i = 0; i < niv; ++i, buf += NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH) {
|
||||
nghttp2_put_uint16be(buf, iv[i].settings_id);
|
||||
nghttp2_put_uint32be(buf + 2, iv[i].value);
|
||||
}
|
||||
@ -507,16 +459,15 @@ size_t nghttp2_frame_pack_settings_payload(uint8_t *buf,
|
||||
|
||||
int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||
nghttp2_settings_entry *iv,
|
||||
size_t niv)
|
||||
{
|
||||
size_t niv) {
|
||||
size_t payloadlen = niv * sizeof(nghttp2_settings_entry);
|
||||
|
||||
if(niv == 0) {
|
||||
if (niv == 0) {
|
||||
frame->iv = NULL;
|
||||
} else {
|
||||
frame->iv = malloc(payloadlen);
|
||||
|
||||
if(frame->iv == NULL) {
|
||||
if (frame->iv == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -528,8 +479,7 @@ int nghttp2_frame_unpack_settings_payload(nghttp2_settings *frame,
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||
const uint8_t *payload)
|
||||
{
|
||||
const uint8_t *payload) {
|
||||
iv->settings_id = nghttp2_get_uint16(&payload[0]);
|
||||
iv->value = nghttp2_get_uint32(&payload[2]);
|
||||
}
|
||||
@ -537,26 +487,24 @@ void nghttp2_frame_unpack_settings_entry(nghttp2_settings_entry *iv,
|
||||
int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
||||
size_t *niv_ptr,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
size_t payloadlen) {
|
||||
size_t i;
|
||||
|
||||
*niv_ptr = payloadlen / NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
|
||||
|
||||
if(*niv_ptr == 0) {
|
||||
if (*niv_ptr == 0) {
|
||||
*iv_ptr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
*iv_ptr = malloc((*niv_ptr) * sizeof(nghttp2_settings_entry));
|
||||
|
||||
*iv_ptr = malloc((*niv_ptr)*sizeof(nghttp2_settings_entry));
|
||||
|
||||
if(*iv_ptr == NULL) {
|
||||
if (*iv_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for(i = 0; i < *niv_ptr; ++i) {
|
||||
for (i = 0; i < *niv_ptr; ++i) {
|
||||
size_t off = i * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH;
|
||||
nghttp2_frame_unpack_settings_entry(&(*iv_ptr)[i], &payload[off]);
|
||||
}
|
||||
@ -566,8 +514,7 @@ int nghttp2_frame_unpack_settings_payload2(nghttp2_settings_entry **iv_ptr,
|
||||
|
||||
int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
nghttp2_push_promise *frame,
|
||||
nghttp2_hd_deflater *deflater)
|
||||
{
|
||||
nghttp2_hd_deflater *deflater) {
|
||||
size_t nv_offset = 4;
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
@ -582,13 +529,13 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
/* This call will adjust buf->last to the correct position */
|
||||
rv = nghttp2_hd_deflate_hd_bufs(deflater, bufs, frame->nva, frame->nvlen);
|
||||
|
||||
if(rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
rv = NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
|
||||
buf->pos -= nv_offset;
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -602,17 +549,15 @@ int nghttp2_frame_pack_push_promise(nghttp2_bufs *bufs,
|
||||
|
||||
int nghttp2_frame_unpack_push_promise_payload(nghttp2_push_promise *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_)
|
||||
{
|
||||
frame->promised_stream_id = nghttp2_get_uint32(payload) &
|
||||
NGHTTP2_STREAM_ID_MASK;
|
||||
size_t payloadlen _U_) {
|
||||
frame->promised_stream_id =
|
||||
nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||
frame->nva = NULL;
|
||||
frame->nvlen = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame)
|
||||
{
|
||||
int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@ -625,21 +570,19 @@ int nghttp2_frame_pack_ping(nghttp2_bufs *bufs, nghttp2_ping *frame)
|
||||
|
||||
nghttp2_frame_pack_frame_hd(buf->pos, &frame->hd);
|
||||
|
||||
buf->last = nghttp2_cpymem(buf->last, frame->opaque_data,
|
||||
sizeof(frame->opaque_data));
|
||||
buf->last =
|
||||
nghttp2_cpymem(buf->last, frame->opaque_data, sizeof(frame->opaque_data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_frame_unpack_ping_payload(nghttp2_ping *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_)
|
||||
{
|
||||
size_t payloadlen _U_) {
|
||||
memcpy(frame->opaque_data, payload, sizeof(frame->opaque_data));
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame)
|
||||
{
|
||||
int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame) {
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
|
||||
@ -659,11 +602,11 @@ int nghttp2_frame_pack_goaway(nghttp2_bufs *bufs, nghttp2_goaway *frame)
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, frame->opaque_data, frame->opaque_data_len);
|
||||
|
||||
if(rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -674,8 +617,7 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_,
|
||||
uint8_t *var_gift_payload,
|
||||
size_t var_gift_payloadlen)
|
||||
{
|
||||
size_t var_gift_payloadlen) {
|
||||
frame->last_stream_id = nghttp2_get_uint32(payload) & NGHTTP2_STREAM_ID_MASK;
|
||||
frame->error_code = nghttp2_get_uint32(payload + 4);
|
||||
|
||||
@ -685,12 +627,11 @@ void nghttp2_frame_unpack_goaway_payload(nghttp2_goaway *frame,
|
||||
|
||||
int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen)
|
||||
{
|
||||
size_t payloadlen) {
|
||||
uint8_t *var_gift_payload;
|
||||
size_t var_gift_payloadlen;
|
||||
|
||||
if(payloadlen > 8) {
|
||||
if (payloadlen > 8) {
|
||||
var_gift_payloadlen = payloadlen - 8;
|
||||
} else {
|
||||
var_gift_payloadlen = 0;
|
||||
@ -698,12 +639,12 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
|
||||
payloadlen -= var_gift_payloadlen;
|
||||
|
||||
if(!var_gift_payloadlen) {
|
||||
if (!var_gift_payloadlen) {
|
||||
var_gift_payload = NULL;
|
||||
} else {
|
||||
var_gift_payload = malloc(var_gift_payloadlen);
|
||||
|
||||
if(var_gift_payload == NULL) {
|
||||
if (var_gift_payload == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -717,8 +658,7 @@ int nghttp2_frame_unpack_goaway_payload2(nghttp2_goaway *frame,
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
nghttp2_window_update *frame)
|
||||
{
|
||||
nghttp2_window_update *frame) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
assert(bufs->head == bufs->cur);
|
||||
@ -739,14 +679,12 @@ int nghttp2_frame_pack_window_update(nghttp2_bufs *bufs,
|
||||
|
||||
void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_)
|
||||
{
|
||||
frame->window_size_increment = nghttp2_get_uint32(payload) &
|
||||
NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
||||
size_t payloadlen _U_) {
|
||||
frame->window_size_increment =
|
||||
nghttp2_get_uint32(payload) & NGHTTP2_WINDOW_SIZE_INCREMENT_MASK;
|
||||
}
|
||||
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame)
|
||||
{
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame) {
|
||||
int rv;
|
||||
nghttp2_buf *buf;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
@ -771,30 +709,30 @@ int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame)
|
||||
++buf->last;
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, altsvc->protocol_id, altsvc->protocol_id_len);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = nghttp2_bufs_addb(bufs, altsvc->host_len);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, altsvc->host, altsvc->host_len);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
rv = nghttp2_bufs_add(bufs, altsvc->origin, altsvc->origin_len);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
goto fail;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
|
||||
if(rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
if (rv == NGHTTP2_ERR_BUFFER_ERROR) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
@ -805,8 +743,7 @@ int nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
const uint8_t *payload,
|
||||
size_t payloadlen _U_,
|
||||
uint8_t *var_gift_payload,
|
||||
size_t var_gift_payloadlen)
|
||||
{
|
||||
size_t var_gift_payloadlen) {
|
||||
nghttp2_buf buf;
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
|
||||
@ -824,7 +761,7 @@ int nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
buf.last += var_gift_payloadlen;
|
||||
|
||||
/* 1 for Host-Len */
|
||||
if(nghttp2_buf_len(&buf) < 1 + (ssize_t)altsvc->protocol_id_len) {
|
||||
if (nghttp2_buf_len(&buf) < 1 + (ssize_t)altsvc->protocol_id_len) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
@ -834,7 +771,7 @@ int nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
altsvc->host_len = *buf.pos;
|
||||
++buf.pos;
|
||||
|
||||
if(nghttp2_buf_len(&buf) < (ssize_t)altsvc->host_len) {
|
||||
if (nghttp2_buf_len(&buf) < (ssize_t)altsvc->host_len) {
|
||||
return NGHTTP2_ERR_FRAME_SIZE_ERROR;
|
||||
}
|
||||
|
||||
@ -847,19 +784,18 @@ int nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
size_t niv)
|
||||
{
|
||||
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
size_t niv) {
|
||||
nghttp2_settings_entry *iv_copy;
|
||||
size_t len = niv*sizeof(nghttp2_settings_entry);
|
||||
size_t len = niv * sizeof(nghttp2_settings_entry);
|
||||
|
||||
if(len == 0) {
|
||||
if (len == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
iv_copy = malloc(len);
|
||||
|
||||
if(iv_copy == NULL) {
|
||||
if (iv_copy == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -868,31 +804,26 @@ nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
return iv_copy;
|
||||
}
|
||||
|
||||
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b)
|
||||
{
|
||||
int nghttp2_nv_equal(const nghttp2_nv *a, const nghttp2_nv *b) {
|
||||
return a->namelen == b->namelen && a->valuelen == b->valuelen &&
|
||||
memcmp(a->name, b->name, a->namelen) == 0 &&
|
||||
memcmp(a->value, b->value, a->valuelen) == 0;
|
||||
memcmp(a->name, b->name, a->namelen) == 0 &&
|
||||
memcmp(a->value, b->value, a->valuelen) == 0;
|
||||
}
|
||||
|
||||
void nghttp2_nv_array_del(nghttp2_nv *nva)
|
||||
{
|
||||
free(nva);
|
||||
}
|
||||
void nghttp2_nv_array_del(nghttp2_nv *nva) { free(nva); }
|
||||
|
||||
static int bytes_compar(const uint8_t *a, size_t alen,
|
||||
const uint8_t *b, size_t blen)
|
||||
{
|
||||
static int bytes_compar(const uint8_t *a, size_t alen, const uint8_t *b,
|
||||
size_t blen) {
|
||||
int rv;
|
||||
|
||||
if(alen == blen) {
|
||||
if (alen == blen) {
|
||||
return memcmp(a, b, alen);
|
||||
}
|
||||
|
||||
if(alen < blen) {
|
||||
if (alen < blen) {
|
||||
rv = memcmp(a, b, alen);
|
||||
|
||||
if(rv == 0) {
|
||||
if (rv == 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -901,68 +832,64 @@ static int bytes_compar(const uint8_t *a, size_t alen,
|
||||
|
||||
rv = memcmp(a, b, blen);
|
||||
|
||||
if(rv == 0) {
|
||||
if (rv == 0) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs)
|
||||
{
|
||||
int nghttp2_nv_compare_name(const nghttp2_nv *lhs, const nghttp2_nv *rhs) {
|
||||
return bytes_compar(lhs->name, lhs->namelen, rhs->name, rhs->namelen);
|
||||
}
|
||||
|
||||
static int nv_compar(const void *lhs, const void *rhs)
|
||||
{
|
||||
const nghttp2_nv *a = (const nghttp2_nv*)lhs;
|
||||
const nghttp2_nv *b = (const nghttp2_nv*)rhs;
|
||||
static int nv_compar(const void *lhs, const void *rhs) {
|
||||
const nghttp2_nv *a = (const nghttp2_nv *)lhs;
|
||||
const nghttp2_nv *b = (const nghttp2_nv *)rhs;
|
||||
int rv;
|
||||
|
||||
rv = bytes_compar(a->name, a->namelen, b->name, b->namelen);
|
||||
|
||||
if(rv == 0) {
|
||||
if (rv == 0) {
|
||||
return bytes_compar(a->value, a->valuelen, b->value, b->valuelen);
|
||||
}
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen) {
|
||||
qsort(nva, nvlen, sizeof(nghttp2_nv), nv_compar);
|
||||
}
|
||||
|
||||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
|
||||
const nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
||||
size_t nvlen) {
|
||||
size_t i;
|
||||
uint8_t *data;
|
||||
size_t buflen = 0;
|
||||
nghttp2_nv *p;
|
||||
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
buflen += nva[i].namelen + nva[i].valuelen;
|
||||
}
|
||||
|
||||
if(nvlen == 0) {
|
||||
if (nvlen == 0) {
|
||||
*nva_ptr = NULL;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
buflen += sizeof(nghttp2_nv)*nvlen;
|
||||
buflen += sizeof(nghttp2_nv) * nvlen;
|
||||
|
||||
*nva_ptr = malloc(buflen);
|
||||
|
||||
if(*nva_ptr == NULL) {
|
||||
if (*nva_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
p = *nva_ptr;
|
||||
data = (uint8_t*)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen;
|
||||
data = (uint8_t *)(*nva_ptr) + sizeof(nghttp2_nv) * nvlen;
|
||||
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
p->flags = nva[i].flags;
|
||||
|
||||
memcpy(data, nva[i].name, nva[i].namelen);
|
||||
@ -979,31 +906,30 @@ int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
|
||||
{
|
||||
int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv) {
|
||||
size_t i;
|
||||
for(i = 0; i < niv; ++i) {
|
||||
switch(iv[i].settings_id) {
|
||||
for (i = 0; i < niv; ++i) {
|
||||
switch (iv[i].settings_id) {
|
||||
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
|
||||
if(iv[i].value > NGHTTP2_MAX_HEADER_TABLE_SIZE) {
|
||||
if (iv[i].value > NGHTTP2_MAX_HEADER_TABLE_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS:
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_ENABLE_PUSH:
|
||||
if(iv[i].value != 0 && iv[i].value != 1) {
|
||||
if (iv[i].value != 0 && iv[i].value != 1) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE:
|
||||
if(iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) {
|
||||
if (iv[i].value > (uint32_t)NGHTTP2_MAX_WINDOW_SIZE) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_SETTINGS_MAX_FRAME_SIZE:
|
||||
if(iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
|
||||
iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
|
||||
if (iv[i].value < NGHTTP2_MAX_FRAME_SIZE_MIN ||
|
||||
iv[i].value > NGHTTP2_MAX_FRAME_SIZE_MAX) {
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@ -1014,8 +940,7 @@ int nghttp2_iv_check(const nghttp2_settings_entry *iv, size_t niv)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
|
||||
{
|
||||
static void frame_set_pad(nghttp2_buf *buf, size_t padlen) {
|
||||
size_t trail_padlen;
|
||||
size_t newlen;
|
||||
|
||||
@ -1043,11 +968,10 @@ static void frame_set_pad(nghttp2_buf *buf, size_t padlen)
|
||||
}
|
||||
|
||||
int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
size_t padlen)
|
||||
{
|
||||
size_t padlen) {
|
||||
nghttp2_buf *buf;
|
||||
|
||||
if(padlen == 0) {
|
||||
if (padlen == 0) {
|
||||
DEBUGF(fprintf(stderr, "send: padlen = 0, nothing to do\n"));
|
||||
|
||||
return 0;
|
||||
@ -1082,8 +1006,8 @@ int nghttp2_frame_add_pad(nghttp2_bufs *bufs, nghttp2_frame_hd *hd,
|
||||
hd->length += padlen;
|
||||
hd->flags |= NGHTTP2_FLAG_PADDED;
|
||||
|
||||
DEBUGF(fprintf(stderr, "send: final payloadlen=%zu, padlen=%zu\n",
|
||||
hd->length, padlen));
|
||||
DEBUGF(fprintf(stderr, "send: final payloadlen=%zu, padlen=%zu\n", hd->length,
|
||||
padlen));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_FRAME_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -49,7 +49,7 @@
|
||||
/* The one frame buffer length for tranmission. We may use several of
|
||||
them to support CONTINUATION. To account for Pad Length field, we
|
||||
allocate extra 1 byte, which saves extra large memcopying. */
|
||||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||
#define NGHTTP2_FRAMEBUF_CHUNKLEN \
|
||||
(NGHTTP2_FRAME_HDLEN + 1 + NGHTTP2_MAX_PAYLOADLEN)
|
||||
|
||||
/* Number of inbound buffer */
|
||||
@ -57,7 +57,8 @@
|
||||
|
||||
/* The default length of DATA frame payload. This should be small enough
|
||||
* for the data payload and the header to fit into 1 TLS record */
|
||||
#define NGHTTP2_DATA_PAYLOADLEN ((NGHTTP2_MAX_FRAME_SIZE_MIN) - (NGHTTP2_FRAME_HDLEN))
|
||||
#define NGHTTP2_DATA_PAYLOADLEN \
|
||||
((NGHTTP2_MAX_FRAME_SIZE_MIN) - (NGHTTP2_FRAME_HDLEN))
|
||||
|
||||
/* Maximum headers payload length, calculated in compressed form.
|
||||
This applies to transmission only. */
|
||||
@ -84,21 +85,18 @@
|
||||
#define NGHTTP2_MAX_PADLEN 256
|
||||
|
||||
/* Union of extension frame payload */
|
||||
typedef union {
|
||||
nghttp2_ext_altsvc altsvc;
|
||||
} nghttp2_ext_frame_payload;
|
||||
typedef union { nghttp2_ext_altsvc altsvc; } nghttp2_ext_frame_payload;
|
||||
|
||||
void nghttp2_frame_pack_frame_hd(uint8_t *buf, const nghttp2_frame_hd *hd);
|
||||
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t* buf);
|
||||
void nghttp2_frame_unpack_frame_hd(nghttp2_frame_hd *hd, const uint8_t *buf);
|
||||
|
||||
/**
|
||||
* Initializes frame header |hd| with given parameters. Reserved bit
|
||||
* is set to 0.
|
||||
*/
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length,
|
||||
uint8_t type, uint8_t flags,
|
||||
int32_t stream_id);
|
||||
void nghttp2_frame_hd_init(nghttp2_frame_hd *hd, size_t length, uint8_t type,
|
||||
uint8_t flags, int32_t stream_id);
|
||||
|
||||
/**
|
||||
* Returns the number of priority field depending on the |flags|. If
|
||||
@ -121,8 +119,7 @@ void nghttp2_frame_pack_priority_spec(uint8_t *buf,
|
||||
* assumes the |payload| contains whole priority specification.
|
||||
*/
|
||||
void nghttp2_frame_unpack_priority_spec(nghttp2_priority_spec *pri_spec,
|
||||
uint8_t flags,
|
||||
const uint8_t *payload,
|
||||
uint8_t flags, const uint8_t *payload,
|
||||
size_t payloadlen);
|
||||
|
||||
/*
|
||||
@ -151,8 +148,7 @@ size_t nghttp2_frame_headers_payload_nv_offset(nghttp2_headers *frame);
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs,
|
||||
nghttp2_headers *frame,
|
||||
int nghttp2_frame_pack_headers(nghttp2_bufs *bufs, nghttp2_headers *frame,
|
||||
nghttp2_hd_deflater *deflater);
|
||||
|
||||
/*
|
||||
@ -175,8 +171,7 @@ int nghttp2_frame_unpack_headers_payload(nghttp2_headers *frame,
|
||||
*
|
||||
* This function always succeeds and returns 0.
|
||||
*/
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs,
|
||||
nghttp2_priority *frame);
|
||||
int nghttp2_frame_pack_priority(nghttp2_bufs *bufs, nghttp2_priority *frame);
|
||||
|
||||
/*
|
||||
* Unpacks PRIORITY wire format into |frame|.
|
||||
@ -405,7 +400,6 @@ void nghttp2_frame_unpack_window_update_payload(nghttp2_window_update *frame,
|
||||
*/
|
||||
int nghttp2_frame_pack_altsvc(nghttp2_bufs *bufs, nghttp2_extension *frame);
|
||||
|
||||
|
||||
/*
|
||||
* Unpacks ALTSVC frame byte sequence into |frame|.
|
||||
* The |payload| of length |payloadlen| contains first 8 bytes of
|
||||
@ -434,22 +428,19 @@ int nghttp2_frame_unpack_altsvc_payload(nghttp2_extension *frame,
|
||||
* ownership of |nva|, so caller must not free it. If |stream_id| is
|
||||
* not assigned yet, it must be -1.
|
||||
*/
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
nghttp2_headers_category cat,
|
||||
void nghttp2_frame_headers_init(nghttp2_headers *frame, uint8_t flags,
|
||||
int32_t stream_id, nghttp2_headers_category cat,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void nghttp2_frame_headers_free(nghttp2_headers *frame);
|
||||
|
||||
|
||||
void nghttp2_frame_priority_init(nghttp2_priority *frame, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
void nghttp2_frame_priority_free(nghttp2_priority *frame);
|
||||
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame,
|
||||
int32_t stream_id,
|
||||
void nghttp2_frame_rst_stream_init(nghttp2_rst_stream *frame, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
|
||||
@ -458,8 +449,8 @@ void nghttp2_frame_rst_stream_free(nghttp2_rst_stream *frame);
|
||||
* Initializes PUSH_PROMISE frame |frame| with given values. |frame|
|
||||
* takes ownership of |nva|, so caller must not free it.
|
||||
*/
|
||||
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
void nghttp2_frame_push_promise_init(nghttp2_push_promise *frame, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t promised_stream_id,
|
||||
nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
@ -492,14 +483,13 @@ void nghttp2_frame_ping_free(nghttp2_ping *frame);
|
||||
* free it. If the |opaque_data_len| is 0, opaque_data could be NULL.
|
||||
*/
|
||||
void nghttp2_frame_goaway_init(nghttp2_goaway *frame, int32_t last_stream_id,
|
||||
uint32_t error_code,
|
||||
uint8_t *opaque_data, size_t opaque_data_len);
|
||||
uint32_t error_code, uint8_t *opaque_data,
|
||||
size_t opaque_data_len);
|
||||
|
||||
void nghttp2_frame_goaway_free(nghttp2_goaway *frame);
|
||||
|
||||
void nghttp2_frame_window_update_init(nghttp2_window_update *frame,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
int32_t window_size_increment);
|
||||
|
||||
void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
||||
@ -511,12 +501,10 @@ void nghttp2_frame_window_update_free(nghttp2_window_update *frame);
|
||||
|protocol_id_len|, |host_len| and |origin_len| are all zero,
|
||||
|protocol_id| can be NULL. */
|
||||
void nghttp2_frame_altsvc_init(nghttp2_extension *frame, int32_t stream_id,
|
||||
uint32_t max_age,
|
||||
uint16_t port,
|
||||
uint8_t *protocol_id,
|
||||
size_t protocol_id_len,
|
||||
uint8_t *host, size_t host_len,
|
||||
uint8_t *origin, size_t origin_len);
|
||||
uint32_t max_age, uint16_t port,
|
||||
uint8_t *protocol_id, size_t protocol_id_len,
|
||||
uint8_t *host, size_t host_len, uint8_t *origin,
|
||||
size_t origin_len);
|
||||
|
||||
/*
|
||||
* Frees resources used by |frame|. This function does not free
|
||||
@ -541,7 +529,7 @@ void nghttp2_frame_data_free(nghttp2_data *frame);
|
||||
* entries in |iv|. This function returns the pointer to the copy if
|
||||
* it succeeds, or NULL.
|
||||
*/
|
||||
nghttp2_settings_entry* nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
nghttp2_settings_entry *nghttp2_frame_iv_copy(const nghttp2_settings_entry *iv,
|
||||
size_t niv);
|
||||
|
||||
/*
|
||||
@ -563,8 +551,8 @@ void nghttp2_nv_array_sort(nghttp2_nv *nva, size_t nvlen);
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr,
|
||||
const nghttp2_nv *nva, size_t nvlen);
|
||||
int nghttp2_nv_array_copy(nghttp2_nv **nva_ptr, const nghttp2_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
/*
|
||||
* Returns nonzero if the name/value pair |a| equals to |b|. The name
|
||||
|
896
lib/nghttp2_hd.c
896
lib/nghttp2_hd.c
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_HD_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -183,9 +183,8 @@ struct nghttp2_hd_inflater {
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags,
|
||||
uint8_t *name, size_t namelen,
|
||||
uint8_t *value, size_t valuelen,
|
||||
int nghttp2_hd_entry_init(nghttp2_hd_entry *ent, uint8_t flags, uint8_t *name,
|
||||
size_t namelen, uint8_t *value, size_t valuelen,
|
||||
uint32_t name_hash, uint32_t value_hash);
|
||||
|
||||
void nghttp2_hd_entry_free(nghttp2_hd_entry *ent);
|
||||
@ -248,8 +247,8 @@ void nghttp2_hd_deflate_free(nghttp2_hd_deflater *deflater);
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_hd_deflate_hd_bufs(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_bufs *bufs,
|
||||
const nghttp2_nv *nva, size_t nvlen);
|
||||
nghttp2_bufs *bufs, const nghttp2_nv *nva,
|
||||
size_t nvlen);
|
||||
|
||||
/*
|
||||
* Initializes |inflater| for inflating name/values pairs.
|
||||
@ -279,13 +278,13 @@ int nghttp2_hd_emit_newname_block(nghttp2_bufs *bufs, nghttp2_nv *nv,
|
||||
int nghttp2_hd_emit_table_size(nghttp2_bufs *bufs, size_t table_size);
|
||||
|
||||
/* For unittesting purpose */
|
||||
nghttp2_hd_entry* nghttp2_hd_table_get(nghttp2_hd_context *context,
|
||||
nghttp2_hd_entry *nghttp2_hd_table_get(nghttp2_hd_context *context,
|
||||
size_t index);
|
||||
|
||||
/* For unittesting purpose */
|
||||
ssize_t nghttp2_hd_decode_length(uint32_t *res, size_t *shift_ptr, int *final,
|
||||
uint32_t initial, size_t shift,
|
||||
uint8_t *in, uint8_t *last, size_t prefix);
|
||||
uint32_t initial, size_t shift, uint8_t *in,
|
||||
uint8_t *last, size_t prefix);
|
||||
|
||||
/* Huffman encoding/decoding functions */
|
||||
|
||||
@ -310,8 +309,8 @@ size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len);
|
||||
* NGHTTP2_ERR_BUFFER_ERROR
|
||||
* Out of buffer space.
|
||||
*/
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
|
||||
const uint8_t *src, size_t srclen);
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen);
|
||||
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
||||
|
||||
@ -339,7 +338,7 @@ void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx);
|
||||
* Decoding process has failed.
|
||||
*/
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_bufs *bufs,
|
||||
const uint8_t *src, size_t srclen, int final);
|
||||
nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen, int final);
|
||||
|
||||
#endif /* NGHTTP2_HD_H */
|
||||
|
@ -41,19 +41,17 @@ extern const nghttp2_huff_decode huff_decode_table[][16];
|
||||
* unfilled bits in the pointed location is returned.
|
||||
*/
|
||||
static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
|
||||
size_t rembits,
|
||||
const nghttp2_huff_sym *sym)
|
||||
{
|
||||
size_t rembits, const nghttp2_huff_sym *sym) {
|
||||
int rv;
|
||||
size_t nbits = sym->nbits;
|
||||
|
||||
for(;;) {
|
||||
if(rembits > nbits) {
|
||||
if(*avail_ptr) {
|
||||
for (;;) {
|
||||
if (rembits > nbits) {
|
||||
if (*avail_ptr) {
|
||||
nghttp2_bufs_fast_orb_hold(bufs, sym->code << (rembits - nbits));
|
||||
} else {
|
||||
rv = nghttp2_bufs_orb_hold(bufs, sym->code << (rembits - nbits));
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -65,12 +63,12 @@ static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
|
||||
break;
|
||||
}
|
||||
|
||||
if(*avail_ptr) {
|
||||
if (*avail_ptr) {
|
||||
nghttp2_bufs_fast_orb(bufs, sym->code >> (nbits - rembits));
|
||||
--*avail_ptr;
|
||||
} else {
|
||||
rv = nghttp2_bufs_orb(bufs, sym->code >> (nbits - rembits));
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -80,15 +78,15 @@ static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
|
||||
nbits -= rembits;
|
||||
rembits = 8;
|
||||
|
||||
if(nbits == 0) {
|
||||
if (nbits == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(*avail_ptr) {
|
||||
if (*avail_ptr) {
|
||||
nghttp2_bufs_fast_addb_hold(bufs, 0);
|
||||
} else {
|
||||
rv = nghttp2_bufs_addb_hold(bufs, 0);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -98,21 +96,19 @@ static ssize_t huff_encode_sym(nghttp2_bufs *bufs, size_t *avail_ptr,
|
||||
return (ssize_t)rembits;
|
||||
}
|
||||
|
||||
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len)
|
||||
{
|
||||
size_t nghttp2_hd_huff_encode_count(const uint8_t *src, size_t len) {
|
||||
size_t i;
|
||||
size_t nbits = 0;
|
||||
|
||||
for(i = 0; i < len; ++i) {
|
||||
for (i = 0; i < len; ++i) {
|
||||
nbits += huff_sym_table[src[i]].nbits;
|
||||
}
|
||||
/* pad the prefix of EOS (256) */
|
||||
return (nbits + 7) / 8;
|
||||
}
|
||||
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
|
||||
const uint8_t *src, size_t srclen)
|
||||
{
|
||||
int nghttp2_hd_huff_encode(nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen) {
|
||||
int rv;
|
||||
ssize_t rembits = 8;
|
||||
size_t i;
|
||||
@ -120,34 +116,34 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
|
||||
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
|
||||
for(i = 0; i < srclen; ++i) {
|
||||
for (i = 0; i < srclen; ++i) {
|
||||
const nghttp2_huff_sym *sym = &huff_sym_table[src[i]];
|
||||
if(rembits == 8) {
|
||||
if(avail) {
|
||||
if (rembits == 8) {
|
||||
if (avail) {
|
||||
nghttp2_bufs_fast_addb_hold(bufs, 0);
|
||||
} else {
|
||||
rv = nghttp2_bufs_addb_hold(bufs, 0);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
}
|
||||
}
|
||||
rembits = huff_encode_sym(bufs, &avail, rembits, sym);
|
||||
if(rembits < 0) {
|
||||
if (rembits < 0) {
|
||||
return (int)rembits;
|
||||
}
|
||||
}
|
||||
/* 256 is special terminal symbol, pad with its prefix */
|
||||
if(rembits < 8) {
|
||||
if (rembits < 8) {
|
||||
const nghttp2_huff_sym *sym = &huff_sym_table[256];
|
||||
|
||||
/* Caution we no longer adjust avail here */
|
||||
if(avail) {
|
||||
if (avail) {
|
||||
nghttp2_bufs_fast_orb(bufs, sym->code >> (sym->nbits - rembits));
|
||||
} else {
|
||||
rv = nghttp2_bufs_orb(bufs, sym->code >> (sym->nbits - rembits));
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -156,16 +152,14 @@ int nghttp2_hd_huff_encode(nghttp2_bufs *bufs,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx)
|
||||
{
|
||||
void nghttp2_hd_huff_decode_context_init(nghttp2_hd_huff_decode_context *ctx) {
|
||||
ctx->state = 0;
|
||||
ctx->accept = 1;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
nghttp2_bufs *bufs,
|
||||
const uint8_t *src, size_t srclen, int final)
|
||||
{
|
||||
nghttp2_bufs *bufs, const uint8_t *src,
|
||||
size_t srclen, int final) {
|
||||
size_t i, j;
|
||||
int rv;
|
||||
size_t avail;
|
||||
@ -174,22 +168,22 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
|
||||
/* We use the decoding algorithm described in
|
||||
http://graphics.ics.uci.edu/pub/Prefix.pdf */
|
||||
for(i = 0; i < srclen; ++i) {
|
||||
for (i = 0; i < srclen; ++i) {
|
||||
uint8_t in = src[i] >> 4;
|
||||
for(j = 0; j < 2; ++j) {
|
||||
for (j = 0; j < 2; ++j) {
|
||||
const nghttp2_huff_decode *t;
|
||||
|
||||
t = &huff_decode_table[ctx->state][in];
|
||||
if(t->flags & NGHTTP2_HUFF_FAIL) {
|
||||
if (t->flags & NGHTTP2_HUFF_FAIL) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
if(t->flags & NGHTTP2_HUFF_SYM) {
|
||||
if(avail) {
|
||||
if (t->flags & NGHTTP2_HUFF_SYM) {
|
||||
if (avail) {
|
||||
nghttp2_bufs_fast_addb(bufs, t->sym);
|
||||
--avail;
|
||||
} else {
|
||||
rv = nghttp2_bufs_addb(bufs, t->sym);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
avail = nghttp2_bufs_cur_avail(bufs);
|
||||
@ -200,7 +194,7 @@ ssize_t nghttp2_hd_huff_decode(nghttp2_hd_huff_decode_context *ctx,
|
||||
in = src[i] & 0xf;
|
||||
}
|
||||
}
|
||||
if(final && !ctx->accept) {
|
||||
if (final && !ctx->accept) {
|
||||
return NGHTTP2_ERR_HEADER_COMP;
|
||||
}
|
||||
return (ssize_t)i;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_HD_HUFFMAN_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,42 +29,37 @@
|
||||
|
||||
#include "nghttp2_net.h"
|
||||
|
||||
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n)
|
||||
{
|
||||
void nghttp2_put_uint16be(uint8_t *buf, uint16_t n) {
|
||||
uint16_t x = htons(n);
|
||||
memcpy(buf, &x, sizeof(uint16_t));
|
||||
}
|
||||
|
||||
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n)
|
||||
{
|
||||
void nghttp2_put_uint32be(uint8_t *buf, uint32_t n) {
|
||||
uint32_t x = htonl(n);
|
||||
memcpy(buf, &x, sizeof(uint32_t));
|
||||
}
|
||||
|
||||
uint16_t nghttp2_get_uint16(const uint8_t *data)
|
||||
{
|
||||
uint16_t nghttp2_get_uint16(const uint8_t *data) {
|
||||
uint16_t n;
|
||||
memcpy(&n, data, sizeof(uint16_t));
|
||||
return ntohs(n);
|
||||
}
|
||||
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data)
|
||||
{
|
||||
uint32_t nghttp2_get_uint32(const uint8_t *data) {
|
||||
uint32_t n;
|
||||
memcpy(&n, data, sizeof(uint32_t));
|
||||
return ntohl(n);
|
||||
}
|
||||
|
||||
void* nghttp2_memdup(const void* src, size_t n)
|
||||
{
|
||||
void* dest;
|
||||
void *nghttp2_memdup(const void *src, size_t n) {
|
||||
void *dest;
|
||||
|
||||
if(n == 0) {
|
||||
if (n == 0) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dest = malloc(n);
|
||||
if(dest == NULL) {
|
||||
if (dest == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
memcpy(dest, src, n);
|
||||
@ -73,76 +68,75 @@ void* nghttp2_memdup(const void* src, size_t n)
|
||||
|
||||
/* Generated by gendowncasetbl.py */
|
||||
static const int DOWNCASE_TBL[] = {
|
||||
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
|
||||
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
|
||||
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
|
||||
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
|
||||
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
|
||||
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
|
||||
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
|
||||
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
|
||||
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
|
||||
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
|
||||
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
|
||||
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
|
||||
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
|
||||
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
|
||||
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
|
||||
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
|
||||
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
|
||||
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
|
||||
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
|
||||
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
|
||||
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
|
||||
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
|
||||
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
|
||||
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
|
||||
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
|
||||
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
|
||||
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
|
||||
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
|
||||
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
|
||||
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
|
||||
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
|
||||
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
|
||||
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
|
||||
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
|
||||
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
|
||||
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
|
||||
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
|
||||
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
|
||||
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
|
||||
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
|
||||
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
|
||||
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
|
||||
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
|
||||
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
|
||||
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
|
||||
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
|
||||
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
|
||||
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
|
||||
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
|
||||
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
|
||||
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
|
||||
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
|
||||
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
|
||||
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
|
||||
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
|
||||
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
|
||||
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
|
||||
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
|
||||
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
|
||||
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
|
||||
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
|
||||
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
|
||||
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
|
||||
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
|
||||
0 /* NUL */, 1 /* SOH */, 2 /* STX */, 3 /* ETX */,
|
||||
4 /* EOT */, 5 /* ENQ */, 6 /* ACK */, 7 /* BEL */,
|
||||
8 /* BS */, 9 /* HT */, 10 /* LF */, 11 /* VT */,
|
||||
12 /* FF */, 13 /* CR */, 14 /* SO */, 15 /* SI */,
|
||||
16 /* DLE */, 17 /* DC1 */, 18 /* DC2 */, 19 /* DC3 */,
|
||||
20 /* DC4 */, 21 /* NAK */, 22 /* SYN */, 23 /* ETB */,
|
||||
24 /* CAN */, 25 /* EM */, 26 /* SUB */, 27 /* ESC */,
|
||||
28 /* FS */, 29 /* GS */, 30 /* RS */, 31 /* US */,
|
||||
32 /* SPC */, 33 /* ! */, 34 /* " */, 35 /* # */,
|
||||
36 /* $ */, 37 /* % */, 38 /* & */, 39 /* ' */,
|
||||
40 /* ( */, 41 /* ) */, 42 /* * */, 43 /* + */,
|
||||
44 /* , */, 45 /* - */, 46 /* . */, 47 /* / */,
|
||||
48 /* 0 */, 49 /* 1 */, 50 /* 2 */, 51 /* 3 */,
|
||||
52 /* 4 */, 53 /* 5 */, 54 /* 6 */, 55 /* 7 */,
|
||||
56 /* 8 */, 57 /* 9 */, 58 /* : */, 59 /* ; */,
|
||||
60 /* < */, 61 /* = */, 62 /* > */, 63 /* ? */,
|
||||
64 /* @ */, 97 /* A */, 98 /* B */, 99 /* C */,
|
||||
100 /* D */, 101 /* E */, 102 /* F */, 103 /* G */,
|
||||
104 /* H */, 105 /* I */, 106 /* J */, 107 /* K */,
|
||||
108 /* L */, 109 /* M */, 110 /* N */, 111 /* O */,
|
||||
112 /* P */, 113 /* Q */, 114 /* R */, 115 /* S */,
|
||||
116 /* T */, 117 /* U */, 118 /* V */, 119 /* W */,
|
||||
120 /* X */, 121 /* Y */, 122 /* Z */, 91 /* [ */,
|
||||
92 /* \ */, 93 /* ] */, 94 /* ^ */, 95 /* _ */,
|
||||
96 /* ` */, 97 /* a */, 98 /* b */, 99 /* c */,
|
||||
100 /* d */, 101 /* e */, 102 /* f */, 103 /* g */,
|
||||
104 /* h */, 105 /* i */, 106 /* j */, 107 /* k */,
|
||||
108 /* l */, 109 /* m */, 110 /* n */, 111 /* o */,
|
||||
112 /* p */, 113 /* q */, 114 /* r */, 115 /* s */,
|
||||
116 /* t */, 117 /* u */, 118 /* v */, 119 /* w */,
|
||||
120 /* x */, 121 /* y */, 122 /* z */, 123 /* { */,
|
||||
124 /* | */, 125 /* } */, 126 /* ~ */, 127 /* DEL */,
|
||||
128 /* 0x80 */, 129 /* 0x81 */, 130 /* 0x82 */, 131 /* 0x83 */,
|
||||
132 /* 0x84 */, 133 /* 0x85 */, 134 /* 0x86 */, 135 /* 0x87 */,
|
||||
136 /* 0x88 */, 137 /* 0x89 */, 138 /* 0x8a */, 139 /* 0x8b */,
|
||||
140 /* 0x8c */, 141 /* 0x8d */, 142 /* 0x8e */, 143 /* 0x8f */,
|
||||
144 /* 0x90 */, 145 /* 0x91 */, 146 /* 0x92 */, 147 /* 0x93 */,
|
||||
148 /* 0x94 */, 149 /* 0x95 */, 150 /* 0x96 */, 151 /* 0x97 */,
|
||||
152 /* 0x98 */, 153 /* 0x99 */, 154 /* 0x9a */, 155 /* 0x9b */,
|
||||
156 /* 0x9c */, 157 /* 0x9d */, 158 /* 0x9e */, 159 /* 0x9f */,
|
||||
160 /* 0xa0 */, 161 /* 0xa1 */, 162 /* 0xa2 */, 163 /* 0xa3 */,
|
||||
164 /* 0xa4 */, 165 /* 0xa5 */, 166 /* 0xa6 */, 167 /* 0xa7 */,
|
||||
168 /* 0xa8 */, 169 /* 0xa9 */, 170 /* 0xaa */, 171 /* 0xab */,
|
||||
172 /* 0xac */, 173 /* 0xad */, 174 /* 0xae */, 175 /* 0xaf */,
|
||||
176 /* 0xb0 */, 177 /* 0xb1 */, 178 /* 0xb2 */, 179 /* 0xb3 */,
|
||||
180 /* 0xb4 */, 181 /* 0xb5 */, 182 /* 0xb6 */, 183 /* 0xb7 */,
|
||||
184 /* 0xb8 */, 185 /* 0xb9 */, 186 /* 0xba */, 187 /* 0xbb */,
|
||||
188 /* 0xbc */, 189 /* 0xbd */, 190 /* 0xbe */, 191 /* 0xbf */,
|
||||
192 /* 0xc0 */, 193 /* 0xc1 */, 194 /* 0xc2 */, 195 /* 0xc3 */,
|
||||
196 /* 0xc4 */, 197 /* 0xc5 */, 198 /* 0xc6 */, 199 /* 0xc7 */,
|
||||
200 /* 0xc8 */, 201 /* 0xc9 */, 202 /* 0xca */, 203 /* 0xcb */,
|
||||
204 /* 0xcc */, 205 /* 0xcd */, 206 /* 0xce */, 207 /* 0xcf */,
|
||||
208 /* 0xd0 */, 209 /* 0xd1 */, 210 /* 0xd2 */, 211 /* 0xd3 */,
|
||||
212 /* 0xd4 */, 213 /* 0xd5 */, 214 /* 0xd6 */, 215 /* 0xd7 */,
|
||||
216 /* 0xd8 */, 217 /* 0xd9 */, 218 /* 0xda */, 219 /* 0xdb */,
|
||||
220 /* 0xdc */, 221 /* 0xdd */, 222 /* 0xde */, 223 /* 0xdf */,
|
||||
224 /* 0xe0 */, 225 /* 0xe1 */, 226 /* 0xe2 */, 227 /* 0xe3 */,
|
||||
228 /* 0xe4 */, 229 /* 0xe5 */, 230 /* 0xe6 */, 231 /* 0xe7 */,
|
||||
232 /* 0xe8 */, 233 /* 0xe9 */, 234 /* 0xea */, 235 /* 0xeb */,
|
||||
236 /* 0xec */, 237 /* 0xed */, 238 /* 0xee */, 239 /* 0xef */,
|
||||
240 /* 0xf0 */, 241 /* 0xf1 */, 242 /* 0xf2 */, 243 /* 0xf3 */,
|
||||
244 /* 0xf4 */, 245 /* 0xf5 */, 246 /* 0xf6 */, 247 /* 0xf7 */,
|
||||
248 /* 0xf8 */, 249 /* 0xf9 */, 250 /* 0xfa */, 251 /* 0xfb */,
|
||||
252 /* 0xfc */, 253 /* 0xfd */, 254 /* 0xfe */, 255 /* 0xff */,
|
||||
};
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len)
|
||||
{
|
||||
void nghttp2_downcase(uint8_t *s, size_t len) {
|
||||
size_t i;
|
||||
for(i = 0; i < len; ++i) {
|
||||
for (i = 0; i < len; ++i) {
|
||||
s[i] = DOWNCASE_TBL[s[i]];
|
||||
}
|
||||
}
|
||||
@ -176,26 +170,25 @@ void nghttp2_downcase(uint8_t *s, size_t len)
|
||||
int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
int32_t *recv_window_size_ptr,
|
||||
int32_t *recv_reduction_ptr,
|
||||
int32_t *delta_ptr)
|
||||
{
|
||||
if(*delta_ptr > 0) {
|
||||
int32_t *delta_ptr) {
|
||||
if (*delta_ptr > 0) {
|
||||
int32_t new_recv_window_size =
|
||||
nghttp2_max(0, *recv_window_size_ptr) - *delta_ptr;
|
||||
if(new_recv_window_size < 0) {
|
||||
nghttp2_max(0, *recv_window_size_ptr) - *delta_ptr;
|
||||
if (new_recv_window_size < 0) {
|
||||
/* The delta size is strictly more than received bytes. Increase
|
||||
local_window_size by that difference. */
|
||||
int32_t recv_reduction_diff;
|
||||
if(*local_window_size_ptr >
|
||||
NGHTTP2_MAX_WINDOW_SIZE + new_recv_window_size) {
|
||||
if (*local_window_size_ptr >
|
||||
NGHTTP2_MAX_WINDOW_SIZE + new_recv_window_size) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
*local_window_size_ptr -= new_recv_window_size;
|
||||
/* If there is recv_reduction due to earlier window_size
|
||||
reduction, we have to adjust it too. */
|
||||
recv_reduction_diff = nghttp2_min(*recv_reduction_ptr,
|
||||
-new_recv_window_size);
|
||||
recv_reduction_diff =
|
||||
nghttp2_min(*recv_reduction_ptr, -new_recv_window_size);
|
||||
*recv_reduction_ptr -= recv_reduction_diff;
|
||||
if(*recv_window_size_ptr < 0) {
|
||||
if (*recv_window_size_ptr < 0) {
|
||||
*recv_window_size_ptr += recv_reduction_diff;
|
||||
} else {
|
||||
/* If *recv_window_size_ptr > 0, then those bytes are going to
|
||||
@ -213,9 +206,9 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
if(*local_window_size_ptr + *delta_ptr < 0 ||
|
||||
*recv_window_size_ptr < INT32_MIN - *delta_ptr ||
|
||||
*recv_reduction_ptr > INT32_MAX + *delta_ptr) {
|
||||
if (*local_window_size_ptr + *delta_ptr < 0 ||
|
||||
*recv_window_size_ptr < INT32_MIN - *delta_ptr ||
|
||||
*recv_reduction_ptr > INT32_MAX + *delta_ptr) {
|
||||
return NGHTTP2_ERR_FLOW_CONTROL;
|
||||
}
|
||||
/* Decreasing local window size. Note that we achieve this without
|
||||
@ -231,14 +224,12 @@ int nghttp2_adjust_local_window_size(int32_t *local_window_size_ptr,
|
||||
}
|
||||
|
||||
int nghttp2_should_send_window_update(int32_t local_window_size,
|
||||
int32_t recv_window_size)
|
||||
{
|
||||
int32_t recv_window_size) {
|
||||
return recv_window_size >= local_window_size / 2;
|
||||
}
|
||||
|
||||
const char* nghttp2_strerror(int error_code)
|
||||
{
|
||||
switch(error_code) {
|
||||
const char *nghttp2_strerror(int error_code) {
|
||||
switch (error_code) {
|
||||
case 0:
|
||||
return "Success";
|
||||
case NGHTTP2_ERR_INVALID_ARGUMENT:
|
||||
@ -308,94 +299,78 @@ const char* nghttp2_strerror(int error_code)
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_free(void *ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
void nghttp2_free(void *ptr) { free(ptr); }
|
||||
|
||||
/* Generated by gennmchartbl.py */
|
||||
static int VALID_HD_NAME_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 0 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
0 /* SPC */, 1 /* ! */, 0 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */,
|
||||
0 /* , */, 1 /* - */, 1 /* . */, 0 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */,
|
||||
0 /* @ */, 0 /* A */, 0 /* B */, 0 /* C */,
|
||||
0 /* D */, 0 /* E */, 0 /* F */, 0 /* G */,
|
||||
0 /* H */, 0 /* I */, 0 /* J */, 0 /* K */,
|
||||
0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */,
|
||||
0 /* T */, 0 /* U */, 0 /* V */, 0 /* W */,
|
||||
0 /* X */, 0 /* Y */, 0 /* Z */, 0 /* [ */,
|
||||
0 /* \ */, 0 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */,
|
||||
1 /* | */, 0 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
0 /* 0x80 */, 0 /* 0x81 */, 0 /* 0x82 */, 0 /* 0x83 */,
|
||||
0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */, 0 /* 0x87 */,
|
||||
0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */,
|
||||
0 /* 0x90 */, 0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */,
|
||||
0 /* 0x94 */, 0 /* 0x95 */, 0 /* 0x96 */, 0 /* 0x97 */,
|
||||
0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */, 0 /* 0x9b */,
|
||||
0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */,
|
||||
0 /* 0xa4 */, 0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */,
|
||||
0 /* 0xa8 */, 0 /* 0xa9 */, 0 /* 0xaa */, 0 /* 0xab */,
|
||||
0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */, 0 /* 0xaf */,
|
||||
0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */,
|
||||
0 /* 0xb8 */, 0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */,
|
||||
0 /* 0xbc */, 0 /* 0xbd */, 0 /* 0xbe */, 0 /* 0xbf */,
|
||||
0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */, 0 /* 0xc3 */,
|
||||
0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */,
|
||||
0 /* 0xcc */, 0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */,
|
||||
0 /* 0xd0 */, 0 /* 0xd1 */, 0 /* 0xd2 */, 0 /* 0xd3 */,
|
||||
0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */, 0 /* 0xd7 */,
|
||||
0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */,
|
||||
0 /* 0xe0 */, 0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */,
|
||||
0 /* 0xe4 */, 0 /* 0xe5 */, 0 /* 0xe6 */, 0 /* 0xe7 */,
|
||||
0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */, 0 /* 0xeb */,
|
||||
0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */,
|
||||
0 /* 0xf4 */, 0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */,
|
||||
0 /* 0xf8 */, 0 /* 0xf9 */, 0 /* 0xfa */, 0 /* 0xfb */,
|
||||
0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */, 0 /* 0xff */
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 0 /* HT */,
|
||||
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||
0 /* RS */, 0 /* US */, 0 /* SPC */, 1 /* ! */, 0 /* " */,
|
||||
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
0 /* ( */, 0 /* ) */, 1 /* * */, 1 /* + */, 0 /* , */,
|
||||
1 /* - */, 1 /* . */, 0 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 0 /* : */, 0 /* ; */,
|
||||
0 /* < */, 0 /* = */, 0 /* > */, 0 /* ? */, 0 /* @ */,
|
||||
0 /* A */, 0 /* B */, 0 /* C */, 0 /* D */, 0 /* E */,
|
||||
0 /* F */, 0 /* G */, 0 /* H */, 0 /* I */, 0 /* J */,
|
||||
0 /* K */, 0 /* L */, 0 /* M */, 0 /* N */, 0 /* O */,
|
||||
0 /* P */, 0 /* Q */, 0 /* R */, 0 /* S */, 0 /* T */,
|
||||
0 /* U */, 0 /* V */, 0 /* W */, 0 /* X */, 0 /* Y */,
|
||||
0 /* Z */, 0 /* [ */, 0 /* \ */, 0 /* ] */, 1 /* ^ */,
|
||||
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 0 /* { */, 1 /* | */,
|
||||
0 /* } */, 1 /* ~ */, 0 /* DEL */, 0 /* 0x80 */, 0 /* 0x81 */,
|
||||
0 /* 0x82 */, 0 /* 0x83 */, 0 /* 0x84 */, 0 /* 0x85 */, 0 /* 0x86 */,
|
||||
0 /* 0x87 */, 0 /* 0x88 */, 0 /* 0x89 */, 0 /* 0x8a */, 0 /* 0x8b */,
|
||||
0 /* 0x8c */, 0 /* 0x8d */, 0 /* 0x8e */, 0 /* 0x8f */, 0 /* 0x90 */,
|
||||
0 /* 0x91 */, 0 /* 0x92 */, 0 /* 0x93 */, 0 /* 0x94 */, 0 /* 0x95 */,
|
||||
0 /* 0x96 */, 0 /* 0x97 */, 0 /* 0x98 */, 0 /* 0x99 */, 0 /* 0x9a */,
|
||||
0 /* 0x9b */, 0 /* 0x9c */, 0 /* 0x9d */, 0 /* 0x9e */, 0 /* 0x9f */,
|
||||
0 /* 0xa0 */, 0 /* 0xa1 */, 0 /* 0xa2 */, 0 /* 0xa3 */, 0 /* 0xa4 */,
|
||||
0 /* 0xa5 */, 0 /* 0xa6 */, 0 /* 0xa7 */, 0 /* 0xa8 */, 0 /* 0xa9 */,
|
||||
0 /* 0xaa */, 0 /* 0xab */, 0 /* 0xac */, 0 /* 0xad */, 0 /* 0xae */,
|
||||
0 /* 0xaf */, 0 /* 0xb0 */, 0 /* 0xb1 */, 0 /* 0xb2 */, 0 /* 0xb3 */,
|
||||
0 /* 0xb4 */, 0 /* 0xb5 */, 0 /* 0xb6 */, 0 /* 0xb7 */, 0 /* 0xb8 */,
|
||||
0 /* 0xb9 */, 0 /* 0xba */, 0 /* 0xbb */, 0 /* 0xbc */, 0 /* 0xbd */,
|
||||
0 /* 0xbe */, 0 /* 0xbf */, 0 /* 0xc0 */, 0 /* 0xc1 */, 0 /* 0xc2 */,
|
||||
0 /* 0xc3 */, 0 /* 0xc4 */, 0 /* 0xc5 */, 0 /* 0xc6 */, 0 /* 0xc7 */,
|
||||
0 /* 0xc8 */, 0 /* 0xc9 */, 0 /* 0xca */, 0 /* 0xcb */, 0 /* 0xcc */,
|
||||
0 /* 0xcd */, 0 /* 0xce */, 0 /* 0xcf */, 0 /* 0xd0 */, 0 /* 0xd1 */,
|
||||
0 /* 0xd2 */, 0 /* 0xd3 */, 0 /* 0xd4 */, 0 /* 0xd5 */, 0 /* 0xd6 */,
|
||||
0 /* 0xd7 */, 0 /* 0xd8 */, 0 /* 0xd9 */, 0 /* 0xda */, 0 /* 0xdb */,
|
||||
0 /* 0xdc */, 0 /* 0xdd */, 0 /* 0xde */, 0 /* 0xdf */, 0 /* 0xe0 */,
|
||||
0 /* 0xe1 */, 0 /* 0xe2 */, 0 /* 0xe3 */, 0 /* 0xe4 */, 0 /* 0xe5 */,
|
||||
0 /* 0xe6 */, 0 /* 0xe7 */, 0 /* 0xe8 */, 0 /* 0xe9 */, 0 /* 0xea */,
|
||||
0 /* 0xeb */, 0 /* 0xec */, 0 /* 0xed */, 0 /* 0xee */, 0 /* 0xef */,
|
||||
0 /* 0xf0 */, 0 /* 0xf1 */, 0 /* 0xf2 */, 0 /* 0xf3 */, 0 /* 0xf4 */,
|
||||
0 /* 0xf5 */, 0 /* 0xf6 */, 0 /* 0xf7 */, 0 /* 0xf8 */, 0 /* 0xf9 */,
|
||||
0 /* 0xfa */, 0 /* 0xfb */, 0 /* 0xfc */, 0 /* 0xfd */, 0 /* 0xfe */,
|
||||
0 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_header_name(const uint8_t *name, size_t len)
|
||||
{
|
||||
int nghttp2_check_header_name(const uint8_t *name, size_t len) {
|
||||
const uint8_t *last;
|
||||
if(len == 0) {
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
if(*name == ':') {
|
||||
if(len == 1) {
|
||||
if (*name == ':') {
|
||||
if (len == 1) {
|
||||
return 0;
|
||||
}
|
||||
++name;
|
||||
--len;
|
||||
}
|
||||
for(last = name + len; name != last; ++name) {
|
||||
if(!VALID_HD_NAME_CHARS[*name]) {
|
||||
for (last = name + len; name != last; ++name) {
|
||||
if (!VALID_HD_NAME_CHARS[*name]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@ -404,85 +379,71 @@ int nghttp2_check_header_name(const uint8_t *name, size_t len)
|
||||
|
||||
/* Generated by genvchartbl.py */
|
||||
static int VALID_HD_VALUE_CHARS[] = {
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */,
|
||||
0 /* EOT */, 0 /* ENQ */, 0 /* ACK */, 0 /* BEL */,
|
||||
0 /* BS */, 1 /* HT */, 0 /* LF */, 0 /* VT */,
|
||||
0 /* FF */, 0 /* CR */, 0 /* SO */, 0 /* SI */,
|
||||
0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */,
|
||||
0 /* CAN */, 0 /* EM */, 0 /* SUB */, 0 /* ESC */,
|
||||
0 /* FS */, 0 /* GS */, 0 /* RS */, 0 /* US */,
|
||||
1 /* SPC */, 1 /* ! */, 1 /* " */, 1 /* # */,
|
||||
1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */,
|
||||
1 /* , */, 1 /* - */, 1 /* . */, 1 /* / */,
|
||||
1 /* 0 */, 1 /* 1 */, 1 /* 2 */, 1 /* 3 */,
|
||||
1 /* 4 */, 1 /* 5 */, 1 /* 6 */, 1 /* 7 */,
|
||||
1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */,
|
||||
1 /* @ */, 1 /* A */, 1 /* B */, 1 /* C */,
|
||||
1 /* D */, 1 /* E */, 1 /* F */, 1 /* G */,
|
||||
1 /* H */, 1 /* I */, 1 /* J */, 1 /* K */,
|
||||
1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */,
|
||||
1 /* T */, 1 /* U */, 1 /* V */, 1 /* W */,
|
||||
1 /* X */, 1 /* Y */, 1 /* Z */, 1 /* [ */,
|
||||
1 /* \ */, 1 /* ] */, 1 /* ^ */, 1 /* _ */,
|
||||
1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */,
|
||||
1 /* h */, 1 /* i */, 1 /* j */, 1 /* k */,
|
||||
1 /* l */, 1 /* m */, 1 /* n */, 1 /* o */,
|
||||
1 /* p */, 1 /* q */, 1 /* r */, 1 /* s */,
|
||||
1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */,
|
||||
1 /* | */, 1 /* } */, 1 /* ~ */, 0 /* DEL */,
|
||||
1 /* 0x80 */, 1 /* 0x81 */, 1 /* 0x82 */, 1 /* 0x83 */,
|
||||
1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */, 1 /* 0x87 */,
|
||||
1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
|
||||
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */,
|
||||
1 /* 0x90 */, 1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */,
|
||||
1 /* 0x94 */, 1 /* 0x95 */, 1 /* 0x96 */, 1 /* 0x97 */,
|
||||
1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */, 1 /* 0x9b */,
|
||||
1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
|
||||
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */,
|
||||
1 /* 0xa4 */, 1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */,
|
||||
1 /* 0xa8 */, 1 /* 0xa9 */, 1 /* 0xaa */, 1 /* 0xab */,
|
||||
1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */, 1 /* 0xaf */,
|
||||
1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
|
||||
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */,
|
||||
1 /* 0xb8 */, 1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */,
|
||||
1 /* 0xbc */, 1 /* 0xbd */, 1 /* 0xbe */, 1 /* 0xbf */,
|
||||
1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */, 1 /* 0xc3 */,
|
||||
1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
|
||||
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */,
|
||||
1 /* 0xcc */, 1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */,
|
||||
1 /* 0xd0 */, 1 /* 0xd1 */, 1 /* 0xd2 */, 1 /* 0xd3 */,
|
||||
1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */, 1 /* 0xd7 */,
|
||||
1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
|
||||
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */,
|
||||
1 /* 0xe0 */, 1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */,
|
||||
1 /* 0xe4 */, 1 /* 0xe5 */, 1 /* 0xe6 */, 1 /* 0xe7 */,
|
||||
1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */, 1 /* 0xeb */,
|
||||
1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
|
||||
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */,
|
||||
1 /* 0xf4 */, 1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */,
|
||||
1 /* 0xf8 */, 1 /* 0xf9 */, 1 /* 0xfa */, 1 /* 0xfb */,
|
||||
1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */, 1 /* 0xff */
|
||||
0 /* NUL */, 0 /* SOH */, 0 /* STX */, 0 /* ETX */, 0 /* EOT */,
|
||||
0 /* ENQ */, 0 /* ACK */, 0 /* BEL */, 0 /* BS */, 1 /* HT */,
|
||||
0 /* LF */, 0 /* VT */, 0 /* FF */, 0 /* CR */, 0 /* SO */,
|
||||
0 /* SI */, 0 /* DLE */, 0 /* DC1 */, 0 /* DC2 */, 0 /* DC3 */,
|
||||
0 /* DC4 */, 0 /* NAK */, 0 /* SYN */, 0 /* ETB */, 0 /* CAN */,
|
||||
0 /* EM */, 0 /* SUB */, 0 /* ESC */, 0 /* FS */, 0 /* GS */,
|
||||
0 /* RS */, 0 /* US */, 1 /* SPC */, 1 /* ! */, 1 /* " */,
|
||||
1 /* # */, 1 /* $ */, 1 /* % */, 1 /* & */, 1 /* ' */,
|
||||
1 /* ( */, 1 /* ) */, 1 /* * */, 1 /* + */, 1 /* , */,
|
||||
1 /* - */, 1 /* . */, 1 /* / */, 1 /* 0 */, 1 /* 1 */,
|
||||
1 /* 2 */, 1 /* 3 */, 1 /* 4 */, 1 /* 5 */, 1 /* 6 */,
|
||||
1 /* 7 */, 1 /* 8 */, 1 /* 9 */, 1 /* : */, 1 /* ; */,
|
||||
1 /* < */, 1 /* = */, 1 /* > */, 1 /* ? */, 1 /* @ */,
|
||||
1 /* A */, 1 /* B */, 1 /* C */, 1 /* D */, 1 /* E */,
|
||||
1 /* F */, 1 /* G */, 1 /* H */, 1 /* I */, 1 /* J */,
|
||||
1 /* K */, 1 /* L */, 1 /* M */, 1 /* N */, 1 /* O */,
|
||||
1 /* P */, 1 /* Q */, 1 /* R */, 1 /* S */, 1 /* T */,
|
||||
1 /* U */, 1 /* V */, 1 /* W */, 1 /* X */, 1 /* Y */,
|
||||
1 /* Z */, 1 /* [ */, 1 /* \ */, 1 /* ] */, 1 /* ^ */,
|
||||
1 /* _ */, 1 /* ` */, 1 /* a */, 1 /* b */, 1 /* c */,
|
||||
1 /* d */, 1 /* e */, 1 /* f */, 1 /* g */, 1 /* h */,
|
||||
1 /* i */, 1 /* j */, 1 /* k */, 1 /* l */, 1 /* m */,
|
||||
1 /* n */, 1 /* o */, 1 /* p */, 1 /* q */, 1 /* r */,
|
||||
1 /* s */, 1 /* t */, 1 /* u */, 1 /* v */, 1 /* w */,
|
||||
1 /* x */, 1 /* y */, 1 /* z */, 1 /* { */, 1 /* | */,
|
||||
1 /* } */, 1 /* ~ */, 0 /* DEL */, 1 /* 0x80 */, 1 /* 0x81 */,
|
||||
1 /* 0x82 */, 1 /* 0x83 */, 1 /* 0x84 */, 1 /* 0x85 */, 1 /* 0x86 */,
|
||||
1 /* 0x87 */, 1 /* 0x88 */, 1 /* 0x89 */, 1 /* 0x8a */, 1 /* 0x8b */,
|
||||
1 /* 0x8c */, 1 /* 0x8d */, 1 /* 0x8e */, 1 /* 0x8f */, 1 /* 0x90 */,
|
||||
1 /* 0x91 */, 1 /* 0x92 */, 1 /* 0x93 */, 1 /* 0x94 */, 1 /* 0x95 */,
|
||||
1 /* 0x96 */, 1 /* 0x97 */, 1 /* 0x98 */, 1 /* 0x99 */, 1 /* 0x9a */,
|
||||
1 /* 0x9b */, 1 /* 0x9c */, 1 /* 0x9d */, 1 /* 0x9e */, 1 /* 0x9f */,
|
||||
1 /* 0xa0 */, 1 /* 0xa1 */, 1 /* 0xa2 */, 1 /* 0xa3 */, 1 /* 0xa4 */,
|
||||
1 /* 0xa5 */, 1 /* 0xa6 */, 1 /* 0xa7 */, 1 /* 0xa8 */, 1 /* 0xa9 */,
|
||||
1 /* 0xaa */, 1 /* 0xab */, 1 /* 0xac */, 1 /* 0xad */, 1 /* 0xae */,
|
||||
1 /* 0xaf */, 1 /* 0xb0 */, 1 /* 0xb1 */, 1 /* 0xb2 */, 1 /* 0xb3 */,
|
||||
1 /* 0xb4 */, 1 /* 0xb5 */, 1 /* 0xb6 */, 1 /* 0xb7 */, 1 /* 0xb8 */,
|
||||
1 /* 0xb9 */, 1 /* 0xba */, 1 /* 0xbb */, 1 /* 0xbc */, 1 /* 0xbd */,
|
||||
1 /* 0xbe */, 1 /* 0xbf */, 1 /* 0xc0 */, 1 /* 0xc1 */, 1 /* 0xc2 */,
|
||||
1 /* 0xc3 */, 1 /* 0xc4 */, 1 /* 0xc5 */, 1 /* 0xc6 */, 1 /* 0xc7 */,
|
||||
1 /* 0xc8 */, 1 /* 0xc9 */, 1 /* 0xca */, 1 /* 0xcb */, 1 /* 0xcc */,
|
||||
1 /* 0xcd */, 1 /* 0xce */, 1 /* 0xcf */, 1 /* 0xd0 */, 1 /* 0xd1 */,
|
||||
1 /* 0xd2 */, 1 /* 0xd3 */, 1 /* 0xd4 */, 1 /* 0xd5 */, 1 /* 0xd6 */,
|
||||
1 /* 0xd7 */, 1 /* 0xd8 */, 1 /* 0xd9 */, 1 /* 0xda */, 1 /* 0xdb */,
|
||||
1 /* 0xdc */, 1 /* 0xdd */, 1 /* 0xde */, 1 /* 0xdf */, 1 /* 0xe0 */,
|
||||
1 /* 0xe1 */, 1 /* 0xe2 */, 1 /* 0xe3 */, 1 /* 0xe4 */, 1 /* 0xe5 */,
|
||||
1 /* 0xe6 */, 1 /* 0xe7 */, 1 /* 0xe8 */, 1 /* 0xe9 */, 1 /* 0xea */,
|
||||
1 /* 0xeb */, 1 /* 0xec */, 1 /* 0xed */, 1 /* 0xee */, 1 /* 0xef */,
|
||||
1 /* 0xf0 */, 1 /* 0xf1 */, 1 /* 0xf2 */, 1 /* 0xf3 */, 1 /* 0xf4 */,
|
||||
1 /* 0xf5 */, 1 /* 0xf6 */, 1 /* 0xf7 */, 1 /* 0xf8 */, 1 /* 0xf9 */,
|
||||
1 /* 0xfa */, 1 /* 0xfb */, 1 /* 0xfc */, 1 /* 0xfd */, 1 /* 0xfe */,
|
||||
1 /* 0xff */
|
||||
};
|
||||
|
||||
int nghttp2_check_header_value(const uint8_t *value, size_t len)
|
||||
{
|
||||
int nghttp2_check_header_value(const uint8_t *value, size_t len) {
|
||||
const uint8_t *last;
|
||||
for(last = value + len; value != last; ++value) {
|
||||
if(!VALID_HD_VALUE_CHARS[*value]) {
|
||||
for (last = value + len; value != last; ++value) {
|
||||
if (!VALID_HD_VALUE_CHARS[*value]) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t* nghttp2_cpymem(uint8_t *dest, const void *src, size_t len)
|
||||
{
|
||||
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len) {
|
||||
memcpy(dest, src, len);
|
||||
|
||||
return dest + len;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_HELPER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -68,7 +68,7 @@ uint32_t nghttp2_get_uint32(const uint8_t *data);
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
void* nghttp2_memdup(const void* src, size_t n);
|
||||
void *nghttp2_memdup(const void *src, size_t n);
|
||||
|
||||
void nghttp2_downcase(uint8_t *s, size_t len);
|
||||
|
||||
@ -112,6 +112,6 @@ void nghttp2_free(void *ptr);
|
||||
* by the |dest|, assuming that the |dest| is at lest |len| bytes long
|
||||
* . Returns dest + len.
|
||||
*/
|
||||
uint8_t* nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
|
||||
uint8_t *nghttp2_cpymem(uint8_t *dest, const void *src, size_t len);
|
||||
|
||||
#endif /* NGHTTP2_HELPER_H */
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_INT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
/* Macros, types and constants for internal use */
|
||||
@ -34,7 +34,9 @@
|
||||
#ifdef DEBUGBUILD
|
||||
#define DEBUGF(x) x
|
||||
#else
|
||||
#define DEBUGF(x) do { } while(0)
|
||||
#define DEBUGF(x) \
|
||||
do { \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
typedef int (*nghttp2_compar)(const void *lhs, const void *rhs);
|
||||
|
@ -28,11 +28,10 @@
|
||||
|
||||
#define INITIAL_TABLE_LENGTH 256
|
||||
|
||||
int nghttp2_map_init(nghttp2_map *map)
|
||||
{
|
||||
int nghttp2_map_init(nghttp2_map *map) {
|
||||
map->tablelen = INITIAL_TABLE_LENGTH;
|
||||
map->table = calloc(map->tablelen, sizeof(nghttp2_map_entry*));
|
||||
if(map->table == NULL) {
|
||||
map->table = calloc(map->tablelen, sizeof(nghttp2_map_entry *));
|
||||
if (map->table == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -41,19 +40,15 @@ int nghttp2_map_init(nghttp2_map *map)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_map_free(nghttp2_map *map)
|
||||
{
|
||||
free(map->table);
|
||||
}
|
||||
void nghttp2_map_free(nghttp2_map *map) { free(map->table); }
|
||||
|
||||
void nghttp2_map_each_free(nghttp2_map *map,
|
||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
||||
void *ptr)
|
||||
{
|
||||
void *ptr) {
|
||||
size_t i;
|
||||
for(i = 0; i < map->tablelen; ++i) {
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
nghttp2_map_entry *entry;
|
||||
for(entry = map->table[i]; entry;) {
|
||||
for (entry = map->table[i]; entry;) {
|
||||
nghttp2_map_entry *next = entry->next;
|
||||
func(entry, ptr);
|
||||
entry = next;
|
||||
@ -64,15 +59,14 @@ void nghttp2_map_each_free(nghttp2_map *map,
|
||||
|
||||
int nghttp2_map_each(nghttp2_map *map,
|
||||
int (*func)(nghttp2_map_entry *entry, void *ptr),
|
||||
void *ptr)
|
||||
{
|
||||
void *ptr) {
|
||||
int rv;
|
||||
size_t i;
|
||||
for(i = 0; i < map->tablelen; ++i) {
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
nghttp2_map_entry *entry;
|
||||
for(entry = map->table[i]; entry; entry = entry->next) {
|
||||
for (entry = map->table[i]; entry; entry = entry->next) {
|
||||
rv = func(entry, ptr);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -80,32 +74,29 @@ int nghttp2_map_each(nghttp2_map *map,
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key)
|
||||
{
|
||||
void nghttp2_map_entry_init(nghttp2_map_entry *entry, key_type key) {
|
||||
entry->key = key;
|
||||
entry->next = NULL;
|
||||
}
|
||||
|
||||
/* Same hash function in android HashMap source code. */
|
||||
/* The |mod| must be power of 2 */
|
||||
static int32_t hash(int32_t h, size_t mod)
|
||||
{
|
||||
static int32_t hash(int32_t h, size_t mod) {
|
||||
h ^= (h >> 20) ^ (h >> 12);
|
||||
h ^= (h >> 7) ^ (h >> 4);
|
||||
return h & (mod - 1);
|
||||
}
|
||||
|
||||
static int insert(nghttp2_map_entry **table, size_t tablelen,
|
||||
nghttp2_map_entry *entry)
|
||||
{
|
||||
nghttp2_map_entry *entry) {
|
||||
int32_t h = hash(entry->key, tablelen);
|
||||
if(table[h] == NULL) {
|
||||
if (table[h] == NULL) {
|
||||
table[h] = entry;
|
||||
} else {
|
||||
nghttp2_map_entry *p;
|
||||
/* We won't allow duplicated key, so check it out. */
|
||||
for(p = table[h]; p; p = p->next) {
|
||||
if(p->key == entry->key) {
|
||||
for (p = table[h]; p; p = p->next) {
|
||||
if (p->key == entry->key) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
@ -116,18 +107,17 @@ static int insert(nghttp2_map_entry **table, size_t tablelen,
|
||||
}
|
||||
|
||||
/* new_tablelen must be power of 2 */
|
||||
static int resize(nghttp2_map *map, size_t new_tablelen)
|
||||
{
|
||||
static int resize(nghttp2_map *map, size_t new_tablelen) {
|
||||
size_t i;
|
||||
nghttp2_map_entry **new_table;
|
||||
new_table = calloc(new_tablelen, sizeof(nghttp2_map_entry*));
|
||||
if(new_table == NULL) {
|
||||
new_table = calloc(new_tablelen, sizeof(nghttp2_map_entry *));
|
||||
if (new_table == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
for(i = 0; i < map->tablelen; ++i) {
|
||||
for (i = 0; i < map->tablelen; ++i) {
|
||||
nghttp2_map_entry *entry;
|
||||
for(entry = map->table[i]; entry;) {
|
||||
for (entry = map->table[i]; entry;) {
|
||||
nghttp2_map_entry *next = entry->next;
|
||||
entry->next = NULL;
|
||||
/* This function must succeed */
|
||||
@ -142,46 +132,43 @@ static int resize(nghttp2_map *map, size_t new_tablelen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry)
|
||||
{
|
||||
int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *new_entry) {
|
||||
int rv;
|
||||
/* Load factor is 0.75 */
|
||||
if((map->size + 1) * 4 > map->tablelen * 3) {
|
||||
if ((map->size + 1) * 4 > map->tablelen * 3) {
|
||||
rv = resize(map, map->tablelen * 2);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
rv = insert(map->table, map->tablelen, new_entry);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
++map->size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
nghttp2_map_entry* nghttp2_map_find(nghttp2_map *map, key_type key)
|
||||
{
|
||||
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key) {
|
||||
int32_t h;
|
||||
nghttp2_map_entry *entry;
|
||||
h = hash(key, map->tablelen);
|
||||
for(entry = map->table[h]; entry; entry = entry->next) {
|
||||
if(entry->key == key) {
|
||||
for (entry = map->table[h]; entry; entry = entry->next) {
|
||||
if (entry->key == key) {
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int nghttp2_map_remove(nghttp2_map *map, key_type key)
|
||||
{
|
||||
int nghttp2_map_remove(nghttp2_map *map, key_type key) {
|
||||
int32_t h;
|
||||
nghttp2_map_entry *entry, *prev;
|
||||
h = hash(key, map->tablelen);
|
||||
prev = NULL;
|
||||
for(entry = map->table[h]; entry; entry = entry->next) {
|
||||
if(entry->key == key) {
|
||||
if(prev == NULL) {
|
||||
for (entry = map->table[h]; entry; entry = entry->next) {
|
||||
if (entry->key == key) {
|
||||
if (prev == NULL) {
|
||||
map->table[h] = entry->next;
|
||||
} else {
|
||||
prev->next = entry->next;
|
||||
@ -194,7 +181,4 @@ int nghttp2_map_remove(nghttp2_map *map, key_type key)
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
size_t nghttp2_map_size(nghttp2_map *map)
|
||||
{
|
||||
return map->size;
|
||||
}
|
||||
size_t nghttp2_map_size(nghttp2_map *map) { return map->size; }
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_MAP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -98,7 +98,7 @@ int nghttp2_map_insert(nghttp2_map *map, nghttp2_map_entry *entry);
|
||||
* Returns the entry associated by the key |key|. If there is no such
|
||||
* entry, this function returns NULL.
|
||||
*/
|
||||
nghttp2_map_entry* nghttp2_map_find(nghttp2_map *map, key_type key);
|
||||
nghttp2_map_entry *nghttp2_map_find(nghttp2_map *map, key_type key);
|
||||
|
||||
/*
|
||||
* Removes the entry associated by the key |key| from the |map|. The
|
||||
|
@ -26,19 +26,19 @@
|
||||
#define NGHTTP2_NET_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#ifdef HAVE_ARPA_INET_H
|
||||
# include <arpa/inet.h>
|
||||
#include <arpa/inet.h>
|
||||
#endif /* HAVE_ARPA_INET_H */
|
||||
|
||||
#ifdef HAVE_NETINET_IN_H
|
||||
# include <netinet/in.h>
|
||||
#include <netinet/in.h>
|
||||
#endif /* HAVE_NETINET_IN_H */
|
||||
|
||||
#ifdef HAVE_WINSOCK2_H
|
||||
# include <winsock2.h>
|
||||
#include <winsock2.h>
|
||||
#endif /* HAVE_WINSOCK2_H */
|
||||
|
||||
#endif /* NGHTTP2_NET_H */
|
||||
|
@ -27,28 +27,26 @@
|
||||
#include <string.h>
|
||||
|
||||
int nghttp2_select_next_protocol(unsigned char **out, unsigned char *outlen,
|
||||
const unsigned char *in, unsigned int inlen)
|
||||
{
|
||||
const unsigned char *in, unsigned int inlen) {
|
||||
int http_selected = 0;
|
||||
unsigned int i = 0;
|
||||
for(; i < inlen; i += in[i]+1) {
|
||||
if(in[i] == NGHTTP2_PROTO_VERSION_ID_LEN &&
|
||||
i + 1 + in[i] <= inlen &&
|
||||
memcmp(&in[i+1], NGHTTP2_PROTO_VERSION_ID, in[i]) == 0) {
|
||||
*out = (unsigned char*)&in[i+1];
|
||||
for (; i < inlen; i += in [i] + 1) {
|
||||
if (in[i] == NGHTTP2_PROTO_VERSION_ID_LEN && i + 1 + in[i] <= inlen &&
|
||||
memcmp(&in[i + 1], NGHTTP2_PROTO_VERSION_ID, in[i]) == 0) {
|
||||
*out = (unsigned char *)&in[i + 1];
|
||||
*outlen = in[i];
|
||||
return 1;
|
||||
}
|
||||
if(in[i] == 8 && i + 1 + in[i] <= inlen &&
|
||||
memcmp(&in[i+1], "http/1.1", in[i]) == 0) {
|
||||
if (in[i] == 8 && i + 1 + in[i] <= inlen &&
|
||||
memcmp(&in[i + 1], "http/1.1", in[i]) == 0) {
|
||||
http_selected = 1;
|
||||
*out = (unsigned char*)&in[i+1];
|
||||
*out = (unsigned char *)&in[i + 1];
|
||||
*outlen = in[i];
|
||||
/* Go through to the next iteration, because "HTTP/2" may be
|
||||
there */
|
||||
}
|
||||
}
|
||||
if(http_selected) {
|
||||
if (http_selected) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_NPN_H
|
||||
|
||||
#ifdef HAVE_CONFIG
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
@ -24,38 +24,30 @@
|
||||
*/
|
||||
#include "nghttp2_option.h"
|
||||
|
||||
int nghttp2_option_new(nghttp2_option **option_ptr)
|
||||
{
|
||||
int nghttp2_option_new(nghttp2_option **option_ptr) {
|
||||
*option_ptr = calloc(1, sizeof(nghttp2_option));
|
||||
|
||||
if(*option_ptr == NULL) {
|
||||
if (*option_ptr == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_option_del(nghttp2_option *option)
|
||||
{
|
||||
free(option);
|
||||
}
|
||||
void nghttp2_option_del(nghttp2_option *option) { free(option); }
|
||||
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val)
|
||||
{
|
||||
void nghttp2_option_set_no_auto_window_update(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_NO_AUTO_WINDOW_UPDATE;
|
||||
option->no_auto_window_update = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_peer_max_concurrent_streams(nghttp2_option *option,
|
||||
uint32_t val)
|
||||
{
|
||||
uint32_t val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_PEER_MAX_CONCURRENT_STREAMS;
|
||||
option->peer_max_concurrent_streams = val;
|
||||
}
|
||||
|
||||
void nghttp2_option_set_recv_client_preface
|
||||
(nghttp2_option *option, int val)
|
||||
{
|
||||
void nghttp2_option_set_recv_client_preface(nghttp2_option *option, int val) {
|
||||
option->opt_set_mask |= NGHTTP2_OPT_RECV_CLIENT_PREFACE;
|
||||
option->recv_client_preface = val;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_OPTION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
@ -26,17 +26,16 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item)
|
||||
{
|
||||
void nghttp2_outbound_item_free(nghttp2_outbound_item *item) {
|
||||
nghttp2_frame *frame;
|
||||
|
||||
if(item == NULL) {
|
||||
if (item == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
switch(frame->hd.type) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
break;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_OUTBOUND_ITEM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
@ -24,11 +24,10 @@
|
||||
*/
|
||||
#include "nghttp2_pq.h"
|
||||
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar)
|
||||
{
|
||||
int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar) {
|
||||
pq->capacity = 128;
|
||||
pq->q = malloc(pq->capacity * sizeof(void*));
|
||||
if(pq->q == NULL) {
|
||||
pq->q = malloc(pq->capacity * sizeof(void *));
|
||||
if (pq->q == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
pq->length = 0;
|
||||
@ -36,38 +35,34 @@ int nghttp2_pq_init(nghttp2_pq *pq, nghttp2_compar compar)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_pq_free(nghttp2_pq *pq)
|
||||
{
|
||||
void nghttp2_pq_free(nghttp2_pq *pq) {
|
||||
free(pq->q);
|
||||
pq->q = NULL;
|
||||
}
|
||||
|
||||
static void swap(nghttp2_pq *pq, size_t i, size_t j)
|
||||
{
|
||||
static void swap(nghttp2_pq *pq, size_t i, size_t j) {
|
||||
void *t = pq->q[i];
|
||||
pq->q[i] = pq->q[j];
|
||||
pq->q[j] = t;
|
||||
}
|
||||
|
||||
static void bubble_up(nghttp2_pq *pq, size_t index)
|
||||
{
|
||||
if(index == 0) {
|
||||
static void bubble_up(nghttp2_pq *pq, size_t index) {
|
||||
if (index == 0) {
|
||||
return;
|
||||
} else {
|
||||
size_t parent = (index-1)/2;
|
||||
if(pq->compar(pq->q[parent], pq->q[index]) > 0) {
|
||||
size_t parent = (index - 1) / 2;
|
||||
if (pq->compar(pq->q[parent], pq->q[index]) > 0) {
|
||||
swap(pq, parent, index);
|
||||
bubble_up(pq, parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_push(nghttp2_pq *pq, void *item)
|
||||
{
|
||||
if(pq->capacity <= pq->length) {
|
||||
int nghttp2_pq_push(nghttp2_pq *pq, void *item) {
|
||||
if (pq->capacity <= pq->length) {
|
||||
void *nq;
|
||||
nq = realloc(pq->q, (pq->capacity*2) * sizeof(void*));
|
||||
if(nq == NULL) {
|
||||
nq = realloc(pq->q, (pq->capacity * 2) * sizeof(void *));
|
||||
if (nq == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
pq->capacity *= 2;
|
||||
@ -75,70 +70,60 @@ int nghttp2_pq_push(nghttp2_pq *pq, void *item)
|
||||
}
|
||||
pq->q[pq->length] = item;
|
||||
++pq->length;
|
||||
bubble_up(pq, pq->length-1);
|
||||
bubble_up(pq, pq->length - 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* nghttp2_pq_top(nghttp2_pq *pq)
|
||||
{
|
||||
if(pq->length == 0) {
|
||||
void *nghttp2_pq_top(nghttp2_pq *pq) {
|
||||
if (pq->length == 0) {
|
||||
return NULL;
|
||||
} else {
|
||||
return pq->q[0];
|
||||
}
|
||||
}
|
||||
|
||||
static void bubble_down(nghttp2_pq *pq, size_t index)
|
||||
{
|
||||
size_t lchild = index*2+1;
|
||||
static void bubble_down(nghttp2_pq *pq, size_t index) {
|
||||
size_t lchild = index * 2 + 1;
|
||||
size_t minindex = index;
|
||||
size_t i, j;
|
||||
for(i = 0; i < 2; ++i) {
|
||||
j = lchild+i;
|
||||
if(j >= pq->length) {
|
||||
for (i = 0; i < 2; ++i) {
|
||||
j = lchild + i;
|
||||
if (j >= pq->length) {
|
||||
break;
|
||||
}
|
||||
if(pq->compar(pq->q[minindex], pq->q[j]) > 0) {
|
||||
if (pq->compar(pq->q[minindex], pq->q[j]) > 0) {
|
||||
minindex = j;
|
||||
}
|
||||
}
|
||||
if(minindex != index) {
|
||||
if (minindex != index) {
|
||||
swap(pq, index, minindex);
|
||||
bubble_down(pq, minindex);
|
||||
}
|
||||
}
|
||||
|
||||
void nghttp2_pq_pop(nghttp2_pq *pq)
|
||||
{
|
||||
if(pq->length > 0) {
|
||||
pq->q[0] = pq->q[pq->length-1];
|
||||
void nghttp2_pq_pop(nghttp2_pq *pq) {
|
||||
if (pq->length > 0) {
|
||||
pq->q[0] = pq->q[pq->length - 1];
|
||||
--pq->length;
|
||||
bubble_down(pq, 0);
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_pq_empty(nghttp2_pq *pq)
|
||||
{
|
||||
return pq->length == 0;
|
||||
}
|
||||
int nghttp2_pq_empty(nghttp2_pq *pq) { return pq->length == 0; }
|
||||
|
||||
size_t nghttp2_pq_size(nghttp2_pq *pq)
|
||||
{
|
||||
return pq->length;
|
||||
}
|
||||
size_t nghttp2_pq_size(nghttp2_pq *pq) { return pq->length; }
|
||||
|
||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg)
|
||||
{
|
||||
void nghttp2_pq_update(nghttp2_pq *pq, nghttp2_pq_item_cb fun, void *arg) {
|
||||
size_t i;
|
||||
int rv = 0;
|
||||
if(pq->length == 0) {
|
||||
if (pq->length == 0) {
|
||||
return;
|
||||
}
|
||||
for(i = 0; i < pq->length; ++i) {
|
||||
for (i = 0; i < pq->length; ++i) {
|
||||
rv |= (*fun)(pq->q[i], arg);
|
||||
}
|
||||
if(rv) {
|
||||
for(i = pq->length; i > 0; --i) {
|
||||
if (rv) {
|
||||
for (i = pq->length; i > 0; --i) {
|
||||
bubble_down(pq, i - 1);
|
||||
}
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_PQ_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -78,7 +78,7 @@ int nghttp2_pq_push(nghttp2_pq *pq, void *item);
|
||||
* Returns item at the top of the queue |pq|. If the queue is empty,
|
||||
* this function returns NULL.
|
||||
*/
|
||||
void* nghttp2_pq_top(nghttp2_pq *pq);
|
||||
void *nghttp2_pq_top(nghttp2_pq *pq);
|
||||
|
||||
/*
|
||||
* Pops item at the top of the queue |pq|. The popped item is not
|
||||
|
@ -26,23 +26,19 @@
|
||||
|
||||
void nghttp2_priority_spec_init(nghttp2_priority_spec *pri_spec,
|
||||
int32_t stream_id, int32_t weight,
|
||||
int exclusive)
|
||||
{
|
||||
int exclusive) {
|
||||
pri_spec->stream_id = stream_id;
|
||||
pri_spec->weight = weight;
|
||||
pri_spec->exclusive = exclusive != 0;
|
||||
}
|
||||
|
||||
void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
void nghttp2_priority_spec_default_init(nghttp2_priority_spec *pri_spec) {
|
||||
pri_spec->stream_id = 0;
|
||||
pri_spec->weight = NGHTTP2_DEFAULT_WEIGHT;
|
||||
pri_spec->exclusive = 0;
|
||||
}
|
||||
|
||||
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
int nghttp2_priority_spec_check_default(const nghttp2_priority_spec *pri_spec) {
|
||||
return pri_spec->stream_id == 0 &&
|
||||
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT &&
|
||||
pri_spec->exclusive == 0;
|
||||
pri_spec->weight == NGHTTP2_DEFAULT_WEIGHT && pri_spec->exclusive == 0;
|
||||
}
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_PRIORITY_SPEC_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
@ -27,18 +27,16 @@
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
void nghttp2_queue_init(nghttp2_queue *queue)
|
||||
{
|
||||
void nghttp2_queue_init(nghttp2_queue *queue) {
|
||||
queue->front = queue->back = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_queue_free(nghttp2_queue *queue)
|
||||
{
|
||||
if(!queue) {
|
||||
void nghttp2_queue_free(nghttp2_queue *queue) {
|
||||
if (!queue) {
|
||||
return;
|
||||
} else {
|
||||
nghttp2_queue_cell *p = queue->front;
|
||||
while(p) {
|
||||
while (p) {
|
||||
nghttp2_queue_cell *next = p->next;
|
||||
free(p);
|
||||
p = next;
|
||||
@ -46,16 +44,15 @@ void nghttp2_queue_free(nghttp2_queue *queue)
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data)
|
||||
{
|
||||
nghttp2_queue_cell *new_cell = (nghttp2_queue_cell*)malloc
|
||||
(sizeof(nghttp2_queue_cell));
|
||||
if(!new_cell) {
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data) {
|
||||
nghttp2_queue_cell *new_cell =
|
||||
(nghttp2_queue_cell *)malloc(sizeof(nghttp2_queue_cell));
|
||||
if (!new_cell) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
new_cell->data = data;
|
||||
new_cell->next = NULL;
|
||||
if(queue->back) {
|
||||
if (queue->back) {
|
||||
queue->back->next = new_cell;
|
||||
queue->back = new_cell;
|
||||
|
||||
@ -65,30 +62,24 @@ int nghttp2_queue_push(nghttp2_queue *queue, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue)
|
||||
{
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue) {
|
||||
nghttp2_queue_cell *front = queue->front;
|
||||
assert(front);
|
||||
queue->front = front->next;
|
||||
if(front == queue->back) {
|
||||
if (front == queue->back) {
|
||||
queue->back = NULL;
|
||||
}
|
||||
free(front);
|
||||
}
|
||||
|
||||
void* nghttp2_queue_front(nghttp2_queue *queue)
|
||||
{
|
||||
void *nghttp2_queue_front(nghttp2_queue *queue) {
|
||||
assert(queue->front);
|
||||
return queue->front->data;
|
||||
}
|
||||
|
||||
void* nghttp2_queue_back(nghttp2_queue *queue)
|
||||
{
|
||||
void *nghttp2_queue_back(nghttp2_queue *queue) {
|
||||
assert(queue->back);
|
||||
return queue->back->data;
|
||||
}
|
||||
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue)
|
||||
{
|
||||
return queue->front == NULL;
|
||||
}
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue) { return queue->front == NULL; }
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_QUEUE_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#include "config.h"
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -36,16 +36,14 @@ typedef struct nghttp2_queue_cell {
|
||||
struct nghttp2_queue_cell *next;
|
||||
} nghttp2_queue_cell;
|
||||
|
||||
typedef struct {
|
||||
nghttp2_queue_cell *front, *back;
|
||||
} nghttp2_queue;
|
||||
typedef struct { nghttp2_queue_cell *front, *back; } nghttp2_queue;
|
||||
|
||||
void nghttp2_queue_init(nghttp2_queue *queue);
|
||||
void nghttp2_queue_free(nghttp2_queue *queue);
|
||||
int nghttp2_queue_push(nghttp2_queue *queue, void *data);
|
||||
void nghttp2_queue_pop(nghttp2_queue *queue);
|
||||
void* nghttp2_queue_front(nghttp2_queue *queue);
|
||||
void* nghttp2_queue_back(nghttp2_queue *queue);
|
||||
void *nghttp2_queue_front(nghttp2_queue *queue);
|
||||
void *nghttp2_queue_back(nghttp2_queue *queue);
|
||||
int nghttp2_queue_empty(nghttp2_queue *queue);
|
||||
|
||||
#endif /* NGHTTP2_QUEUE_H */
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_SESSION_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -264,7 +264,7 @@ int nghttp2_session_is_my_stream_id(nghttp2_session *session,
|
||||
* Don't call nghttp2_outbound_item_free() until frame member is
|
||||
* initialized.
|
||||
*/
|
||||
void nghttp2_session_outbound_item_init(nghttp2_session* session,
|
||||
void nghttp2_session_outbound_item_init(nghttp2_session *session,
|
||||
nghttp2_outbound_item *item);
|
||||
|
||||
/*
|
||||
@ -298,8 +298,7 @@ int nghttp2_session_add_item(nghttp2_session *session,
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory.
|
||||
*/
|
||||
int nghttp2_session_add_rst_stream(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
int nghttp2_session_add_rst_stream(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code);
|
||||
|
||||
/*
|
||||
@ -332,10 +331,8 @@ int nghttp2_session_add_ping(nghttp2_session *session, uint8_t flags,
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The |opaque_data_len| is too large.
|
||||
*/
|
||||
int nghttp2_session_add_goaway(nghttp2_session *session,
|
||||
int32_t last_stream_id,
|
||||
uint32_t error_code,
|
||||
const uint8_t *opaque_data,
|
||||
int nghttp2_session_add_goaway(nghttp2_session *session, int32_t last_stream_id,
|
||||
uint32_t error_code, const uint8_t *opaque_data,
|
||||
size_t opaque_data_len);
|
||||
|
||||
/*
|
||||
@ -378,9 +375,8 @@ int nghttp2_session_add_settings(nghttp2_session *session, uint8_t flags,
|
||||
* This function returns a pointer to created new stream object, or
|
||||
* NULL.
|
||||
*/
|
||||
nghttp2_stream* nghttp2_session_open_stream(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
uint8_t flags,
|
||||
nghttp2_stream *nghttp2_session_open_stream(nghttp2_session *session,
|
||||
int32_t stream_id, uint8_t flags,
|
||||
nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_stream_state initial_state,
|
||||
void *stream_user_data);
|
||||
@ -461,7 +457,6 @@ void nghttp2_session_adjust_closed_stream(nghttp2_session *session,
|
||||
int nghttp2_session_close_stream_if_shut_rdwr(nghttp2_session *session,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
|
||||
int nghttp2_session_end_request_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
@ -505,7 +500,6 @@ int nghttp2_session_on_headers_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
nghttp2_stream *stream);
|
||||
|
||||
|
||||
/*
|
||||
* Called when PRIORITY is received, assuming |frame| is properly
|
||||
* initialized.
|
||||
@ -551,8 +545,7 @@ int nghttp2_session_on_rst_stream_received(nghttp2_session *session,
|
||||
* The read_callback failed
|
||||
*/
|
||||
int nghttp2_session_on_settings_received(nghttp2_session *session,
|
||||
nghttp2_frame *frame,
|
||||
int noack);
|
||||
nghttp2_frame *frame, int noack);
|
||||
|
||||
/*
|
||||
* Called when PUSH_PROMISE is received, assuming |frame| is properly
|
||||
@ -652,7 +645,7 @@ int nghttp2_session_on_data_received(nghttp2_session *session,
|
||||
* could be NULL if such stream does not exist. This function returns
|
||||
* NULL if stream is marked as closed.
|
||||
*/
|
||||
nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
|
||||
nghttp2_stream *nghttp2_session_get_stream(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
@ -660,7 +653,7 @@ nghttp2_stream* nghttp2_session_get_stream(nghttp2_session *session,
|
||||
* returns stream object even if it is marked as closed or in
|
||||
* NGHTTP2_STREAM_IDLE state.
|
||||
*/
|
||||
nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
nghttp2_stream *nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
int32_t stream_id);
|
||||
|
||||
/*
|
||||
@ -680,17 +673,15 @@ nghttp2_stream* nghttp2_session_get_stream_raw(nghttp2_session *session,
|
||||
* NGHTTP2_ERR_CALLBACK_FAILURE
|
||||
* The read_callback failed (session error).
|
||||
*/
|
||||
int nghttp2_session_pack_data(nghttp2_session *session,
|
||||
nghttp2_bufs *bufs,
|
||||
size_t datamax,
|
||||
nghttp2_frame *frame,
|
||||
int nghttp2_session_pack_data(nghttp2_session *session, nghttp2_bufs *bufs,
|
||||
size_t datamax, nghttp2_frame *frame,
|
||||
nghttp2_data_aux_data *aux_data);
|
||||
|
||||
/*
|
||||
* Returns top of outbound frame queue. This function returns NULL if
|
||||
* queue is empty.
|
||||
*/
|
||||
nghttp2_outbound_item* nghttp2_session_get_ob_pq_top(nghttp2_session *session);
|
||||
nghttp2_outbound_item *nghttp2_session_get_ob_pq_top(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Pops and returns next item to send. If there is no such item,
|
||||
@ -699,8 +690,8 @@ nghttp2_outbound_item* nghttp2_session_get_ob_pq_top(nghttp2_session *session);
|
||||
* session->ob_ss_pq has item and max concurrent streams is reached,
|
||||
* then this function returns NULL.
|
||||
*/
|
||||
nghttp2_outbound_item* nghttp2_session_pop_next_ob_item
|
||||
(nghttp2_session *session);
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_pop_next_ob_item(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Returns next item to send. If there is no such item, this function
|
||||
@ -709,8 +700,8 @@ nghttp2_outbound_item* nghttp2_session_pop_next_ob_item
|
||||
* session->ob_ss_pq has item and max concurrent streams is reached,
|
||||
* then this function returns NULL.
|
||||
*/
|
||||
nghttp2_outbound_item* nghttp2_session_get_next_ob_item
|
||||
(nghttp2_session *session);
|
||||
nghttp2_outbound_item *
|
||||
nghttp2_session_get_next_ob_item(nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Updates local settings with the |iv|. The number of elements in the
|
||||
@ -742,9 +733,9 @@ int nghttp2_session_update_local_settings(nghttp2_session *session,
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_session_reprioritize_stream
|
||||
(nghttp2_session *session, nghttp2_stream *stream,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
int nghttp2_session_reprioritize_stream(nghttp2_session *session,
|
||||
nghttp2_stream *stream,
|
||||
const nghttp2_priority_spec *pri_spec);
|
||||
|
||||
/*
|
||||
* Terminates current |session| with the |error_code|. The |reason|
|
||||
@ -758,7 +749,8 @@ int nghttp2_session_reprioritize_stream
|
||||
* NGHTTP2_ERR_INVALID_ARGUMENT
|
||||
* The |reason| is too long.
|
||||
*/
|
||||
int nghttp2_session_terminate_session_with_reason
|
||||
(nghttp2_session *session, uint32_t error_code, const char *reason);
|
||||
int nghttp2_session_terminate_session_with_reason(nghttp2_session *session,
|
||||
uint32_t error_code,
|
||||
const char *reason);
|
||||
|
||||
#endif /* NGHTTP2_SESSION_H */
|
||||
|
@ -31,14 +31,11 @@
|
||||
#include "nghttp2_helper.h"
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
uint8_t flags,
|
||||
nghttp2_stream_state initial_state,
|
||||
int32_t weight,
|
||||
nghttp2_stream_roots *roots,
|
||||
uint8_t flags, nghttp2_stream_state initial_state,
|
||||
int32_t weight, nghttp2_stream_roots *roots,
|
||||
int32_t remote_initial_window_size,
|
||||
int32_t local_initial_window_size,
|
||||
void *stream_user_data)
|
||||
{
|
||||
void *stream_user_data) {
|
||||
nghttp2_map_entry_init(&stream->map_entry, stream_id);
|
||||
stream->stream_id = stream_id;
|
||||
stream->flags = flags;
|
||||
@ -74,21 +71,18 @@ void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
stream->root_next = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_stream_free(nghttp2_stream *stream _U_)
|
||||
{
|
||||
void nghttp2_stream_free(nghttp2_stream *stream _U_) {
|
||||
/* We don't free stream->data_item. If it is assigned to aob, then
|
||||
active_outbound_item_reset() will delete it. If it is queued,
|
||||
then it is deleted when pq is deleted in nghttp2_session_del().
|
||||
Otherwise, nghttp2_session_del() will delete it. */
|
||||
}
|
||||
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag)
|
||||
{
|
||||
void nghttp2_stream_shutdown(nghttp2_stream *stream, nghttp2_shut_flag flag) {
|
||||
stream->shut_flags |= flag;
|
||||
}
|
||||
|
||||
static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session)
|
||||
{
|
||||
static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
|
||||
@ -99,22 +93,22 @@ static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session)
|
||||
|
||||
/* If item is now sent, don't push it to the queue. Otherwise, we
|
||||
may push same item twice. */
|
||||
if(session->aob.item == item) {
|
||||
if (session->aob.item == item) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(item->weight > stream->effective_weight) {
|
||||
if (item->weight > stream->effective_weight) {
|
||||
item->weight = stream->effective_weight;
|
||||
}
|
||||
|
||||
item->cycle = session->last_cycle;
|
||||
|
||||
switch(item->frame.hd.type) {
|
||||
switch (item->frame.hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
rv = nghttp2_pq_push(&session->ob_da_pq, item);
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
if(stream->state == NGHTTP2_STREAM_RESERVED) {
|
||||
if (stream->state == NGHTTP2_STREAM_RESERVED) {
|
||||
rv = nghttp2_pq_push(&session->ob_ss_pq, item);
|
||||
} else {
|
||||
rv = nghttp2_pq_push(&session->ob_pq, item);
|
||||
@ -125,7 +119,7 @@ static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session)
|
||||
assert(0);
|
||||
}
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -134,28 +128,27 @@ static int stream_push_data(nghttp2_stream *stream, nghttp2_session *session)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static nghttp2_stream* stream_first_sib(nghttp2_stream *stream)
|
||||
{
|
||||
for(; stream->sib_prev; stream = stream->sib_prev);
|
||||
static nghttp2_stream *stream_first_sib(nghttp2_stream *stream) {
|
||||
for (; stream->sib_prev; stream = stream->sib_prev)
|
||||
;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static nghttp2_stream* stream_last_sib(nghttp2_stream *stream)
|
||||
{
|
||||
for(; stream->sib_next; stream = stream->sib_next);
|
||||
static nghttp2_stream *stream_last_sib(nghttp2_stream *stream) {
|
||||
for (; stream->sib_next; stream = stream->sib_next)
|
||||
;
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
static nghttp2_stream* stream_update_dep_length(nghttp2_stream *stream,
|
||||
ssize_t delta)
|
||||
{
|
||||
static nghttp2_stream *stream_update_dep_length(nghttp2_stream *stream,
|
||||
ssize_t delta) {
|
||||
stream->num_substreams += delta;
|
||||
|
||||
stream = stream_first_sib(stream);
|
||||
|
||||
if(stream->dep_prev) {
|
||||
if (stream->dep_prev) {
|
||||
return stream_update_dep_length(stream->dep_prev, delta);
|
||||
}
|
||||
|
||||
@ -163,17 +156,15 @@ static nghttp2_stream* stream_update_dep_length(nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
|
||||
int32_t weight)
|
||||
{
|
||||
int32_t weight) {
|
||||
weight = stream->weight * weight / stream->sum_dep_weight;
|
||||
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
int32_t nghttp2_stream_dep_distributed_effective_weight
|
||||
(nghttp2_stream *stream, int32_t weight)
|
||||
{
|
||||
if(stream->sum_norest_weight == 0) {
|
||||
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
|
||||
int32_t weight) {
|
||||
if (stream->sum_norest_weight == 0) {
|
||||
return stream->effective_weight;
|
||||
}
|
||||
|
||||
@ -182,10 +173,10 @@ int32_t nghttp2_stream_dep_distributed_effective_weight
|
||||
return nghttp2_max(1, weight);
|
||||
}
|
||||
|
||||
static int32_t stream_dep_distributed_top_effective_weight
|
||||
(nghttp2_stream *stream, int32_t weight)
|
||||
{
|
||||
if(stream->sum_top_weight == 0) {
|
||||
static int32_t
|
||||
stream_dep_distributed_top_effective_weight(nghttp2_stream *stream,
|
||||
int32_t weight) {
|
||||
if (stream->sum_top_weight == 0) {
|
||||
return stream->effective_weight;
|
||||
}
|
||||
|
||||
@ -199,31 +190,30 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream);
|
||||
/* Updates effective_weight of descendant streams in subtree of
|
||||
|stream|. We assume that stream->effective_weight is already set
|
||||
right. */
|
||||
static void stream_update_dep_effective_weight(nghttp2_stream *stream)
|
||||
{
|
||||
static void stream_update_dep_effective_weight(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: update_dep_effective_weight "
|
||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d, "
|
||||
"sum_top_weight=%d\n",
|
||||
"stream(%p)=%d, weight=%d, sum_norest_weight=%d, "
|
||||
"sum_top_weight=%d\n",
|
||||
stream, stream->stream_id, stream->weight,
|
||||
stream->sum_norest_weight, stream->sum_top_weight));
|
||||
|
||||
/* stream->sum_norest_weight == 0 means there is no
|
||||
NGHTTP2_STREAM_DPRI_TOP under stream */
|
||||
if(stream->dpri != NGHTTP2_STREAM_DPRI_NO_DATA ||
|
||||
stream->sum_norest_weight == 0) {
|
||||
if (stream->dpri != NGHTTP2_STREAM_DPRI_NO_DATA ||
|
||||
stream->sum_norest_weight == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If there is no direct descendant whose dpri is
|
||||
NGHTTP2_STREAM_DPRI_TOP, indirect descendants have the chance to
|
||||
send data, so recursively set weight for descendants. */
|
||||
if(stream->sum_top_weight == 0) {
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
if(si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
||||
si->effective_weight = nghttp2_stream_dep_distributed_effective_weight
|
||||
(stream, si->weight);
|
||||
if (stream->sum_top_weight == 0) {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
if (si->dpri != NGHTTP2_STREAM_DPRI_REST) {
|
||||
si->effective_weight =
|
||||
nghttp2_stream_dep_distributed_effective_weight(stream, si->weight);
|
||||
}
|
||||
|
||||
stream_update_dep_effective_weight(si);
|
||||
@ -235,10 +225,10 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
|
||||
NGHTTP2_STREAM_DPRI_TOP, we won't give a chance to indirect
|
||||
descendants, since closed or blocked stream's weight is
|
||||
distributed among its siblings */
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
if(si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
si->effective_weight = stream_dep_distributed_top_effective_weight
|
||||
(stream, si->weight);
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
if (si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
si->effective_weight =
|
||||
stream_dep_distributed_top_effective_weight(stream, si->weight);
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d top eweight=%d\n",
|
||||
si->stream_id, si->effective_weight));
|
||||
@ -246,7 +236,7 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
|
||||
continue;
|
||||
}
|
||||
|
||||
if(si->dpri == NGHTTP2_STREAM_DPRI_NO_DATA) {
|
||||
if (si->dpri == NGHTTP2_STREAM_DPRI_NO_DATA) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d no_data, ignored\n",
|
||||
si->stream_id));
|
||||
|
||||
@ -254,25 +244,24 @@ static void stream_update_dep_effective_weight(nghttp2_stream *stream)
|
||||
them NGHTTP2_STREAM_DPRI_REST again. */
|
||||
stream_update_dep_set_rest(si->dep_next);
|
||||
} else {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d rest, ignored\n",
|
||||
si->stream_id));
|
||||
DEBUGF(
|
||||
fprintf(stderr, "stream: stream=%d rest, ignored\n", si->stream_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void stream_update_dep_set_rest(nghttp2_stream *stream)
|
||||
{
|
||||
if(stream == NULL) {
|
||||
static void stream_update_dep_set_rest(nghttp2_stream *stream) {
|
||||
if (stream == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d is rest\n", stream->stream_id));
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
|
||||
|
||||
stream_update_dep_set_rest(stream->sib_next);
|
||||
@ -288,24 +277,23 @@ static void stream_update_dep_set_rest(nghttp2_stream *stream)
|
||||
* Performs dfs starting |stream|, search stream which can become
|
||||
* NGHTTP2_STREAM_DPRI_TOP and set its dpri.
|
||||
*/
|
||||
static void stream_update_dep_set_top(nghttp2_stream *stream)
|
||||
{
|
||||
static void stream_update_dep_set_top(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d data is top\n",
|
||||
stream->stream_id));
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
DEBUGF(
|
||||
fprintf(stderr, "stream: stream=%d data is top\n", stream->stream_id));
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_TOP;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
stream_update_dep_set_top(si);
|
||||
}
|
||||
}
|
||||
@ -321,22 +309,20 @@ static void stream_update_dep_set_top(nghttp2_stream *stream)
|
||||
* Out of memory.
|
||||
*/
|
||||
static int stream_update_dep_queue_top(nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
int rv;
|
||||
nghttp2_stream *si;
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if(!stream->data_item->queued) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n",
|
||||
stream->stream_id));
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if (!stream->data_item->queued) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d enqueue\n", stream->stream_id));
|
||||
rv = stream_push_data(stream, session);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -344,10 +330,10 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
rv = stream_update_dep_queue_top(si, session);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
@ -369,32 +355,31 @@ static int stream_update_dep_queue_top(nghttp2_stream *stream,
|
||||
* stream->sum_norest_weight. It just adds up the weight of direct
|
||||
* descendants whose dpri is NGHTTP2_STREAM_DPRI_TOP.
|
||||
*/
|
||||
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
|
||||
{
|
||||
static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
int rv;
|
||||
|
||||
stream->sum_norest_weight = 0;
|
||||
stream->sum_top_weight = 0;
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
if (stream->dpri == NGHTTP2_STREAM_DPRI_REST) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = 0;
|
||||
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
|
||||
if(stream_update_dep_sum_norest_weight(si)) {
|
||||
if (stream_update_dep_sum_norest_weight(si)) {
|
||||
rv = 1;
|
||||
stream->sum_norest_weight += si->weight;
|
||||
}
|
||||
|
||||
if(si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
if (si->dpri == NGHTTP2_STREAM_DPRI_TOP) {
|
||||
stream->sum_top_weight += si->weight;
|
||||
}
|
||||
}
|
||||
@ -403,8 +388,7 @@ static int stream_update_dep_sum_norest_weight(nghttp2_stream *stream)
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_REST;
|
||||
@ -424,8 +408,7 @@ static int stream_update_dep_on_attach_data(nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
static int stream_update_dep_on_detach_data(nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
stream->dpri = NGHTTP2_STREAM_DPRI_NO_DATA;
|
||||
@ -442,8 +425,7 @@ static int stream_update_dep_on_detach_data(nghttp2_stream *stream,
|
||||
|
||||
int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
nghttp2_outbound_item *data_item,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
assert((stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) == 0);
|
||||
assert(stream->data_item == NULL);
|
||||
|
||||
@ -456,8 +438,7 @@ int nghttp2_stream_attach_data(nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
int nghttp2_stream_detach_data(nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d detach data=%p\n",
|
||||
stream->stream_id, stream->data_item));
|
||||
|
||||
@ -468,8 +449,7 @@ int nghttp2_stream_detach_data(nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
assert(stream->data_item);
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d defer data=%p cause=%02x\n",
|
||||
@ -481,8 +461,7 @@ int nghttp2_stream_defer_data(nghttp2_stream *stream, uint8_t flags,
|
||||
}
|
||||
|
||||
int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
assert(stream->data_item);
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: stream=%d resume data=%p flags=%02x\n",
|
||||
@ -490,75 +469,65 @@ int nghttp2_stream_resume_deferred_data(nghttp2_stream *stream, uint8_t flags,
|
||||
|
||||
stream->flags &= ~flags;
|
||||
|
||||
if(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
|
||||
if (stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return stream_update_dep_on_attach_data(stream, session);
|
||||
}
|
||||
|
||||
int nghttp2_stream_check_deferred_data(nghttp2_stream *stream)
|
||||
{
|
||||
int nghttp2_stream_check_deferred_data(nghttp2_stream *stream) {
|
||||
return stream->data_item &&
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_ALL);
|
||||
}
|
||||
|
||||
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream)
|
||||
{
|
||||
int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream) {
|
||||
return stream->data_item &&
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
(stream->flags & NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL);
|
||||
}
|
||||
|
||||
static int update_initial_window_size
|
||||
(int32_t *window_size_ptr,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size)
|
||||
{
|
||||
static int update_initial_window_size(int32_t *window_size_ptr,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size) {
|
||||
int64_t new_window_size = (int64_t)(*window_size_ptr) +
|
||||
new_initial_window_size - old_initial_window_size;
|
||||
if(INT32_MIN > new_window_size ||
|
||||
new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
|
||||
new_initial_window_size - old_initial_window_size;
|
||||
if (INT32_MIN > new_window_size ||
|
||||
new_window_size > NGHTTP2_MAX_WINDOW_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
*window_size_ptr = (int32_t)new_window_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int nghttp2_stream_update_remote_initial_window_size
|
||||
(nghttp2_stream *stream,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size)
|
||||
{
|
||||
int nghttp2_stream_update_remote_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size) {
|
||||
return update_initial_window_size(&stream->remote_window_size,
|
||||
new_initial_window_size,
|
||||
old_initial_window_size);
|
||||
}
|
||||
|
||||
int nghttp2_stream_update_local_initial_window_size
|
||||
(nghttp2_stream *stream,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size)
|
||||
{
|
||||
int nghttp2_stream_update_local_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size) {
|
||||
return update_initial_window_size(&stream->local_window_size,
|
||||
new_initial_window_size,
|
||||
old_initial_window_size);
|
||||
}
|
||||
|
||||
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream)
|
||||
{
|
||||
void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream) {
|
||||
stream->state = NGHTTP2_STREAM_OPENED;
|
||||
}
|
||||
|
||||
nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream)
|
||||
{
|
||||
for(;;) {
|
||||
if(stream->sib_prev) {
|
||||
nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream) {
|
||||
for (;;) {
|
||||
if (stream->sib_prev) {
|
||||
stream = stream->sib_prev;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if(stream->dep_prev) {
|
||||
if (stream->dep_prev) {
|
||||
stream = stream->dep_prev;
|
||||
|
||||
continue;
|
||||
@ -571,17 +540,16 @@ nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream)
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
|
||||
nghttp2_stream *target)
|
||||
{
|
||||
if(stream == NULL) {
|
||||
nghttp2_stream *target) {
|
||||
if (stream == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(stream == target) {
|
||||
if (stream == target) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(nghttp2_stream_dep_subtree_find(stream->sib_next, target)) {
|
||||
if (nghttp2_stream_dep_subtree_find(stream->sib_next, target)) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -589,8 +557,7 @@ int nghttp2_stream_dep_subtree_find(nghttp2_stream *stream,
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *si;
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
@ -598,14 +565,13 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"stream: dep_insert dep_stream(%p)=%d, stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
dep_stream, dep_stream->stream_id, stream, stream->stream_id));
|
||||
|
||||
stream->sum_dep_weight = dep_stream->sum_dep_weight;
|
||||
dep_stream->sum_dep_weight = stream->weight;
|
||||
|
||||
if(dep_stream->dep_next) {
|
||||
for(si = dep_stream->dep_next; si; si = si->sib_next) {
|
||||
if (dep_stream->dep_next) {
|
||||
for (si = dep_stream->dep_next; si; si = si->sib_next) {
|
||||
stream->num_substreams += si->num_substreams;
|
||||
}
|
||||
|
||||
@ -624,21 +590,18 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
++stream->roots->num_streams;
|
||||
}
|
||||
|
||||
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream)
|
||||
{
|
||||
static void link_dep(nghttp2_stream *dep_stream, nghttp2_stream *stream) {
|
||||
dep_stream->dep_next = stream;
|
||||
stream->dep_prev = dep_stream;
|
||||
}
|
||||
|
||||
static void link_sib(nghttp2_stream *prev_stream, nghttp2_stream *stream)
|
||||
{
|
||||
static void link_sib(nghttp2_stream *prev_stream, nghttp2_stream *stream) {
|
||||
prev_stream->sib_next = stream;
|
||||
stream->sib_prev = prev_stream;
|
||||
}
|
||||
|
||||
static void insert_link_dep(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *sib_next;
|
||||
|
||||
assert(stream->sib_prev == NULL);
|
||||
@ -652,8 +615,7 @@ static void insert_link_dep(nghttp2_stream *dep_stream,
|
||||
link_dep(dep_stream, stream);
|
||||
}
|
||||
|
||||
static void unlink_sib(nghttp2_stream *stream)
|
||||
{
|
||||
static void unlink_sib(nghttp2_stream *stream) {
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
prev = stream->sib_prev;
|
||||
@ -661,7 +623,7 @@ static void unlink_sib(nghttp2_stream *stream)
|
||||
|
||||
assert(prev);
|
||||
|
||||
if(dep_next) {
|
||||
if (dep_next) {
|
||||
/*
|
||||
* prev--stream(--sib_next--...)
|
||||
* |
|
||||
@ -671,7 +633,7 @@ static void unlink_sib(nghttp2_stream *stream)
|
||||
|
||||
link_sib(prev, dep_next);
|
||||
|
||||
if(stream->sib_next) {
|
||||
if (stream->sib_next) {
|
||||
link_sib(stream_last_sib(dep_next), stream->sib_next);
|
||||
}
|
||||
} else {
|
||||
@ -682,14 +644,13 @@ static void unlink_sib(nghttp2_stream *stream)
|
||||
|
||||
prev->sib_next = next;
|
||||
|
||||
if(next) {
|
||||
if (next) {
|
||||
next->sib_prev = prev;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void unlink_dep(nghttp2_stream *stream)
|
||||
{
|
||||
static void unlink_dep(nghttp2_stream *stream) {
|
||||
nghttp2_stream *prev, *next, *dep_next;
|
||||
|
||||
prev = stream->dep_prev;
|
||||
@ -697,7 +658,7 @@ static void unlink_dep(nghttp2_stream *stream)
|
||||
|
||||
assert(prev);
|
||||
|
||||
if(dep_next) {
|
||||
if (dep_next) {
|
||||
/*
|
||||
* prev
|
||||
* |
|
||||
@ -707,10 +668,10 @@ static void unlink_dep(nghttp2_stream *stream)
|
||||
*/
|
||||
link_dep(prev, dep_next);
|
||||
|
||||
if(stream->sib_next) {
|
||||
if (stream->sib_next) {
|
||||
link_sib(stream_last_sib(dep_next), stream->sib_next);
|
||||
}
|
||||
} else if(stream->sib_next) {
|
||||
} else if (stream->sib_next) {
|
||||
/*
|
||||
* prev
|
||||
* |
|
||||
@ -727,22 +688,19 @@ static void unlink_dep(nghttp2_stream *stream)
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
assert(stream->data_item == NULL);
|
||||
|
||||
DEBUGF(fprintf(stderr,
|
||||
"stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
DEBUGF(fprintf(stderr, "stream: dep_add dep_stream(%p)=%d, stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id, stream, stream->stream_id));
|
||||
|
||||
root_stream = stream_update_dep_length(dep_stream, 1);
|
||||
|
||||
dep_stream->sum_dep_weight += stream->weight;
|
||||
|
||||
if(dep_stream->dep_next == NULL) {
|
||||
if (dep_stream->dep_next == NULL) {
|
||||
link_dep(dep_stream, stream);
|
||||
} else {
|
||||
insert_link_dep(dep_stream, stream);
|
||||
@ -754,20 +712,19 @@ void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
++stream->roots->num_streams;
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
{
|
||||
void nghttp2_stream_dep_remove(nghttp2_stream *stream) {
|
||||
nghttp2_stream *prev, *next, *dep_prev, *si, *root_stream;
|
||||
int32_t sum_dep_weight_delta;
|
||||
|
||||
root_stream = NULL;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n",
|
||||
stream, stream->stream_id));
|
||||
DEBUGF(fprintf(stderr, "stream: dep_remove stream(%p)=%d\n", stream,
|
||||
stream->stream_id));
|
||||
|
||||
/* Distribute weight of |stream| to direct descendants */
|
||||
sum_dep_weight_delta = -stream->weight;
|
||||
|
||||
for(si = stream->dep_next; si; si = si->sib_next) {
|
||||
for (si = stream->dep_next; si; si = si->sib_next) {
|
||||
si->weight = nghttp2_stream_dep_distributed_weight(stream, si->weight);
|
||||
|
||||
sum_dep_weight_delta += si->weight;
|
||||
@ -777,15 +734,15 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
|
||||
dep_prev = prev->dep_prev;
|
||||
|
||||
if(dep_prev) {
|
||||
if (dep_prev) {
|
||||
root_stream = stream_update_dep_length(dep_prev, -1);
|
||||
|
||||
dep_prev->sum_dep_weight += sum_dep_weight_delta;
|
||||
}
|
||||
|
||||
if(stream->sib_prev) {
|
||||
if (stream->sib_prev) {
|
||||
unlink_sib(stream);
|
||||
} else if(stream->dep_prev) {
|
||||
} else if (stream->dep_prev) {
|
||||
unlink_dep(stream);
|
||||
} else {
|
||||
nghttp2_stream_roots_remove(stream->roots, stream);
|
||||
@ -793,7 +750,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
/* stream is a root of tree. Removing stream makes its
|
||||
descendants a root of its own subtree. */
|
||||
|
||||
for(si = stream->dep_next; si;) {
|
||||
for (si = stream->dep_next; si;) {
|
||||
next = si->sib_next;
|
||||
|
||||
si->dep_prev = NULL;
|
||||
@ -809,7 +766,7 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
}
|
||||
}
|
||||
|
||||
if(root_stream) {
|
||||
if (root_stream) {
|
||||
stream_update_dep_sum_norest_weight(root_stream);
|
||||
stream_update_dep_effective_weight(root_stream);
|
||||
}
|
||||
@ -827,23 +784,21 @@ void nghttp2_stream_dep_remove(nghttp2_stream *stream)
|
||||
|
||||
int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
nghttp2_stream *last_sib;
|
||||
nghttp2_stream *dep_next;
|
||||
nghttp2_stream *root_stream;
|
||||
size_t delta_substreams;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_insert_subtree dep_stream(%p)=%d "
|
||||
"stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
"stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id, stream, stream->stream_id));
|
||||
|
||||
delta_substreams = stream->num_substreams;
|
||||
|
||||
stream_update_dep_set_rest(stream);
|
||||
|
||||
if(dep_stream->dep_next) {
|
||||
if (dep_stream->dep_next) {
|
||||
/* dep_stream->num_substreams includes dep_stream itself */
|
||||
stream->num_substreams += dep_stream->num_substreams - 1;
|
||||
|
||||
@ -856,7 +811,7 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
|
||||
link_dep(dep_stream, stream);
|
||||
|
||||
if(stream->dep_next) {
|
||||
if (stream->dep_next) {
|
||||
last_sib = stream_last_sib(stream->dep_next);
|
||||
|
||||
link_sib(last_sib, dep_next);
|
||||
@ -884,18 +839,16 @@ int nghttp2_stream_dep_insert_subtree(nghttp2_stream *dep_stream,
|
||||
|
||||
int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
nghttp2_session *session) {
|
||||
nghttp2_stream *root_stream;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_add_subtree dep_stream(%p)=%d "
|
||||
"stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id,
|
||||
stream, stream->stream_id));
|
||||
"stream(%p)=%d\n",
|
||||
dep_stream, dep_stream->stream_id, stream, stream->stream_id));
|
||||
|
||||
stream_update_dep_set_rest(stream);
|
||||
|
||||
if(dep_stream->dep_next) {
|
||||
if (dep_stream->dep_next) {
|
||||
dep_stream->sum_dep_weight += stream->weight;
|
||||
|
||||
insert_link_dep(dep_stream, stream);
|
||||
@ -916,18 +869,17 @@ int nghttp2_stream_dep_add_subtree(nghttp2_stream *dep_stream,
|
||||
return stream_update_dep_queue_top(root_stream, session);
|
||||
}
|
||||
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
{
|
||||
void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream) {
|
||||
nghttp2_stream *prev, *next, *dep_prev, *root_stream;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n",
|
||||
stream, stream->stream_id));
|
||||
DEBUGF(fprintf(stderr, "stream: dep_remove_subtree stream(%p)=%d\n", stream,
|
||||
stream->stream_id));
|
||||
|
||||
if(stream->sib_prev) {
|
||||
if (stream->sib_prev) {
|
||||
prev = stream->sib_prev;
|
||||
|
||||
prev->sib_next = stream->sib_next;
|
||||
if(prev->sib_next) {
|
||||
if (prev->sib_next) {
|
||||
prev->sib_next->sib_prev = prev;
|
||||
}
|
||||
|
||||
@ -935,13 +887,13 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
|
||||
dep_prev = prev->dep_prev;
|
||||
|
||||
} else if(stream->dep_prev) {
|
||||
} else if (stream->dep_prev) {
|
||||
dep_prev = stream->dep_prev;
|
||||
next = stream->sib_next;
|
||||
|
||||
dep_prev->dep_next = next;
|
||||
|
||||
if(next) {
|
||||
if (next) {
|
||||
next->dep_prev = dep_prev;
|
||||
|
||||
next->sib_prev = NULL;
|
||||
@ -953,7 +905,7 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
dep_prev = NULL;
|
||||
}
|
||||
|
||||
if(dep_prev) {
|
||||
if (dep_prev) {
|
||||
dep_prev->sum_dep_weight -= stream->weight;
|
||||
|
||||
root_stream = stream_update_dep_length(dep_prev, -stream->num_substreams);
|
||||
@ -968,10 +920,9 @@ void nghttp2_stream_dep_remove_subtree(nghttp2_stream *stream)
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
|
||||
nghttp2_session *session)
|
||||
{
|
||||
DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n",
|
||||
stream, stream->stream_id));
|
||||
nghttp2_session *session) {
|
||||
DEBUGF(fprintf(stderr, "stream: dep_make_root stream(%p)=%d\n", stream,
|
||||
stream->stream_id));
|
||||
|
||||
nghttp2_stream_roots_add(stream->roots, stream);
|
||||
|
||||
@ -987,13 +938,13 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
|
||||
return stream_update_dep_queue_top(stream, session);
|
||||
}
|
||||
|
||||
int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
(nghttp2_stream *stream, nghttp2_session *session)
|
||||
{
|
||||
int
|
||||
nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
|
||||
nghttp2_session *session) {
|
||||
nghttp2_stream *first, *si;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: ALL YOUR STREAM ARE BELONG TO US "
|
||||
"stream(%p)=%d\n",
|
||||
"stream(%p)=%d\n",
|
||||
stream, stream->stream_id));
|
||||
|
||||
first = stream->roots->head;
|
||||
@ -1001,23 +952,23 @@ int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
/* stream must not be include in stream->roots->head list */
|
||||
assert(first != stream);
|
||||
|
||||
if(first) {
|
||||
if (first) {
|
||||
nghttp2_stream *prev;
|
||||
|
||||
prev = first;
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: root stream(%p)=%d\n",
|
||||
first, first->stream_id));
|
||||
DEBUGF(fprintf(stderr, "stream: root stream(%p)=%d\n", first,
|
||||
first->stream_id));
|
||||
|
||||
stream->sum_dep_weight += first->weight;
|
||||
stream->num_substreams += first->num_substreams;
|
||||
|
||||
for(si = first->root_next; si; si = si->root_next) {
|
||||
for (si = first->root_next; si; si = si->root_next) {
|
||||
|
||||
assert(si != stream);
|
||||
|
||||
DEBUGF(fprintf(stderr, "stream: root stream(%p)=%d\n",
|
||||
si, si->stream_id));
|
||||
DEBUGF(
|
||||
fprintf(stderr, "stream: root stream(%p)=%d\n", si, si->stream_id));
|
||||
|
||||
stream->sum_dep_weight += si->weight;
|
||||
stream->num_substreams += si->num_substreams;
|
||||
@ -1027,7 +978,7 @@ int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
prev = si;
|
||||
}
|
||||
|
||||
if(stream->dep_next) {
|
||||
if (stream->dep_next) {
|
||||
nghttp2_stream *sib_next;
|
||||
|
||||
sib_next = stream->dep_next;
|
||||
@ -1046,27 +997,22 @@ int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
return nghttp2_stream_dep_make_root(stream, session);
|
||||
}
|
||||
|
||||
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream)
|
||||
{
|
||||
return stream->dep_prev || stream->dep_next ||
|
||||
stream->sib_prev || stream->sib_next ||
|
||||
stream->root_next || stream->root_prev ||
|
||||
stream->roots->head == stream;
|
||||
int nghttp2_stream_in_dep_tree(nghttp2_stream *stream) {
|
||||
return stream->dep_prev || stream->dep_next || stream->sib_prev ||
|
||||
stream->sib_next || stream->root_next || stream->root_prev ||
|
||||
stream->roots->head == stream;
|
||||
}
|
||||
|
||||
void nghttp2_stream_roots_init(nghttp2_stream_roots *roots)
|
||||
{
|
||||
void nghttp2_stream_roots_init(nghttp2_stream_roots *roots) {
|
||||
roots->head = NULL;
|
||||
roots->num_streams = 0;
|
||||
}
|
||||
|
||||
void nghttp2_stream_roots_free(nghttp2_stream_roots *roots _U_)
|
||||
{}
|
||||
void nghttp2_stream_roots_free(nghttp2_stream_roots *roots _U_) {}
|
||||
|
||||
void nghttp2_stream_roots_add(nghttp2_stream_roots *roots,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
if(roots->head) {
|
||||
nghttp2_stream *stream) {
|
||||
if (roots->head) {
|
||||
stream->root_next = roots->head;
|
||||
roots->head->root_prev = stream;
|
||||
}
|
||||
@ -1075,21 +1021,20 @@ void nghttp2_stream_roots_add(nghttp2_stream_roots *roots,
|
||||
}
|
||||
|
||||
void nghttp2_stream_roots_remove(nghttp2_stream_roots *roots,
|
||||
nghttp2_stream *stream)
|
||||
{
|
||||
nghttp2_stream *stream) {
|
||||
nghttp2_stream *root_prev, *root_next;
|
||||
|
||||
root_prev = stream->root_prev;
|
||||
root_next = stream->root_next;
|
||||
|
||||
if(root_prev) {
|
||||
if (root_prev) {
|
||||
root_prev->root_next = root_next;
|
||||
|
||||
if(root_next) {
|
||||
if (root_next) {
|
||||
root_next->root_prev = root_prev;
|
||||
}
|
||||
} else {
|
||||
if(root_next) {
|
||||
if (root_next) {
|
||||
root_next->root_prev = NULL;
|
||||
}
|
||||
|
||||
@ -1100,11 +1045,10 @@ void nghttp2_stream_roots_remove(nghttp2_stream_roots *roots,
|
||||
stream->root_next = NULL;
|
||||
}
|
||||
|
||||
void nghttp2_stream_roots_remove_all(nghttp2_stream_roots *roots)
|
||||
{
|
||||
void nghttp2_stream_roots_remove_all(nghttp2_stream_roots *roots) {
|
||||
nghttp2_stream *si, *next;
|
||||
|
||||
for(si = roots->head; si;) {
|
||||
for (si = roots->head; si;) {
|
||||
next = si->root_next;
|
||||
|
||||
si->root_prev = NULL;
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_STREAM_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
@ -94,7 +94,7 @@ typedef enum {
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER = 0x08,
|
||||
/* bitwise OR of NGHTTP2_STREAM_FLAG_DEFERRED_FLOW_CONTROL and
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_USER. */
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
|
||||
NGHTTP2_STREAM_FLAG_DEFERRED_ALL = 0x0c
|
||||
|
||||
} nghttp2_stream_flag;
|
||||
|
||||
@ -189,10 +189,8 @@ struct nghttp2_stream {
|
||||
};
|
||||
|
||||
void nghttp2_stream_init(nghttp2_stream *stream, int32_t stream_id,
|
||||
uint8_t flags,
|
||||
nghttp2_stream_state initial_state,
|
||||
int32_t weight,
|
||||
nghttp2_stream_roots *roots,
|
||||
uint8_t flags, nghttp2_stream_state initial_state,
|
||||
int32_t weight, nghttp2_stream_roots *roots,
|
||||
int32_t remote_initial_window_size,
|
||||
int32_t local_initial_window_size,
|
||||
void *stream_user_data);
|
||||
@ -250,10 +248,9 @@ int nghttp2_stream_check_deferred_by_flow_control(nghttp2_stream *stream);
|
||||
* This function returns 0 if it succeeds or -1. The failure is due to
|
||||
* overflow.
|
||||
*/
|
||||
int nghttp2_stream_update_remote_initial_window_size
|
||||
(nghttp2_stream *stream,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
int nghttp2_stream_update_remote_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
|
||||
/*
|
||||
* Updates the local window size with the new value
|
||||
@ -263,10 +260,9 @@ int nghttp2_stream_update_remote_initial_window_size
|
||||
* This function returns 0 if it succeeds or -1. The failure is due to
|
||||
* overflow.
|
||||
*/
|
||||
int nghttp2_stream_update_local_initial_window_size
|
||||
(nghttp2_stream *stream,
|
||||
int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
int nghttp2_stream_update_local_initial_window_size(
|
||||
nghttp2_stream *stream, int32_t new_initial_window_size,
|
||||
int32_t old_initial_window_size);
|
||||
|
||||
/*
|
||||
* Call this function if promised stream |stream| is replied with
|
||||
@ -279,7 +275,7 @@ void nghttp2_stream_promise_fulfilled(nghttp2_stream *stream);
|
||||
* Returns the stream positioned in root of the dependency tree the
|
||||
* |stream| belongs to.
|
||||
*/
|
||||
nghttp2_stream* nghttp2_stream_get_dep_root(nghttp2_stream *stream);
|
||||
nghttp2_stream *nghttp2_stream_get_dep_root(nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |target| is found in subtree of |stream|.
|
||||
@ -302,8 +298,8 @@ int32_t nghttp2_stream_dep_distributed_weight(nghttp2_stream *stream,
|
||||
* rather than stream->weight. This function is used to determine
|
||||
* weight in dependency tree.
|
||||
*/
|
||||
int32_t nghttp2_stream_dep_distributed_effective_weight
|
||||
(nghttp2_stream *stream, int32_t weight);
|
||||
int32_t nghttp2_stream_dep_distributed_effective_weight(nghttp2_stream *stream,
|
||||
int32_t weight);
|
||||
|
||||
/*
|
||||
* Makes the |stream| depend on the |dep_stream|. This dependency is
|
||||
@ -320,8 +316,7 @@ void nghttp2_stream_dep_insert(nghttp2_stream *dep_stream,
|
||||
* not exclusive. This function assumes |stream->data| is NULL and no
|
||||
* dpri members are changed in this dependency tree.
|
||||
*/
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream,
|
||||
nghttp2_stream *stream);
|
||||
void nghttp2_stream_dep_add(nghttp2_stream *dep_stream, nghttp2_stream *stream);
|
||||
|
||||
/*
|
||||
* Removes the |stream| from the current dependency tree. This
|
||||
@ -421,8 +416,9 @@ int nghttp2_stream_dep_make_root(nghttp2_stream *stream,
|
||||
* NGHTTP2_ERR_NOMEM
|
||||
* Out of memory
|
||||
*/
|
||||
int nghttp2_stream_dep_all_your_stream_are_belong_to_us
|
||||
(nghttp2_stream *stream, nghttp2_session *session);
|
||||
int
|
||||
nghttp2_stream_dep_all_your_stream_are_belong_to_us(nghttp2_stream *stream,
|
||||
nghttp2_session *session);
|
||||
|
||||
/*
|
||||
* Returns nonzero if |stream| is in any dependency tree.
|
||||
|
@ -35,49 +35,44 @@
|
||||
/* This function takes ownership of |nva_copy|. Regardless of the
|
||||
return value, the caller must not free |nva_copy| after this
|
||||
function returns. */
|
||||
static int32_t submit_headers_shared
|
||||
(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva_copy,
|
||||
size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data,
|
||||
uint8_t attach_stream)
|
||||
{
|
||||
static int32_t submit_headers_shared(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
nghttp2_nv *nva_copy, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data,
|
||||
uint8_t attach_stream) {
|
||||
int rv;
|
||||
uint8_t flags_copy;
|
||||
nghttp2_outbound_item *item = NULL;
|
||||
nghttp2_frame *frame = NULL;
|
||||
nghttp2_headers_category hcat;
|
||||
|
||||
if(stream_id == 0) {
|
||||
if (stream_id == 0) {
|
||||
rv = NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
if(item == NULL) {
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
nghttp2_session_outbound_item_init(session, item);
|
||||
|
||||
if(data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
if (data_prd != NULL && data_prd->read_callback != NULL) {
|
||||
item->aux_data.headers.data_prd = *data_prd;
|
||||
}
|
||||
|
||||
item->aux_data.headers.stream_user_data = stream_user_data;
|
||||
item->aux_data.headers.attach_stream = attach_stream;
|
||||
|
||||
flags_copy =
|
||||
(flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
|
||||
NGHTTP2_FLAG_END_HEADERS;
|
||||
flags_copy = (flags & (NGHTTP2_FLAG_END_STREAM | NGHTTP2_FLAG_PRIORITY)) |
|
||||
NGHTTP2_FLAG_END_HEADERS;
|
||||
|
||||
if(stream_id == -1) {
|
||||
if(session->next_stream_id > INT32_MAX) {
|
||||
if (stream_id == -1) {
|
||||
if (session->next_stream_id > INT32_MAX) {
|
||||
rv = NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
|
||||
goto fail;
|
||||
}
|
||||
@ -93,56 +88,51 @@ static int32_t submit_headers_shared
|
||||
|
||||
frame = &item->frame;
|
||||
|
||||
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id,
|
||||
hcat, pri_spec, nva_copy, nvlen);
|
||||
nghttp2_frame_headers_init(&frame->headers, flags_copy, stream_id, hcat,
|
||||
pri_spec, nva_copy, nvlen);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_headers_free(&frame->headers);
|
||||
goto fail2;
|
||||
}
|
||||
|
||||
if(hcat == NGHTTP2_HCAT_REQUEST) {
|
||||
if (hcat == NGHTTP2_HCAT_REQUEST) {
|
||||
return stream_id;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
fail:
|
||||
/* nghttp2_frame_headers_init() takes ownership of nva_copy. */
|
||||
nghttp2_nv_array_del(nva_copy);
|
||||
fail2:
|
||||
fail2:
|
||||
free(item);
|
||||
|
||||
return rv;
|
||||
}
|
||||
|
||||
static void adjust_priority_spec_weight(nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
if(pri_spec->weight < NGHTTP2_MIN_WEIGHT) {
|
||||
static void adjust_priority_spec_weight(nghttp2_priority_spec *pri_spec) {
|
||||
if (pri_spec->weight < NGHTTP2_MIN_WEIGHT) {
|
||||
pri_spec->weight = NGHTTP2_MIN_WEIGHT;
|
||||
} else if(pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
|
||||
} else if (pri_spec->weight > NGHTTP2_MAX_WEIGHT) {
|
||||
pri_spec->weight = NGHTTP2_MAX_WEIGHT;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t submit_headers_shared_nva
|
||||
(nghttp2_session *session,
|
||||
uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva,
|
||||
size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data,
|
||||
uint8_t attach_stream)
|
||||
{
|
||||
static int32_t submit_headers_shared_nva(nghttp2_session *session,
|
||||
uint8_t flags, int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data,
|
||||
uint8_t attach_stream) {
|
||||
int rv;
|
||||
nghttp2_nv *nva_copy;
|
||||
nghttp2_priority_spec copy_pri_spec;
|
||||
|
||||
if(pri_spec) {
|
||||
if (pri_spec) {
|
||||
copy_pri_spec = *pri_spec;
|
||||
adjust_priority_spec_weight(©_pri_spec);
|
||||
} else {
|
||||
@ -150,54 +140,50 @@ static int32_t submit_headers_shared_nva
|
||||
}
|
||||
|
||||
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return submit_headers_shared(session, flags, stream_id,
|
||||
©_pri_spec, nva_copy, nvlen, data_prd,
|
||||
stream_user_data, attach_stream);
|
||||
return submit_headers_shared(session, flags, stream_id, ©_pri_spec,
|
||||
nva_copy, nvlen, data_prd, stream_user_data,
|
||||
attach_stream);
|
||||
}
|
||||
|
||||
int32_t nghttp2_submit_headers(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *stream_user_data)
|
||||
{
|
||||
void *stream_user_data) {
|
||||
flags &= NGHTTP2_FLAG_END_STREAM;
|
||||
|
||||
if(pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
if (pri_spec && !nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
} else {
|
||||
pri_spec = NULL;
|
||||
}
|
||||
|
||||
return submit_headers_shared_nva(session, flags, stream_id, pri_spec,
|
||||
nva, nvlen, NULL, stream_user_data, 0);
|
||||
return submit_headers_shared_nva(session, flags, stream_id, pri_spec, nva,
|
||||
nvlen, NULL, stream_user_data, 0);
|
||||
}
|
||||
|
||||
|
||||
int nghttp2_submit_ping(nghttp2_session *session, uint8_t flags _U_,
|
||||
const uint8_t *opaque_data)
|
||||
{
|
||||
const uint8_t *opaque_data) {
|
||||
return nghttp2_session_add_ping(session, NGHTTP2_FLAG_NONE, opaque_data);
|
||||
}
|
||||
|
||||
int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t stream_id,
|
||||
const nghttp2_priority_spec *pri_spec)
|
||||
{
|
||||
const nghttp2_priority_spec *pri_spec) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_priority_spec copy_pri_spec;
|
||||
|
||||
if(stream_id == 0 || pri_spec == NULL) {
|
||||
if (stream_id == 0 || pri_spec == NULL) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if(stream_id == pri_spec->stream_id) {
|
||||
if (stream_id == pri_spec->stream_id) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
@ -207,7 +193,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
||||
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
|
||||
if(item == NULL) {
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -219,7 +205,7 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_priority_free(&frame->priority);
|
||||
free(item);
|
||||
|
||||
@ -230,10 +216,8 @@ int nghttp2_submit_priority(nghttp2_session *session, uint8_t flags _U_,
|
||||
}
|
||||
|
||||
int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t stream_id,
|
||||
uint32_t error_code)
|
||||
{
|
||||
if(stream_id == 0) {
|
||||
int32_t stream_id, uint32_t error_code) {
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
@ -241,25 +225,21 @@ int nghttp2_submit_rst_stream(nghttp2_session *session, uint8_t flags _U_,
|
||||
}
|
||||
|
||||
int nghttp2_submit_goaway(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t last_stream_id,
|
||||
uint32_t error_code,
|
||||
const uint8_t *opaque_data, size_t opaque_data_len)
|
||||
{
|
||||
return nghttp2_session_add_goaway(session, last_stream_id,
|
||||
error_code, opaque_data, opaque_data_len);
|
||||
int32_t last_stream_id, uint32_t error_code,
|
||||
const uint8_t *opaque_data, size_t opaque_data_len) {
|
||||
return nghttp2_session_add_goaway(session, last_stream_id, error_code,
|
||||
opaque_data, opaque_data_len);
|
||||
}
|
||||
|
||||
int nghttp2_submit_settings(nghttp2_session *session, uint8_t flags _U_,
|
||||
const nghttp2_settings_entry *iv, size_t niv)
|
||||
{
|
||||
const nghttp2_settings_entry *iv, size_t niv) {
|
||||
return nghttp2_session_add_settings(session, NGHTTP2_FLAG_NONE, iv, niv);
|
||||
}
|
||||
|
||||
int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
void *promised_stream_user_data)
|
||||
{
|
||||
int32_t stream_id, const nghttp2_nv *nva,
|
||||
size_t nvlen,
|
||||
void *promised_stream_user_data) {
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_nv *nva_copy;
|
||||
@ -267,21 +247,21 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t promised_stream_id;
|
||||
int rv;
|
||||
|
||||
if(stream_id == 0) {
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if(!session->server) {
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
/* All 32bit signed stream IDs are spent. */
|
||||
if(session->next_stream_id > INT32_MAX) {
|
||||
if (session->next_stream_id > INT32_MAX) {
|
||||
return NGHTTP2_ERR_STREAM_ID_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
if(item == NULL) {
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -292,7 +272,7 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||
frame = &item->frame;
|
||||
|
||||
rv = nghttp2_nv_array_copy(&nva_copy, nva, nvlen);
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
free(item);
|
||||
return rv;
|
||||
}
|
||||
@ -302,13 +282,12 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||
promised_stream_id = session->next_stream_id;
|
||||
session->next_stream_id += 2;
|
||||
|
||||
nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy,
|
||||
stream_id, promised_stream_id,
|
||||
nva_copy, nvlen);
|
||||
nghttp2_frame_push_promise_init(&frame->push_promise, flags_copy, stream_id,
|
||||
promised_stream_id, nva_copy, nvlen);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_push_promise_free(&frame->push_promise);
|
||||
free(item);
|
||||
|
||||
@ -320,44 +299,41 @@ int32_t nghttp2_submit_push_promise(nghttp2_session *session, uint8_t flags _U_,
|
||||
|
||||
int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
int32_t window_size_increment)
|
||||
{
|
||||
int32_t window_size_increment) {
|
||||
int rv;
|
||||
nghttp2_stream *stream = 0;
|
||||
if(window_size_increment == 0) {
|
||||
if (window_size_increment == 0) {
|
||||
return 0;
|
||||
}
|
||||
flags = 0;
|
||||
if(stream_id == 0) {
|
||||
rv = nghttp2_adjust_local_window_size(&session->local_window_size,
|
||||
&session->recv_window_size,
|
||||
&session->recv_reduction,
|
||||
&window_size_increment);
|
||||
if(rv != 0) {
|
||||
if (stream_id == 0) {
|
||||
rv = nghttp2_adjust_local_window_size(
|
||||
&session->local_window_size, &session->recv_window_size,
|
||||
&session->recv_reduction, &window_size_increment);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
} else {
|
||||
stream = nghttp2_session_get_stream(session, stream_id);
|
||||
if(!stream) {
|
||||
if (!stream) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
rv = nghttp2_adjust_local_window_size(&stream->local_window_size,
|
||||
&stream->recv_window_size,
|
||||
&stream->recv_reduction,
|
||||
&window_size_increment);
|
||||
if(rv != 0) {
|
||||
rv = nghttp2_adjust_local_window_size(
|
||||
&stream->local_window_size, &stream->recv_window_size,
|
||||
&stream->recv_reduction, &window_size_increment);
|
||||
if (rv != 0) {
|
||||
return rv;
|
||||
}
|
||||
}
|
||||
|
||||
if(window_size_increment > 0) {
|
||||
if(stream_id == 0) {
|
||||
if (window_size_increment > 0) {
|
||||
if (stream_id == 0) {
|
||||
session->consumed_size =
|
||||
nghttp2_max(0, session->consumed_size - window_size_increment);
|
||||
nghttp2_max(0, session->consumed_size - window_size_increment);
|
||||
} else {
|
||||
stream->consumed_size =
|
||||
nghttp2_max(0, stream->consumed_size - window_size_increment);
|
||||
nghttp2_max(0, stream->consumed_size - window_size_increment);
|
||||
}
|
||||
|
||||
return nghttp2_session_add_window_update(session, flags, stream_id,
|
||||
@ -367,12 +343,10 @@ int nghttp2_submit_window_update(nghttp2_session *session, uint8_t flags,
|
||||
}
|
||||
|
||||
int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
int32_t stream_id,
|
||||
uint32_t max_age, uint16_t port,
|
||||
int32_t stream_id, uint32_t max_age, uint16_t port,
|
||||
const uint8_t *protocol_id, size_t protocol_id_len,
|
||||
const uint8_t *host, size_t host_len,
|
||||
const uint8_t *origin, size_t origin_len)
|
||||
{
|
||||
const uint8_t *origin, size_t origin_len) {
|
||||
int rv;
|
||||
size_t varlen;
|
||||
uint8_t *var, *varp;
|
||||
@ -381,26 +355,26 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
nghttp2_ext_altsvc *altsvc;
|
||||
uint8_t *copy_protocol_id, *copy_host, *copy_origin;
|
||||
|
||||
if(!session->server) {
|
||||
if (!session->server) {
|
||||
return NGHTTP2_ERR_PROTO;
|
||||
}
|
||||
|
||||
varlen = protocol_id_len + host_len + origin_len;
|
||||
|
||||
/* 9 = fixed part 8 bytes + HOST_LEN 1 byte */
|
||||
if(varlen + 9 > NGHTTP2_MAX_PAYLOADLEN) {
|
||||
if (varlen + 9 > NGHTTP2_MAX_PAYLOADLEN) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
altsvc = malloc(sizeof(nghttp2_ext_altsvc));
|
||||
|
||||
if(altsvc == NULL) {
|
||||
if (altsvc == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if(varlen == 0) {
|
||||
if (varlen == 0) {
|
||||
var = NULL;
|
||||
copy_protocol_id = NULL;
|
||||
copy_host = NULL;
|
||||
@ -408,7 +382,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
} else {
|
||||
var = malloc(varlen);
|
||||
|
||||
if(var == NULL) {
|
||||
if (var == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
|
||||
goto var_alloc_fail;
|
||||
@ -433,7 +407,7 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
|
||||
if(item == NULL) {
|
||||
if (item == NULL) {
|
||||
rv = NGHTTP2_ERR_NOMEM;
|
||||
|
||||
goto frame_alloc_fail;
|
||||
@ -445,12 +419,12 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
frame->ext.payload = altsvc;
|
||||
|
||||
nghttp2_frame_altsvc_init(&frame->ext, stream_id, max_age, port,
|
||||
copy_protocol_id, protocol_id_len,
|
||||
copy_host, host_len, copy_origin, origin_len);
|
||||
copy_protocol_id, protocol_id_len, copy_host,
|
||||
host_len, copy_origin, origin_len);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_altsvc_free(&frame->ext);
|
||||
free(item);
|
||||
free(altsvc);
|
||||
@ -460,25 +434,24 @@ int nghttp2_submit_altsvc(nghttp2_session *session, uint8_t flags _U_,
|
||||
|
||||
return 0;
|
||||
|
||||
frame_alloc_fail:
|
||||
frame_alloc_fail:
|
||||
free(var);
|
||||
|
||||
var_alloc_fail:
|
||||
var_alloc_fail:
|
||||
free(altsvc);
|
||||
|
||||
fail:
|
||||
fail:
|
||||
return rv;
|
||||
}
|
||||
|
||||
static uint8_t set_request_flags(const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
{
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if(data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
if (data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
|
||||
if(pri_spec) {
|
||||
if (pri_spec) {
|
||||
flags |= NGHTTP2_FLAG_PRIORITY;
|
||||
}
|
||||
|
||||
@ -489,57 +462,50 @@ int32_t nghttp2_submit_request(nghttp2_session *session,
|
||||
const nghttp2_priority_spec *pri_spec,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd,
|
||||
void *stream_user_data)
|
||||
{
|
||||
void *stream_user_data) {
|
||||
uint8_t flags;
|
||||
|
||||
if(pri_spec && nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
if (pri_spec && nghttp2_priority_spec_check_default(pri_spec)) {
|
||||
pri_spec = NULL;
|
||||
}
|
||||
|
||||
flags = set_request_flags(pri_spec, data_prd);
|
||||
|
||||
return submit_headers_shared_nva(session, flags, -1, pri_spec,
|
||||
nva, nvlen,
|
||||
return submit_headers_shared_nva(session, flags, -1, pri_spec, nva, nvlen,
|
||||
data_prd, stream_user_data, 0);
|
||||
}
|
||||
|
||||
static uint8_t set_response_flags(const nghttp2_data_provider *data_prd)
|
||||
{
|
||||
static uint8_t set_response_flags(const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = NGHTTP2_FLAG_NONE;
|
||||
if(data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
if (data_prd == NULL || data_prd->read_callback == NULL) {
|
||||
flags |= NGHTTP2_FLAG_END_STREAM;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
int nghttp2_submit_response(nghttp2_session *session,
|
||||
int32_t stream_id,
|
||||
int nghttp2_submit_response(nghttp2_session *session, int32_t stream_id,
|
||||
const nghttp2_nv *nva, size_t nvlen,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
{
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
uint8_t flags = set_response_flags(data_prd);
|
||||
return submit_headers_shared_nva(session, flags, stream_id,
|
||||
NULL, nva, nvlen,
|
||||
return submit_headers_shared_nva(session, flags, stream_id, NULL, nva, nvlen,
|
||||
data_prd, NULL, 1);
|
||||
}
|
||||
|
||||
int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id,
|
||||
const nghttp2_data_provider *data_prd)
|
||||
{
|
||||
const nghttp2_data_provider *data_prd) {
|
||||
int rv;
|
||||
nghttp2_outbound_item *item;
|
||||
nghttp2_frame *frame;
|
||||
nghttp2_data_aux_data *aux_data;
|
||||
uint8_t nflags = flags & NGHTTP2_FLAG_END_STREAM;
|
||||
|
||||
if(stream_id == 0) {
|
||||
if (stream_id == 0) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
item = malloc(sizeof(nghttp2_outbound_item));
|
||||
if(item == NULL) {
|
||||
if (item == NULL) {
|
||||
return NGHTTP2_ERR_NOMEM;
|
||||
}
|
||||
|
||||
@ -555,7 +521,7 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
nghttp2_frame_data_init(&frame->data, NGHTTP2_FLAG_NONE, stream_id);
|
||||
|
||||
rv = nghttp2_session_add_item(session, item);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
nghttp2_frame_data_free(&frame->data);
|
||||
free(item);
|
||||
return rv;
|
||||
@ -563,16 +529,14 @@ int nghttp2_submit_data(nghttp2_session *session, uint8_t flags,
|
||||
return 0;
|
||||
}
|
||||
|
||||
ssize_t nghttp2_pack_settings_payload(uint8_t *buf,
|
||||
size_t buflen,
|
||||
ssize_t nghttp2_pack_settings_payload(uint8_t *buf, size_t buflen,
|
||||
const nghttp2_settings_entry *iv,
|
||||
size_t niv)
|
||||
{
|
||||
if(!nghttp2_iv_check(iv, niv)) {
|
||||
size_t niv) {
|
||||
if (!nghttp2_iv_check(iv, niv)) {
|
||||
return NGHTTP2_ERR_INVALID_ARGUMENT;
|
||||
}
|
||||
|
||||
if(buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
|
||||
if (buflen < (niv * NGHTTP2_FRAME_SETTINGS_ENTRY_LENGTH)) {
|
||||
return NGHTTP2_ERR_INSUFF_BUFSIZE;
|
||||
}
|
||||
|
||||
|
@ -26,7 +26,7 @@
|
||||
#define NGHTTP2_SUBMIT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
@ -23,21 +23,16 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
static nghttp2_info version = {
|
||||
NGHTTP2_VERSION_AGE,
|
||||
NGHTTP2_VERSION_NUM,
|
||||
NGHTTP2_VERSION,
|
||||
NGHTTP2_PROTO_VERSION_ID
|
||||
};
|
||||
static nghttp2_info version = {NGHTTP2_VERSION_AGE, NGHTTP2_VERSION_NUM,
|
||||
NGHTTP2_VERSION, NGHTTP2_PROTO_VERSION_ID};
|
||||
|
||||
nghttp2_info *nghttp2_version(int least_version)
|
||||
{
|
||||
if(least_version > NGHTTP2_VERSION_NUM)
|
||||
nghttp2_info *nghttp2_version(int least_version) {
|
||||
if (least_version > NGHTTP2_VERSION_NUM)
|
||||
return NULL;
|
||||
return &version;
|
||||
}
|
||||
|
@ -30,30 +30,21 @@
|
||||
|
||||
namespace nghttp2 {
|
||||
|
||||
ParserData::ParserData(const std::string& base_uri)
|
||||
: base_uri(base_uri)
|
||||
{}
|
||||
ParserData::ParserData(const std::string &base_uri) : base_uri(base_uri) {}
|
||||
|
||||
HtmlParser::HtmlParser(const std::string& base_uri)
|
||||
: base_uri_(base_uri),
|
||||
parser_ctx_(nullptr),
|
||||
parser_data_(base_uri)
|
||||
{}
|
||||
HtmlParser::HtmlParser(const std::string &base_uri)
|
||||
: base_uri_(base_uri), parser_ctx_(nullptr), parser_data_(base_uri) {}
|
||||
|
||||
HtmlParser::~HtmlParser()
|
||||
{
|
||||
htmlFreeParserCtxt(parser_ctx_);
|
||||
}
|
||||
HtmlParser::~HtmlParser() { htmlFreeParserCtxt(parser_ctx_); }
|
||||
|
||||
namespace {
|
||||
const char* get_attr(const xmlChar **attrs, const char *name)
|
||||
{
|
||||
if(attrs == nullptr) {
|
||||
const char *get_attr(const xmlChar **attrs, const char *name) {
|
||||
if (attrs == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
for(; *attrs; attrs += 2) {
|
||||
if(util::strieq(reinterpret_cast<const char*>(attrs[0]), name)) {
|
||||
return reinterpret_cast<const char*>(attrs[1]);
|
||||
for (; *attrs; attrs += 2) {
|
||||
if (util::strieq(reinterpret_cast<const char *>(attrs[0]), name)) {
|
||||
return reinterpret_cast<const char *>(attrs[1]);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
@ -61,46 +52,42 @@ const char* get_attr(const xmlChar **attrs, const char *name)
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void add_link(ParserData *parser_data, const char *uri, RequestPriority pri)
|
||||
{
|
||||
auto u = xmlBuildURI(reinterpret_cast<const xmlChar*>(uri),
|
||||
reinterpret_cast<const xmlChar*>
|
||||
(parser_data->base_uri.c_str()));
|
||||
if(u) {
|
||||
parser_data->links.push_back(std::make_pair(reinterpret_cast<char*>(u),
|
||||
pri));
|
||||
void add_link(ParserData *parser_data, const char *uri, RequestPriority pri) {
|
||||
auto u = xmlBuildURI(
|
||||
reinterpret_cast<const xmlChar *>(uri),
|
||||
reinterpret_cast<const xmlChar *>(parser_data->base_uri.c_str()));
|
||||
if (u) {
|
||||
parser_data->links.push_back(
|
||||
std::make_pair(reinterpret_cast<char *>(u), pri));
|
||||
free(u);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void start_element_func
|
||||
(void* user_data,
|
||||
const xmlChar *name,
|
||||
const xmlChar **attrs)
|
||||
{
|
||||
auto parser_data = static_cast<ParserData*>(user_data);
|
||||
if(util::strieq(reinterpret_cast<const char*>(name), "link")) {
|
||||
void start_element_func(void *user_data, const xmlChar *name,
|
||||
const xmlChar **attrs) {
|
||||
auto parser_data = static_cast<ParserData *>(user_data);
|
||||
if (util::strieq(reinterpret_cast<const char *>(name), "link")) {
|
||||
auto rel_attr = get_attr(attrs, "rel");
|
||||
auto href_attr = get_attr(attrs, "href");
|
||||
if(!href_attr) {
|
||||
if (!href_attr) {
|
||||
return;
|
||||
}
|
||||
if(util::strieq(rel_attr, "shortcut icon")) {
|
||||
if (util::strieq(rel_attr, "shortcut icon")) {
|
||||
add_link(parser_data, href_attr, REQ_PRI_LOWEST);
|
||||
} else if(util::strieq(rel_attr, "stylesheet")) {
|
||||
} else if (util::strieq(rel_attr, "stylesheet")) {
|
||||
add_link(parser_data, href_attr, REQ_PRI_MEDIUM);
|
||||
}
|
||||
} else if(util::strieq(reinterpret_cast<const char*>(name), "img")) {
|
||||
} else if (util::strieq(reinterpret_cast<const char *>(name), "img")) {
|
||||
auto src_attr = get_attr(attrs, "src");
|
||||
if(!src_attr) {
|
||||
if (!src_attr) {
|
||||
return;
|
||||
}
|
||||
add_link(parser_data, src_attr, REQ_PRI_LOWEST);
|
||||
} else if(util::strieq(reinterpret_cast<const char*>(name), "script")) {
|
||||
} else if (util::strieq(reinterpret_cast<const char *>(name), "script")) {
|
||||
auto src_attr = get_attr(attrs, "src");
|
||||
if(!src_attr) {
|
||||
if (!src_attr) {
|
||||
return;
|
||||
}
|
||||
add_link(parser_data, src_attr, REQ_PRI_LOW);
|
||||
@ -109,55 +96,51 @@ void start_element_func
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
xmlSAXHandler saxHandler =
|
||||
{
|
||||
nullptr, // internalSubsetSAXFunc
|
||||
nullptr, // isStandaloneSAXFunc
|
||||
nullptr, // hasInternalSubsetSAXFunc
|
||||
nullptr, // hasExternalSubsetSAXFunc
|
||||
nullptr, // resolveEntitySAXFunc
|
||||
nullptr, // getEntitySAXFunc
|
||||
nullptr, // entityDeclSAXFunc
|
||||
nullptr, // notationDeclSAXFunc
|
||||
nullptr, // attributeDeclSAXFunc
|
||||
nullptr, // elementDeclSAXFunc
|
||||
nullptr, // unparsedEntityDeclSAXFunc
|
||||
nullptr, // setDocumentLocatorSAXFunc
|
||||
nullptr, // startDocumentSAXFunc
|
||||
nullptr, // endDocumentSAXFunc
|
||||
xmlSAXHandler saxHandler = {
|
||||
nullptr, // internalSubsetSAXFunc
|
||||
nullptr, // isStandaloneSAXFunc
|
||||
nullptr, // hasInternalSubsetSAXFunc
|
||||
nullptr, // hasExternalSubsetSAXFunc
|
||||
nullptr, // resolveEntitySAXFunc
|
||||
nullptr, // getEntitySAXFunc
|
||||
nullptr, // entityDeclSAXFunc
|
||||
nullptr, // notationDeclSAXFunc
|
||||
nullptr, // attributeDeclSAXFunc
|
||||
nullptr, // elementDeclSAXFunc
|
||||
nullptr, // unparsedEntityDeclSAXFunc
|
||||
nullptr, // setDocumentLocatorSAXFunc
|
||||
nullptr, // startDocumentSAXFunc
|
||||
nullptr, // endDocumentSAXFunc
|
||||
&start_element_func, // startElementSAXFunc
|
||||
nullptr, // endElementSAXFunc
|
||||
nullptr, // referenceSAXFunc
|
||||
nullptr, // charactersSAXFunc
|
||||
nullptr, // ignorableWhitespaceSAXFunc
|
||||
nullptr, // processingInstructionSAXFunc
|
||||
nullptr, // commentSAXFunc
|
||||
nullptr, // warningSAXFunc
|
||||
nullptr, // errorSAXFunc
|
||||
nullptr, // fatalErrorSAXFunc
|
||||
nullptr, // getParameterEntitySAXFunc
|
||||
nullptr, // cdataBlockSAXFunc
|
||||
nullptr, // externalSubsetSAXFunc
|
||||
0, // unsigned int initialized
|
||||
nullptr, // void * _private
|
||||
nullptr, // startElementNsSAX2Func
|
||||
nullptr, // endElementNsSAX2Func
|
||||
nullptr, // xmlStructuredErrorFunc
|
||||
};
|
||||
nullptr, // endElementSAXFunc
|
||||
nullptr, // referenceSAXFunc
|
||||
nullptr, // charactersSAXFunc
|
||||
nullptr, // ignorableWhitespaceSAXFunc
|
||||
nullptr, // processingInstructionSAXFunc
|
||||
nullptr, // commentSAXFunc
|
||||
nullptr, // warningSAXFunc
|
||||
nullptr, // errorSAXFunc
|
||||
nullptr, // fatalErrorSAXFunc
|
||||
nullptr, // getParameterEntitySAXFunc
|
||||
nullptr, // cdataBlockSAXFunc
|
||||
nullptr, // externalSubsetSAXFunc
|
||||
0, // unsigned int initialized
|
||||
nullptr, // void * _private
|
||||
nullptr, // startElementNsSAX2Func
|
||||
nullptr, // endElementNsSAX2Func
|
||||
nullptr, // xmlStructuredErrorFunc
|
||||
};
|
||||
} // namespace
|
||||
|
||||
int HtmlParser::parse_chunk(const char *chunk, size_t size, int fin)
|
||||
{
|
||||
if(!parser_ctx_) {
|
||||
parser_ctx_ = htmlCreatePushParserCtxt(&saxHandler,
|
||||
&parser_data_,
|
||||
chunk, size,
|
||||
base_uri_.c_str(),
|
||||
XML_CHAR_ENCODING_NONE);
|
||||
if(!parser_ctx_) {
|
||||
int HtmlParser::parse_chunk(const char *chunk, size_t size, int fin) {
|
||||
if (!parser_ctx_) {
|
||||
parser_ctx_ =
|
||||
htmlCreatePushParserCtxt(&saxHandler, &parser_data_, chunk, size,
|
||||
base_uri_.c_str(), XML_CHAR_ENCODING_NONE);
|
||||
if (!parser_ctx_) {
|
||||
return -1;
|
||||
} else {
|
||||
if(fin) {
|
||||
if (fin) {
|
||||
return parse_chunk_internal(nullptr, 0, fin);
|
||||
} else {
|
||||
return 0;
|
||||
@ -168,26 +151,20 @@ int HtmlParser::parse_chunk(const char *chunk, size_t size, int fin)
|
||||
}
|
||||
}
|
||||
|
||||
int HtmlParser::parse_chunk_internal(const char *chunk, size_t size,
|
||||
int fin)
|
||||
{
|
||||
int HtmlParser::parse_chunk_internal(const char *chunk, size_t size, int fin) {
|
||||
int rv = htmlParseChunk(parser_ctx_, chunk, size, fin);
|
||||
if(rv == 0) {
|
||||
if (rv == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
const std::vector<std::pair<std::string, RequestPriority>>&
|
||||
HtmlParser::get_links() const
|
||||
{
|
||||
const std::vector<std::pair<std::string, RequestPriority>> &
|
||||
HtmlParser::get_links() const {
|
||||
return parser_data_.links;
|
||||
}
|
||||
|
||||
void HtmlParser::clear_links()
|
||||
{
|
||||
parser_data_.links.clear();
|
||||
}
|
||||
void HtmlParser::clear_links() { parser_data_.links.clear(); }
|
||||
|
||||
} // namespace nghttp2
|
||||
|
@ -48,19 +48,19 @@ enum RequestPriority {
|
||||
struct ParserData {
|
||||
std::string base_uri;
|
||||
std::vector<std::pair<std::string, RequestPriority>> links;
|
||||
ParserData(const std::string& base_uri);
|
||||
ParserData(const std::string &base_uri);
|
||||
};
|
||||
|
||||
#ifdef HAVE_LIBXML2
|
||||
|
||||
class HtmlParser {
|
||||
public:
|
||||
HtmlParser(const std::string& base_uri);
|
||||
HtmlParser(const std::string &base_uri);
|
||||
~HtmlParser();
|
||||
int parse_chunk(const char *chunk, size_t size, int fin);
|
||||
const std::vector<std::pair<std::string, RequestPriority>>&
|
||||
get_links() const;
|
||||
const std::vector<std::pair<std::string, RequestPriority>> &get_links() const;
|
||||
void clear_links();
|
||||
|
||||
private:
|
||||
int parse_chunk_internal(const char *chunk, size_t size, int fin);
|
||||
|
||||
@ -73,11 +73,14 @@ private:
|
||||
|
||||
class HtmlParser {
|
||||
public:
|
||||
HtmlParser(const std::string& base_uri) {}
|
||||
HtmlParser(const std::string &base_uri) {}
|
||||
int parse_chunk(const char *chunk, size_t size, int fin) { return 0; }
|
||||
const std::vector<std::pair<std::string, RequestPriority>>&
|
||||
get_links() const { return links_; }
|
||||
const std::vector<std::pair<std::string, RequestPriority>> &
|
||||
get_links() const {
|
||||
return links_;
|
||||
}
|
||||
void clear_links() {}
|
||||
|
||||
private:
|
||||
std::vector<std::pair<std::string, RequestPriority>> links_;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -44,7 +44,7 @@
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -112,36 +112,31 @@ public:
|
||||
int on_connect();
|
||||
int verify_npn_result();
|
||||
|
||||
int submit_file_response(const std::string& status,
|
||||
Stream *stream,
|
||||
time_t last_modified,
|
||||
off_t file_length,
|
||||
int submit_file_response(const std::string &status, Stream *stream,
|
||||
time_t last_modified, off_t file_length,
|
||||
nghttp2_data_provider *data_prd);
|
||||
|
||||
int submit_response(const std::string& status,
|
||||
int32_t stream_id,
|
||||
int submit_response(const std::string &status, int32_t stream_id,
|
||||
nghttp2_data_provider *data_prd);
|
||||
|
||||
int submit_response
|
||||
(const std::string& status,
|
||||
int32_t stream_id,
|
||||
const Headers& headers,
|
||||
nghttp2_data_provider *data_prd);
|
||||
int submit_response(const std::string &status, int32_t stream_id,
|
||||
const Headers &headers, nghttp2_data_provider *data_prd);
|
||||
|
||||
int submit_non_final_response(const std::string& status, int32_t stream_id);
|
||||
int submit_non_final_response(const std::string &status, int32_t stream_id);
|
||||
|
||||
int submit_push_promise(Stream *stream, const std::string& push_path);
|
||||
int submit_push_promise(Stream *stream, const std::string &push_path);
|
||||
|
||||
int submit_rst_stream(Stream *stream, uint32_t error_code);
|
||||
|
||||
void add_stream(int32_t stream_id, std::unique_ptr<Stream> stream);
|
||||
void remove_stream(int32_t stream_id);
|
||||
Stream* get_stream(int32_t stream_id);
|
||||
Stream *get_stream(int32_t stream_id);
|
||||
int64_t session_id() const;
|
||||
Sessions* get_sessions() const;
|
||||
const Config* get_config() const;
|
||||
Sessions *get_sessions() const;
|
||||
const Config *get_config() const;
|
||||
void remove_settings_timer();
|
||||
void terminate_session(uint32_t error_code);
|
||||
|
||||
private:
|
||||
std::map<int32_t, std::unique_ptr<Stream>> id2stream_;
|
||||
int64_t session_id_;
|
||||
@ -155,18 +150,18 @@ private:
|
||||
|
||||
class HttpServer {
|
||||
public:
|
||||
HttpServer(const Config* config);
|
||||
HttpServer(const Config *config);
|
||||
int listen();
|
||||
int run();
|
||||
const Config* get_config() const;
|
||||
const Config *get_config() const;
|
||||
|
||||
private:
|
||||
const Config *config_;
|
||||
};
|
||||
|
||||
ssize_t file_read_callback
|
||||
(nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, int *eof,
|
||||
nghttp2_data_source *source, void *user_data);
|
||||
ssize_t file_read_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint8_t *buf, size_t length, int *eof,
|
||||
nghttp2_data_source *source, void *user_data);
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
|
@ -52,9 +52,8 @@
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace {
|
||||
const char* strstatus(uint32_t error_code)
|
||||
{
|
||||
switch(error_code) {
|
||||
const char *strstatus(uint32_t error_code) {
|
||||
switch (error_code) {
|
||||
case NGHTTP2_NO_ERROR:
|
||||
return "NO_ERROR";
|
||||
case NGHTTP2_PROTOCOL_ERROR:
|
||||
@ -90,9 +89,8 @@ const char* strstatus(uint32_t error_code)
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char* strsettingsid(int32_t id)
|
||||
{
|
||||
switch(id) {
|
||||
const char *strsettingsid(int32_t id) {
|
||||
switch (id) {
|
||||
case NGHTTP2_SETTINGS_HEADER_TABLE_SIZE:
|
||||
return "SETTINGS_HEADER_TABLE_SIZE";
|
||||
case NGHTTP2_SETTINGS_ENABLE_PUSH:
|
||||
@ -112,9 +110,8 @@ const char* strsettingsid(int32_t id)
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char* strframetype(uint8_t type)
|
||||
{
|
||||
switch(type) {
|
||||
const char *strframetype(uint8_t type) {
|
||||
switch (type) {
|
||||
case NGHTTP2_DATA:
|
||||
return "DATA";
|
||||
case NGHTTP2_HEADERS:
|
||||
@ -145,44 +142,28 @@ namespace {
|
||||
bool color_output = false;
|
||||
} // namespace
|
||||
|
||||
void set_color_output(bool f)
|
||||
{
|
||||
color_output = f;
|
||||
}
|
||||
void set_color_output(bool f) { color_output = f; }
|
||||
|
||||
namespace {
|
||||
FILE *outfile = stdout;
|
||||
} // namespace
|
||||
|
||||
void set_output(FILE *file)
|
||||
{
|
||||
outfile = file;
|
||||
}
|
||||
void set_output(FILE *file) { outfile = file; }
|
||||
|
||||
namespace {
|
||||
void print_frame_attr_indent()
|
||||
{
|
||||
fprintf(outfile, " ");
|
||||
}
|
||||
void print_frame_attr_indent() { fprintf(outfile, " "); }
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char* ansi_esc(const char *code)
|
||||
{
|
||||
return color_output ? code : "";
|
||||
}
|
||||
const char *ansi_esc(const char *code) { return color_output ? code : ""; }
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
const char* ansi_escend()
|
||||
{
|
||||
return color_output ? "\033[0m" : "";
|
||||
}
|
||||
const char *ansi_escend() { return color_output ? "\033[0m" : ""; }
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_nv(nghttp2_nv *nv)
|
||||
{
|
||||
void print_nv(nghttp2_nv *nv) {
|
||||
fprintf(outfile, "%s", ansi_esc("\033[1;34m"));
|
||||
fwrite(nv->name, nv->namelen, 1, outfile);
|
||||
fprintf(outfile, "%s: ", ansi_escend());
|
||||
@ -191,10 +172,9 @@ void print_nv(nghttp2_nv *nv)
|
||||
}
|
||||
} // namespace
|
||||
namespace {
|
||||
void print_nv(nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
void print_nv(nghttp2_nv *nva, size_t nvlen) {
|
||||
auto end = nva + nvlen;
|
||||
for(; nva != end; ++nva) {
|
||||
for (; nva != end; ++nva) {
|
||||
print_frame_attr_indent();
|
||||
|
||||
print_nv(nva);
|
||||
@ -202,57 +182,53 @@ void print_nv(nghttp2_nv *nva, size_t nvlen)
|
||||
}
|
||||
} // namelen
|
||||
|
||||
void print_timer()
|
||||
{
|
||||
void print_timer() {
|
||||
auto millis = get_timer();
|
||||
fprintf(outfile, "%s[%3ld.%03ld]%s",
|
||||
ansi_esc("\033[33m"),
|
||||
(long int)(millis.count()/1000), (long int)(millis.count()%1000),
|
||||
fprintf(outfile, "%s[%3ld.%03ld]%s", ansi_esc("\033[33m"),
|
||||
(long int)(millis.count() / 1000), (long int)(millis.count() % 1000),
|
||||
ansi_escend());
|
||||
}
|
||||
|
||||
namespace {
|
||||
void print_frame_hd(const nghttp2_frame_hd& hd)
|
||||
{
|
||||
fprintf(outfile, "<length=%zu, flags=0x%02x, stream_id=%d>\n",
|
||||
hd.length, hd.flags, hd.stream_id);
|
||||
void print_frame_hd(const nghttp2_frame_hd &hd) {
|
||||
fprintf(outfile, "<length=%zu, flags=0x%02x, stream_id=%d>\n", hd.length,
|
||||
hd.flags, hd.stream_id);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_flags(const nghttp2_frame_hd& hd)
|
||||
{
|
||||
void print_flags(const nghttp2_frame_hd &hd) {
|
||||
std::string s;
|
||||
switch(hd.type) {
|
||||
switch (hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
if (hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
s += "END_STREAM";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if(!s.empty()) {
|
||||
if (hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if (!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PADDED";
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_HEADERS:
|
||||
if(hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
if (hd.flags & NGHTTP2_FLAG_END_STREAM) {
|
||||
s += "END_STREAM";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||
if(!s.empty()) {
|
||||
if (hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||
if (!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "END_HEADERS";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if(!s.empty()) {
|
||||
if (hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if (!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PADDED";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
if(!s.empty()) {
|
||||
if (hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
if (!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PRIORITY";
|
||||
@ -262,23 +238,23 @@ void print_flags(const nghttp2_frame_hd& hd)
|
||||
case NGHTTP2_PRIORITY:
|
||||
break;
|
||||
case NGHTTP2_SETTINGS:
|
||||
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
if (hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
s += "ACK";
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
if(hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||
if (hd.flags & NGHTTP2_FLAG_END_HEADERS) {
|
||||
s += "END_HEADERS";
|
||||
}
|
||||
if(hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if(!s.empty()) {
|
||||
if (hd.flags & NGHTTP2_FLAG_PADDED) {
|
||||
if (!s.empty()) {
|
||||
s += " | ";
|
||||
}
|
||||
s += "PADDED";
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
if(hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
if (hd.flags & NGHTTP2_FLAG_ACK) {
|
||||
s += "ACK";
|
||||
}
|
||||
break;
|
||||
@ -287,33 +263,26 @@ void print_flags(const nghttp2_frame_hd& hd)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
enum print_type {
|
||||
PRINT_SEND,
|
||||
PRINT_RECV
|
||||
};
|
||||
enum print_type { PRINT_SEND, PRINT_RECV };
|
||||
|
||||
namespace {
|
||||
const char* frame_name_ansi_esc(print_type ptype)
|
||||
{
|
||||
const char *frame_name_ansi_esc(print_type ptype) {
|
||||
return ansi_esc(ptype == PRINT_SEND ? "\033[1;35m" : "\033[1;36m");
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
{
|
||||
fprintf(outfile, "%s%s%s frame ",
|
||||
frame_name_ansi_esc(ptype),
|
||||
strframetype(frame->hd.type),
|
||||
ansi_escend());
|
||||
void print_frame(print_type ptype, const nghttp2_frame *frame) {
|
||||
fprintf(outfile, "%s%s%s frame ", frame_name_ansi_esc(ptype),
|
||||
strframetype(frame->hd.type), ansi_escend());
|
||||
print_frame_hd(frame->hd);
|
||||
if(frame->hd.flags) {
|
||||
if (frame->hd.flags) {
|
||||
print_frame_attr_indent();
|
||||
print_flags(frame->hd);
|
||||
}
|
||||
switch(frame->hd.type) {
|
||||
switch (frame->hd.type) {
|
||||
case NGHTTP2_DATA:
|
||||
if(frame->data.padlen > 0) {
|
||||
if (frame->data.padlen > 0) {
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(padlen=%zu)\n", frame->data.padlen);
|
||||
}
|
||||
@ -321,14 +290,13 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
case NGHTTP2_HEADERS:
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(padlen=%zu", frame->headers.padlen);
|
||||
if(frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
if (frame->hd.flags & NGHTTP2_FLAG_PRIORITY) {
|
||||
fprintf(outfile, ", stream_id=%d, weight=%u, exclusive=%d",
|
||||
frame->headers.pri_spec.stream_id,
|
||||
frame->headers.pri_spec.weight,
|
||||
frame->headers.pri_spec.stream_id, frame->headers.pri_spec.weight,
|
||||
frame->headers.pri_spec.exclusive);
|
||||
}
|
||||
fprintf(outfile, ")\n");
|
||||
switch(frame->headers.cat) {
|
||||
switch (frame->headers.cat) {
|
||||
case NGHTTP2_HCAT_REQUEST:
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "; Open new stream\n");
|
||||
@ -350,8 +318,7 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
print_frame_attr_indent();
|
||||
|
||||
fprintf(outfile, "(stream_id=%d, weight=%u, exclusive=%d)\n",
|
||||
frame->priority.pri_spec.stream_id,
|
||||
frame->priority.pri_spec.weight,
|
||||
frame->priority.pri_spec.stream_id, frame->priority.pri_spec.weight,
|
||||
frame->priority.pri_spec.exclusive);
|
||||
|
||||
break;
|
||||
@ -365,19 +332,17 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(niv=%lu)\n",
|
||||
static_cast<unsigned long>(frame->settings.niv));
|
||||
for(size_t i = 0; i < frame->settings.niv; ++i) {
|
||||
for (size_t i = 0; i < frame->settings.niv; ++i) {
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "[%s(0x%02x):%u]\n",
|
||||
strsettingsid(frame->settings.iv[i].settings_id),
|
||||
frame->settings.iv[i].settings_id,
|
||||
frame->settings.iv[i].value);
|
||||
frame->settings.iv[i].settings_id, frame->settings.iv[i].value);
|
||||
}
|
||||
break;
|
||||
case NGHTTP2_PUSH_PROMISE:
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile, "(padlen=%zu, promised_stream_id=%d)\n",
|
||||
frame->push_promise.padlen,
|
||||
frame->push_promise.promised_stream_id);
|
||||
frame->push_promise.padlen, frame->push_promise.promised_stream_id);
|
||||
print_nv(frame->push_promise.nva, frame->push_promise.nvlen);
|
||||
break;
|
||||
case NGHTTP2_PING:
|
||||
@ -387,11 +352,9 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
break;
|
||||
case NGHTTP2_GOAWAY:
|
||||
print_frame_attr_indent();
|
||||
fprintf(outfile,
|
||||
"(last_stream_id=%d, error_code=%s(0x%02x), "
|
||||
"opaque_data(%u)=[%s])\n",
|
||||
frame->goaway.last_stream_id,
|
||||
strstatus(frame->goaway.error_code),
|
||||
fprintf(outfile, "(last_stream_id=%d, error_code=%s(0x%02x), "
|
||||
"opaque_data(%u)=[%s])\n",
|
||||
frame->goaway.last_stream_id, strstatus(frame->goaway.error_code),
|
||||
frame->goaway.error_code,
|
||||
static_cast<unsigned int>(frame->goaway.opaque_data_len),
|
||||
util::ascii_dump(frame->goaway.opaque_data,
|
||||
@ -405,24 +368,24 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
case NGHTTP2_EXT_ALTSVC: {
|
||||
print_frame_attr_indent();
|
||||
|
||||
auto altsvc = static_cast<const nghttp2_ext_altsvc*>(frame->ext.payload);
|
||||
auto altsvc = static_cast<const nghttp2_ext_altsvc *>(frame->ext.payload);
|
||||
|
||||
fprintf(outfile, "(max-age=%u, port=%u, protocol_id=",
|
||||
altsvc->max_age, altsvc->port);
|
||||
fprintf(outfile, "(max-age=%u, port=%u, protocol_id=", altsvc->max_age,
|
||||
altsvc->port);
|
||||
|
||||
if(altsvc->protocol_id_len) {
|
||||
if (altsvc->protocol_id_len) {
|
||||
fwrite(altsvc->protocol_id, altsvc->protocol_id_len, 1, outfile);
|
||||
}
|
||||
|
||||
fprintf(outfile, ", host=");
|
||||
|
||||
if(altsvc->host_len) {
|
||||
if (altsvc->host_len) {
|
||||
fwrite(altsvc->host, altsvc->host_len, 1, outfile);
|
||||
}
|
||||
|
||||
fprintf(outfile, ", origin=");
|
||||
|
||||
if(altsvc->origin_len) {
|
||||
if (altsvc->origin_len) {
|
||||
fwrite(altsvc->origin, altsvc->origin_len, 1, outfile);
|
||||
}
|
||||
|
||||
@ -437,16 +400,12 @@ void print_frame(print_type ptype, const nghttp2_frame *frame)
|
||||
} // namespace
|
||||
|
||||
int verbose_on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *user_data)
|
||||
{
|
||||
nghttp2_nv nv = {
|
||||
const_cast<uint8_t*>(name), const_cast<uint8_t*>(value),
|
||||
namelen, valuelen
|
||||
};
|
||||
const nghttp2_frame *frame, const uint8_t *name,
|
||||
size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, uint8_t flags,
|
||||
void *user_data) {
|
||||
nghttp2_nv nv = {const_cast<uint8_t *>(name), const_cast<uint8_t *>(value),
|
||||
namelen, valuelen};
|
||||
|
||||
print_timer();
|
||||
fprintf(outfile, " recv (stream_id=%d, noind=%d) ", frame->hd.stream_id,
|
||||
@ -458,9 +417,9 @@ int verbose_on_header_callback(nghttp2_session *session,
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verbose_on_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
int verbose_on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
print_timer();
|
||||
fprintf(outfile, " recv ");
|
||||
print_frame(PRINT_RECV, frame);
|
||||
@ -468,10 +427,10 @@ int verbose_on_frame_recv_callback
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verbose_on_invalid_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
uint32_t error_code, void *user_data)
|
||||
{
|
||||
int verbose_on_invalid_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
uint32_t error_code,
|
||||
void *user_data) {
|
||||
print_timer();
|
||||
fprintf(outfile, " [INVALID; status=%s] recv ", strstatus(error_code));
|
||||
print_frame(PRINT_RECV, frame);
|
||||
@ -479,9 +438,9 @@ int verbose_on_invalid_frame_recv_callback
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verbose_on_frame_send_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data)
|
||||
{
|
||||
int verbose_on_frame_send_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
print_timer();
|
||||
fprintf(outfile, " send ");
|
||||
print_frame(PRINT_SEND, frame);
|
||||
@ -489,13 +448,12 @@ int verbose_on_frame_send_callback
|
||||
return 0;
|
||||
}
|
||||
|
||||
int verbose_on_data_chunk_recv_callback
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data)
|
||||
{
|
||||
int verbose_on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
print_timer();
|
||||
auto srecv = nghttp2_session_get_stream_effective_recv_data_length
|
||||
(session, stream_id);
|
||||
auto srecv =
|
||||
nghttp2_session_get_stream_effective_recv_data_length(session, stream_id);
|
||||
auto crecv = nghttp2_session_get_effective_recv_data_length(session);
|
||||
|
||||
fprintf(outfile,
|
||||
@ -510,24 +468,18 @@ namespace {
|
||||
std::chrono::steady_clock::time_point base_tv;
|
||||
} // namespace
|
||||
|
||||
void reset_timer()
|
||||
{
|
||||
base_tv = std::chrono::steady_clock::now();
|
||||
}
|
||||
void reset_timer() { base_tv = std::chrono::steady_clock::now(); }
|
||||
|
||||
std::chrono::milliseconds get_timer()
|
||||
{
|
||||
std::chrono::milliseconds get_timer() {
|
||||
return time_delta(std::chrono::steady_clock::now(), base_tv);
|
||||
}
|
||||
|
||||
std::chrono::steady_clock::time_point get_time()
|
||||
{
|
||||
std::chrono::steady_clock::time_point get_time() {
|
||||
return std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
|
||||
size_t inlen) {
|
||||
int rv;
|
||||
z_stream zst;
|
||||
uint8_t temp_out[8192];
|
||||
@ -538,15 +490,15 @@ ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
zst.zfree = Z_NULL;
|
||||
zst.opaque = Z_NULL;
|
||||
|
||||
rv = deflateInit2(&zst, Z_DEFAULT_COMPRESSION, Z_DEFLATED,
|
||||
31, 9, Z_DEFAULT_STRATEGY);
|
||||
rv = deflateInit2(&zst, Z_DEFAULT_COMPRESSION, Z_DEFLATED, 31, 9,
|
||||
Z_DEFAULT_STRATEGY);
|
||||
|
||||
if(rv != Z_OK) {
|
||||
if (rv != Z_OK) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
zst.avail_in = inlen;
|
||||
zst.next_in = (uint8_t*)in;
|
||||
zst.next_in = (uint8_t *)in;
|
||||
zst.avail_out = temp_outlen;
|
||||
zst.next_out = temp_out;
|
||||
|
||||
@ -554,13 +506,13 @@ ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
|
||||
deflateEnd(&zst);
|
||||
|
||||
if(rv != Z_STREAM_END) {
|
||||
if (rv != Z_STREAM_END) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
temp_outlen -= zst.avail_out;
|
||||
|
||||
if(temp_outlen > outlen) {
|
||||
if (temp_outlen > outlen) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
@ -40,31 +40,29 @@
|
||||
namespace nghttp2 {
|
||||
|
||||
int verbose_on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *user_data);
|
||||
const nghttp2_frame *frame, const uint8_t *name,
|
||||
size_t namelen, const uint8_t *value,
|
||||
size_t valuelen, uint8_t flags, void *user_data);
|
||||
|
||||
int verbose_on_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
int verbose_on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data);
|
||||
|
||||
int verbose_on_invalid_frame_recv_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
uint32_t error_code, void *user_data);
|
||||
int verbose_on_invalid_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
uint32_t error_code,
|
||||
void *user_data);
|
||||
|
||||
int verbose_on_frame_send_callback
|
||||
(nghttp2_session *session, const nghttp2_frame *frame, void *user_data);
|
||||
int verbose_on_frame_send_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame, void *user_data);
|
||||
|
||||
int verbose_on_data_chunk_recv_callback
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data);
|
||||
int verbose_on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data);
|
||||
|
||||
// Returns difference between |a| and |b| in milliseconds, assuming
|
||||
// |a| is more recent than |b|.
|
||||
template<typename TimePoint>
|
||||
std::chrono::milliseconds time_delta(const TimePoint& a, const TimePoint& b)
|
||||
{
|
||||
template <typename TimePoint>
|
||||
std::chrono::milliseconds time_delta(const TimePoint &a, const TimePoint &b) {
|
||||
return std::chrono::duration_cast<std::chrono::milliseconds>(a - b);
|
||||
}
|
||||
|
||||
@ -88,8 +86,8 @@ void set_color_output(bool f);
|
||||
// used.
|
||||
void set_output(FILE *file);
|
||||
|
||||
ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
const uint8_t *in, size_t inlen);
|
||||
ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
|
||||
size_t inlen);
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
|
@ -56,81 +56,62 @@ namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
/// Represents a single connection from a client.
|
||||
template<typename socket_type>
|
||||
class connection
|
||||
: public std::enable_shared_from_this<connection<socket_type>>,
|
||||
private boost::noncopyable
|
||||
{
|
||||
template <typename socket_type>
|
||||
class connection : public std::enable_shared_from_this<connection<socket_type>>,
|
||||
private boost::noncopyable {
|
||||
public:
|
||||
/// Construct a connection with the given io_service.
|
||||
template<typename... SocketArgs>
|
||||
explicit connection(request_cb cb,
|
||||
boost::asio::io_service& task_io_service,
|
||||
SocketArgs&&... args)
|
||||
: socket_(std::forward<SocketArgs>(args)...),
|
||||
request_cb_(std::move(cb)),
|
||||
task_io_service_(task_io_service),
|
||||
writing_(false)
|
||||
{}
|
||||
template <typename... SocketArgs>
|
||||
explicit connection(request_cb cb, boost::asio::io_service &task_io_service,
|
||||
SocketArgs &&... args)
|
||||
: socket_(std::forward<SocketArgs>(args)...), request_cb_(std::move(cb)),
|
||||
task_io_service_(task_io_service), writing_(false) {}
|
||||
|
||||
/// Start the first asynchronous operation for the connection.
|
||||
void start()
|
||||
{
|
||||
handler_ = std::make_shared<http2_handler>
|
||||
(socket_.get_io_service(),
|
||||
task_io_service_,
|
||||
[this]()
|
||||
{
|
||||
do_write();
|
||||
},
|
||||
request_cb_);
|
||||
if(handler_->start() != 0) {
|
||||
void start() {
|
||||
handler_ = std::make_shared<http2_handler>(
|
||||
socket_.get_io_service(), task_io_service_, [this]() { do_write(); },
|
||||
request_cb_);
|
||||
if (handler_->start() != 0) {
|
||||
return;
|
||||
}
|
||||
do_read();
|
||||
}
|
||||
|
||||
socket_type& socket()
|
||||
{
|
||||
return socket_;
|
||||
}
|
||||
socket_type &socket() { return socket_; }
|
||||
|
||||
void do_read()
|
||||
{
|
||||
void do_read() {
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
socket_.async_read_some
|
||||
(boost::asio::buffer(buffer_),
|
||||
[this, self](const boost::system::error_code& e,
|
||||
std::size_t bytes_transferred)
|
||||
{
|
||||
if (!e) {
|
||||
if(handler_->on_read(buffer_, bytes_transferred) != 0) {
|
||||
return;
|
||||
}
|
||||
socket_.async_read_some(boost::asio::buffer(buffer_),
|
||||
[this, self](const boost::system::error_code &e,
|
||||
std::size_t bytes_transferred) {
|
||||
if (!e) {
|
||||
if (handler_->on_read(buffer_, bytes_transferred) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_write();
|
||||
do_write();
|
||||
|
||||
if(!writing_ && handler_->should_stop()) {
|
||||
return;
|
||||
}
|
||||
if (!writing_ && handler_->should_stop()) {
|
||||
return;
|
||||
}
|
||||
|
||||
do_read();
|
||||
}
|
||||
do_read();
|
||||
}
|
||||
|
||||
// If an error occurs then no new asynchronous operations are
|
||||
// started. This means that all shared_ptr references to the
|
||||
// connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The
|
||||
// connection class's destructor closes the socket.
|
||||
});
|
||||
// If an error occurs then no new asynchronous operations are
|
||||
// started. This means that all shared_ptr references to the
|
||||
// connection object will disappear and the object will be
|
||||
// destroyed automatically after this handler returns. The
|
||||
// connection class's destructor closes the socket.
|
||||
});
|
||||
}
|
||||
|
||||
void do_write()
|
||||
{
|
||||
void do_write() {
|
||||
auto self = this->shared_from_this();
|
||||
|
||||
if(writing_) {
|
||||
if (writing_) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -139,27 +120,25 @@ public:
|
||||
|
||||
rv = handler_->on_write(outbuf_, nwrite);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if(nwrite == 0) {
|
||||
if (nwrite == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
writing_ = true;
|
||||
|
||||
boost::asio::async_write
|
||||
(socket_, boost::asio::buffer(outbuf_, nwrite),
|
||||
[this, self](const boost::system::error_code& e,
|
||||
std::size_t)
|
||||
{
|
||||
if(!e) {
|
||||
writing_ = false;
|
||||
boost::asio::async_write(
|
||||
socket_, boost::asio::buffer(outbuf_, nwrite),
|
||||
[this, self](const boost::system::error_code &e, std::size_t) {
|
||||
if (!e) {
|
||||
writing_ = false;
|
||||
|
||||
do_write();
|
||||
}
|
||||
});
|
||||
do_write();
|
||||
}
|
||||
});
|
||||
|
||||
// No new asynchronous operations are started. This means that all
|
||||
// shared_ptr references to the connection object will disappear and
|
||||
@ -172,7 +151,7 @@ private:
|
||||
|
||||
request_cb request_cb_;
|
||||
|
||||
boost::asio::io_service& task_io_service_;
|
||||
boost::asio::io_service &task_io_service_;
|
||||
|
||||
std::shared_ptr<http2_handler> handler_;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -46,6 +46,7 @@ public:
|
||||
channel_impl();
|
||||
void post(void_cb cb);
|
||||
void strand(boost::asio::io_service::strand *strand);
|
||||
|
||||
private:
|
||||
boost::asio::io_service::strand *strand_;
|
||||
};
|
||||
@ -59,12 +60,12 @@ class request_impl {
|
||||
public:
|
||||
request_impl();
|
||||
|
||||
const std::vector<header>& headers() const;
|
||||
const std::string& method() const;
|
||||
const std::string& scheme() const;
|
||||
const std::string& authority() const;
|
||||
const std::string& host() const;
|
||||
const std::string& path() const;
|
||||
const std::vector<header> &headers() const;
|
||||
const std::string &method() const;
|
||||
const std::string &scheme() const;
|
||||
const std::string &authority() const;
|
||||
const std::string &host() const;
|
||||
const std::string &path() const;
|
||||
|
||||
bool push(std::string method, std::string path,
|
||||
std::vector<header> headers = {});
|
||||
@ -89,6 +90,7 @@ public:
|
||||
void stream(std::weak_ptr<http2_stream> s);
|
||||
void call_on_data(const uint8_t *data, std::size_t len);
|
||||
void call_on_end();
|
||||
|
||||
private:
|
||||
std::vector<header> headers_;
|
||||
std::string method_;
|
||||
@ -113,11 +115,12 @@ public:
|
||||
bool closed() const;
|
||||
|
||||
unsigned int status_code() const;
|
||||
const std::vector<header>& headers() const;
|
||||
const std::vector<header> &headers() const;
|
||||
bool started() const;
|
||||
void handler(std::weak_ptr<http2_handler> h);
|
||||
void stream(std::weak_ptr<http2_stream> s);
|
||||
read_cb::result_type call_read(uint8_t *data, std::size_t len);
|
||||
|
||||
private:
|
||||
std::vector<header> headers_;
|
||||
read_cb read_cb_;
|
||||
@ -132,8 +135,9 @@ public:
|
||||
http2_stream(int32_t stream_id);
|
||||
|
||||
int32_t get_stream_id() const;
|
||||
const std::shared_ptr<request>& get_request();
|
||||
const std::shared_ptr<response>& get_response();
|
||||
const std::shared_ptr<request> &get_request();
|
||||
const std::shared_ptr<response> &get_response();
|
||||
|
||||
private:
|
||||
std::shared_ptr<request> request_;
|
||||
std::shared_ptr<response> response_;
|
||||
@ -141,19 +145,18 @@ private:
|
||||
};
|
||||
|
||||
struct callback_guard {
|
||||
callback_guard(http2_handler& h);
|
||||
callback_guard(http2_handler &h);
|
||||
~callback_guard();
|
||||
http2_handler& handler;
|
||||
http2_handler &handler;
|
||||
};
|
||||
|
||||
typedef std::function<void(void)> connection_write;
|
||||
|
||||
class http2_handler : public std::enable_shared_from_this<http2_handler> {
|
||||
public:
|
||||
http2_handler(boost::asio::io_service& io_service,
|
||||
boost::asio::io_service& task_io_service,
|
||||
connection_write writefun,
|
||||
request_cb cb);
|
||||
http2_handler(boost::asio::io_service &io_service,
|
||||
boost::asio::io_service &task_io_service,
|
||||
connection_write writefun, request_cb cb);
|
||||
|
||||
~http2_handler();
|
||||
|
||||
@ -163,11 +166,11 @@ public:
|
||||
void close_stream(int32_t stream_id);
|
||||
std::shared_ptr<http2_stream> find_stream(int32_t stream_id);
|
||||
|
||||
void call_on_request(http2_stream& stream);
|
||||
void call_on_request(http2_stream &stream);
|
||||
|
||||
bool should_stop() const;
|
||||
|
||||
int start_response(http2_stream& stream);
|
||||
int start_response(http2_stream &stream);
|
||||
|
||||
void stream_error(int32_t stream_id, uint32_t error_code);
|
||||
|
||||
@ -177,40 +180,37 @@ public:
|
||||
void leave_callback();
|
||||
bool inside_callback() const;
|
||||
|
||||
void resume(http2_stream& stream);
|
||||
void resume(http2_stream &stream);
|
||||
|
||||
int push_promise(http2_stream& stream, std::string method,
|
||||
std::string path,
|
||||
int push_promise(http2_stream &stream, std::string method, std::string path,
|
||||
std::vector<header> headers);
|
||||
|
||||
bool run_task(thread_cb start);
|
||||
|
||||
boost::asio::io_service& io_service();
|
||||
boost::asio::io_service &io_service();
|
||||
|
||||
template<size_t N>
|
||||
int on_read(const boost::array<uint8_t, N>& buffer, std::size_t len)
|
||||
{
|
||||
template <size_t N>
|
||||
int on_read(const boost::array<uint8_t, N> &buffer, std::size_t len) {
|
||||
callback_guard cg(*this);
|
||||
|
||||
int rv;
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, buffer.data(), len);
|
||||
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<size_t N>
|
||||
int on_write(boost::array<uint8_t, N>& buffer, std::size_t& len)
|
||||
{
|
||||
template <size_t N>
|
||||
int on_write(boost::array<uint8_t, N> &buffer, std::size_t &len) {
|
||||
callback_guard cg(*this);
|
||||
|
||||
len = 0;
|
||||
|
||||
if(buf_) {
|
||||
if (buf_) {
|
||||
std::copy(buf_, buf_ + buflen_, std::begin(buffer));
|
||||
|
||||
len += buflen_;
|
||||
@ -219,18 +219,18 @@ public:
|
||||
buflen_ = 0;
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
const uint8_t *data;
|
||||
auto nread = nghttp2_session_mem_send(session_, &data);
|
||||
if(nread < 0) {
|
||||
if (nread < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(nread == 0) {
|
||||
if (nread == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(len + nread > buffer.size()) {
|
||||
if (len + nread > buffer.size()) {
|
||||
buf_ = data;
|
||||
buflen_ = nread;
|
||||
|
||||
@ -249,8 +249,8 @@ private:
|
||||
std::map<int32_t, std::shared_ptr<http2_stream>> streams_;
|
||||
connection_write writefun_;
|
||||
request_cb request_cb_;
|
||||
boost::asio::io_service& io_service_;
|
||||
boost::asio::io_service& task_io_service_;
|
||||
boost::asio::io_service &io_service_;
|
||||
boost::asio::io_service &task_io_service_;
|
||||
std::shared_ptr<boost::asio::io_service::strand> strand_;
|
||||
nghttp2_session *session_;
|
||||
const uint8_t *buf_;
|
||||
|
@ -40,76 +40,55 @@ namespace asio_http2 {
|
||||
|
||||
namespace server {
|
||||
|
||||
http2::http2()
|
||||
: impl_(util::make_unique<http2_impl>())
|
||||
{}
|
||||
http2::http2() : impl_(util::make_unique<http2_impl>()) {}
|
||||
|
||||
http2::~http2()
|
||||
{}
|
||||
http2::~http2() {}
|
||||
|
||||
void http2::listen(const std::string& address, uint16_t port, request_cb cb)
|
||||
{
|
||||
void http2::listen(const std::string &address, uint16_t port, request_cb cb) {
|
||||
impl_->listen(address, port, std::move(cb));
|
||||
}
|
||||
|
||||
void http2::num_threads(size_t num_threads)
|
||||
{
|
||||
impl_->num_threads(num_threads);
|
||||
}
|
||||
void http2::num_threads(size_t num_threads) { impl_->num_threads(num_threads); }
|
||||
|
||||
void http2::tls(std::string private_key_file,
|
||||
std::string certificate_file)
|
||||
{
|
||||
void http2::tls(std::string private_key_file, std::string certificate_file) {
|
||||
impl_->tls(std::move(private_key_file), std::move(certificate_file));
|
||||
}
|
||||
|
||||
void http2::num_concurrent_tasks(size_t num_concurrent_tasks)
|
||||
{
|
||||
void http2::num_concurrent_tasks(size_t num_concurrent_tasks) {
|
||||
impl_->num_concurrent_tasks(num_concurrent_tasks);
|
||||
}
|
||||
|
||||
void http2::backlog(int backlog)
|
||||
{
|
||||
impl_->backlog(backlog);
|
||||
}
|
||||
void http2::backlog(int backlog) { impl_->backlog(backlog); }
|
||||
|
||||
http2_impl::http2_impl()
|
||||
: num_threads_(1),
|
||||
num_concurrent_tasks_(1),
|
||||
backlog_(-1)
|
||||
{}
|
||||
: num_threads_(1), num_concurrent_tasks_(1), backlog_(-1) {}
|
||||
|
||||
namespace {
|
||||
std::vector<unsigned char>&
|
||||
get_alpn_token()
|
||||
{
|
||||
std::vector<unsigned char> &get_alpn_token() {
|
||||
static auto alpn_token = util::get_default_alpn();
|
||||
return alpn_token;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void http2_impl::listen(const std::string& address, uint16_t port,
|
||||
request_cb cb)
|
||||
{
|
||||
void http2_impl::listen(const std::string &address, uint16_t port,
|
||||
request_cb cb) {
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx;
|
||||
|
||||
if(!private_key_file_.empty() && !certificate_file_.empty()) {
|
||||
ssl_ctx = util::make_unique<boost::asio::ssl::context>
|
||||
(boost::asio::ssl::context::sslv23);
|
||||
if (!private_key_file_.empty() && !certificate_file_.empty()) {
|
||||
ssl_ctx = util::make_unique<boost::asio::ssl::context>(
|
||||
boost::asio::ssl::context::sslv23);
|
||||
|
||||
ssl_ctx->use_private_key_file(private_key_file_,
|
||||
boost::asio::ssl::context::pem);
|
||||
boost::asio::ssl::context::pem);
|
||||
ssl_ctx->use_certificate_chain_file(certificate_file_);
|
||||
|
||||
auto ctx = ssl_ctx->native_handle();
|
||||
|
||||
SSL_CTX_set_options(ctx,
|
||||
SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_SINGLE_ECDH_USE |
|
||||
SSL_OP_NO_TICKET |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
SSL_CTX_set_options(ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
|
||||
SSL_OP_NO_COMPRESSION |
|
||||
SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
|
||||
SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
|
||||
SSL_OP_CIPHER_SERVER_PREFERENCE);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_AUTO_RETRY);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_RELEASE_BUFFERS);
|
||||
SSL_CTX_set_mode(ctx, SSL_MODE_ENABLE_PARTIAL_WRITE);
|
||||
@ -117,103 +96,86 @@ void http2_impl::listen(const std::string& address, uint16_t port,
|
||||
SSL_CTX_set_cipher_list(ctx, ssl::DEFAULT_CIPHER_LIST);
|
||||
|
||||
auto ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1);
|
||||
if(ecdh) {
|
||||
if (ecdh) {
|
||||
SSL_CTX_set_tmp_ecdh(ctx, ecdh);
|
||||
EC_KEY_free(ecdh);
|
||||
}
|
||||
|
||||
SSL_CTX_set_next_protos_advertised_cb
|
||||
(ctx,
|
||||
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
|
||||
auto& token = get_alpn_token();
|
||||
SSL_CTX_set_next_protos_advertised_cb(
|
||||
ctx,
|
||||
[](SSL *s, const unsigned char **data, unsigned int *len, void *arg) {
|
||||
auto &token = get_alpn_token();
|
||||
|
||||
*data = token.data();
|
||||
*len = token.size();
|
||||
*data = token.data();
|
||||
*len = token.size();
|
||||
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
}, nullptr);
|
||||
return SSL_TLSEXT_ERR_OK;
|
||||
},
|
||||
nullptr);
|
||||
}
|
||||
|
||||
server(address, port, num_threads_, num_concurrent_tasks_,
|
||||
std::move(cb), std::move(ssl_ctx), backlog_).run();
|
||||
server(address, port, num_threads_, num_concurrent_tasks_, std::move(cb),
|
||||
std::move(ssl_ctx), backlog_).run();
|
||||
}
|
||||
|
||||
void http2_impl::num_threads(size_t num_threads)
|
||||
{
|
||||
num_threads_ = num_threads;
|
||||
}
|
||||
void http2_impl::num_threads(size_t num_threads) { num_threads_ = num_threads; }
|
||||
|
||||
void http2_impl::tls(std::string private_key_file,
|
||||
std::string certificate_file)
|
||||
{
|
||||
std::string certificate_file) {
|
||||
private_key_file_ = std::move(private_key_file);
|
||||
certificate_file_ = std::move(certificate_file);
|
||||
}
|
||||
|
||||
void http2_impl::num_concurrent_tasks(size_t num_concurrent_tasks)
|
||||
{
|
||||
void http2_impl::num_concurrent_tasks(size_t num_concurrent_tasks) {
|
||||
num_concurrent_tasks_ = num_concurrent_tasks;
|
||||
}
|
||||
|
||||
void http2_impl::backlog(int backlog)
|
||||
{
|
||||
backlog_ = backlog;
|
||||
}
|
||||
void http2_impl::backlog(int backlog) { backlog_ = backlog; }
|
||||
|
||||
} // namespace server
|
||||
|
||||
template<typename T, typename F>
|
||||
std::shared_ptr<util::Defer<T, F>> defer_shared(T&& t, F f)
|
||||
{
|
||||
template <typename T, typename F>
|
||||
std::shared_ptr<util::Defer<T, F>> defer_shared(T &&t, F f) {
|
||||
return std::make_shared<util::Defer<T, F>>(std::forward<T>(t),
|
||||
std::forward<F>(f));
|
||||
}
|
||||
|
||||
read_cb file_reader(const std::string& path)
|
||||
{
|
||||
read_cb file_reader(const std::string &path) {
|
||||
auto fd = open(path.c_str(), O_RDONLY);
|
||||
if(fd == -1) {
|
||||
if (fd == -1) {
|
||||
return read_cb();
|
||||
}
|
||||
|
||||
return file_reader_from_fd(fd);
|
||||
}
|
||||
|
||||
read_cb file_reader_from_fd(int fd)
|
||||
{
|
||||
read_cb file_reader_from_fd(int fd) {
|
||||
auto d = defer_shared(static_cast<int>(fd), close);
|
||||
|
||||
return [fd, d](uint8_t *buf, size_t len) -> read_cb::result_type
|
||||
{
|
||||
int rv;
|
||||
while((rv = read(fd, buf, len)) == -1 && errno == EINTR);
|
||||
return [fd, d](uint8_t *buf, size_t len) -> read_cb::result_type {
|
||||
int rv;
|
||||
while ((rv = read(fd, buf, len)) == -1 && errno == EINTR)
|
||||
;
|
||||
|
||||
if(rv == -1) {
|
||||
return std::make_pair(-1, false);
|
||||
}
|
||||
if (rv == -1) {
|
||||
return std::make_pair(-1, false);
|
||||
}
|
||||
|
||||
if(rv == 0) {
|
||||
return std::make_pair(rv, true);
|
||||
}
|
||||
if (rv == 0) {
|
||||
return std::make_pair(rv, true);
|
||||
}
|
||||
|
||||
return std::make_pair(rv, false);
|
||||
};
|
||||
return std::make_pair(rv, false);
|
||||
};
|
||||
}
|
||||
|
||||
bool check_path(const std::string& path)
|
||||
{
|
||||
return util::check_path(path);
|
||||
}
|
||||
bool check_path(const std::string &path) { return util::check_path(path); }
|
||||
|
||||
std::string percent_decode(const std::string& s)
|
||||
{
|
||||
std::string percent_decode(const std::string &s) {
|
||||
return util::percentDecode(std::begin(s), std::end(s));
|
||||
}
|
||||
|
||||
std::string http_date(int64_t t)
|
||||
{
|
||||
return util::http_date(t);
|
||||
}
|
||||
std::string http_date(int64_t t) { return util::http_date(t); }
|
||||
|
||||
} // namespace asio_http2
|
||||
|
||||
|
@ -40,12 +40,12 @@ class server;
|
||||
class http2_impl {
|
||||
public:
|
||||
http2_impl();
|
||||
void listen(const std::string& address, uint16_t port,
|
||||
request_cb cb);
|
||||
void listen(const std::string &address, uint16_t port, request_cb cb);
|
||||
void num_threads(size_t num_threads);
|
||||
void tls(std::string private_key_file, std::string certificate_file);
|
||||
void num_concurrent_tasks(size_t num_concurrent_tasks);
|
||||
void backlog(int backlog);
|
||||
|
||||
private:
|
||||
std::string private_key_file_;
|
||||
std::string certificate_file_;
|
||||
|
@ -48,9 +48,7 @@ namespace server {
|
||||
|
||||
io_service_pool::io_service_pool(std::size_t pool_size,
|
||||
std::size_t thread_pool_size)
|
||||
: next_io_service_(0),
|
||||
thread_pool_size_(thread_pool_size)
|
||||
{
|
||||
: next_io_service_(0), thread_pool_size_(thread_pool_size) {
|
||||
if (pool_size == 0) {
|
||||
throw std::runtime_error("io_service_pool size is 0");
|
||||
}
|
||||
@ -64,54 +62,45 @@ io_service_pool::io_service_pool(std::size_t pool_size,
|
||||
work_.push_back(work);
|
||||
}
|
||||
|
||||
auto work = std::make_shared<boost::asio::io_service::work>
|
||||
(task_io_service_);
|
||||
auto work = std::make_shared<boost::asio::io_service::work>(task_io_service_);
|
||||
work_.push_back(work);
|
||||
}
|
||||
|
||||
void io_service_pool::run()
|
||||
{
|
||||
for(std::size_t i = 0; i < thread_pool_size_; ++i) {
|
||||
thread_pool_.create_thread
|
||||
([this]()
|
||||
{
|
||||
task_io_service_.run();
|
||||
});
|
||||
void io_service_pool::run() {
|
||||
for (std::size_t i = 0; i < thread_pool_size_; ++i) {
|
||||
thread_pool_.create_thread([this]() { task_io_service_.run(); });
|
||||
}
|
||||
|
||||
// Create a pool of threads to run all of the io_services.
|
||||
auto futs = std::vector<std::future<std::size_t>>();
|
||||
|
||||
for (std::size_t i = 0; i < io_services_.size(); ++i) {
|
||||
futs.push_back
|
||||
(std::async(std::launch::async,
|
||||
(size_t(boost::asio::io_service::*)(void))
|
||||
&boost::asio::io_service::run,
|
||||
io_services_[i]));
|
||||
futs.push_back(std::async(std::launch::async,
|
||||
(size_t (boost::asio::io_service::*)(void)) &
|
||||
boost::asio::io_service::run,
|
||||
io_services_[i]));
|
||||
}
|
||||
|
||||
// Wait for all threads in the pool to exit.
|
||||
for (auto& fut : futs) {
|
||||
for (auto &fut : futs) {
|
||||
fut.get();
|
||||
}
|
||||
|
||||
thread_pool_.join_all();
|
||||
}
|
||||
|
||||
void io_service_pool::stop()
|
||||
{
|
||||
void io_service_pool::stop() {
|
||||
// Explicitly stop all io_services.
|
||||
for (auto& iosv : io_services_) {
|
||||
for (auto &iosv : io_services_) {
|
||||
iosv->stop();
|
||||
}
|
||||
|
||||
task_io_service_.stop();
|
||||
}
|
||||
|
||||
boost::asio::io_service& io_service_pool::get_io_service()
|
||||
{
|
||||
boost::asio::io_service &io_service_pool::get_io_service() {
|
||||
// Use a round-robin scheme to choose the next io_service to use.
|
||||
auto& io_service = *io_services_[next_io_service_];
|
||||
auto &io_service = *io_services_[next_io_service_];
|
||||
++next_io_service_;
|
||||
if (next_io_service_ == io_services_.size()) {
|
||||
next_io_service_ = 0;
|
||||
@ -119,8 +108,7 @@ boost::asio::io_service& io_service_pool::get_io_service()
|
||||
return io_service;
|
||||
}
|
||||
|
||||
boost::asio::io_service& io_service_pool::get_task_io_service()
|
||||
{
|
||||
boost::asio::io_service &io_service_pool::get_task_io_service() {
|
||||
return task_io_service_;
|
||||
}
|
||||
|
||||
|
@ -54,13 +54,10 @@ namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
/// A pool of io_service objects.
|
||||
class io_service_pool
|
||||
: private boost::noncopyable
|
||||
{
|
||||
class io_service_pool : private boost::noncopyable {
|
||||
public:
|
||||
/// Construct the io_service pool.
|
||||
explicit io_service_pool(std::size_t pool_size,
|
||||
std::size_t thread_pool_size);
|
||||
explicit io_service_pool(std::size_t pool_size, std::size_t thread_pool_size);
|
||||
|
||||
/// Run all io_service objects in the pool.
|
||||
void run();
|
||||
@ -69,9 +66,9 @@ public:
|
||||
void stop();
|
||||
|
||||
/// Get an io_service to use.
|
||||
boost::asio::io_service& get_io_service();
|
||||
boost::asio::io_service &get_io_service();
|
||||
|
||||
boost::asio::io_service& get_task_io_service();
|
||||
boost::asio::io_service &get_task_io_service();
|
||||
|
||||
private:
|
||||
typedef std::shared_ptr<boost::asio::io_service> io_service_ptr;
|
||||
|
@ -42,20 +42,16 @@ namespace nghttp2 {
|
||||
namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
server::server(const std::string& address, uint16_t port,
|
||||
std::size_t io_service_pool_size,
|
||||
std::size_t thread_pool_size,
|
||||
server::server(const std::string &address, uint16_t port,
|
||||
std::size_t io_service_pool_size, std::size_t thread_pool_size,
|
||||
request_cb cb,
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx,
|
||||
int backlog)
|
||||
: io_service_pool_(io_service_pool_size, thread_pool_size),
|
||||
signals_(io_service_pool_.get_io_service()),
|
||||
tick_timer_(io_service_pool_.get_io_service(),
|
||||
boost::posix_time::seconds(1)),
|
||||
acceptor_(io_service_pool_.get_io_service()),
|
||||
ssl_ctx_(std::move(ssl_ctx)),
|
||||
request_cb_(std::move(cb))
|
||||
{
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx, int backlog)
|
||||
: io_service_pool_(io_service_pool_size, thread_pool_size),
|
||||
signals_(io_service_pool_.get_io_service()),
|
||||
tick_timer_(io_service_pool_.get_io_service(),
|
||||
boost::posix_time::seconds(1)),
|
||||
acceptor_(io_service_pool_.get_io_service()),
|
||||
ssl_ctx_(std::move(ssl_ctx)), request_cb_(std::move(cb)) {
|
||||
// Register to handle the signals that indicate when the server should exit.
|
||||
// It is safe to register for the same signal multiple times in a program,
|
||||
// provided all registration for the specified signal is made through Asio.
|
||||
@ -64,11 +60,8 @@ server::server(const std::string& address, uint16_t port,
|
||||
#if defined(SIGQUIT)
|
||||
signals_.add(SIGQUIT);
|
||||
#endif // defined(SIGQUIT)
|
||||
signals_.async_wait([this](const boost::system::error_code& error,
|
||||
int signal_number)
|
||||
{
|
||||
io_service_pool_.stop();
|
||||
});
|
||||
signals_.async_wait([this](const boost::system::error_code &error,
|
||||
int signal_number) { io_service_pool_.stop(); });
|
||||
|
||||
// Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR).
|
||||
boost::asio::ip::tcp::resolver resolver(acceptor_.get_io_service());
|
||||
@ -77,7 +70,7 @@ server::server(const std::string& address, uint16_t port,
|
||||
acceptor_.open(endpoint.protocol());
|
||||
acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
|
||||
acceptor_.bind(endpoint);
|
||||
if(backlog == -1) {
|
||||
if (backlog == -1) {
|
||||
acceptor_.listen();
|
||||
} else {
|
||||
acceptor_.listen(backlog);
|
||||
@ -88,80 +81,68 @@ server::server(const std::string& address, uint16_t port,
|
||||
start_timer();
|
||||
}
|
||||
|
||||
void server::run()
|
||||
{
|
||||
io_service_pool_.run();
|
||||
}
|
||||
void server::run() { io_service_pool_.run(); }
|
||||
|
||||
std::shared_ptr<std::string> cached_date;
|
||||
|
||||
namespace {
|
||||
void update_date()
|
||||
{
|
||||
void update_date() {
|
||||
cached_date = std::make_shared<std::string>(util::http_date(time(nullptr)));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void server::start_timer()
|
||||
{
|
||||
void server::start_timer() {
|
||||
update_date();
|
||||
|
||||
tick_timer_.async_wait
|
||||
([this](const boost::system::error_code& e)
|
||||
{
|
||||
tick_timer_.expires_at(tick_timer_.expires_at() +
|
||||
boost::posix_time::seconds(1));
|
||||
start_timer();
|
||||
});
|
||||
tick_timer_.async_wait([this](const boost::system::error_code &e) {
|
||||
tick_timer_.expires_at(tick_timer_.expires_at() +
|
||||
boost::posix_time::seconds(1));
|
||||
start_timer();
|
||||
});
|
||||
}
|
||||
|
||||
typedef boost::asio::ssl::stream<boost::asio::ip::tcp::socket> ssl_socket;
|
||||
|
||||
void server::start_accept()
|
||||
{
|
||||
if(ssl_ctx_) {
|
||||
auto new_connection =
|
||||
std::make_shared<connection<ssl_socket>>
|
||||
(request_cb_, io_service_pool_.get_task_io_service(),
|
||||
io_service_pool_.get_io_service(), *ssl_ctx_);
|
||||
void server::start_accept() {
|
||||
if (ssl_ctx_) {
|
||||
auto new_connection = std::make_shared<connection<ssl_socket>>(
|
||||
request_cb_, io_service_pool_.get_task_io_service(),
|
||||
io_service_pool_.get_io_service(), *ssl_ctx_);
|
||||
|
||||
acceptor_.async_accept
|
||||
(new_connection->socket().lowest_layer(),
|
||||
[this, new_connection](const boost::system::error_code& e)
|
||||
{
|
||||
if(!e) {
|
||||
new_connection->socket().lowest_layer().set_option
|
||||
(boost::asio::ip::tcp::no_delay(true));
|
||||
new_connection->socket().async_handshake
|
||||
(boost::asio::ssl::stream_base::server,
|
||||
[new_connection](const boost::system::error_code& e)
|
||||
{
|
||||
if(!e) {
|
||||
new_connection->start();
|
||||
}
|
||||
});
|
||||
}
|
||||
acceptor_.async_accept(
|
||||
new_connection->socket().lowest_layer(),
|
||||
[this, new_connection](const boost::system::error_code &e) {
|
||||
if (!e) {
|
||||
new_connection->socket().lowest_layer().set_option(
|
||||
boost::asio::ip::tcp::no_delay(true));
|
||||
new_connection->socket().async_handshake(
|
||||
boost::asio::ssl::stream_base::server,
|
||||
[new_connection](const boost::system::error_code &e) {
|
||||
if (!e) {
|
||||
new_connection->start();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
start_accept();
|
||||
});
|
||||
start_accept();
|
||||
});
|
||||
} else {
|
||||
auto new_connection =
|
||||
std::make_shared<connection<boost::asio::ip::tcp::socket>>
|
||||
(request_cb_, io_service_pool_.get_task_io_service(),
|
||||
io_service_pool_.get_io_service());
|
||||
std::make_shared<connection<boost::asio::ip::tcp::socket>>(
|
||||
request_cb_, io_service_pool_.get_task_io_service(),
|
||||
io_service_pool_.get_io_service());
|
||||
|
||||
acceptor_.async_accept
|
||||
(new_connection->socket(),
|
||||
[this, new_connection](const boost::system::error_code& e)
|
||||
{
|
||||
if (!e) {
|
||||
new_connection->socket().set_option
|
||||
(boost::asio::ip::tcp::no_delay(true));
|
||||
new_connection->start();
|
||||
}
|
||||
acceptor_.async_accept(
|
||||
new_connection->socket(),
|
||||
[this, new_connection](const boost::system::error_code &e) {
|
||||
if (!e) {
|
||||
new_connection->socket().set_option(
|
||||
boost::asio::ip::tcp::no_delay(true));
|
||||
new_connection->start();
|
||||
}
|
||||
|
||||
start_accept();
|
||||
});
|
||||
start_accept();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,16 +58,13 @@ namespace asio_http2 {
|
||||
namespace server {
|
||||
|
||||
/// The top-level class of the HTTP server.
|
||||
class server
|
||||
: private boost::noncopyable
|
||||
{
|
||||
class server : private boost::noncopyable {
|
||||
public:
|
||||
/// Construct the server to listen on the specified TCP address and port, and
|
||||
/// serve up files from the given directory.
|
||||
explicit server(const std::string& address, uint16_t port,
|
||||
explicit server(const std::string &address, uint16_t port,
|
||||
std::size_t io_service_pool_size,
|
||||
std::size_t thread_pool_size,
|
||||
request_cb cb,
|
||||
std::size_t thread_pool_size, request_cb cb,
|
||||
std::unique_ptr<boost::asio::ssl::context> ssl_ctx,
|
||||
int backlog = -1);
|
||||
|
||||
|
127
src/base64.h
127
src/base64.h
@ -33,28 +33,24 @@ namespace nghttp2 {
|
||||
|
||||
namespace base64 {
|
||||
|
||||
template<typename InputIterator>
|
||||
std::string encode(InputIterator first, InputIterator last)
|
||||
{
|
||||
template <typename InputIterator>
|
||||
std::string encode(InputIterator first, InputIterator last) {
|
||||
static const char CHAR_TABLE[] = {
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H',
|
||||
'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
|
||||
'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X',
|
||||
'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f',
|
||||
'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
|
||||
'o', 'p', 'q', 'r', 's', 't', 'u', 'v',
|
||||
'w', 'x', 'y', 'z', '0', '1', '2', '3',
|
||||
'4', '5', '6', '7', '8', '9', '+', '/',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
|
||||
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/',
|
||||
};
|
||||
std::string res;
|
||||
size_t len = last-first;
|
||||
if(len == 0) {
|
||||
size_t len = last - first;
|
||||
if (len == 0) {
|
||||
return res;
|
||||
}
|
||||
size_t r = len%3;
|
||||
InputIterator j = last-r;
|
||||
size_t r = len % 3;
|
||||
InputIterator j = last - r;
|
||||
char temp[4];
|
||||
while(first != j) {
|
||||
while (first != j) {
|
||||
int n = static_cast<unsigned char>(*first++) << 16;
|
||||
n += static_cast<unsigned char>(*first++) << 8;
|
||||
n += static_cast<unsigned char>(*first++);
|
||||
@ -64,7 +60,7 @@ std::string encode(InputIterator first, InputIterator last)
|
||||
temp[3] = CHAR_TABLE[n & 0x3fu];
|
||||
res.append(temp, sizeof(temp));
|
||||
}
|
||||
if(r == 2) {
|
||||
if (r == 2) {
|
||||
int n = static_cast<unsigned char>(*first++) << 16;
|
||||
n += static_cast<unsigned char>(*first++) << 8;
|
||||
temp[0] = CHAR_TABLE[n >> 18];
|
||||
@ -72,7 +68,7 @@ std::string encode(InputIterator first, InputIterator last)
|
||||
temp[2] = CHAR_TABLE[(n >> 6) & 0x3fu];
|
||||
temp[3] = '=';
|
||||
res.append(temp, sizeof(temp));
|
||||
} else if(r == 1) {
|
||||
} else if (r == 1) {
|
||||
int n = static_cast<unsigned char>(*first++) << 16;
|
||||
temp[0] = CHAR_TABLE[n >> 18];
|
||||
temp[1] = CHAR_TABLE[(n >> 12) & 0x3fu];
|
||||
@ -83,89 +79,82 @@ std::string encode(InputIterator first, InputIterator last)
|
||||
return res;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
InputIterator getNext
|
||||
(InputIterator first,
|
||||
InputIterator last,
|
||||
const int* tbl)
|
||||
{
|
||||
for(; first != last; ++first) {
|
||||
if(tbl[static_cast<size_t>(*first)] != -1 || *first == '=') {
|
||||
template <typename InputIterator>
|
||||
InputIterator getNext(InputIterator first, InputIterator last, const int *tbl) {
|
||||
for (; first != last; ++first) {
|
||||
if (tbl[static_cast<size_t>(*first)] != -1 || *first == '=') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return first;
|
||||
}
|
||||
|
||||
template<typename InputIterator>
|
||||
std::string decode(InputIterator first, InputIterator last)
|
||||
{
|
||||
template <typename InputIterator>
|
||||
std::string decode(InputIterator first, InputIterator last) {
|
||||
static const int INDEX_TABLE[] = {
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
|
||||
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
|
||||
-1, 0, 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, -1, -1, -1, -1, -1,
|
||||
-1, 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, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
|
||||
};
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57,
|
||||
58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 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, -1, -1, -1, -1, -1, -1, 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, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
|
||||
-1, -1, -1, -1};
|
||||
std::string res;
|
||||
InputIterator k[4];
|
||||
int eq = 0;
|
||||
for(; first != last;) {
|
||||
for(int i = 1; i <= 4; ++i) {
|
||||
k[i-1] = getNext(first, last, INDEX_TABLE);
|
||||
if(k[i-1] == last) {
|
||||
for (; first != last;) {
|
||||
for (int i = 1; i <= 4; ++i) {
|
||||
k[i - 1] = getNext(first, last, INDEX_TABLE);
|
||||
if (k[i - 1] == last) {
|
||||
// If i == 1, input may look like this: "TWFu\n" (i.e.,
|
||||
// garbage at the end)
|
||||
if(i != 1) {
|
||||
if (i != 1) {
|
||||
res.clear();
|
||||
}
|
||||
return res;
|
||||
} else if(*k[i-1] == '=' && eq == 0) {
|
||||
} else if (*k[i - 1] == '=' && eq == 0) {
|
||||
eq = i;
|
||||
}
|
||||
first = k[i-1]+1;
|
||||
first = k[i - 1] + 1;
|
||||
}
|
||||
if(eq) {
|
||||
if (eq) {
|
||||
break;
|
||||
}
|
||||
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18)+
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12)+
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6)+
|
||||
INDEX_TABLE[static_cast<unsigned char>(*k[3])];
|
||||
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18) +
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12) +
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6) +
|
||||
INDEX_TABLE[static_cast<unsigned char>(*k[3])];
|
||||
res += n >> 16;
|
||||
res += n >> 8 & 0xffu;
|
||||
res += n & 0xffu;
|
||||
}
|
||||
if(eq) {
|
||||
if(eq <= 2) {
|
||||
if (eq) {
|
||||
if (eq <= 2) {
|
||||
res.clear();
|
||||
return res;
|
||||
} else {
|
||||
for(int i = eq; i <= 4; ++i) {
|
||||
if(*k[i-1] != '=') {
|
||||
for (int i = eq; i <= 4; ++i) {
|
||||
if (*k[i - 1] != '=') {
|
||||
res.clear();
|
||||
return res;
|
||||
}
|
||||
}
|
||||
if(eq == 3) {
|
||||
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18)+
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12);
|
||||
if (eq == 3) {
|
||||
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18) +
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12);
|
||||
res += n >> 16;
|
||||
} else if(eq == 4) {
|
||||
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18)+
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12)+
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6);
|
||||
} else if (eq == 4) {
|
||||
int n = (INDEX_TABLE[static_cast<unsigned char>(*k[0])] << 18) +
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[1])] << 12) +
|
||||
(INDEX_TABLE[static_cast<unsigned char>(*k[2])] << 6);
|
||||
res += n >> 16;
|
||||
res += n >> 8 & 0xffu;
|
||||
}
|
||||
|
@ -25,19 +25,17 @@
|
||||
#include "comp_helper.h"
|
||||
#include <string.h>
|
||||
|
||||
static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len)
|
||||
{
|
||||
static void dump_val(json_t *jent, const char *key, uint8_t *val, size_t len) {
|
||||
json_object_set_new(jent, key, json_pack("s#", val, len));
|
||||
}
|
||||
|
||||
json_t* dump_header_table(nghttp2_hd_context *context)
|
||||
{
|
||||
json_t *dump_header_table(nghttp2_hd_context *context) {
|
||||
json_t *obj, *entries;
|
||||
size_t i;
|
||||
|
||||
obj = json_object();
|
||||
entries = json_array();
|
||||
for(i = 0; i < context->hd_table.len; ++i) {
|
||||
for (i = 0; i < context->hd_table.len; ++i) {
|
||||
nghttp2_hd_entry *ent = nghttp2_hd_table_get(context, i);
|
||||
json_t *outent = json_object();
|
||||
json_object_set_new(outent, "index", json_integer(i + 1));
|
||||
@ -55,9 +53,8 @@ json_t* dump_header_table(nghttp2_hd_context *context)
|
||||
return obj;
|
||||
}
|
||||
|
||||
json_t* dump_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen)
|
||||
{
|
||||
json_t *dump_header(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t valuelen) {
|
||||
json_t *nv_pair = json_object();
|
||||
char *cname = malloc(namelen + 1);
|
||||
memcpy(cname, name, namelen);
|
||||
@ -67,29 +64,25 @@ json_t* dump_header(const uint8_t *name, size_t namelen,
|
||||
return nv_pair;
|
||||
}
|
||||
|
||||
json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
json_t *dump_headers(const nghttp2_nv *nva, size_t nvlen) {
|
||||
json_t *headers;
|
||||
size_t i;
|
||||
|
||||
headers = json_array();
|
||||
for(i = 0; i < nvlen; ++i) {
|
||||
json_array_append_new(headers,
|
||||
dump_header(nva[i].name, nva[i].namelen,
|
||||
nva[i].value, nva[i].valuelen));
|
||||
for (i = 0; i < nvlen; ++i) {
|
||||
json_array_append_new(headers, dump_header(nva[i].name, nva[i].namelen,
|
||||
nva[i].value, nva[i].valuelen));
|
||||
}
|
||||
return headers;
|
||||
}
|
||||
|
||||
void output_json_header(void)
|
||||
{
|
||||
void output_json_header(void) {
|
||||
printf("{\n"
|
||||
" \"cases\":\n"
|
||||
" [\n");
|
||||
}
|
||||
|
||||
void output_json_footer(void)
|
||||
{
|
||||
void output_json_footer(void) {
|
||||
printf(" ]\n"
|
||||
"}\n");
|
||||
}
|
||||
|
@ -26,19 +26,19 @@
|
||||
#define NGHTTP2_COMP_HELPER_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <jansson.h>
|
||||
|
||||
#include "nghttp2_hd.h"
|
||||
|
||||
json_t* dump_header_table(nghttp2_hd_context *context);
|
||||
json_t *dump_header_table(nghttp2_hd_context *context);
|
||||
|
||||
json_t* dump_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t vlauelen);
|
||||
json_t *dump_header(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t vlauelen);
|
||||
|
||||
json_t* dump_headers(const nghttp2_nv *nva, size_t nvlen);
|
||||
json_t *dump_headers(const nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
void output_json_header(void);
|
||||
|
||||
|
164
src/deflatehd.cc
164
src/deflatehd.cc
@ -23,7 +23,7 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <unistd.h>
|
||||
@ -45,7 +45,6 @@ extern "C" {
|
||||
#include "nghttp2_frame.h"
|
||||
|
||||
#include "comp_helper.h"
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
@ -60,28 +59,24 @@ static deflate_config config;
|
||||
static size_t input_sum;
|
||||
static size_t output_sum;
|
||||
|
||||
static char to_hex_digit(uint8_t n)
|
||||
{
|
||||
if(n > 9) {
|
||||
static char to_hex_digit(uint8_t n) {
|
||||
if (n > 9) {
|
||||
return n - 10 + 'a';
|
||||
}
|
||||
return n + '0';
|
||||
}
|
||||
|
||||
static void to_hex(char *dest, const uint8_t *src, size_t len)
|
||||
{
|
||||
static void to_hex(char *dest, const uint8_t *src, size_t len) {
|
||||
size_t i;
|
||||
for(i = 0; i < len; ++i) {
|
||||
for (i = 0; i < len; ++i) {
|
||||
*dest++ = to_hex_digit(src[i] >> 4);
|
||||
*dest++ = to_hex_digit(src[i] & 0xf);
|
||||
}
|
||||
}
|
||||
|
||||
static void output_to_json(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_bufs *bufs, size_t inputlen,
|
||||
const std::vector<nghttp2_nv>& nva,
|
||||
int seq)
|
||||
{
|
||||
static void output_to_json(nghttp2_hd_deflater *deflater, nghttp2_bufs *bufs,
|
||||
size_t inputlen, const std::vector<nghttp2_nv> &nva,
|
||||
int seq) {
|
||||
auto len = nghttp2_bufs_len(bufs);
|
||||
auto hex = std::vector<char>(len * 2);
|
||||
auto obj = json_object();
|
||||
@ -94,26 +89,25 @@ static void output_to_json(nghttp2_hd_deflater *deflater,
|
||||
json_real(comp_ratio));
|
||||
|
||||
auto hexp = hex.data();
|
||||
for(auto ci = bufs->head; ci; ci = ci->next) {
|
||||
for (auto ci = bufs->head; ci; ci = ci->next) {
|
||||
auto buf = &ci->buf;
|
||||
to_hex(hexp, buf->pos, nghttp2_buf_len(buf));
|
||||
hexp += nghttp2_buf_len(buf);
|
||||
}
|
||||
|
||||
if(len == 0) {
|
||||
if (len == 0) {
|
||||
json_object_set_new(obj, "wire", json_string(""));
|
||||
} else {
|
||||
json_object_set_new(obj, "wire", json_pack("s#", hex.data(), hex.size()));
|
||||
}
|
||||
json_object_set_new(obj, "headers", dump_headers(nva.data(), nva.size()));
|
||||
if(seq == 0) {
|
||||
if (seq == 0) {
|
||||
// We only change the header table size only once at the beginning
|
||||
json_object_set_new(obj, "header_table_size",
|
||||
json_integer(config.table_size));
|
||||
}
|
||||
if(config.dump_header_table) {
|
||||
json_object_set_new(obj, "header_table",
|
||||
dump_header_table(&deflater->ctx));
|
||||
if (config.dump_header_table) {
|
||||
json_object_set_new(obj, "header_table", dump_header_table(&deflater->ctx));
|
||||
}
|
||||
json_dumpf(obj, stdout, JSON_PRESERVE_ORDER | JSON_INDENT(2));
|
||||
printf("\n");
|
||||
@ -121,17 +115,16 @@ static void output_to_json(nghttp2_hd_deflater *deflater,
|
||||
}
|
||||
|
||||
static void deflate_hd(nghttp2_hd_deflater *deflater,
|
||||
const std::vector<nghttp2_nv>& nva,
|
||||
size_t inputlen, int seq)
|
||||
{
|
||||
const std::vector<nghttp2_nv> &nva, size_t inputlen,
|
||||
int seq) {
|
||||
ssize_t rv;
|
||||
nghttp2_bufs bufs;
|
||||
|
||||
nghttp2_bufs_init2(&bufs, 4096, 16, 0);
|
||||
|
||||
rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs,
|
||||
(nghttp2_nv*)nva.data(), nva.size());
|
||||
if(rv < 0) {
|
||||
rv = nghttp2_hd_deflate_hd_bufs(deflater, &bufs, (nghttp2_nv *)nva.data(),
|
||||
nva.size());
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "deflate failed with error code %zd at %d\n", rv, seq);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -143,44 +136,43 @@ static void deflate_hd(nghttp2_hd_deflater *deflater,
|
||||
nghttp2_bufs_free(&bufs);
|
||||
}
|
||||
|
||||
static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
|
||||
{
|
||||
static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater,
|
||||
int seq) {
|
||||
size_t inputlen = 0;
|
||||
|
||||
auto js = json_object_get(obj, "headers");
|
||||
if(js == nullptr) {
|
||||
if (js == nullptr) {
|
||||
fprintf(stderr, "'headers' key is missing at %d\n", seq);
|
||||
return -1;
|
||||
}
|
||||
if(!json_is_array(js)) {
|
||||
fprintf(stderr,
|
||||
"The value of 'headers' key must be an array at %d\n", seq);
|
||||
if (!json_is_array(js)) {
|
||||
fprintf(stderr, "The value of 'headers' key must be an array at %d\n", seq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto len = json_array_size(js);
|
||||
auto nva = std::vector<nghttp2_nv>(len);
|
||||
|
||||
for(size_t i = 0; i < len; ++i) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
auto nv_pair = json_array_get(js, i);
|
||||
const char *name;
|
||||
json_t *value;
|
||||
|
||||
if(!json_is_object(nv_pair) || json_object_size(nv_pair) != 1) {
|
||||
if (!json_is_object(nv_pair) || json_object_size(nv_pair) != 1) {
|
||||
fprintf(stderr, "bad formatted name/value pair object at %d\n", seq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
json_object_foreach(nv_pair, name, value) {
|
||||
nva[i].name = (uint8_t*)name;
|
||||
nva[i].name = (uint8_t *)name;
|
||||
nva[i].namelen = strlen(name);
|
||||
|
||||
if(!json_is_string(value)) {
|
||||
if (!json_is_string(value)) {
|
||||
fprintf(stderr, "value is not string at %d\n", seq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
nva[i].value = (uint8_t*)json_string_value(value);
|
||||
nva[i].value = (uint8_t *)json_string_value(value);
|
||||
nva[i].valuelen = strlen(json_string_value(value));
|
||||
|
||||
nva[i].flags = NGHTTP2_NV_FLAG_NONE;
|
||||
@ -194,37 +186,34 @@ static int deflate_hd_json(json_t *obj, nghttp2_hd_deflater *deflater, int seq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void init_deflater(nghttp2_hd_deflater *deflater)
|
||||
{
|
||||
static void init_deflater(nghttp2_hd_deflater *deflater) {
|
||||
nghttp2_hd_deflate_init2(deflater, config.deflate_table_size);
|
||||
nghttp2_hd_deflate_change_table_size(deflater, config.table_size);
|
||||
}
|
||||
|
||||
static void deinit_deflater(nghttp2_hd_deflater *deflater)
|
||||
{
|
||||
static void deinit_deflater(nghttp2_hd_deflater *deflater) {
|
||||
nghttp2_hd_deflate_free(deflater);
|
||||
}
|
||||
|
||||
static int perform(void)
|
||||
{
|
||||
static int perform(void) {
|
||||
json_error_t error;
|
||||
nghttp2_hd_deflater deflater;
|
||||
|
||||
auto json = json_loadf(stdin, 0, &error);
|
||||
|
||||
if(json == nullptr) {
|
||||
if (json == nullptr) {
|
||||
fprintf(stderr, "JSON loading failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto cases = json_object_get(json, "cases");
|
||||
|
||||
if(cases == nullptr) {
|
||||
if (cases == nullptr) {
|
||||
fprintf(stderr, "Missing 'cases' key in root object\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(!json_is_array(cases)) {
|
||||
if (!json_is_array(cases)) {
|
||||
fprintf(stderr, "'cases' must be JSON array\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -233,17 +222,16 @@ static int perform(void)
|
||||
output_json_header();
|
||||
auto len = json_array_size(cases);
|
||||
|
||||
for(size_t i = 0; i < len; ++i) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
auto obj = json_array_get(cases, i);
|
||||
if(!json_is_object(obj)) {
|
||||
fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n",
|
||||
i);
|
||||
if (!json_is_object(obj)) {
|
||||
fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n", i);
|
||||
continue;
|
||||
}
|
||||
if(deflate_hd_json(obj, &deflater, i) != 0) {
|
||||
if (deflate_hd_json(obj, &deflater, i) != 0) {
|
||||
continue;
|
||||
}
|
||||
if(i + 1 < len) {
|
||||
if (i + 1 < len) {
|
||||
printf(",\n");
|
||||
}
|
||||
}
|
||||
@ -253,65 +241,67 @@ static int perform(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perform_from_http1text(void)
|
||||
{
|
||||
static int perform_from_http1text(void) {
|
||||
char line[1 << 14];
|
||||
int seq = 0;
|
||||
nghttp2_hd_deflater deflater;
|
||||
init_deflater(&deflater);
|
||||
output_json_header();
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
std::vector<nghttp2_nv> nva;
|
||||
int end = 0;
|
||||
size_t inputlen = 0;
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
char *rv = fgets(line, sizeof(line), stdin);
|
||||
char *val, *val_end;
|
||||
if(rv == nullptr) {
|
||||
if (rv == nullptr) {
|
||||
end = 1;
|
||||
break;
|
||||
} else if(line[0] == '\n') {
|
||||
} else if (line[0] == '\n') {
|
||||
break;
|
||||
}
|
||||
|
||||
nva.emplace_back();
|
||||
auto& nv = nva.back();
|
||||
auto &nv = nva.back();
|
||||
|
||||
val = strchr(line+1, ':');
|
||||
if(val == nullptr) {
|
||||
val = strchr(line + 1, ':');
|
||||
if (val == nullptr) {
|
||||
fprintf(stderr, "Bad HTTP/1 header field format at %d.\n", seq);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
*val = '\0';
|
||||
++val;
|
||||
for(; *val && (*val == ' ' || *val == '\t'); ++val);
|
||||
for(val_end = val; *val_end && (*val_end != '\r' && *val_end != '\n');
|
||||
++val_end);
|
||||
for (; *val && (*val == ' ' || *val == '\t'); ++val)
|
||||
;
|
||||
for (val_end = val; *val_end && (*val_end != '\r' && *val_end != '\n');
|
||||
++val_end)
|
||||
;
|
||||
*val_end = '\0';
|
||||
|
||||
nv.namelen = strlen(line);
|
||||
nv.valuelen = strlen(val);
|
||||
nv.name = (uint8_t*)strdup(line);
|
||||
nv.value = (uint8_t*)strdup(val);
|
||||
nv.name = (uint8_t *)strdup(line);
|
||||
nv.value = (uint8_t *)strdup(val);
|
||||
nv.flags = NGHTTP2_NV_FLAG_NONE;
|
||||
|
||||
inputlen += nv.namelen + nv.valuelen;
|
||||
}
|
||||
|
||||
if(!end) {
|
||||
if(seq > 0) {
|
||||
if (!end) {
|
||||
if (seq > 0) {
|
||||
printf(",\n");
|
||||
}
|
||||
deflate_hd(&deflater, nva, inputlen, seq);
|
||||
}
|
||||
|
||||
for(auto& nv : nva) {
|
||||
for (auto &nv : nva) {
|
||||
free(nv.name);
|
||||
free(nv.value);
|
||||
}
|
||||
|
||||
if(end) break;
|
||||
if (end)
|
||||
break;
|
||||
++seq;
|
||||
}
|
||||
output_json_footer();
|
||||
@ -319,8 +309,7 @@ static int perform_from_http1text(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
static void print_help(void) {
|
||||
std::cout << R"(HPACK HTTP/2 header encoder
|
||||
Usage: deflatehd [OPTIONS] < INPUT
|
||||
|
||||
@ -385,33 +374,30 @@ OPTIONS:
|
||||
buffer.
|
||||
Default: 4096
|
||||
-d, --dump-header-table
|
||||
Output dynamic header table.)"
|
||||
<< std::endl;
|
||||
Output dynamic header table.)" << std::endl;
|
||||
}
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"http1text", no_argument, nullptr, 't'},
|
||||
{"table-size", required_argument, nullptr, 's'},
|
||||
{"deflate-table-size", required_argument, nullptr, 'S'},
|
||||
{"dump-header-table", no_argument, nullptr, 'd'},
|
||||
{nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
{"http1text", no_argument, nullptr, 't'},
|
||||
{"table-size", required_argument, nullptr, 's'},
|
||||
{"deflate-table-size", required_argument, nullptr, 'S'},
|
||||
{"dump-header-table", no_argument, nullptr, 'd'},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
char *end;
|
||||
|
||||
config.table_size = NGHTTP2_HD_DEFAULT_MAX_BUFFER_SIZE;
|
||||
config.deflate_table_size = NGHTTP2_HD_DEFAULT_MAX_DEFLATE_BUFFER_SIZE;
|
||||
config.http1text = 0;
|
||||
config.dump_header_table = 0;
|
||||
while(1) {
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "S:dhs:t", long_options, &option_index);
|
||||
if(c == -1) {
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
switch(c) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(EXIT_SUCCESS);
|
||||
@ -423,7 +409,7 @@ int main(int argc, char **argv)
|
||||
// --table-size
|
||||
errno = 0;
|
||||
config.table_size = strtoul(optarg, &end, 10);
|
||||
if(errno == ERANGE || *end != '\0') {
|
||||
if (errno == ERANGE || *end != '\0') {
|
||||
fprintf(stderr, "-s: Bad option value\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -432,7 +418,7 @@ int main(int argc, char **argv)
|
||||
// --deflate-table-size
|
||||
errno = 0;
|
||||
config.deflate_table_size = strtoul(optarg, &end, 10);
|
||||
if(errno == ERANGE || *end != '\0') {
|
||||
if (errno == ERANGE || *end != '\0') {
|
||||
fprintf(stderr, "-S: Bad option value\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -447,7 +433,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(config.http1text) {
|
||||
if (config.http1text) {
|
||||
perform_from_http1text();
|
||||
} else {
|
||||
perform();
|
||||
@ -455,7 +441,7 @@ int main(int argc, char **argv)
|
||||
|
||||
auto comp_ratio = input_sum == 0 ? 0.0 : (double)output_sum / input_sum;
|
||||
|
||||
fprintf(stderr, "Overall: input=%zu output=%zu ratio=%.02f\n",
|
||||
input_sum, output_sum, comp_ratio);
|
||||
fprintf(stderr, "Overall: input=%zu output=%zu ratio=%.02f\n", input_sum,
|
||||
output_sum, comp_ratio);
|
||||
return 0;
|
||||
}
|
||||
|
580
src/h2load.cc
580
src/h2load.cc
File diff suppressed because it is too large
Load Diff
17
src/h2load.h
17
src/h2load.h
@ -51,7 +51,7 @@ class Session;
|
||||
|
||||
struct Config {
|
||||
std::vector<std::vector<nghttp2_nv>> nva;
|
||||
std::vector<std::vector<const char*>> nv;
|
||||
std::vector<std::vector<const char *>> nv;
|
||||
nghttp2::Headers custom_headers;
|
||||
std::string scheme;
|
||||
std::string host;
|
||||
@ -64,12 +64,7 @@ struct Config {
|
||||
ssize_t max_concurrent_streams;
|
||||
size_t window_bits;
|
||||
size_t connection_window_bits;
|
||||
enum {
|
||||
PROTO_HTTP2,
|
||||
PROTO_SPDY2,
|
||||
PROTO_SPDY3,
|
||||
PROTO_SPDY3_1
|
||||
} no_tls_proto;
|
||||
enum { PROTO_HTTP2, PROTO_SPDY2, PROTO_SPDY3, PROTO_SPDY3_1 } no_tls_proto;
|
||||
uint16_t port;
|
||||
uint16_t default_port;
|
||||
bool verbose;
|
||||
@ -105,10 +100,7 @@ struct Stats {
|
||||
size_t status[6];
|
||||
};
|
||||
|
||||
enum ClientState {
|
||||
CLIENT_IDLE,
|
||||
CLIENT_CONNECTED
|
||||
};
|
||||
enum ClientState { CLIENT_IDLE, CLIENT_CONNECTED };
|
||||
|
||||
struct Client;
|
||||
|
||||
@ -163,8 +155,7 @@ struct Client {
|
||||
int on_read();
|
||||
int on_write();
|
||||
void on_request(int32_t stream_id);
|
||||
void on_header(int32_t stream_id,
|
||||
const uint8_t *name, size_t namelen,
|
||||
void on_header(int32_t stream_id, const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen);
|
||||
void on_stream_close(int32_t stream_id, bool success);
|
||||
};
|
||||
|
@ -35,26 +35,18 @@ using namespace nghttp2;
|
||||
namespace h2load {
|
||||
|
||||
Http2Session::Http2Session(Client *client)
|
||||
: client_(client),
|
||||
session_(nullptr)
|
||||
{}
|
||||
: client_(client), session_(nullptr) {}
|
||||
|
||||
Http2Session::~Http2Session()
|
||||
{
|
||||
nghttp2_session_del(session_);
|
||||
}
|
||||
Http2Session::~Http2Session() { nghttp2_session_del(session_); }
|
||||
|
||||
namespace {
|
||||
int on_header_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
int on_header_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
uint8_t flags,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
||||
const uint8_t *value, size_t valuelen, uint8_t flags,
|
||||
void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
if (frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
||||
return 0;
|
||||
}
|
||||
client->on_header(frame->hd.stream_id, name, namelen, value, valuelen);
|
||||
@ -63,13 +55,11 @@ int on_header_callback(nghttp2_session *session,
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_frame_recv_callback(nghttp2_session *session,
|
||||
const nghttp2_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
if(frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
||||
int on_frame_recv_callback(nghttp2_session *session, const nghttp2_frame *frame,
|
||||
void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
if (frame->hd.type != NGHTTP2_HEADERS ||
|
||||
frame->headers.cat != NGHTTP2_HCAT_RESPONSE) {
|
||||
return 0;
|
||||
}
|
||||
client->worker->stats.bytes_head += frame->hd.length;
|
||||
@ -78,29 +68,25 @@ int on_frame_recv_callback(nghttp2_session *session,
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_data_chunk_recv_callback
|
||||
(nghttp2_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
client->worker->stats.bytes_body += len;
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
int on_stream_close_callback
|
||||
(nghttp2_session *session, int32_t stream_id, uint32_t error_code,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
|
||||
uint32_t error_code, void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
client->on_stream_close(stream_id, error_code == NGHTTP2_NO_ERROR);
|
||||
return 0;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Http2Session::on_connect()
|
||||
{
|
||||
void Http2Session::on_connect() {
|
||||
int rv;
|
||||
|
||||
nghttp2_session_callbacks *callbacks;
|
||||
@ -108,19 +94,19 @@ void Http2Session::on_connect()
|
||||
nghttp2_session_callbacks_new(&callbacks);
|
||||
|
||||
auto callbacks_deleter =
|
||||
util::defer(callbacks, nghttp2_session_callbacks_del);
|
||||
util::defer(callbacks, nghttp2_session_callbacks_del);
|
||||
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback
|
||||
(callbacks, on_frame_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_frame_recv_callback(callbacks,
|
||||
on_frame_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback
|
||||
(callbacks, on_data_chunk_recv_callback);
|
||||
nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
|
||||
callbacks, on_data_chunk_recv_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback
|
||||
(callbacks, on_stream_close_callback);
|
||||
nghttp2_session_callbacks_set_on_stream_close_callback(
|
||||
callbacks, on_stream_close_callback);
|
||||
|
||||
nghttp2_session_callbacks_set_on_header_callback
|
||||
(callbacks, on_header_callback);
|
||||
nghttp2_session_callbacks_set_on_header_callback(callbacks,
|
||||
on_header_callback);
|
||||
|
||||
nghttp2_session_client_new(&session_, callbacks, client_);
|
||||
|
||||
@ -136,9 +122,9 @@ void Http2Session::on_connect()
|
||||
assert(rv == 0);
|
||||
|
||||
auto extra_connection_window =
|
||||
(1 << client_->worker->config->connection_window_bits) - 1
|
||||
- NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
||||
if(extra_connection_window != 0) {
|
||||
(1 << client_->worker->config->connection_window_bits) - 1 -
|
||||
NGHTTP2_INITIAL_CONNECTION_WINDOW_SIZE;
|
||||
if (extra_connection_window != 0) {
|
||||
nghttp2_submit_window_update(session_, NGHTTP2_FLAG_NONE, 0,
|
||||
extra_connection_window);
|
||||
}
|
||||
@ -147,34 +133,31 @@ void Http2Session::on_connect()
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN);
|
||||
}
|
||||
|
||||
void Http2Session::submit_request()
|
||||
{
|
||||
void Http2Session::submit_request() {
|
||||
auto config = client_->worker->config;
|
||||
auto& nva = config->nva[client_->reqidx++];
|
||||
auto &nva = config->nva[client_->reqidx++];
|
||||
|
||||
if(client_->reqidx == config->nva.size()) {
|
||||
if (client_->reqidx == config->nva.size()) {
|
||||
client_->reqidx = 0;
|
||||
}
|
||||
|
||||
auto stream_id = nghttp2_submit_request(session_, nullptr,
|
||||
nva.data(), nva.size(),
|
||||
nullptr, nullptr);
|
||||
auto stream_id = nghttp2_submit_request(session_, nullptr, nva.data(),
|
||||
nva.size(), nullptr, nullptr);
|
||||
assert(stream_id > 0);
|
||||
|
||||
client_->on_request(stream_id);
|
||||
}
|
||||
|
||||
ssize_t Http2Session::on_read()
|
||||
{
|
||||
ssize_t Http2Session::on_read() {
|
||||
int rv;
|
||||
size_t nread = 0;
|
||||
|
||||
auto input = bufferevent_get_input(client_->bev);
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
auto inputlen = evbuffer_get_contiguous_space(input);
|
||||
|
||||
if(inputlen == 0) {
|
||||
if (inputlen == 0) {
|
||||
assert(evbuffer_get_length(input) == 0);
|
||||
|
||||
return nread;
|
||||
@ -184,53 +167,51 @@ ssize_t Http2Session::on_read()
|
||||
|
||||
rv = nghttp2_session_mem_recv(session_, mem, inputlen);
|
||||
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nread += rv;
|
||||
|
||||
if(evbuffer_drain(input, rv) != 0) {
|
||||
if (evbuffer_drain(input, rv) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int Http2Session::on_write()
|
||||
{
|
||||
int Http2Session::on_write() {
|
||||
int rv;
|
||||
uint8_t buf[16384];
|
||||
auto output = bufferevent_get_output(client_->bev);
|
||||
util::EvbufferBuffer evbbuf(output, buf, sizeof(buf));
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
const uint8_t *data;
|
||||
auto datalen = nghttp2_session_mem_send(session_, &data);
|
||||
|
||||
if(datalen < 0) {
|
||||
if (datalen < 0) {
|
||||
return -1;
|
||||
}
|
||||
if(datalen == 0) {
|
||||
if (datalen == 0) {
|
||||
break;
|
||||
}
|
||||
rv = evbbuf.add(data, datalen);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
rv = evbbuf.flush();
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
if(nghttp2_session_want_read(session_) == 0 &&
|
||||
nghttp2_session_want_write(session_) == 0 &&
|
||||
evbuffer_get_length(output) == 0) {
|
||||
if (nghttp2_session_want_read(session_) == 0 &&
|
||||
nghttp2_session_want_write(session_) == 0 &&
|
||||
evbuffer_get_length(output) == 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Http2Session::terminate()
|
||||
{
|
||||
void Http2Session::terminate() {
|
||||
nghttp2_session_terminate_session(session_, NGHTTP2_NO_ERROR);
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,7 @@ public:
|
||||
virtual ssize_t on_read();
|
||||
virtual int on_write();
|
||||
virtual void terminate();
|
||||
|
||||
private:
|
||||
Client *client_;
|
||||
nghttp2_session *session_;
|
||||
|
@ -34,23 +34,16 @@ using namespace nghttp2;
|
||||
namespace h2load {
|
||||
|
||||
SpdySession::SpdySession(Client *client, uint16_t spdy_version)
|
||||
: client_(client),
|
||||
session_(nullptr),
|
||||
spdy_version_(spdy_version)
|
||||
{}
|
||||
: client_(client), session_(nullptr), spdy_version_(spdy_version) {}
|
||||
|
||||
SpdySession::~SpdySession()
|
||||
{
|
||||
spdylay_session_del(session_);
|
||||
}
|
||||
SpdySession::~SpdySession() { spdylay_session_del(session_); }
|
||||
|
||||
namespace {
|
||||
void before_ctrl_send_callback
|
||||
(spdylay_session *session, spdylay_frame_type type, spdylay_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
if(type != SPDYLAY_SYN_STREAM) {
|
||||
void before_ctrl_send_callback(spdylay_session *session,
|
||||
spdylay_frame_type type, spdylay_frame *frame,
|
||||
void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
if (type != SPDYLAY_SYN_STREAM) {
|
||||
return;
|
||||
}
|
||||
client->on_request(frame->syn_stream.stream_id);
|
||||
@ -58,71 +51,61 @@ void before_ctrl_send_callback
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void on_ctrl_recv_callback(spdylay_session *session,
|
||||
spdylay_frame_type type,
|
||||
spdylay_frame *frame,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
if(type != SPDYLAY_SYN_REPLY) {
|
||||
void on_ctrl_recv_callback(spdylay_session *session, spdylay_frame_type type,
|
||||
spdylay_frame *frame, void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
if (type != SPDYLAY_SYN_REPLY) {
|
||||
return;
|
||||
}
|
||||
for(auto p = frame->syn_reply.nv; *p; p += 2) {
|
||||
for (auto p = frame->syn_reply.nv; *p; p += 2) {
|
||||
auto name = *p;
|
||||
auto value = *(p + 1);
|
||||
client->on_header(frame->syn_reply.stream_id,
|
||||
reinterpret_cast<const uint8_t*>(name),
|
||||
strlen(name),
|
||||
reinterpret_cast<const uint8_t*>(value),
|
||||
strlen(value));
|
||||
reinterpret_cast<const uint8_t *>(name), strlen(name),
|
||||
reinterpret_cast<const uint8_t *>(value), strlen(value));
|
||||
}
|
||||
client->worker->stats.bytes_head += frame->syn_reply.hd.length;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void on_data_chunk_recv_callback
|
||||
(spdylay_session *session, uint8_t flags, int32_t stream_id,
|
||||
const uint8_t *data, size_t len, void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
void on_data_chunk_recv_callback(spdylay_session *session, uint8_t flags,
|
||||
int32_t stream_id, const uint8_t *data,
|
||||
size_t len, void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
client->worker->stats.bytes_body += len;
|
||||
|
||||
auto spdy_session = static_cast<SpdySession*>(client->session.get());
|
||||
auto spdy_session = static_cast<SpdySession *>(client->session.get());
|
||||
|
||||
spdy_session->handle_window_update(stream_id, len);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void on_stream_close_callback
|
||||
(spdylay_session *session, int32_t stream_id, spdylay_status_code status_code,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
void on_stream_close_callback(spdylay_session *session, int32_t stream_id,
|
||||
spdylay_status_code status_code,
|
||||
void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
client->on_stream_close(stream_id, status_code == SPDYLAY_OK);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
ssize_t send_callback(spdylay_session *session,
|
||||
const uint8_t *data, size_t length, int flags,
|
||||
void *user_data)
|
||||
{
|
||||
auto client = static_cast<Client*>(user_data);
|
||||
auto spdy_session = static_cast<SpdySession*>(client->session.get());
|
||||
ssize_t send_callback(spdylay_session *session, const uint8_t *data,
|
||||
size_t length, int flags, void *user_data) {
|
||||
auto client = static_cast<Client *>(user_data);
|
||||
auto spdy_session = static_cast<SpdySession *>(client->session.get());
|
||||
int rv;
|
||||
|
||||
rv = spdy_session->sendbuf.add(data, length);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return SPDYLAY_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
return length;
|
||||
}
|
||||
} //namespace
|
||||
} // namespace
|
||||
|
||||
void SpdySession::on_connect()
|
||||
{
|
||||
void SpdySession::on_connect() {
|
||||
spdylay_session_callbacks callbacks = {0};
|
||||
callbacks.send_callback = send_callback;
|
||||
callbacks.before_ctrl_send_callback = before_ctrl_send_callback;
|
||||
@ -133,8 +116,8 @@ void SpdySession::on_connect()
|
||||
spdylay_session_client_new(&session_, spdy_version_, &callbacks, client_);
|
||||
|
||||
int val = 1;
|
||||
spdylay_session_set_option(session_, SPDYLAY_OPT_NO_AUTO_WINDOW_UPDATE,
|
||||
&val, sizeof(val));
|
||||
spdylay_session_set_option(session_, SPDYLAY_OPT_NO_AUTO_WINDOW_UPDATE, &val,
|
||||
sizeof(val));
|
||||
|
||||
spdylay_settings_entry iv[1];
|
||||
iv[0].settings_id = SPDYLAY_SETTINGS_INITIAL_WINDOW_SIZE;
|
||||
@ -145,36 +128,34 @@ void SpdySession::on_connect()
|
||||
|
||||
auto config = client_->worker->config;
|
||||
|
||||
if(spdy_version_ >= SPDYLAY_PROTO_SPDY3_1 &&
|
||||
config->connection_window_bits > 16) {
|
||||
auto delta = (1 << config->connection_window_bits)
|
||||
- SPDYLAY_INITIAL_WINDOW_SIZE;
|
||||
if (spdy_version_ >= SPDYLAY_PROTO_SPDY3_1 &&
|
||||
config->connection_window_bits > 16) {
|
||||
auto delta =
|
||||
(1 << config->connection_window_bits) - SPDYLAY_INITIAL_WINDOW_SIZE;
|
||||
spdylay_submit_window_update(session_, 0, delta);
|
||||
}
|
||||
}
|
||||
|
||||
void SpdySession::submit_request()
|
||||
{
|
||||
void SpdySession::submit_request() {
|
||||
auto config = client_->worker->config;
|
||||
auto& nv = config->nv[client_->reqidx++];
|
||||
auto &nv = config->nv[client_->reqidx++];
|
||||
|
||||
if(client_->reqidx == config->nv.size()) {
|
||||
if (client_->reqidx == config->nv.size()) {
|
||||
client_->reqidx = 0;
|
||||
}
|
||||
|
||||
spdylay_submit_request(session_, 0, nv.data(), nullptr, nullptr);
|
||||
}
|
||||
|
||||
ssize_t SpdySession::on_read()
|
||||
{
|
||||
ssize_t SpdySession::on_read() {
|
||||
int rv;
|
||||
size_t nread = 0;
|
||||
auto input = bufferevent_get_input(client_->bev);
|
||||
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
auto inputlen = evbuffer_get_contiguous_space(input);
|
||||
|
||||
if(inputlen == 0) {
|
||||
if (inputlen == 0) {
|
||||
assert(evbuffer_get_length(input) == 0);
|
||||
|
||||
return nread;
|
||||
@ -184,65 +165,62 @@ ssize_t SpdySession::on_read()
|
||||
|
||||
rv = spdylay_session_mem_recv(session_, mem, inputlen);
|
||||
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
nread += rv;
|
||||
|
||||
if(evbuffer_drain(input, rv) != 0) {
|
||||
if (evbuffer_drain(input, rv) != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int SpdySession::on_write()
|
||||
{
|
||||
int SpdySession::on_write() {
|
||||
int rv;
|
||||
uint8_t buf[16384];
|
||||
|
||||
sendbuf.reset(bufferevent_get_output(client_->bev), buf, sizeof(buf));
|
||||
|
||||
rv = spdylay_session_send(session_);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
rv = sendbuf.flush();
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(spdylay_session_want_read(session_) == 0 &&
|
||||
spdylay_session_want_write(session_) == 0 &&
|
||||
evbuffer_get_length(bufferevent_get_output(client_->bev)) == 0) {
|
||||
if (spdylay_session_want_read(session_) == 0 &&
|
||||
spdylay_session_want_write(session_) == 0 &&
|
||||
evbuffer_get_length(bufferevent_get_output(client_->bev)) == 0) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void SpdySession::terminate()
|
||||
{
|
||||
void SpdySession::terminate() {
|
||||
spdylay_session_fail_session(session_, SPDYLAY_OK);
|
||||
}
|
||||
|
||||
namespace {
|
||||
int32_t determine_window_update_transmission(spdylay_session *session,
|
||||
int32_t stream_id,
|
||||
size_t window_bits)
|
||||
{
|
||||
size_t window_bits) {
|
||||
int32_t recv_length;
|
||||
|
||||
if(stream_id == 0) {
|
||||
if (stream_id == 0) {
|
||||
recv_length = spdylay_session_get_recv_data_length(session);
|
||||
} else {
|
||||
recv_length = spdylay_session_get_stream_recv_data_length
|
||||
(session, stream_id);
|
||||
recv_length =
|
||||
spdylay_session_get_stream_recv_data_length(session, stream_id);
|
||||
}
|
||||
|
||||
auto window_size = 1 << window_bits;
|
||||
|
||||
if(recv_length != -1 && recv_length >= window_size / 2) {
|
||||
if (recv_length != -1 && recv_length >= window_size / 2) {
|
||||
return recv_length;
|
||||
}
|
||||
|
||||
@ -250,26 +228,25 @@ int32_t determine_window_update_transmission(spdylay_session *session,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void SpdySession::handle_window_update(int32_t stream_id, size_t recvlen)
|
||||
{
|
||||
void SpdySession::handle_window_update(int32_t stream_id, size_t recvlen) {
|
||||
auto config = client_->worker->config;
|
||||
size_t connection_window_bits;
|
||||
|
||||
if(config->connection_window_bits > 16) {
|
||||
if (config->connection_window_bits > 16) {
|
||||
connection_window_bits = config->connection_window_bits;
|
||||
} else {
|
||||
connection_window_bits = 16;
|
||||
}
|
||||
|
||||
auto delta = determine_window_update_transmission
|
||||
(session_, 0, connection_window_bits);
|
||||
if(delta > 0) {
|
||||
auto delta =
|
||||
determine_window_update_transmission(session_, 0, connection_window_bits);
|
||||
if (delta > 0) {
|
||||
spdylay_submit_window_update(session_, 0, delta);
|
||||
}
|
||||
|
||||
delta = determine_window_update_transmission
|
||||
(session_, stream_id, config->window_bits);
|
||||
if(delta > 0) {
|
||||
delta = determine_window_update_transmission(session_, stream_id,
|
||||
config->window_bits);
|
||||
if (delta > 0) {
|
||||
spdylay_submit_window_update(session_, stream_id, delta);
|
||||
}
|
||||
}
|
||||
|
@ -48,6 +48,7 @@ public:
|
||||
void handle_window_update(int32_t stream_id, size_t recvlen);
|
||||
|
||||
nghttp2::util::EvbufferBuffer sendbuf;
|
||||
|
||||
private:
|
||||
Client *client_;
|
||||
spdylay_session *session_;
|
||||
|
471
src/http2.cc
471
src/http2.cc
@ -30,66 +30,112 @@ namespace nghttp2 {
|
||||
|
||||
namespace http2 {
|
||||
|
||||
std::string get_status_string(unsigned int status_code)
|
||||
{
|
||||
switch(status_code) {
|
||||
case 100: return "100 Continue";
|
||||
case 101: return "101 Switching Protocols";
|
||||
case 200: return "200 OK";
|
||||
case 201: return "201 Created";
|
||||
case 202: return "202 Accepted";
|
||||
case 203: return "203 Non-Authoritative Information";
|
||||
case 204: return "204 No Content";
|
||||
case 205: return "205 Reset Content";
|
||||
case 206: return "206 Partial Content";
|
||||
case 300: return "300 Multiple Choices";
|
||||
case 301: return "301 Moved Permanently";
|
||||
case 302: return "302 Found";
|
||||
case 303: return "303 See Other";
|
||||
case 304: return "304 Not Modified";
|
||||
case 305: return "305 Use Proxy";
|
||||
// case 306: return "306 (Unused)";
|
||||
case 307: return "307 Temporary Redirect";
|
||||
case 308: return "308 Permanent Redirect";
|
||||
case 400: return "400 Bad Request";
|
||||
case 401: return "401 Unauthorized";
|
||||
case 402: return "402 Payment Required";
|
||||
case 403: return "403 Forbidden";
|
||||
case 404: return "404 Not Found";
|
||||
case 405: return "405 Method Not Allowed";
|
||||
case 406: return "406 Not Acceptable";
|
||||
case 407: return "407 Proxy Authentication Required";
|
||||
case 408: return "408 Request Timeout";
|
||||
case 409: return "409 Conflict";
|
||||
case 410: return "410 Gone";
|
||||
case 411: return "411 Length Required";
|
||||
case 412: return "412 Precondition Failed";
|
||||
case 413: return "413 Payload Too Large";
|
||||
case 414: return "414 URI Too Long";
|
||||
case 415: return "415 Unsupported Media Type";
|
||||
case 416: return "416 Requested Range Not Satisfiable";
|
||||
case 417: return "417 Expectation Failed";
|
||||
case 421: return "421 Misdirected Request";
|
||||
case 426: return "426 Upgrade Required";
|
||||
case 428: return "428 Precondition Required";
|
||||
case 429: return "429 Too Many Requests";
|
||||
case 431: return "431 Request Header Fields Too Large";
|
||||
case 500: return "500 Internal Server Error";
|
||||
case 501: return "501 Not Implemented";
|
||||
case 502: return "502 Bad Gateway";
|
||||
case 503: return "503 Service Unavailable";
|
||||
case 504: return "504 Gateway Timeout";
|
||||
case 505: return "505 HTTP Version Not Supported";
|
||||
case 511: return "511 Network Authentication Required";
|
||||
default: return util::utos(status_code);
|
||||
std::string get_status_string(unsigned int status_code) {
|
||||
switch (status_code) {
|
||||
case 100:
|
||||
return "100 Continue";
|
||||
case 101:
|
||||
return "101 Switching Protocols";
|
||||
case 200:
|
||||
return "200 OK";
|
||||
case 201:
|
||||
return "201 Created";
|
||||
case 202:
|
||||
return "202 Accepted";
|
||||
case 203:
|
||||
return "203 Non-Authoritative Information";
|
||||
case 204:
|
||||
return "204 No Content";
|
||||
case 205:
|
||||
return "205 Reset Content";
|
||||
case 206:
|
||||
return "206 Partial Content";
|
||||
case 300:
|
||||
return "300 Multiple Choices";
|
||||
case 301:
|
||||
return "301 Moved Permanently";
|
||||
case 302:
|
||||
return "302 Found";
|
||||
case 303:
|
||||
return "303 See Other";
|
||||
case 304:
|
||||
return "304 Not Modified";
|
||||
case 305:
|
||||
return "305 Use Proxy";
|
||||
// case 306: return "306 (Unused)";
|
||||
case 307:
|
||||
return "307 Temporary Redirect";
|
||||
case 308:
|
||||
return "308 Permanent Redirect";
|
||||
case 400:
|
||||
return "400 Bad Request";
|
||||
case 401:
|
||||
return "401 Unauthorized";
|
||||
case 402:
|
||||
return "402 Payment Required";
|
||||
case 403:
|
||||
return "403 Forbidden";
|
||||
case 404:
|
||||
return "404 Not Found";
|
||||
case 405:
|
||||
return "405 Method Not Allowed";
|
||||
case 406:
|
||||
return "406 Not Acceptable";
|
||||
case 407:
|
||||
return "407 Proxy Authentication Required";
|
||||
case 408:
|
||||
return "408 Request Timeout";
|
||||
case 409:
|
||||
return "409 Conflict";
|
||||
case 410:
|
||||
return "410 Gone";
|
||||
case 411:
|
||||
return "411 Length Required";
|
||||
case 412:
|
||||
return "412 Precondition Failed";
|
||||
case 413:
|
||||
return "413 Payload Too Large";
|
||||
case 414:
|
||||
return "414 URI Too Long";
|
||||
case 415:
|
||||
return "415 Unsupported Media Type";
|
||||
case 416:
|
||||
return "416 Requested Range Not Satisfiable";
|
||||
case 417:
|
||||
return "417 Expectation Failed";
|
||||
case 421:
|
||||
return "421 Misdirected Request";
|
||||
case 426:
|
||||
return "426 Upgrade Required";
|
||||
case 428:
|
||||
return "428 Precondition Required";
|
||||
case 429:
|
||||
return "429 Too Many Requests";
|
||||
case 431:
|
||||
return "431 Request Header Fields Too Large";
|
||||
case 500:
|
||||
return "500 Internal Server Error";
|
||||
case 501:
|
||||
return "501 Not Implemented";
|
||||
case 502:
|
||||
return "502 Bad Gateway";
|
||||
case 503:
|
||||
return "503 Service Unavailable";
|
||||
case 504:
|
||||
return "504 Gateway Timeout";
|
||||
case 505:
|
||||
return "505 HTTP Version Not Supported";
|
||||
case 511:
|
||||
return "511 Network Authentication Required";
|
||||
default:
|
||||
return util::utos(status_code);
|
||||
}
|
||||
}
|
||||
|
||||
void capitalize(std::string& s, size_t offset)
|
||||
{
|
||||
void capitalize(std::string &s, size_t offset) {
|
||||
s[offset] = util::upcase(s[offset]);
|
||||
for(size_t i = offset+1, eoi = s.size(); i < eoi; ++i) {
|
||||
if(s[i-1] == '-') {
|
||||
for (size_t i = offset + 1, eoi = s.size(); i < eoi; ++i) {
|
||||
if (s[i - 1] == '-') {
|
||||
s[i] = util::upcase(s[i]);
|
||||
} else {
|
||||
s[i] = util::lowcase(s[i]);
|
||||
@ -97,10 +143,9 @@ void capitalize(std::string& s, size_t offset)
|
||||
}
|
||||
}
|
||||
|
||||
bool lws(const char *value)
|
||||
{
|
||||
for(; *value; ++value) {
|
||||
switch(*value) {
|
||||
bool lws(const char *value) {
|
||||
for (; *value; ++value) {
|
||||
switch (*value) {
|
||||
case '\t':
|
||||
case ' ':
|
||||
continue;
|
||||
@ -111,8 +156,7 @@ bool lws(const char *value)
|
||||
return true;
|
||||
}
|
||||
|
||||
void sanitize_header_value(std::string& s, size_t offset)
|
||||
{
|
||||
void sanitize_header_value(std::string &s, size_t offset) {
|
||||
// Since both nghttp2 and spdylay do not allow \n and \r in header
|
||||
// values, we don't have to do this anymore.
|
||||
|
||||
@ -123,40 +167,32 @@ void sanitize_header_value(std::string& s, size_t offset)
|
||||
// }
|
||||
}
|
||||
|
||||
void copy_url_component(std::string& dest, const http_parser_url *u, int field,
|
||||
const char* url)
|
||||
{
|
||||
if(u->field_set & (1 << field)) {
|
||||
dest.assign(url+u->field_data[field].off, u->field_data[field].len);
|
||||
void copy_url_component(std::string &dest, const http_parser_url *u, int field,
|
||||
const char *url) {
|
||||
if (u->field_set & (1 << field)) {
|
||||
dest.assign(url + u->field_data[field].off, u->field_data[field].len);
|
||||
}
|
||||
}
|
||||
|
||||
bool check_http2_allowed_header(const char *name)
|
||||
{
|
||||
return check_http2_allowed_header(reinterpret_cast<const uint8_t*>(name),
|
||||
bool check_http2_allowed_header(const char *name) {
|
||||
return check_http2_allowed_header(reinterpret_cast<const uint8_t *>(name),
|
||||
strlen(name));
|
||||
}
|
||||
|
||||
bool check_http2_allowed_header(const uint8_t *name, size_t namelen)
|
||||
{
|
||||
return
|
||||
!util::strieq("connection", name, namelen) &&
|
||||
!util::strieq("host", name, namelen) &&
|
||||
!util::strieq("keep-alive", name, namelen) &&
|
||||
!util::strieq("proxy-connection", name, namelen) &&
|
||||
!util::strieq("te", name, namelen) &&
|
||||
!util::strieq("transfer-encoding", name, namelen) &&
|
||||
!util::strieq("upgrade", name, namelen);
|
||||
bool check_http2_allowed_header(const uint8_t *name, size_t namelen) {
|
||||
return !util::strieq("connection", name, namelen) &&
|
||||
!util::strieq("host", name, namelen) &&
|
||||
!util::strieq("keep-alive", name, namelen) &&
|
||||
!util::strieq("proxy-connection", name, namelen) &&
|
||||
!util::strieq("te", name, namelen) &&
|
||||
!util::strieq("transfer-encoding", name, namelen) &&
|
||||
!util::strieq("upgrade", name, namelen);
|
||||
}
|
||||
|
||||
namespace {
|
||||
const char *DISALLOWED_HD[] = {
|
||||
"connection",
|
||||
"keep-alive",
|
||||
"proxy-connection",
|
||||
"te",
|
||||
"transfer-encoding",
|
||||
"upgrade",
|
||||
"connection", "keep-alive", "proxy-connection",
|
||||
"te", "transfer-encoding", "upgrade",
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -166,10 +202,7 @@ auto DISALLOWED_HDLEN = util::array_size(DISALLOWED_HD);
|
||||
|
||||
namespace {
|
||||
const char *REQUEST_PSEUDO_HD[] = {
|
||||
":authority",
|
||||
":method",
|
||||
":path",
|
||||
":scheme",
|
||||
":authority", ":method", ":path", ":scheme",
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -179,7 +212,7 @@ auto REQUEST_PSEUDO_HDLEN = util::array_size(REQUEST_PSEUDO_HD);
|
||||
|
||||
namespace {
|
||||
const char *RESPONSE_PSEUDO_HD[] = {
|
||||
":status",
|
||||
":status",
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -189,17 +222,9 @@ auto RESPONSE_PSEUDO_HDLEN = util::array_size(RESPONSE_PSEUDO_HD);
|
||||
|
||||
namespace {
|
||||
const char *IGN_HD[] = {
|
||||
"connection",
|
||||
"http2-settings",
|
||||
"keep-alive",
|
||||
"proxy-connection",
|
||||
"server",
|
||||
"te",
|
||||
"transfer-encoding",
|
||||
"upgrade",
|
||||
"via",
|
||||
"x-forwarded-for",
|
||||
"x-forwarded-proto",
|
||||
"connection", "http2-settings", "keep-alive", "proxy-connection",
|
||||
"server", "te", "transfer-encoding", "upgrade",
|
||||
"via", "x-forwarded-for", "x-forwarded-proto",
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -209,16 +234,9 @@ auto IGN_HDLEN = util::array_size(IGN_HD);
|
||||
|
||||
namespace {
|
||||
const char *HTTP1_IGN_HD[] = {
|
||||
"connection",
|
||||
"cookie",
|
||||
"http2-settings",
|
||||
"keep-alive",
|
||||
"proxy-connection",
|
||||
"server",
|
||||
"upgrade",
|
||||
"via",
|
||||
"x-forwarded-for",
|
||||
"x-forwarded-proto",
|
||||
"connection", "cookie", "http2-settings", "keep-alive",
|
||||
"proxy-connection", "server", "upgrade", "via",
|
||||
"x-forwarded-for", "x-forwarded-proto",
|
||||
};
|
||||
} // namespace
|
||||
|
||||
@ -226,49 +244,43 @@ namespace {
|
||||
auto HTTP1_IGN_HDLEN = util::array_size(HTTP1_IGN_HD);
|
||||
} // namespace
|
||||
|
||||
bool name_less(const Headers::value_type& lhs,
|
||||
const Headers::value_type& rhs)
|
||||
{
|
||||
if(lhs.name.c_str()[0] == ':') {
|
||||
if(rhs.name.c_str()[0] != ':') {
|
||||
bool name_less(const Headers::value_type &lhs, const Headers::value_type &rhs) {
|
||||
if (lhs.name.c_str()[0] == ':') {
|
||||
if (rhs.name.c_str()[0] != ':') {
|
||||
return true;
|
||||
}
|
||||
} else if(rhs.name.c_str()[0] == ':') {
|
||||
} else if (rhs.name.c_str()[0] == ':') {
|
||||
return false;
|
||||
}
|
||||
|
||||
return lhs.name < rhs.name;
|
||||
}
|
||||
|
||||
bool check_http2_headers(const Headers& nva)
|
||||
{
|
||||
for(size_t i = 0; i < DISALLOWED_HDLEN; ++i) {
|
||||
if(std::binary_search(std::begin(nva), std::end(nva),
|
||||
Header(DISALLOWED_HD[i], ""), name_less)) {
|
||||
bool check_http2_headers(const Headers &nva) {
|
||||
for (size_t i = 0; i < DISALLOWED_HDLEN; ++i) {
|
||||
if (std::binary_search(std::begin(nva), std::end(nva),
|
||||
Header(DISALLOWED_HD[i], ""), name_less)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_http2_request_headers(const Headers& nva)
|
||||
{
|
||||
bool check_http2_request_headers(const Headers &nva) {
|
||||
return check_http2_headers(nva);
|
||||
}
|
||||
|
||||
bool check_http2_response_headers(const Headers& nva)
|
||||
{
|
||||
bool check_http2_response_headers(const Headers &nva) {
|
||||
return check_http2_headers(nva);
|
||||
}
|
||||
|
||||
namespace {
|
||||
template<typename InputIterator>
|
||||
template <typename InputIterator>
|
||||
bool check_pseudo_header(const uint8_t *name, size_t namelen,
|
||||
InputIterator allowed_first,
|
||||
InputIterator allowed_last)
|
||||
{
|
||||
for(auto i = allowed_first; i != allowed_last; ++i) {
|
||||
if(util::streq(*i, name, namelen)) {
|
||||
InputIterator allowed_last) {
|
||||
for (auto i = allowed_first; i != allowed_last; ++i) {
|
||||
if (util::streq(*i, name, namelen)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -277,21 +289,18 @@ bool check_pseudo_header(const uint8_t *name, size_t namelen,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
bool check_http2_request_pseudo_header(const uint8_t *name, size_t namelen)
|
||||
{
|
||||
bool check_http2_request_pseudo_header(const uint8_t *name, size_t namelen) {
|
||||
return check_pseudo_header(name, namelen, REQUEST_PSEUDO_HD,
|
||||
REQUEST_PSEUDO_HD + REQUEST_PSEUDO_HDLEN);
|
||||
}
|
||||
|
||||
bool check_http2_response_pseudo_header(const uint8_t *name, size_t namelen)
|
||||
{
|
||||
bool check_http2_response_pseudo_header(const uint8_t *name, size_t namelen) {
|
||||
return check_pseudo_header(name, namelen, RESPONSE_PSEUDO_HD,
|
||||
RESPONSE_PSEUDO_HD + RESPONSE_PSEUDO_HDLEN);
|
||||
}
|
||||
|
||||
void normalize_headers(Headers& nva)
|
||||
{
|
||||
for(auto& kv : nva) {
|
||||
void normalize_headers(Headers &nva) {
|
||||
for (auto &kv : nva) {
|
||||
util::inp_strlower(kv.name);
|
||||
}
|
||||
std::stable_sort(std::begin(nva), std::end(nva), name_less);
|
||||
@ -299,112 +308,98 @@ void normalize_headers(Headers& nva)
|
||||
|
||||
Headers::value_type to_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index)
|
||||
{
|
||||
return Header(std::string(reinterpret_cast<const char*>(name),
|
||||
namelen),
|
||||
std::string(reinterpret_cast<const char*>(value),
|
||||
valuelen),
|
||||
bool no_index) {
|
||||
return Header(std::string(reinterpret_cast<const char *>(name), namelen),
|
||||
std::string(reinterpret_cast<const char *>(value), valuelen),
|
||||
no_index);
|
||||
}
|
||||
|
||||
void add_header(Headers& nva,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index)
|
||||
{
|
||||
void add_header(Headers &nva, const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, bool no_index) {
|
||||
nva.push_back(to_header(name, namelen, value, valuelen, no_index));
|
||||
}
|
||||
|
||||
const Headers::value_type* get_unique_header(const Headers& nva,
|
||||
const char *name)
|
||||
{
|
||||
const Headers::value_type *get_unique_header(const Headers &nva,
|
||||
const char *name) {
|
||||
auto nv = Headers::value_type(name, "");
|
||||
auto i = std::lower_bound(std::begin(nva), std::end(nva), nv, name_less);
|
||||
if(i != std::end(nva) && (*i).name == nv.name) {
|
||||
if (i != std::end(nva) && (*i).name == nv.name) {
|
||||
auto j = i + 1;
|
||||
if(j == std::end(nva) || (*j).name != nv.name) {
|
||||
if (j == std::end(nva) || (*j).name != nv.name) {
|
||||
return &(*i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const Headers::value_type* get_header(const Headers& nva, const char *name)
|
||||
{
|
||||
const Headers::value_type *get_header(const Headers &nva, const char *name) {
|
||||
auto nv = Headers::value_type(name, "");
|
||||
auto i = std::lower_bound(std::begin(nva), std::end(nva), nv, name_less);
|
||||
if(i != std::end(nva) && (*i).name == nv.name) {
|
||||
if (i != std::end(nva) && (*i).name == nv.name) {
|
||||
return &(*i);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string value_to_str(const Headers::value_type *nv)
|
||||
{
|
||||
if(nv) {
|
||||
std::string value_to_str(const Headers::value_type *nv) {
|
||||
if (nv) {
|
||||
return nv->value;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
bool value_lws(const Headers::value_type *nv)
|
||||
{
|
||||
bool value_lws(const Headers::value_type *nv) {
|
||||
return (*nv).value.find_first_not_of("\t ") == std::string::npos;
|
||||
}
|
||||
|
||||
bool non_empty_value(const Headers::value_type *nv)
|
||||
{
|
||||
bool non_empty_value(const Headers::value_type *nv) {
|
||||
return nv && !value_lws(nv);
|
||||
}
|
||||
|
||||
nghttp2_nv make_nv(const std::string& name, const std::string& value,
|
||||
bool no_index)
|
||||
{
|
||||
nghttp2_nv make_nv(const std::string &name, const std::string &value,
|
||||
bool no_index) {
|
||||
uint8_t flags;
|
||||
|
||||
flags = no_index ? NGHTTP2_NV_FLAG_NO_INDEX : NGHTTP2_NV_FLAG_NONE;
|
||||
|
||||
return {(uint8_t*)name.c_str(), (uint8_t*)value.c_str(),
|
||||
name.size(), value.size(), flags};
|
||||
return {(uint8_t *)name.c_str(), (uint8_t *)value.c_str(), name.size(),
|
||||
value.size(), flags};
|
||||
}
|
||||
|
||||
void copy_norm_headers_to_nva
|
||||
(std::vector<nghttp2_nv>& nva, const Headers& headers)
|
||||
{
|
||||
void copy_norm_headers_to_nva(std::vector<nghttp2_nv> &nva,
|
||||
const Headers &headers) {
|
||||
size_t i, j;
|
||||
for(i = 0, j = 0; i < headers.size() && j < IGN_HDLEN;) {
|
||||
auto& kv = headers[i];
|
||||
for (i = 0, j = 0; i < headers.size() && j < IGN_HDLEN;) {
|
||||
auto &kv = headers[i];
|
||||
int rv = strcmp(kv.name.c_str(), IGN_HD[j]);
|
||||
if(rv < 0) {
|
||||
if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
if (rv < 0) {
|
||||
if (!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
nva.push_back(make_nv(kv.name, kv.value, kv.no_index));
|
||||
}
|
||||
++i;
|
||||
} else if(rv > 0) {
|
||||
} else if (rv > 0) {
|
||||
++j;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for(; i < headers.size(); ++i) {
|
||||
auto& kv = headers[i];
|
||||
if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
for (; i < headers.size(); ++i) {
|
||||
auto &kv = headers[i];
|
||||
if (!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
nva.push_back(make_nv(kv.name, kv.value, kv.no_index));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void build_http1_headers_from_norm_headers
|
||||
(std::string& hdrs, const Headers& headers)
|
||||
{
|
||||
void build_http1_headers_from_norm_headers(std::string &hdrs,
|
||||
const Headers &headers) {
|
||||
size_t i, j;
|
||||
for(i = 0, j = 0; i < headers.size() && j < HTTP1_IGN_HDLEN;) {
|
||||
auto& kv = headers[i];
|
||||
for (i = 0, j = 0; i < headers.size() && j < HTTP1_IGN_HDLEN;) {
|
||||
auto &kv = headers[i];
|
||||
auto rv = strcmp(kv.name.c_str(), HTTP1_IGN_HD[j]);
|
||||
|
||||
if(rv < 0) {
|
||||
if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
if (rv < 0) {
|
||||
if (!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
hdrs += kv.name;
|
||||
capitalize(hdrs, hdrs.size() - kv.name.size());
|
||||
hdrs += ": ";
|
||||
@ -413,16 +408,16 @@ void build_http1_headers_from_norm_headers
|
||||
hdrs += "\r\n";
|
||||
}
|
||||
++i;
|
||||
} else if(rv > 0) {
|
||||
} else if (rv > 0) {
|
||||
++j;
|
||||
} else {
|
||||
++i;
|
||||
}
|
||||
}
|
||||
for(; i < headers.size(); ++i) {
|
||||
auto& kv = headers[i];
|
||||
for (; i < headers.size(); ++i) {
|
||||
auto &kv = headers[i];
|
||||
|
||||
if(!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
if (!kv.name.empty() && kv.name.c_str()[0] != ':') {
|
||||
hdrs += kv.name;
|
||||
capitalize(hdrs, hdrs.size() - kv.name.size());
|
||||
hdrs += ": ";
|
||||
@ -434,42 +429,39 @@ void build_http1_headers_from_norm_headers
|
||||
}
|
||||
|
||||
int32_t determine_window_update_transmission(nghttp2_session *session,
|
||||
int32_t stream_id)
|
||||
{
|
||||
int32_t stream_id) {
|
||||
int32_t recv_length, window_size;
|
||||
if(stream_id == 0) {
|
||||
if (stream_id == 0) {
|
||||
recv_length = nghttp2_session_get_effective_recv_data_length(session);
|
||||
window_size = nghttp2_session_get_effective_local_window_size(session);
|
||||
} else {
|
||||
recv_length = nghttp2_session_get_stream_effective_recv_data_length
|
||||
(session, stream_id);
|
||||
window_size = nghttp2_session_get_stream_effective_local_window_size
|
||||
(session, stream_id);
|
||||
recv_length = nghttp2_session_get_stream_effective_recv_data_length(
|
||||
session, stream_id);
|
||||
window_size = nghttp2_session_get_stream_effective_local_window_size(
|
||||
session, stream_id);
|
||||
}
|
||||
if(recv_length != -1 && window_size != -1) {
|
||||
if(recv_length >= window_size / 2) {
|
||||
if (recv_length != -1 && window_size != -1) {
|
||||
if (recv_length >= window_size / 2) {
|
||||
return recv_length;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void dump_nv(FILE *out, const char **nv)
|
||||
{
|
||||
for(size_t i = 0; nv[i]; i += 2) {
|
||||
void dump_nv(FILE *out, const char **nv) {
|
||||
for (size_t i = 0; nv[i]; i += 2) {
|
||||
fwrite(nv[i], strlen(nv[i]), 1, out);
|
||||
fwrite(": ", 2, 1, out);
|
||||
fwrite(nv[i+1], strlen(nv[i+1]), 1, out);
|
||||
fwrite(nv[i + 1], strlen(nv[i + 1]), 1, out);
|
||||
fwrite("\n", 1, 1, out);
|
||||
}
|
||||
fwrite("\n", 1, 1, out);
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen)
|
||||
{
|
||||
void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen) {
|
||||
auto end = nva + nvlen;
|
||||
for(; nva != end; ++nva) {
|
||||
for (; nva != end; ++nva) {
|
||||
fwrite(nva->name, nva->namelen, 1, out);
|
||||
fwrite(": ", 2, 1, out);
|
||||
fwrite(nva->value, nva->valuelen, 1, out);
|
||||
@ -479,9 +471,8 @@ void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen)
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
void dump_nv(FILE *out, const Headers& nva)
|
||||
{
|
||||
for(auto& nv : nva) {
|
||||
void dump_nv(FILE *out, const Headers &nva) {
|
||||
for (auto &nv : nva) {
|
||||
fwrite(nv.name.c_str(), nv.name.size(), 1, out);
|
||||
fwrite(": ", 2, 1, out);
|
||||
fwrite(nv.value.c_str(), nv.value.size(), 1, out);
|
||||
@ -491,54 +482,52 @@ void dump_nv(FILE *out, const Headers& nva)
|
||||
fflush(out);
|
||||
}
|
||||
|
||||
std::string rewrite_location_uri(const std::string& uri,
|
||||
const http_parser_url& u,
|
||||
const std::string& request_host,
|
||||
const std::string& upstream_scheme,
|
||||
uint16_t upstream_port)
|
||||
{
|
||||
std::string rewrite_location_uri(const std::string &uri,
|
||||
const http_parser_url &u,
|
||||
const std::string &request_host,
|
||||
const std::string &upstream_scheme,
|
||||
uint16_t upstream_port) {
|
||||
// We just rewrite host and optionally port. We don't rewrite https
|
||||
// link. Not sure it happens in practice.
|
||||
if(u.field_set & (1 << UF_SCHEMA)) {
|
||||
if (u.field_set & (1 << UF_SCHEMA)) {
|
||||
auto field = &u.field_data[UF_SCHEMA];
|
||||
if(!util::streq("http", &uri[field->off], field->len)) {
|
||||
if (!util::streq("http", &uri[field->off], field->len)) {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
if((u.field_set & (1 << UF_HOST)) == 0) {
|
||||
if ((u.field_set & (1 << UF_HOST)) == 0) {
|
||||
return "";
|
||||
}
|
||||
auto field = &u.field_data[UF_HOST];
|
||||
if(!util::startsWith(std::begin(request_host), std::end(request_host),
|
||||
&uri[field->off], &uri[field->off] + field->len) ||
|
||||
(request_host.size() != field->len &&
|
||||
request_host[field->len] != ':')) {
|
||||
if (!util::startsWith(std::begin(request_host), std::end(request_host),
|
||||
&uri[field->off], &uri[field->off] + field->len) ||
|
||||
(request_host.size() != field->len && request_host[field->len] != ':')) {
|
||||
return "";
|
||||
}
|
||||
std::string res = upstream_scheme;
|
||||
res += "://";
|
||||
res.append(&uri[field->off], field->len);
|
||||
if(upstream_scheme == "http") {
|
||||
if(upstream_port != 80) {
|
||||
if (upstream_scheme == "http") {
|
||||
if (upstream_port != 80) {
|
||||
res += ":";
|
||||
res += util::utos(upstream_port);
|
||||
}
|
||||
} else if(upstream_scheme == "https") {
|
||||
if(upstream_port != 443) {
|
||||
} else if (upstream_scheme == "https") {
|
||||
if (upstream_port != 443) {
|
||||
res += ":";
|
||||
res += util::utos(upstream_port);
|
||||
}
|
||||
}
|
||||
if(u.field_set & (1 << UF_PATH)) {
|
||||
if (u.field_set & (1 << UF_PATH)) {
|
||||
field = &u.field_data[UF_PATH];
|
||||
res.append(&uri[field->off], field->len);
|
||||
}
|
||||
if(u.field_set & (1 << UF_QUERY)) {
|
||||
if (u.field_set & (1 << UF_QUERY)) {
|
||||
field = &u.field_data[UF_QUERY];
|
||||
res += "?";
|
||||
res.append(&uri[field->off], field->len);
|
||||
}
|
||||
if(u.field_set & (1 << UF_FRAGMENT)) {
|
||||
if (u.field_set & (1 << UF_FRAGMENT)) {
|
||||
field = &u.field_data[UF_FRAGMENT];
|
||||
res += "#";
|
||||
res.append(&uri[field->off], field->len);
|
||||
@ -546,34 +535,32 @@ std::string rewrite_location_uri(const std::string& uri,
|
||||
return res;
|
||||
}
|
||||
|
||||
int check_nv(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen)
|
||||
{
|
||||
if(!nghttp2_check_header_name(name, namelen)) {
|
||||
int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t valuelen) {
|
||||
if (!nghttp2_check_header_name(name, namelen)) {
|
||||
return 0;
|
||||
}
|
||||
if(!nghttp2_check_header_value(value, valuelen)) {
|
||||
if (!nghttp2_check_header_value(value, valuelen)) {
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int parse_http_status_code(const std::string& src)
|
||||
{
|
||||
if(src.size() != 3) {
|
||||
int parse_http_status_code(const std::string &src) {
|
||||
if (src.size() != 3) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int status = 0;
|
||||
for(auto c : src) {
|
||||
if(!isdigit(c)) {
|
||||
for (auto c : src) {
|
||||
if (!isdigit(c)) {
|
||||
return -1;
|
||||
}
|
||||
status *= 10;
|
||||
status += c - '0';
|
||||
}
|
||||
|
||||
if(status < 100) {
|
||||
if (status < 100) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
97
src/http2.h
97
src/http2.h
@ -39,23 +39,16 @@
|
||||
namespace nghttp2 {
|
||||
|
||||
struct Header {
|
||||
Header(std::string name, std::string value, bool no_index=false)
|
||||
: name(std::move(name)),
|
||||
value(std::move(value)),
|
||||
no_index(no_index)
|
||||
{}
|
||||
Header(std::string name, std::string value, bool no_index = false)
|
||||
: name(std::move(name)), value(std::move(value)), no_index(no_index) {}
|
||||
|
||||
Header()
|
||||
: no_index(false)
|
||||
{}
|
||||
Header() : no_index(false) {}
|
||||
|
||||
bool operator==(const Header& other) const
|
||||
{
|
||||
bool operator==(const Header &other) const {
|
||||
return name == other.name && value == other.value;
|
||||
}
|
||||
|
||||
bool operator<(const Header& rhs) const
|
||||
{
|
||||
bool operator<(const Header &rhs) const {
|
||||
return name < rhs.name || (name == rhs.name && value < rhs.value);
|
||||
}
|
||||
|
||||
@ -70,18 +63,18 @@ namespace http2 {
|
||||
|
||||
std::string get_status_string(unsigned int status_code);
|
||||
|
||||
void capitalize(std::string& s, size_t offset);
|
||||
void capitalize(std::string &s, size_t offset);
|
||||
|
||||
// Returns true if |value| is LWS
|
||||
bool lws(const char *value);
|
||||
|
||||
void sanitize_header_value(std::string& s, size_t offset);
|
||||
void sanitize_header_value(std::string &s, size_t offset);
|
||||
|
||||
// Copies the |field| component value from |u| and |url| to the
|
||||
// |dest|. If |u| does not have |field|, then this function does
|
||||
// nothing.
|
||||
void copy_url_component(std::string& dest, const http_parser_url *u, int field,
|
||||
const char* url);
|
||||
void copy_url_component(std::string &dest, const http_parser_url *u, int field,
|
||||
const char *url);
|
||||
|
||||
// Returns true if the header field |name| with length |namelen| bytes
|
||||
// is valid for HTTP/2.
|
||||
@ -94,13 +87,13 @@ bool check_http2_allowed_header(const char *name);
|
||||
// Checks that headers |nva| do not contain disallowed header fields
|
||||
// in HTTP/2 spec. This function returns true if |nva| does not
|
||||
// contains such headers.
|
||||
bool check_http2_headers(const Headers& nva);
|
||||
bool check_http2_headers(const Headers &nva);
|
||||
|
||||
// Calls check_http2_headers()
|
||||
bool check_http2_request_headers(const Headers& nva);
|
||||
bool check_http2_request_headers(const Headers &nva);
|
||||
|
||||
// Calls check_http2_headers()
|
||||
bool check_http2_response_headers(const Headers& nva);
|
||||
bool check_http2_response_headers(const Headers &nva);
|
||||
|
||||
// Returns true if |name| is allowed pusedo header for request.
|
||||
bool check_http2_request_pseudo_header(const uint8_t *name, size_t namelen);
|
||||
@ -108,9 +101,9 @@ bool check_http2_request_pseudo_header(const uint8_t *name, size_t namelen);
|
||||
// Returns true if |name| is allowed pusedo header for response.
|
||||
bool check_http2_response_pseudo_header(const uint8_t *name, size_t namelen);
|
||||
|
||||
bool name_less(const Headers::value_type& lhs, const Headers::value_type& rhs);
|
||||
bool name_less(const Headers::value_type &lhs, const Headers::value_type &rhs);
|
||||
|
||||
void normalize_headers(Headers& nva);
|
||||
void normalize_headers(Headers &nva);
|
||||
|
||||
Headers::value_type to_header(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
@ -119,22 +112,20 @@ Headers::value_type to_header(const uint8_t *name, size_t namelen,
|
||||
// Add name/value pairs to |nva|. If |no_index| is true, this
|
||||
// name/value pair won't be indexed when it is forwarded to the next
|
||||
// hop.
|
||||
void add_header(Headers& nva,
|
||||
const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen,
|
||||
bool no_index);
|
||||
void add_header(Headers &nva, const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen, bool no_index);
|
||||
|
||||
// Returns the iterator to the entry in |nva| which has name |name|
|
||||
// and the |name| is uinque in the |nva|. If no such entry exist,
|
||||
// returns nullptr.
|
||||
const Headers::value_type* get_unique_header(const Headers& nva,
|
||||
const Headers::value_type *get_unique_header(const Headers &nva,
|
||||
const char *name);
|
||||
|
||||
// Returns the iterator to the entry in |nva| which has name
|
||||
// |name|. If more than one entries which have the name |name|, first
|
||||
// occurrence in |nva| is returned. If no such entry exist, returns
|
||||
// nullptr.
|
||||
const Headers::value_type* get_header(const Headers& nva, const char *name);
|
||||
const Headers::value_type *get_header(const Headers &nva, const char *name);
|
||||
|
||||
// Returns nv->second if nv is not nullptr. Otherwise, returns "".
|
||||
std::string value_to_str(const Headers::value_type *nv);
|
||||
@ -150,44 +141,42 @@ bool non_empty_value(const Headers::value_type *nv);
|
||||
// returned value only references the data pointer to name.c_str() and
|
||||
// value.c_str(). If |no_index| is true, nghttp2_nv flags member has
|
||||
// NGHTTP2_NV_FLAG_NO_INDEX flag set.
|
||||
nghttp2_nv make_nv(const std::string& name, const std::string& value,
|
||||
nghttp2_nv make_nv(const std::string &name, const std::string &value,
|
||||
bool no_index = false);
|
||||
|
||||
// Create nghttp2_nv from string literal |name| and |value|.
|
||||
template<size_t N, size_t M>
|
||||
nghttp2_nv make_nv_ll(const char(&name)[N], const char(&value)[M])
|
||||
{
|
||||
return {(uint8_t*)name, (uint8_t*)value, N - 1, M - 1, NGHTTP2_NV_FLAG_NONE};
|
||||
template <size_t N, size_t M>
|
||||
nghttp2_nv make_nv_ll(const char (&name)[N], const char (&value)[M]) {
|
||||
return {(uint8_t *)name, (uint8_t *)value, N - 1, M - 1,
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
}
|
||||
|
||||
// Create nghttp2_nv from string literal |name| and c-string |value|.
|
||||
template<size_t N>
|
||||
nghttp2_nv make_nv_lc(const char(&name)[N], const char *value)
|
||||
{
|
||||
return {(uint8_t*)name, (uint8_t*)value, N - 1, strlen(value),
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
template <size_t N>
|
||||
nghttp2_nv make_nv_lc(const char (&name)[N], const char *value) {
|
||||
return {(uint8_t *)name, (uint8_t *)value, N - 1, strlen(value),
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
}
|
||||
|
||||
// Create nghttp2_nv from string literal |name| and std::string
|
||||
// |value|.
|
||||
template<size_t N>
|
||||
nghttp2_nv make_nv_ls(const char(&name)[N], const std::string& value)
|
||||
{
|
||||
return {(uint8_t*)name, (uint8_t*)value.c_str(), N - 1, value.size(),
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
template <size_t N>
|
||||
nghttp2_nv make_nv_ls(const char (&name)[N], const std::string &value) {
|
||||
return {(uint8_t *)name, (uint8_t *)value.c_str(), N - 1, value.size(),
|
||||
NGHTTP2_NV_FLAG_NONE};
|
||||
}
|
||||
|
||||
// Appends headers in |headers| to |nv|. Certain headers, including
|
||||
// disallowed headers in HTTP/2 spec and headers which require
|
||||
// special handling (i.e. via), are not copied.
|
||||
void copy_norm_headers_to_nva
|
||||
(std::vector<nghttp2_nv>& nva, const Headers& headers);
|
||||
void copy_norm_headers_to_nva(std::vector<nghttp2_nv> &nva,
|
||||
const Headers &headers);
|
||||
|
||||
// Appends HTTP/1.1 style header lines to |hdrs| from headers in
|
||||
// |headers|. Certain headers, which requires special handling
|
||||
// (i.e. via and cookie), are not appended.
|
||||
void build_http1_headers_from_norm_headers
|
||||
(std::string& hdrs, const Headers& headers);
|
||||
void build_http1_headers_from_norm_headers(std::string &hdrs,
|
||||
const Headers &headers);
|
||||
|
||||
// Return positive window_size_increment if WINDOW_UPDATE should be
|
||||
// sent for the stream |stream_id|. If |stream_id| == 0, this function
|
||||
@ -206,7 +195,7 @@ void dump_nv(FILE *out, const char **nv);
|
||||
void dump_nv(FILE *out, const nghttp2_nv *nva, size_t nvlen);
|
||||
|
||||
// Dumps name/value pairs in |nva| to |out|.
|
||||
void dump_nv(FILE *out, const Headers& nva);
|
||||
void dump_nv(FILE *out, const Headers &nva);
|
||||
|
||||
// Rewrites redirection URI which usually appears in location header
|
||||
// field. The |uri| is the URI in the location header field. The |u|
|
||||
@ -218,20 +207,20 @@ void dump_nv(FILE *out, const Headers& nva);
|
||||
// This function returns the new rewritten URI on success. If the
|
||||
// location URI is not subject to the rewrite, this function returns
|
||||
// emtpy string.
|
||||
std::string rewrite_location_uri(const std::string& uri,
|
||||
const http_parser_url& u,
|
||||
const std::string& request_host,
|
||||
const std::string& upstream_scheme,
|
||||
std::string rewrite_location_uri(const std::string &uri,
|
||||
const http_parser_url &u,
|
||||
const std::string &request_host,
|
||||
const std::string &upstream_scheme,
|
||||
uint16_t upstream_port);
|
||||
|
||||
// Checks the header name/value pair using nghttp2_check_header_name()
|
||||
// and nghttp2_check_header_value(). If both function returns nonzero,
|
||||
// this function returns nonzero.
|
||||
int check_nv(const uint8_t *name, size_t namelen,
|
||||
const uint8_t *value, size_t valuelen);
|
||||
int check_nv(const uint8_t *name, size_t namelen, const uint8_t *value,
|
||||
size_t valuelen);
|
||||
|
||||
// Returns parsed HTTP status code. Returns -1 on failure.
|
||||
int parse_http_status_code(const std::string& src);
|
||||
int parse_http_status_code(const std::string &src);
|
||||
|
||||
} // namespace http2
|
||||
|
||||
|
@ -37,15 +37,16 @@
|
||||
|
||||
using namespace nghttp2;
|
||||
|
||||
#define MAKE_NV(K, V) {(uint8_t*)K, (uint8_t*)V, \
|
||||
sizeof(K) - 1, sizeof(V) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE}
|
||||
#define MAKE_NV(K, V) \
|
||||
{ \
|
||||
(uint8_t *) K, (uint8_t *)V, sizeof(K) - 1, sizeof(V) - 1, \
|
||||
NGHTTP2_NV_FLAG_NONE \
|
||||
}
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
namespace {
|
||||
void check_nv(const Header& a, const nghttp2_nv *b)
|
||||
{
|
||||
void check_nv(const Header &a, const nghttp2_nv *b) {
|
||||
CU_ASSERT(a.name.size() == b->namelen);
|
||||
CU_ASSERT(a.value.size() == b->valuelen);
|
||||
CU_ASSERT(memcmp(a.name.c_str(), b->name, b->namelen) == 0);
|
||||
@ -53,69 +54,52 @@ void check_nv(const Header& a, const nghttp2_nv *b)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void test_http2_add_header(void)
|
||||
{
|
||||
void test_http2_add_header(void) {
|
||||
auto nva = Headers();
|
||||
|
||||
http2::add_header(nva, (const uint8_t*)"alpha", 5,
|
||||
(const uint8_t*)"123", 3, false);
|
||||
http2::add_header(nva, (const uint8_t *)"alpha", 5, (const uint8_t *)"123", 3,
|
||||
false);
|
||||
CU_ASSERT(Headers::value_type("alpha", "123") == nva[0]);
|
||||
CU_ASSERT(!nva[0].no_index);
|
||||
|
||||
nva.clear();
|
||||
|
||||
http2::add_header(nva, (const uint8_t*)"alpha", 5,
|
||||
(const uint8_t*)"", 0, true);
|
||||
http2::add_header(nva, (const uint8_t *)"alpha", 5, (const uint8_t *)"", 0,
|
||||
true);
|
||||
CU_ASSERT(Headers::value_type("alpha", "") == nva[0]);
|
||||
CU_ASSERT(nva[0].no_index);
|
||||
}
|
||||
|
||||
void test_http2_check_http2_headers(void)
|
||||
{
|
||||
auto nva1 = Headers{
|
||||
{ "alpha", "1" },
|
||||
{ "bravo", "2" },
|
||||
{ "upgrade", "http2" }
|
||||
};
|
||||
void test_http2_check_http2_headers(void) {
|
||||
auto nva1 = Headers{{"alpha", "1"}, {"bravo", "2"}, {"upgrade", "http2"}};
|
||||
CU_ASSERT(!http2::check_http2_headers(nva1));
|
||||
|
||||
auto nva2 = Headers{
|
||||
{ "connection", "1" },
|
||||
{ "delta", "2" },
|
||||
{ "echo", "3" }
|
||||
};
|
||||
auto nva2 = Headers{{"connection", "1"}, {"delta", "2"}, {"echo", "3"}};
|
||||
CU_ASSERT(!http2::check_http2_headers(nva2));
|
||||
|
||||
auto nva3 = Headers{
|
||||
{ "alpha", "1" },
|
||||
{ "bravo", "2" },
|
||||
{ "te2", "3" }
|
||||
};
|
||||
auto nva3 = Headers{{"alpha", "1"}, {"bravo", "2"}, {"te2", "3"}};
|
||||
CU_ASSERT(http2::check_http2_headers(nva3));
|
||||
|
||||
auto n1 = ":authority";
|
||||
auto n1u8 = reinterpret_cast<const uint8_t*>(n1);
|
||||
auto n1u8 = reinterpret_cast<const uint8_t *>(n1);
|
||||
|
||||
CU_ASSERT(http2::check_http2_request_pseudo_header(n1u8, strlen(n1)));
|
||||
CU_ASSERT(!http2::check_http2_response_pseudo_header(n1u8, strlen(n1)));
|
||||
|
||||
auto n2 = ":status";
|
||||
auto n2u8 = reinterpret_cast<const uint8_t*>(n2);
|
||||
auto n2u8 = reinterpret_cast<const uint8_t *>(n2);
|
||||
|
||||
CU_ASSERT(!http2::check_http2_request_pseudo_header(n2u8, strlen(n2)));
|
||||
CU_ASSERT(http2::check_http2_response_pseudo_header(n2u8, strlen(n2)));
|
||||
}
|
||||
|
||||
void test_http2_get_unique_header(void)
|
||||
{
|
||||
auto nva = Headers{
|
||||
{ "alpha", "1" },
|
||||
{ "bravo", "2" },
|
||||
{ "bravo", "3" },
|
||||
{ "charlie", "4" },
|
||||
{ "delta", "5" },
|
||||
{ "echo", "6" }
|
||||
};
|
||||
void test_http2_get_unique_header(void) {
|
||||
auto nva = Headers{{"alpha", "1"},
|
||||
{"bravo", "2"},
|
||||
{"bravo", "3"},
|
||||
{"charlie", "4"},
|
||||
{"delta", "5"},
|
||||
{"echo", "6"}};
|
||||
const Headers::value_type *rv;
|
||||
rv = http2::get_unique_header(nva, "delta");
|
||||
CU_ASSERT(rv != nullptr);
|
||||
@ -128,16 +112,13 @@ void test_http2_get_unique_header(void)
|
||||
CU_ASSERT(rv == nullptr);
|
||||
}
|
||||
|
||||
void test_http2_get_header(void)
|
||||
{
|
||||
auto nva = Headers{
|
||||
{ "alpha", "1" },
|
||||
{ "bravo", "2" },
|
||||
{ "bravo", "3" },
|
||||
{ "charlie", "4" },
|
||||
{ "delta", "5" },
|
||||
{ "echo", "6" }
|
||||
};
|
||||
void test_http2_get_header(void) {
|
||||
auto nva = Headers{{"alpha", "1"},
|
||||
{"bravo", "2"},
|
||||
{"bravo", "3"},
|
||||
{"charlie", "4"},
|
||||
{"delta", "5"},
|
||||
{"echo", "6"}};
|
||||
const Headers::value_type *rv;
|
||||
rv = http2::get_header(nva, "delta");
|
||||
CU_ASSERT(rv != nullptr);
|
||||
@ -151,15 +132,9 @@ void test_http2_get_header(void)
|
||||
CU_ASSERT(rv == nullptr);
|
||||
}
|
||||
|
||||
void test_http2_value_lws(void)
|
||||
{
|
||||
void test_http2_value_lws(void) {
|
||||
auto nva = Headers{
|
||||
{ "0", "alpha" },
|
||||
{ "1", " alpha" },
|
||||
{ "2", "" },
|
||||
{" 3", " " },
|
||||
{" 4", " a "}
|
||||
};
|
||||
{"0", "alpha"}, {"1", " alpha"}, {"2", ""}, {" 3", " "}, {" 4", " a "}};
|
||||
CU_ASSERT(!http2::value_lws(&nva[0]));
|
||||
CU_ASSERT(!http2::value_lws(&nva[1]));
|
||||
CU_ASSERT(http2::value_lws(&nva[2]));
|
||||
@ -168,32 +143,30 @@ void test_http2_value_lws(void)
|
||||
}
|
||||
|
||||
namespace {
|
||||
auto headers = Headers
|
||||
{{"alpha", "0", true},
|
||||
{"bravo", "1"},
|
||||
{"connection", "2"},
|
||||
{"connection", "3"},
|
||||
{"delta", "4"},
|
||||
{"expect", "5"},
|
||||
{"foxtrot", "6"},
|
||||
{"tango", "7"},
|
||||
{"te", "8"},
|
||||
{"te", "9"},
|
||||
{"x-forwarded-proto", "10"},
|
||||
{"x-forwarded-proto", "11"},
|
||||
{"zulu", "12"}};
|
||||
auto headers = Headers{{"alpha", "0", true},
|
||||
{"bravo", "1"},
|
||||
{"connection", "2"},
|
||||
{"connection", "3"},
|
||||
{"delta", "4"},
|
||||
{"expect", "5"},
|
||||
{"foxtrot", "6"},
|
||||
{"tango", "7"},
|
||||
{"te", "8"},
|
||||
{"te", "9"},
|
||||
{"x-forwarded-proto", "10"},
|
||||
{"x-forwarded-proto", "11"},
|
||||
{"zulu", "12"}};
|
||||
} // namespace
|
||||
|
||||
void test_http2_copy_norm_headers_to_nva(void)
|
||||
{
|
||||
void test_http2_copy_norm_headers_to_nva(void) {
|
||||
std::vector<nghttp2_nv> nva;
|
||||
http2::copy_norm_headers_to_nva(nva, headers);
|
||||
CU_ASSERT(7 == nva.size());
|
||||
auto ans = std::vector<int>{0, 1, 4, 5, 6, 7, 12};
|
||||
for(size_t i = 0; i < ans.size(); ++i) {
|
||||
for (size_t i = 0; i < ans.size(); ++i) {
|
||||
check_nv(headers[ans[i]], &nva[i]);
|
||||
|
||||
if(ans[i] == 0) {
|
||||
if (ans[i] == 0) {
|
||||
CU_ASSERT(nva[i].flags & NGHTTP2_NV_FLAG_NO_INDEX);
|
||||
} else {
|
||||
CU_ASSERT(NGHTTP2_NV_FLAG_NONE == nva[i].flags);
|
||||
@ -201,20 +174,18 @@ void test_http2_copy_norm_headers_to_nva(void)
|
||||
}
|
||||
}
|
||||
|
||||
void test_http2_build_http1_headers_from_norm_headers(void)
|
||||
{
|
||||
void test_http2_build_http1_headers_from_norm_headers(void) {
|
||||
std::string hdrs;
|
||||
http2::build_http1_headers_from_norm_headers(hdrs, headers);
|
||||
CU_ASSERT(hdrs ==
|
||||
"Alpha: 0\r\n"
|
||||
"Bravo: 1\r\n"
|
||||
"Delta: 4\r\n"
|
||||
"Expect: 5\r\n"
|
||||
"Foxtrot: 6\r\n"
|
||||
"Tango: 7\r\n"
|
||||
"Te: 8\r\n"
|
||||
"Te: 9\r\n"
|
||||
"Zulu: 12\r\n");
|
||||
CU_ASSERT(hdrs == "Alpha: 0\r\n"
|
||||
"Bravo: 1\r\n"
|
||||
"Delta: 4\r\n"
|
||||
"Expect: 5\r\n"
|
||||
"Foxtrot: 6\r\n"
|
||||
"Tango: 7\r\n"
|
||||
"Te: 8\r\n"
|
||||
"Te: 9\r\n"
|
||||
"Zulu: 12\r\n");
|
||||
|
||||
hdrs.clear();
|
||||
// Both nghttp2 and spdylay do not allow \r and \n in header value
|
||||
@ -226,62 +197,50 @@ void test_http2_build_http1_headers_from_norm_headers(void)
|
||||
// CU_ASSERT(hdrs == "Alpha: bravo charlie \r\n");
|
||||
}
|
||||
|
||||
void test_http2_lws(void)
|
||||
{
|
||||
void test_http2_lws(void) {
|
||||
CU_ASSERT(!http2::lws("alpha"));
|
||||
CU_ASSERT(http2::lws(" "));
|
||||
CU_ASSERT(http2::lws(""));
|
||||
}
|
||||
|
||||
namespace {
|
||||
void check_rewrite_location_uri(const std::string& new_uri,
|
||||
const std::string& uri,
|
||||
const std::string& req_host,
|
||||
const std::string& upstream_scheme,
|
||||
uint16_t upstream_port)
|
||||
{
|
||||
void check_rewrite_location_uri(const std::string &new_uri,
|
||||
const std::string &uri,
|
||||
const std::string &req_host,
|
||||
const std::string &upstream_scheme,
|
||||
uint16_t upstream_port) {
|
||||
http_parser_url u;
|
||||
memset(&u, 0, sizeof(u));
|
||||
CU_ASSERT(0 == http_parser_parse_url(uri.c_str(), uri.size(), 0, &u));
|
||||
CU_ASSERT(new_uri ==
|
||||
http2::rewrite_location_uri(uri, u, req_host,
|
||||
upstream_scheme, upstream_port));
|
||||
CU_ASSERT(new_uri == http2::rewrite_location_uri(
|
||||
uri, u, req_host, upstream_scheme, upstream_port));
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void test_http2_rewrite_location_uri(void)
|
||||
{
|
||||
void test_http2_rewrite_location_uri(void) {
|
||||
check_rewrite_location_uri("https://localhost:3000/alpha?bravo#charlie",
|
||||
"http://localhost:3001/alpha?bravo#charlie",
|
||||
"localhost:3001", "https", 3000);
|
||||
check_rewrite_location_uri("https://localhost/",
|
||||
"http://localhost:3001/",
|
||||
check_rewrite_location_uri("https://localhost/", "http://localhost:3001/",
|
||||
"localhost:3001", "https", 443);
|
||||
check_rewrite_location_uri("http://localhost/",
|
||||
"http://localhost:3001/",
|
||||
check_rewrite_location_uri("http://localhost/", "http://localhost:3001/",
|
||||
"localhost:3001", "http", 80);
|
||||
check_rewrite_location_uri("http://localhost:443/",
|
||||
"http://localhost:3001/",
|
||||
check_rewrite_location_uri("http://localhost:443/", "http://localhost:3001/",
|
||||
"localhost:3001", "http", 443);
|
||||
check_rewrite_location_uri("https://localhost:80/",
|
||||
"http://localhost:3001/",
|
||||
check_rewrite_location_uri("https://localhost:80/", "http://localhost:3001/",
|
||||
"localhost:3001", "https", 80);
|
||||
check_rewrite_location_uri("",
|
||||
"http://localhost:3001/",
|
||||
"127.0.0.1", "https", 3000);
|
||||
check_rewrite_location_uri("", "http://localhost:3001/", "127.0.0.1", "https",
|
||||
3000);
|
||||
check_rewrite_location_uri("https://localhost:3000/",
|
||||
"http://localhost:3001/",
|
||||
"localhost", "https", 3000);
|
||||
check_rewrite_location_uri("",
|
||||
"https://localhost:3001/",
|
||||
"localhost", "https", 3000);
|
||||
check_rewrite_location_uri("https://localhost:3000/",
|
||||
"http://localhost/",
|
||||
"http://localhost:3001/", "localhost", "https",
|
||||
3000);
|
||||
check_rewrite_location_uri("", "https://localhost:3001/", "localhost",
|
||||
"https", 3000);
|
||||
check_rewrite_location_uri("https://localhost:3000/", "http://localhost/",
|
||||
"localhost", "https", 3000);
|
||||
}
|
||||
|
||||
void test_http2_parse_http_status_code(void)
|
||||
{
|
||||
void test_http2_parse_http_status_code(void) {
|
||||
CU_ASSERT(200 == http2::parse_http_status_code("200"));
|
||||
CU_ASSERT(102 == http2::parse_http_status_code("102"));
|
||||
CU_ASSERT(-1 == http2::parse_http_status_code("099"));
|
||||
|
@ -40,7 +40,7 @@ struct header {
|
||||
std::string value;
|
||||
};
|
||||
|
||||
typedef std::function<void(const uint8_t*, std::size_t)> data_cb;
|
||||
typedef std::function<void(const uint8_t *, std::size_t)> data_cb;
|
||||
typedef std::function<void(void)> void_cb;
|
||||
|
||||
// Callback function to generate response body. The implementation of
|
||||
@ -53,8 +53,8 @@ typedef std::function<void(void)> void_cb;
|
||||
// callback until application calls response::resume(). This is
|
||||
// useful when there is no data to send at the moment but there will
|
||||
// be more to come in near future.
|
||||
typedef std::function<std::pair<ssize_t, bool>
|
||||
(uint8_t *buf, std::size_t len)> read_cb;
|
||||
typedef std::function<std::pair<ssize_t, bool>(uint8_t *buf, std::size_t len)>
|
||||
read_cb;
|
||||
|
||||
class channel_impl;
|
||||
|
||||
@ -71,12 +71,13 @@ public:
|
||||
void post(void_cb cb);
|
||||
|
||||
// Application must not call this directly.
|
||||
channel_impl& impl();
|
||||
channel_impl &impl();
|
||||
|
||||
private:
|
||||
std::unique_ptr<channel_impl> impl_;
|
||||
};
|
||||
|
||||
typedef std::function<void(channel&)> thread_cb;
|
||||
typedef std::function<void(channel &)> thread_cb;
|
||||
|
||||
namespace server {
|
||||
|
||||
@ -90,25 +91,25 @@ public:
|
||||
|
||||
// Returns request headers. The pusedo headers, which start with
|
||||
// colon (;), are exluced from this list.
|
||||
const std::vector<header>& headers() const;
|
||||
const std::vector<header> &headers() const;
|
||||
|
||||
// Returns method (e.g., GET).
|
||||
const std::string& method() const;
|
||||
const std::string &method() const;
|
||||
|
||||
// Returns scheme (e.g., https).
|
||||
const std::string& scheme() const;
|
||||
const std::string &scheme() const;
|
||||
|
||||
// Returns authority (e.g., example.org). This could be empty
|
||||
// string. In this case, check host().
|
||||
|
||||
const std::string& authority() const;
|
||||
const std::string &authority() const;
|
||||
// Returns host (e.g., example.org). If host header field is not
|
||||
// present, this value is copied from authority().
|
||||
|
||||
const std::string& host() const;
|
||||
const std::string &host() const;
|
||||
|
||||
// Returns path (e.g., /index.html).
|
||||
const std::string& path() const;
|
||||
const std::string &path() const;
|
||||
|
||||
// Sets callback when chunk of request body is received.
|
||||
void on_data(data_cb cb);
|
||||
@ -141,7 +142,8 @@ public:
|
||||
bool run_task(thread_cb start);
|
||||
|
||||
// Application must not call this directly.
|
||||
request_impl& impl();
|
||||
request_impl &impl();
|
||||
|
||||
private:
|
||||
std::unique_ptr<request_impl> impl_;
|
||||
};
|
||||
@ -173,15 +175,16 @@ public:
|
||||
bool started() const;
|
||||
|
||||
// Application must not call this directly.
|
||||
response_impl& impl();
|
||||
response_impl &impl();
|
||||
|
||||
private:
|
||||
std::unique_ptr<response_impl> impl_;
|
||||
};
|
||||
|
||||
// This is so called request callback. Called every time request is
|
||||
// received.
|
||||
typedef std::function<void(const std::shared_ptr<request>&,
|
||||
const std::shared_ptr<response>&)> request_cb;
|
||||
typedef std::function<void(const std::shared_ptr<request> &,
|
||||
const std::shared_ptr<response> &)> request_cb;
|
||||
|
||||
class http2_impl;
|
||||
|
||||
@ -192,8 +195,7 @@ public:
|
||||
|
||||
// Starts listening connection on given address and port. The
|
||||
// incoming requests are handled by given callback |cb|.
|
||||
void listen(const std::string& address, uint16_t port,
|
||||
request_cb cb);
|
||||
void listen(const std::string &address, uint16_t port, request_cb cb);
|
||||
|
||||
// Sets number of native threads to handle incoming HTTP request.
|
||||
// It defaults to 1.
|
||||
@ -212,6 +214,7 @@ public:
|
||||
// Sets the maximum length to which the queue of pending
|
||||
// connections.
|
||||
void backlog(int backlog);
|
||||
|
||||
private:
|
||||
std::unique_ptr<http2_impl> impl_;
|
||||
};
|
||||
@ -220,7 +223,7 @@ private:
|
||||
|
||||
// Convenient function to create function to read file denoted by
|
||||
// |path|. This can be passed to response::end().
|
||||
read_cb file_reader(const std::string& path);
|
||||
read_cb file_reader(const std::string &path);
|
||||
|
||||
// Like file_reader(const std::string&), but it takes opened file
|
||||
// descriptor. The passed descriptor will be closed when returned
|
||||
@ -231,10 +234,10 @@ read_cb file_reader_from_fd(int fd);
|
||||
// vector. Returns true if path is safe. The |path| must start with
|
||||
// "/" otherwise returns false. This function should be called after
|
||||
// percent-decode was performed.
|
||||
bool check_path(const std::string& path);
|
||||
bool check_path(const std::string &path);
|
||||
|
||||
// Performs percent-decode against string |s|.
|
||||
std::string percent_decode(const std::string& s);
|
||||
std::string percent_decode(const std::string &s);
|
||||
|
||||
// Returns HTTP date representation of current posix time |t|.
|
||||
std::string http_date(int64_t t);
|
||||
|
@ -23,7 +23,7 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <unistd.h>
|
||||
@ -45,57 +45,48 @@ extern "C" {
|
||||
#include "nghttp2_frame.h"
|
||||
|
||||
#include "comp_helper.h"
|
||||
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
int dump_header_table;
|
||||
} inflate_config;
|
||||
typedef struct { int dump_header_table; } inflate_config;
|
||||
|
||||
static inflate_config config;
|
||||
|
||||
static uint8_t to_ud(char c)
|
||||
{
|
||||
if(c >= 'A' && c <= 'Z') {
|
||||
static uint8_t to_ud(char c) {
|
||||
if (c >= 'A' && c <= 'Z') {
|
||||
return c - 'A' + 10;
|
||||
} else if(c >= 'a' && c <= 'z') {
|
||||
} else if (c >= 'a' && c <= 'z') {
|
||||
return c - 'a' + 10;
|
||||
} else {
|
||||
return c - '0';
|
||||
}
|
||||
}
|
||||
|
||||
static void decode_hex(uint8_t *dest, const char *src, size_t len)
|
||||
{
|
||||
static void decode_hex(uint8_t *dest, const char *src, size_t len) {
|
||||
size_t i;
|
||||
for(i = 0; i < len; i += 2) {
|
||||
for (i = 0; i < len; i += 2) {
|
||||
*dest++ = to_ud(src[i]) << 4 | to_ud(src[i + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
static void to_json(nghttp2_hd_inflater *inflater,
|
||||
json_t *headers, json_t *wire, int seq,
|
||||
size_t old_settings_table_size)
|
||||
{
|
||||
static void to_json(nghttp2_hd_inflater *inflater, json_t *headers,
|
||||
json_t *wire, int seq, size_t old_settings_table_size) {
|
||||
auto obj = json_object();
|
||||
json_object_set_new(obj, "seq", json_integer(seq));
|
||||
json_object_set(obj, "wire", wire);
|
||||
json_object_set(obj, "headers", headers);
|
||||
if(old_settings_table_size != inflater->settings_hd_table_bufsize_max) {
|
||||
if (old_settings_table_size != inflater->settings_hd_table_bufsize_max) {
|
||||
json_object_set_new(obj, "header_table_size",
|
||||
json_integer(inflater->settings_hd_table_bufsize_max));
|
||||
}
|
||||
if(config.dump_header_table) {
|
||||
json_object_set_new(obj, "header_table",
|
||||
dump_header_table(&inflater->ctx));
|
||||
if (config.dump_header_table) {
|
||||
json_object_set_new(obj, "header_table", dump_header_table(&inflater->ctx));
|
||||
}
|
||||
json_dumpf(obj, stdout, JSON_INDENT(2) | JSON_PRESERVE_ORDER);
|
||||
json_decref(obj);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
||||
{
|
||||
static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq) {
|
||||
ssize_t rv;
|
||||
nghttp2_nv nv;
|
||||
int inflate_flags;
|
||||
@ -103,15 +94,15 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
||||
|
||||
auto wire = json_object_get(obj, "wire");
|
||||
|
||||
if(wire == nullptr) {
|
||||
if (wire == nullptr) {
|
||||
fprintf(stderr, "'wire' key is missing at %d\n", seq);
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto table_size = json_object_get(obj, "header_table_size");
|
||||
|
||||
if(table_size) {
|
||||
if(!json_is_integer(table_size)) {
|
||||
if (table_size) {
|
||||
if (!json_is_integer(table_size)) {
|
||||
fprintf(stderr,
|
||||
"The value of 'header_table_size key' is not integer at %d\n",
|
||||
seq);
|
||||
@ -119,7 +110,7 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
||||
}
|
||||
rv = nghttp2_hd_inflate_change_table_size(inflater,
|
||||
json_integer_value(table_size));
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
fprintf(stderr,
|
||||
"nghttp2_hd_change_table_size() failed with error %s at %d\n",
|
||||
nghttp2_strerror(rv), seq);
|
||||
@ -129,7 +120,7 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
||||
|
||||
auto inputlen = strlen(json_string_value(wire));
|
||||
|
||||
if(inputlen & 1) {
|
||||
if (inputlen & 1) {
|
||||
fprintf(stderr, "Badly formatted output value at %d\n", seq);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -142,20 +133,20 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
||||
auto headers = json_array();
|
||||
|
||||
auto p = buf.data();
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
inflate_flags = 0;
|
||||
rv = nghttp2_hd_inflate_hd(inflater, &nv, &inflate_flags, p, buflen, 1);
|
||||
if(rv < 0) {
|
||||
if (rv < 0) {
|
||||
fprintf(stderr, "inflate failed with error code %zd at %d\n", rv, seq);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
p += rv;
|
||||
buflen -= rv;
|
||||
if(inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
|
||||
json_array_append_new(headers, dump_header(nv.name, nv.namelen,
|
||||
nv.value, nv.valuelen));
|
||||
if (inflate_flags & NGHTTP2_HD_INFLATE_EMIT) {
|
||||
json_array_append_new(
|
||||
headers, dump_header(nv.name, nv.namelen, nv.value, nv.valuelen));
|
||||
}
|
||||
if(inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
|
||||
if (inflate_flags & NGHTTP2_HD_INFLATE_FINAL) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -167,26 +158,25 @@ static int inflate_hd(json_t *obj, nghttp2_hd_inflater *inflater, int seq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int perform(void)
|
||||
{
|
||||
static int perform(void) {
|
||||
nghttp2_hd_inflater inflater;
|
||||
json_error_t error;
|
||||
|
||||
auto json = json_loadf(stdin, 0, &error);
|
||||
|
||||
if(json == nullptr) {
|
||||
if (json == nullptr) {
|
||||
fprintf(stderr, "JSON loading failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
auto cases = json_object_get(json, "cases");
|
||||
|
||||
if(cases == nullptr) {
|
||||
if (cases == nullptr) {
|
||||
fprintf(stderr, "Missing 'cases' key in root object\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(!json_is_array(cases)) {
|
||||
if (!json_is_array(cases)) {
|
||||
fprintf(stderr, "'cases' must be JSON array\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -195,17 +185,16 @@ static int perform(void)
|
||||
output_json_header();
|
||||
auto len = json_array_size(cases);
|
||||
|
||||
for(size_t i = 0; i < len; ++i) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
auto obj = json_array_get(cases, i);
|
||||
if(!json_is_object(obj)) {
|
||||
fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n",
|
||||
i);
|
||||
if (!json_is_object(obj)) {
|
||||
fprintf(stderr, "Unexpected JSON type at %zu. It should be object.\n", i);
|
||||
continue;
|
||||
}
|
||||
if(inflate_hd(obj, &inflater, i) != 0) {
|
||||
if (inflate_hd(obj, &inflater, i) != 0) {
|
||||
continue;
|
||||
}
|
||||
if(i + 1 < len) {
|
||||
if (i + 1 < len) {
|
||||
printf(",\n");
|
||||
}
|
||||
}
|
||||
@ -216,8 +205,7 @@ static int perform(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void print_help(void)
|
||||
{
|
||||
static void print_help(void) {
|
||||
std::cout << R"(HPACK HTTP/2 header decoder
|
||||
Usage: inflatehd [OPTIONS] < INPUT
|
||||
|
||||
@ -248,25 +236,22 @@ The output of this program can be used as input for deflatehd.
|
||||
|
||||
OPTIONS:
|
||||
-d, --dump-header-table
|
||||
Output dynamic header table.)"
|
||||
<< std::endl;;
|
||||
Output dynamic header table.)" << std::endl;
|
||||
;
|
||||
}
|
||||
|
||||
static struct option long_options[] = {
|
||||
{"dump-header-table", no_argument, nullptr, 'd'},
|
||||
{nullptr, 0, nullptr, 0 }
|
||||
};
|
||||
{"dump-header-table", no_argument, nullptr, 'd'}, {nullptr, 0, nullptr, 0}};
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
config.dump_header_table = 0;
|
||||
while(1) {
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "dh", long_options, &option_index);
|
||||
if(c == -1) {
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
switch(c) {
|
||||
switch (c) {
|
||||
case 'h':
|
||||
print_help();
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -32,32 +32,19 @@ namespace nghttp2 {
|
||||
namespace util {
|
||||
|
||||
EvbufferBuffer::EvbufferBuffer()
|
||||
: evbuffer_(nullptr),
|
||||
bucket_(nullptr),
|
||||
buf_(nullptr),
|
||||
bufmax_(0),
|
||||
buflen_(0),
|
||||
limit_(0),
|
||||
writelen_(0)
|
||||
{}
|
||||
: evbuffer_(nullptr), bucket_(nullptr), buf_(nullptr), bufmax_(0),
|
||||
buflen_(0), limit_(0), writelen_(0) {}
|
||||
|
||||
EvbufferBuffer::EvbufferBuffer(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
|
||||
ssize_t limit)
|
||||
: evbuffer_(evbuffer),
|
||||
bucket_(limit == -1 ? nullptr : evbuffer_new()),
|
||||
buf_(buf),
|
||||
bufmax_(bufmax),
|
||||
buflen_(0),
|
||||
limit_(limit),
|
||||
writelen_(0)
|
||||
{}
|
||||
: evbuffer_(evbuffer), bucket_(limit == -1 ? nullptr : evbuffer_new()),
|
||||
buf_(buf), bufmax_(bufmax), buflen_(0), limit_(limit), writelen_(0) {}
|
||||
|
||||
void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
|
||||
ssize_t limit)
|
||||
{
|
||||
ssize_t limit) {
|
||||
evbuffer_ = evbuffer;
|
||||
buf_ = buf;
|
||||
if(limit != -1 && !bucket_) {
|
||||
if (limit != -1 && !bucket_) {
|
||||
bucket_ = evbuffer_new();
|
||||
}
|
||||
bufmax_ = bufmax;
|
||||
@ -66,25 +53,23 @@ void EvbufferBuffer::reset(evbuffer *evbuffer, uint8_t *buf, size_t bufmax,
|
||||
writelen_ = 0;
|
||||
}
|
||||
|
||||
EvbufferBuffer::~EvbufferBuffer()
|
||||
{
|
||||
if(bucket_) {
|
||||
EvbufferBuffer::~EvbufferBuffer() {
|
||||
if (bucket_) {
|
||||
evbuffer_free(bucket_);
|
||||
}
|
||||
}
|
||||
|
||||
int EvbufferBuffer::write_buffer()
|
||||
{
|
||||
for(auto pos = buf_, end = buf_ + buflen_; pos < end;) {
|
||||
int EvbufferBuffer::write_buffer() {
|
||||
for (auto pos = buf_, end = buf_ + buflen_; pos < end;) {
|
||||
// To avoid merging chunks in evbuffer, we first add to temporal
|
||||
// buffer bucket_ and then move its chain to evbuffer_.
|
||||
auto nwrite = std::min(end - pos, limit_);
|
||||
auto rv = evbuffer_add(bucket_, pos, nwrite);
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
return -1;
|
||||
}
|
||||
rv = evbuffer_add_buffer(evbuffer_, bucket_);
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
return -1;
|
||||
}
|
||||
pos += nwrite;
|
||||
@ -92,16 +77,15 @@ int EvbufferBuffer::write_buffer()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EvbufferBuffer::flush()
|
||||
{
|
||||
int EvbufferBuffer::flush() {
|
||||
int rv;
|
||||
if(buflen_ > 0) {
|
||||
if(limit_ == -1) {
|
||||
if (buflen_ > 0) {
|
||||
if (limit_ == -1) {
|
||||
rv = evbuffer_add(evbuffer_, buf_, buflen_);
|
||||
} else {
|
||||
rv = write_buffer();
|
||||
}
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
return -1;
|
||||
}
|
||||
writelen_ += buflen_;
|
||||
@ -110,29 +94,28 @@ int EvbufferBuffer::flush()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EvbufferBuffer::add(const uint8_t *data, size_t datalen)
|
||||
{
|
||||
int EvbufferBuffer::add(const uint8_t *data, size_t datalen) {
|
||||
int rv;
|
||||
if(buflen_ + datalen > bufmax_) {
|
||||
if(buflen_ > 0) {
|
||||
if(limit_ == -1) {
|
||||
if (buflen_ + datalen > bufmax_) {
|
||||
if (buflen_ > 0) {
|
||||
if (limit_ == -1) {
|
||||
rv = evbuffer_add(evbuffer_, buf_, buflen_);
|
||||
} else {
|
||||
rv = write_buffer();
|
||||
}
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
return -1;
|
||||
}
|
||||
writelen_ += buflen_;
|
||||
buflen_ = 0;
|
||||
}
|
||||
if(datalen > bufmax_) {
|
||||
if(limit_ == -1) {
|
||||
if (datalen > bufmax_) {
|
||||
if (limit_ == -1) {
|
||||
rv = evbuffer_add(evbuffer_, data, datalen);
|
||||
} else {
|
||||
rv = write_buffer();
|
||||
}
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
return -1;
|
||||
}
|
||||
writelen_ += buflen_;
|
||||
@ -144,28 +127,20 @@ int EvbufferBuffer::add(const uint8_t *data, size_t datalen)
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t EvbufferBuffer::get_buflen() const
|
||||
{
|
||||
return buflen_;
|
||||
}
|
||||
size_t EvbufferBuffer::get_buflen() const { return buflen_; }
|
||||
|
||||
size_t EvbufferBuffer::get_writelen() const
|
||||
{
|
||||
return writelen_;
|
||||
}
|
||||
size_t EvbufferBuffer::get_writelen() const { return writelen_; }
|
||||
|
||||
void bev_enable_unless(bufferevent *bev, int events)
|
||||
{
|
||||
if((bufferevent_get_enabled(bev) & events) == events) {
|
||||
void bev_enable_unless(bufferevent *bev, int events) {
|
||||
if ((bufferevent_get_enabled(bev) & events) == events) {
|
||||
return;
|
||||
}
|
||||
|
||||
bufferevent_enable(bev, events);
|
||||
}
|
||||
|
||||
void bev_disable_unless(bufferevent *bev, int events)
|
||||
{
|
||||
if((bufferevent_get_enabled(bev) & events) == 0) {
|
||||
void bev_disable_unless(bufferevent *bev, int events) {
|
||||
if ((bufferevent_get_enabled(bev) & events) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,7 @@ public:
|
||||
// Returns the number of written bytes to evbuffer_ so far. reset()
|
||||
// resets this value to 0.
|
||||
size_t get_writelen() const;
|
||||
|
||||
private:
|
||||
evbuffer *evbuffer_;
|
||||
evbuffer *bucket_;
|
||||
|
1310
src/nghttp.cc
1310
src/nghttp.cc
File diff suppressed because it is too large
Load Diff
@ -26,13 +26,13 @@
|
||||
#define NGHTTP2_CONFIG_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
// gcc 4.6 has std::chrono::monotonic_clock, which was renamed as
|
||||
// std::chrono::steady_clock in C++11 standard.
|
||||
#ifndef HAVE_STEADY_CLOCK
|
||||
# define steady_clock monotonic_clock
|
||||
#define steady_clock monotonic_clock
|
||||
#endif // !HAVE_STEADY_CLOCK
|
||||
|
||||
#endif // NGHTTP2_CONFIG_H
|
||||
|
@ -26,11 +26,10 @@
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
int nghttp2_gzip_inflate_new(nghttp2_gzip **inflater_ptr)
|
||||
{
|
||||
int nghttp2_gzip_inflate_new(nghttp2_gzip **inflater_ptr) {
|
||||
int rv;
|
||||
*inflater_ptr = malloc(sizeof(nghttp2_gzip));
|
||||
if(*inflater_ptr == NULL) {
|
||||
if (*inflater_ptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
(*inflater_ptr)->finished = 0;
|
||||
@ -40,31 +39,29 @@ int nghttp2_gzip_inflate_new(nghttp2_gzip **inflater_ptr)
|
||||
(*inflater_ptr)->zst.zfree = Z_NULL;
|
||||
(*inflater_ptr)->zst.opaque = Z_NULL;
|
||||
rv = inflateInit2(&(*inflater_ptr)->zst, 47);
|
||||
if(rv != Z_OK) {
|
||||
if (rv != Z_OK) {
|
||||
free(*inflater_ptr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void nghttp2_gzip_inflate_del(nghttp2_gzip *inflater)
|
||||
{
|
||||
if(inflater != NULL) {
|
||||
void nghttp2_gzip_inflate_del(nghttp2_gzip *inflater) {
|
||||
if (inflater != NULL) {
|
||||
inflateEnd(&inflater->zst);
|
||||
free(inflater);
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_gzip_inflate(nghttp2_gzip *inflater,
|
||||
uint8_t *out, size_t *outlen_ptr,
|
||||
const uint8_t *in, size_t *inlen_ptr)
|
||||
{
|
||||
int nghttp2_gzip_inflate(nghttp2_gzip *inflater, uint8_t *out,
|
||||
size_t *outlen_ptr, const uint8_t *in,
|
||||
size_t *inlen_ptr) {
|
||||
int rv;
|
||||
if(inflater->finished) {
|
||||
if (inflater->finished) {
|
||||
return -1;
|
||||
}
|
||||
inflater->zst.avail_in = (unsigned int)*inlen_ptr;
|
||||
inflater->zst.next_in = (unsigned char*)in;
|
||||
inflater->zst.next_in = (unsigned char *)in;
|
||||
inflater->zst.avail_out = (unsigned int)*outlen_ptr;
|
||||
inflater->zst.next_out = out;
|
||||
|
||||
@ -72,7 +69,7 @@ int nghttp2_gzip_inflate(nghttp2_gzip *inflater,
|
||||
|
||||
*inlen_ptr -= inflater->zst.avail_in;
|
||||
*outlen_ptr -= inflater->zst.avail_out;
|
||||
switch(rv) {
|
||||
switch (rv) {
|
||||
case Z_STREAM_END:
|
||||
inflater->finished = 1;
|
||||
case Z_OK:
|
||||
@ -90,7 +87,6 @@ int nghttp2_gzip_inflate(nghttp2_gzip *inflater,
|
||||
}
|
||||
}
|
||||
|
||||
int nghttp2_gzip_inflate_finished(nghttp2_gzip *inflater)
|
||||
{
|
||||
int nghttp2_gzip_inflate_finished(nghttp2_gzip *inflater) {
|
||||
return inflater->finished;
|
||||
}
|
||||
|
@ -25,13 +25,13 @@
|
||||
#ifndef NGHTTP2_GZIP_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
#include <zlib.h>
|
||||
|
||||
#include <nghttp2/nghttp2.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
@ -102,9 +102,9 @@ void nghttp2_gzip_inflate_del(nghttp2_gzip *inflater);
|
||||
* ....
|
||||
* }
|
||||
*/
|
||||
int nghttp2_gzip_inflate(nghttp2_gzip *inflater,
|
||||
uint8_t *out, size_t *outlen_ptr,
|
||||
const uint8_t *in, size_t *inlen_ptr);
|
||||
int nghttp2_gzip_inflate(nghttp2_gzip *inflater, uint8_t *out,
|
||||
size_t *outlen_ptr, const uint8_t *in,
|
||||
size_t *inlen_ptr);
|
||||
|
||||
/**
|
||||
* @function
|
||||
|
@ -33,9 +33,8 @@
|
||||
|
||||
#include "nghttp2_gzip.h"
|
||||
|
||||
static ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
const uint8_t *in, size_t inlen)
|
||||
{
|
||||
static ssize_t deflate_data(uint8_t *out, size_t outlen, const uint8_t *in,
|
||||
size_t inlen) {
|
||||
int rv;
|
||||
z_stream zst;
|
||||
zst.next_in = Z_NULL;
|
||||
@ -47,7 +46,7 @@ static ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
assert(rv == Z_OK);
|
||||
|
||||
zst.avail_in = (unsigned int)inlen;
|
||||
zst.next_in = (uint8_t*)in;
|
||||
zst.next_in = (uint8_t *)in;
|
||||
zst.avail_out = (unsigned int)outlen;
|
||||
zst.next_out = out;
|
||||
rv = deflate(&zst, Z_SYNC_FLUSH);
|
||||
@ -55,35 +54,34 @@ static ssize_t deflate_data(uint8_t *out, size_t outlen,
|
||||
|
||||
deflateEnd(&zst);
|
||||
|
||||
return outlen-zst.avail_out;
|
||||
return outlen - zst.avail_out;
|
||||
}
|
||||
|
||||
static const char input[] =
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND "
|
||||
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
|
||||
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND "
|
||||
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE "
|
||||
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION "
|
||||
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION "
|
||||
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.";
|
||||
"THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND "
|
||||
"EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF "
|
||||
"MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND "
|
||||
"NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE "
|
||||
"LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION "
|
||||
"OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION "
|
||||
"WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.";
|
||||
|
||||
void test_nghttp2_gzip_inflate(void)
|
||||
{
|
||||
void test_nghttp2_gzip_inflate(void) {
|
||||
nghttp2_gzip *inflater;
|
||||
uint8_t in[4096], out[4096], *inptr;
|
||||
size_t inlen = sizeof(in);
|
||||
size_t inproclen, outproclen;
|
||||
const char *inputptr = input;
|
||||
|
||||
inlen = deflate_data(in, inlen, (const uint8_t*)input, sizeof(input)-1);
|
||||
inlen = deflate_data(in, inlen, (const uint8_t *)input, sizeof(input) - 1);
|
||||
|
||||
CU_ASSERT(0 == nghttp2_gzip_inflate_new(&inflater));
|
||||
/* First 16 bytes */
|
||||
inptr = in;
|
||||
inproclen = inlen;
|
||||
outproclen = 16;
|
||||
CU_ASSERT(0 == nghttp2_gzip_inflate(inflater, out, &outproclen,
|
||||
inptr, &inproclen));
|
||||
CU_ASSERT(
|
||||
0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen));
|
||||
CU_ASSERT(16 == outproclen);
|
||||
CU_ASSERT(inproclen > 0);
|
||||
CU_ASSERT(0 == memcmp(inputptr, out, outproclen));
|
||||
@ -93,8 +91,8 @@ void test_nghttp2_gzip_inflate(void)
|
||||
inproclen = inlen;
|
||||
inputptr += outproclen;
|
||||
outproclen = 32;
|
||||
CU_ASSERT(0 == nghttp2_gzip_inflate(inflater, out, &outproclen,
|
||||
inptr, &inproclen));
|
||||
CU_ASSERT(
|
||||
0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen));
|
||||
CU_ASSERT(32 == outproclen);
|
||||
CU_ASSERT(inproclen > 0);
|
||||
CU_ASSERT(0 == memcmp(inputptr, out, outproclen));
|
||||
@ -104,9 +102,9 @@ void test_nghttp2_gzip_inflate(void)
|
||||
inproclen = inlen;
|
||||
inputptr += outproclen;
|
||||
outproclen = sizeof(out);
|
||||
CU_ASSERT(0 == nghttp2_gzip_inflate(inflater, out, &outproclen,
|
||||
inptr, &inproclen));
|
||||
CU_ASSERT(sizeof(input)-49 == outproclen);
|
||||
CU_ASSERT(
|
||||
0 == nghttp2_gzip_inflate(inflater, out, &outproclen, inptr, &inproclen));
|
||||
CU_ASSERT(sizeof(input) - 49 == outproclen);
|
||||
CU_ASSERT(inproclen > 0);
|
||||
CU_ASSERT(0 == memcmp(inputptr, out, outproclen));
|
||||
|
||||
|
@ -25,7 +25,7 @@
|
||||
#ifndef NGHTTP2_GZIP_TEST_H
|
||||
#define NGHTTP2_GZIP_TEST_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
@ -48,22 +48,21 @@
|
||||
namespace nghttp2 {
|
||||
|
||||
namespace {
|
||||
int parse_push_config(Config& config, const char *optarg)
|
||||
{
|
||||
int parse_push_config(Config &config, const char *optarg) {
|
||||
const char *eq = strchr(optarg, '=');
|
||||
if(eq == NULL) {
|
||||
if (eq == NULL) {
|
||||
return -1;
|
||||
}
|
||||
auto paths = std::vector<std::string>();
|
||||
auto optarg_end = optarg + strlen(optarg);
|
||||
const char *i = eq + 1;
|
||||
for(;;) {
|
||||
for (;;) {
|
||||
const char *j = strchr(i, ',');
|
||||
if(j == NULL) {
|
||||
if (j == NULL) {
|
||||
j = optarg_end;
|
||||
}
|
||||
paths.emplace_back(i, j);
|
||||
if(j == optarg_end) {
|
||||
if (j == optarg_end) {
|
||||
break;
|
||||
}
|
||||
i = j;
|
||||
@ -75,15 +74,13 @@ int parse_push_config(Config& config, const char *optarg)
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_version(std::ostream& out)
|
||||
{
|
||||
void print_version(std::ostream &out) {
|
||||
out << "nghttpd nghttp2/" NGHTTP2_VERSION << std::endl;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_usage(std::ostream& out)
|
||||
{
|
||||
void print_usage(std::ostream &out) {
|
||||
out << "Usage: nghttpd [OPTION]... <PORT> <PRIVATE_KEY> <CERT>\n"
|
||||
<< " or: nghttpd --no-tls [OPTION]... <PORT>\n"
|
||||
<< "HTTP/2 experimental server" << std::endl;
|
||||
@ -91,8 +88,7 @@ void print_usage(std::ostream& out)
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void print_help(std::ostream& out)
|
||||
{
|
||||
void print_help(std::ostream &out) {
|
||||
print_usage(out);
|
||||
out << R"(
|
||||
<PORT> Specify listening port number.
|
||||
@ -142,43 +138,40 @@ Options:
|
||||
received, rather than complete request is
|
||||
received.
|
||||
--version Display version information and exit.
|
||||
-h, --help Display this help and exit.)"
|
||||
<< std::endl;
|
||||
-h, --help Display this help and exit.)" << std::endl;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
int main(int argc, char **argv) {
|
||||
Config config;
|
||||
bool color = false;
|
||||
while(1) {
|
||||
while (1) {
|
||||
static int flag = 0;
|
||||
static option long_options[] = {
|
||||
{"daemon", no_argument, nullptr, 'D'},
|
||||
{"htdocs", required_argument, nullptr, 'd'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{"verify-client", no_argument, nullptr, 'V'},
|
||||
{"header-table-size", required_argument, nullptr, 'c'},
|
||||
{"push", required_argument, nullptr, 'p'},
|
||||
{"padding", required_argument, nullptr, 'b'},
|
||||
{"workers", required_argument, nullptr, 'n'},
|
||||
{"error-gzip", no_argument, nullptr, 'e'},
|
||||
{"no-tls", no_argument, &flag, 1},
|
||||
{"color", no_argument, &flag, 2},
|
||||
{"version", no_argument, &flag, 3},
|
||||
{"dh-param-file", required_argument, &flag, 4},
|
||||
{"early-response", no_argument, &flag, 5},
|
||||
{nullptr, 0, nullptr, 0}
|
||||
};
|
||||
{"daemon", no_argument, nullptr, 'D'},
|
||||
{"htdocs", required_argument, nullptr, 'd'},
|
||||
{"help", no_argument, nullptr, 'h'},
|
||||
{"verbose", no_argument, nullptr, 'v'},
|
||||
{"verify-client", no_argument, nullptr, 'V'},
|
||||
{"header-table-size", required_argument, nullptr, 'c'},
|
||||
{"push", required_argument, nullptr, 'p'},
|
||||
{"padding", required_argument, nullptr, 'b'},
|
||||
{"workers", required_argument, nullptr, 'n'},
|
||||
{"error-gzip", no_argument, nullptr, 'e'},
|
||||
{"no-tls", no_argument, &flag, 1},
|
||||
{"color", no_argument, &flag, 2},
|
||||
{"version", no_argument, &flag, 3},
|
||||
{"dh-param-file", required_argument, &flag, 4},
|
||||
{"early-response", no_argument, &flag, 5},
|
||||
{nullptr, 0, nullptr, 0}};
|
||||
int option_index = 0;
|
||||
int c = getopt_long(argc, argv, "DVb:c:d:ehn:p:v", long_options,
|
||||
&option_index);
|
||||
int c =
|
||||
getopt_long(argc, argv, "DVb:c:d:ehn:p:v", long_options, &option_index);
|
||||
char *end;
|
||||
if(c == -1) {
|
||||
if (c == -1) {
|
||||
break;
|
||||
}
|
||||
switch(c) {
|
||||
switch (c) {
|
||||
case 'D':
|
||||
config.daemon = true;
|
||||
break;
|
||||
@ -196,12 +189,12 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
case 'n':
|
||||
#ifdef NOTHREADS
|
||||
std::cerr << "-n: WARNING: Threading disabled at build time, " <<
|
||||
"no threads created." << std::endl;
|
||||
std::cerr << "-n: WARNING: Threading disabled at build time, "
|
||||
<< "no threads created." << std::endl;
|
||||
#else
|
||||
errno = 0;
|
||||
config.num_worker = strtoul(optarg, &end, 10);
|
||||
if(errno == ERANGE || *end != '\0' || config.num_worker == 0) {
|
||||
if (errno == ERANGE || *end != '\0' || config.num_worker == 0) {
|
||||
std::cerr << "-n: Bad option value: " << optarg << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@ -216,13 +209,13 @@ int main(int argc, char **argv)
|
||||
case 'c':
|
||||
errno = 0;
|
||||
config.header_table_size = strtol(optarg, &end, 10);
|
||||
if(errno == ERANGE || *end != '\0') {
|
||||
if (errno == ERANGE || *end != '\0') {
|
||||
std::cerr << "-c: Bad option value: " << optarg << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
break;
|
||||
case 'p':
|
||||
if(parse_push_config(config, optarg) != 0) {
|
||||
if (parse_push_config(config, optarg) != 0) {
|
||||
std::cerr << "-p: Bad option value: " << optarg << std::endl;
|
||||
}
|
||||
break;
|
||||
@ -230,7 +223,7 @@ int main(int argc, char **argv)
|
||||
util::show_candidates(argv[optind - 1], long_options);
|
||||
exit(EXIT_FAILURE);
|
||||
case 0:
|
||||
switch(flag) {
|
||||
switch (flag) {
|
||||
case 1:
|
||||
// no-tls option
|
||||
config.no_tls = true;
|
||||
@ -257,7 +250,7 @@ int main(int argc, char **argv)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(argc - optind < (config.no_tls ? 1 : 3)) {
|
||||
if (argc - optind < (config.no_tls ? 1 : 3)) {
|
||||
print_usage(std::cerr);
|
||||
std::cerr << "Too few arguments" << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
@ -265,23 +258,23 @@ int main(int argc, char **argv)
|
||||
|
||||
config.port = strtol(argv[optind++], nullptr, 10);
|
||||
|
||||
if(!config.no_tls) {
|
||||
if (!config.no_tls) {
|
||||
config.private_key_file = argv[optind++];
|
||||
config.cert_file = argv[optind++];
|
||||
}
|
||||
|
||||
if(config.daemon) {
|
||||
if(config.htdocs.empty()) {
|
||||
if (config.daemon) {
|
||||
if (config.htdocs.empty()) {
|
||||
print_usage(std::cerr);
|
||||
std::cerr << "-d option must be specified when -D is used." << std::endl;
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
if(daemon(0, 0) == -1) {
|
||||
if (daemon(0, 0) == -1) {
|
||||
perror("daemon");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
if(config.htdocs.empty()) {
|
||||
if (config.htdocs.empty()) {
|
||||
config.htdocs = "./";
|
||||
}
|
||||
|
||||
@ -308,7 +301,4 @@ int main(int argc, char **argv)
|
||||
|
||||
} // namespace nghttp2
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
return nghttp2::main(argc, argv);
|
||||
}
|
||||
int main(int argc, char **argv) { return nghttp2::main(argc, argv); }
|
||||
|
@ -23,7 +23,7 @@
|
||||
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif /* HAVE_CONFIG_H */
|
||||
|
||||
#include <stdio.h>
|
||||
@ -39,39 +39,31 @@
|
||||
#include "util_test.h"
|
||||
#include "nghttp2_gzip_test.h"
|
||||
|
||||
static int init_suite1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int init_suite1(void) { return 0; }
|
||||
|
||||
static int clean_suite1(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static int clean_suite1(void) { return 0; }
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
CU_pSuite pSuite = NULL;
|
||||
unsigned int num_tests_failed;
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
CU_pSuite pSuite = NULL;
|
||||
unsigned int num_tests_failed;
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
|
||||
OpenSSL_add_all_algorithms();
|
||||
SSL_load_error_strings();
|
||||
SSL_library_init();
|
||||
// initialize the CUnit test registry
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
return CU_get_error();
|
||||
|
||||
// initialize the CUnit test registry
|
||||
if (CUE_SUCCESS != CU_initialize_registry())
|
||||
return CU_get_error();
|
||||
// add a suite to the registry
|
||||
pSuite = CU_add_suite("shrpx_TestSuite", init_suite1, clean_suite1);
|
||||
if (NULL == pSuite) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
// add a suite to the registry
|
||||
pSuite = CU_add_suite("shrpx_TestSuite", init_suite1, clean_suite1);
|
||||
if (NULL == pSuite) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
// add the tests to the suite
|
||||
if(!CU_add_test(pSuite, "ssl_create_lookup_tree",
|
||||
// add the tests to the suite
|
||||
if (!CU_add_test(pSuite, "ssl_create_lookup_tree",
|
||||
shrpx::test_shrpx_ssl_create_lookup_tree) ||
|
||||
!CU_add_test(pSuite, "ssl_cert_lookup_tree_add_cert_from_file",
|
||||
shrpx::test_shrpx_ssl_cert_lookup_tree_add_cert_from_file) ||
|
||||
@ -80,16 +72,13 @@ int main(int argc, char* argv[])
|
||||
shrpx::test_http2_check_http2_headers) ||
|
||||
!CU_add_test(pSuite, "http2_get_unique_header",
|
||||
shrpx::test_http2_get_unique_header) ||
|
||||
!CU_add_test(pSuite, "http2_get_header",
|
||||
shrpx::test_http2_get_header) ||
|
||||
!CU_add_test(pSuite, "http2_value_lws",
|
||||
shrpx::test_http2_value_lws) ||
|
||||
!CU_add_test(pSuite, "http2_get_header", shrpx::test_http2_get_header) ||
|
||||
!CU_add_test(pSuite, "http2_value_lws", shrpx::test_http2_value_lws) ||
|
||||
!CU_add_test(pSuite, "http2_copy_norm_headers_to_nva",
|
||||
shrpx::test_http2_copy_norm_headers_to_nva) ||
|
||||
!CU_add_test(pSuite, "http2_build_http1_headers_from_norm_headers",
|
||||
shrpx::test_http2_build_http1_headers_from_norm_headers) ||
|
||||
!CU_add_test(pSuite, "http2_lws",
|
||||
shrpx::test_http2_lws) ||
|
||||
!CU_add_test(pSuite, "http2_lws", shrpx::test_http2_lws) ||
|
||||
!CU_add_test(pSuite, "http2_rewrite_location_uri",
|
||||
shrpx::test_http2_rewrite_location_uri) ||
|
||||
!CU_add_test(pSuite, "http2_parse_http_status_code",
|
||||
@ -106,8 +95,9 @@ int main(int argc, char* argv[])
|
||||
shrpx::test_downstream_crumble_request_cookie) ||
|
||||
!CU_add_test(pSuite, "downstream_assemble_request_cookie",
|
||||
shrpx::test_downstream_assemble_request_cookie) ||
|
||||
!CU_add_test(pSuite, "downstream_rewrite_norm_location_response_header",
|
||||
shrpx::test_downstream_rewrite_norm_location_response_header) ||
|
||||
!CU_add_test(
|
||||
pSuite, "downstream_rewrite_norm_location_response_header",
|
||||
shrpx::test_downstream_rewrite_norm_location_response_header) ||
|
||||
!CU_add_test(pSuite, "config_parse_config_str_list",
|
||||
shrpx::test_shrpx_config_parse_config_str_list) ||
|
||||
!CU_add_test(pSuite, "config_parse_header",
|
||||
@ -118,8 +108,7 @@ int main(int argc, char* argv[])
|
||||
!CU_add_test(pSuite, "util_strieq", shrpx::test_util_strieq) ||
|
||||
!CU_add_test(pSuite, "util_inp_strlower",
|
||||
shrpx::test_util_inp_strlower) ||
|
||||
!CU_add_test(pSuite, "util_to_base64",
|
||||
shrpx::test_util_to_base64) ||
|
||||
!CU_add_test(pSuite, "util_to_base64", shrpx::test_util_to_base64) ||
|
||||
!CU_add_test(pSuite, "util_percent_encode_token",
|
||||
shrpx::test_util_percent_encode_token) ||
|
||||
!CU_add_test(pSuite, "util_quote_string",
|
||||
@ -127,19 +116,19 @@ int main(int argc, char* argv[])
|
||||
!CU_add_test(pSuite, "util_utox", shrpx::test_util_utox) ||
|
||||
!CU_add_test(pSuite, "util_http_date", shrpx::test_util_http_date) ||
|
||||
!CU_add_test(pSuite, "gzip_inflate", test_nghttp2_gzip_inflate)) {
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
CU_cleanup_registry();
|
||||
return CU_get_error();
|
||||
}
|
||||
|
||||
// Run all tests using the CUnit Basic interface
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
num_tests_failed = CU_get_number_of_tests_failed();
|
||||
CU_cleanup_registry();
|
||||
if(CU_get_error() == CUE_SUCCESS) {
|
||||
return num_tests_failed;
|
||||
} else {
|
||||
printf("CUnit Error: %s\n", CU_get_error_msg());
|
||||
return CU_get_error();
|
||||
}
|
||||
// Run all tests using the CUnit Basic interface
|
||||
CU_basic_set_mode(CU_BRM_VERBOSE);
|
||||
CU_basic_run_tests();
|
||||
num_tests_failed = CU_get_number_of_tests_failed();
|
||||
CU_cleanup_registry();
|
||||
if (CU_get_error() == CUE_SUCCESS) {
|
||||
return num_tests_failed;
|
||||
} else {
|
||||
printf("CUnit Error: %s\n", CU_get_error_msg());
|
||||
return CU_get_error();
|
||||
}
|
||||
}
|
||||
|
762
src/shrpx.cc
762
src/shrpx.cc
File diff suppressed because it is too large
Load Diff
@ -26,7 +26,7 @@
|
||||
#define SHRPX_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include <config.h>
|
||||
#include <config.h>
|
||||
#endif // HAVE_CONFIG_H
|
||||
|
||||
#include <sys/types.h>
|
||||
|
@ -49,91 +49,87 @@ using namespace nghttp2;
|
||||
namespace shrpx {
|
||||
|
||||
namespace {
|
||||
void upstream_readcb(bufferevent *bev, void *arg)
|
||||
{
|
||||
auto handler = static_cast<ClientHandler*>(arg);
|
||||
void upstream_readcb(bufferevent *bev, void *arg) {
|
||||
auto handler = static_cast<ClientHandler *>(arg);
|
||||
auto upstream = handler->get_upstream();
|
||||
if(upstream) {
|
||||
if (upstream) {
|
||||
upstream->reset_timeouts();
|
||||
}
|
||||
int rv = handler->on_read();
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void upstream_writecb(bufferevent *bev, void *arg)
|
||||
{
|
||||
auto handler = static_cast<ClientHandler*>(arg);
|
||||
void upstream_writecb(bufferevent *bev, void *arg) {
|
||||
auto handler = static_cast<ClientHandler *>(arg);
|
||||
auto upstream = handler->get_upstream();
|
||||
if(upstream) {
|
||||
if (upstream) {
|
||||
upstream->reset_timeouts();
|
||||
}
|
||||
|
||||
handler->update_last_write_time();
|
||||
|
||||
// We actually depend on write low-water mark == 0.
|
||||
if(handler->get_outbuf_length() > 0) {
|
||||
if (handler->get_outbuf_length() > 0) {
|
||||
// Possibly because of deferred callback, we may get this callback
|
||||
// when the output buffer is not empty.
|
||||
return;
|
||||
}
|
||||
if(handler->get_should_close_after_write()) {
|
||||
if (handler->get_should_close_after_write()) {
|
||||
delete handler;
|
||||
return;
|
||||
}
|
||||
|
||||
if(!upstream) {
|
||||
if (!upstream) {
|
||||
return;
|
||||
}
|
||||
int rv = upstream->on_write();
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void upstream_eventcb(bufferevent *bev, short events, void *arg)
|
||||
{
|
||||
auto handler = static_cast<ClientHandler*>(arg);
|
||||
void upstream_eventcb(bufferevent *bev, short events, void *arg) {
|
||||
auto handler = static_cast<ClientHandler *>(arg);
|
||||
bool finish = false;
|
||||
if(events & BEV_EVENT_EOF) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (events & BEV_EVENT_EOF) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, handler) << "EOF";
|
||||
}
|
||||
finish = true;
|
||||
}
|
||||
if(events & BEV_EVENT_ERROR) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, handler) << "Network error: "
|
||||
<< evutil_socket_error_to_string
|
||||
(EVUTIL_SOCKET_ERROR());
|
||||
if (events & BEV_EVENT_ERROR) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, handler) << "Network error: " << evutil_socket_error_to_string(
|
||||
EVUTIL_SOCKET_ERROR());
|
||||
}
|
||||
finish = true;
|
||||
}
|
||||
if(events & BEV_EVENT_TIMEOUT) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (events & BEV_EVENT_TIMEOUT) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, handler) << "Time out";
|
||||
}
|
||||
finish = true;
|
||||
}
|
||||
if(finish) {
|
||||
if (finish) {
|
||||
delete handler;
|
||||
} else {
|
||||
if(events & BEV_EVENT_CONNECTED) {
|
||||
if (events & BEV_EVENT_CONNECTED) {
|
||||
handler->set_tls_handshake(true);
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, handler) << "SSL/TLS handshake completed";
|
||||
}
|
||||
if(handler->validate_next_proto() != 0) {
|
||||
if (handler->validate_next_proto() != 0) {
|
||||
delete handler;
|
||||
return;
|
||||
}
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if(SSL_session_reused(handler->get_ssl())) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
if (SSL_session_reused(handler->get_ssl())) {
|
||||
CLOG(INFO, handler) << "SSL/TLS session reused";
|
||||
}
|
||||
}
|
||||
@ -143,22 +139,20 @@ void upstream_eventcb(bufferevent *bev, short events, void *arg)
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void upstream_http2_connhd_readcb(bufferevent *bev, void *arg)
|
||||
{
|
||||
void upstream_http2_connhd_readcb(bufferevent *bev, void *arg) {
|
||||
// This callback assumes upstream is Http2Upstream.
|
||||
auto handler = static_cast<ClientHandler*>(arg);
|
||||
if(handler->on_http2_connhd_read() != 0) {
|
||||
auto handler = static_cast<ClientHandler *>(arg);
|
||||
if (handler->on_http2_connhd_read() != 0) {
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
void upstream_http1_connhd_readcb(bufferevent *bev, void *arg)
|
||||
{
|
||||
void upstream_http1_connhd_readcb(bufferevent *bev, void *arg) {
|
||||
// This callback assumes upstream is HttpsUpstream.
|
||||
auto handler = static_cast<ClientHandler*>(arg);
|
||||
if(handler->on_http1_connhd_read() != 0) {
|
||||
auto handler = static_cast<ClientHandler *>(arg);
|
||||
if (handler->on_http1_connhd_read() != 0) {
|
||||
delete handler;
|
||||
}
|
||||
}
|
||||
@ -166,38 +160,26 @@ void upstream_http1_connhd_readcb(bufferevent *bev, void *arg)
|
||||
|
||||
ClientHandler::ClientHandler(bufferevent *bev,
|
||||
bufferevent_rate_limit_group *rate_limit_group,
|
||||
int fd, SSL *ssl,
|
||||
const char *ipaddr,
|
||||
const char *port,
|
||||
WorkerStat *worker_stat,
|
||||
int fd, SSL *ssl, const char *ipaddr,
|
||||
const char *port, WorkerStat *worker_stat,
|
||||
DownstreamConnectionPool *dconn_pool)
|
||||
: ipaddr_(ipaddr),
|
||||
port_(port),
|
||||
dconn_pool_(dconn_pool),
|
||||
bev_(bev),
|
||||
http2session_(nullptr),
|
||||
ssl_(ssl),
|
||||
reneg_shutdown_timerev_(nullptr),
|
||||
worker_stat_(worker_stat),
|
||||
last_write_time_(0),
|
||||
warmup_writelen_(0),
|
||||
left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN),
|
||||
fd_(fd),
|
||||
should_close_after_write_(false),
|
||||
tls_handshake_(false),
|
||||
tls_renegotiation_(false)
|
||||
{
|
||||
: ipaddr_(ipaddr), port_(port), dconn_pool_(dconn_pool), bev_(bev),
|
||||
http2session_(nullptr), ssl_(ssl), reneg_shutdown_timerev_(nullptr),
|
||||
worker_stat_(worker_stat), last_write_time_(0), warmup_writelen_(0),
|
||||
left_connhd_len_(NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN), fd_(fd),
|
||||
should_close_after_write_(false), tls_handshake_(false),
|
||||
tls_renegotiation_(false) {
|
||||
int rv;
|
||||
|
||||
++worker_stat->num_connections;
|
||||
|
||||
rv = bufferevent_set_rate_limit(bev_, get_config()->rate_limit_cfg);
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
CLOG(FATAL, this) << "bufferevent_set_rate_limit() failed";
|
||||
}
|
||||
|
||||
rv = bufferevent_add_to_rate_limit_group(bev_, rate_limit_group);
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
CLOG(FATAL, this) << "bufferevent_add_to_rate_limit_group() failed";
|
||||
}
|
||||
|
||||
@ -205,8 +187,8 @@ ClientHandler::ClientHandler(bufferevent *bev,
|
||||
bufferevent_setwatermark(bev_, EV_READ, 0, SHRPX_READ_WATERMARK);
|
||||
set_upstream_timeouts(&get_config()->upstream_read_timeout,
|
||||
&get_config()->upstream_write_timeout);
|
||||
if(ssl_) {
|
||||
SSL_set_app_data(ssl_, reinterpret_cast<char*>(this));
|
||||
if (ssl_) {
|
||||
SSL_set_app_data(ssl_, reinterpret_cast<char *>(this));
|
||||
set_bev_cb(nullptr, upstream_writecb, upstream_eventcb);
|
||||
} else {
|
||||
// For non-TLS version, first create HttpsUpstream. It may be
|
||||
@ -218,13 +200,12 @@ ClientHandler::ClientHandler(bufferevent *bev,
|
||||
}
|
||||
}
|
||||
|
||||
ClientHandler::~ClientHandler()
|
||||
{
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
ClientHandler::~ClientHandler() {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "Deleting";
|
||||
}
|
||||
|
||||
if(upstream_) {
|
||||
if (upstream_) {
|
||||
upstream_->on_handler_delete();
|
||||
}
|
||||
|
||||
@ -232,15 +213,15 @@ ClientHandler::~ClientHandler()
|
||||
|
||||
// TODO If backend is http/2, and it is in CONNECTED state, signal
|
||||
// it and make it loopbreak when output is zero.
|
||||
if(worker_config->graceful_shutdown && worker_stat_->num_connections == 0) {
|
||||
if (worker_config->graceful_shutdown && worker_stat_->num_connections == 0) {
|
||||
event_base_loopbreak(get_evbase());
|
||||
}
|
||||
|
||||
if(reneg_shutdown_timerev_) {
|
||||
if (reneg_shutdown_timerev_) {
|
||||
event_free(reneg_shutdown_timerev_);
|
||||
}
|
||||
|
||||
if(ssl_) {
|
||||
if (ssl_) {
|
||||
SSL_set_app_data(ssl_, nullptr);
|
||||
SSL_set_shutdown(ssl_, SSL_RECEIVED_SHUTDOWN);
|
||||
SSL_shutdown(ssl_);
|
||||
@ -251,47 +232,37 @@ ClientHandler::~ClientHandler()
|
||||
util::bev_disable_unless(bev_, EV_READ | EV_WRITE);
|
||||
bufferevent_free(bev_);
|
||||
|
||||
if(ssl_) {
|
||||
if (ssl_) {
|
||||
SSL_free(ssl_);
|
||||
}
|
||||
|
||||
shutdown(fd_, SHUT_WR);
|
||||
close(fd_);
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "Deleted";
|
||||
}
|
||||
}
|
||||
|
||||
Upstream* ClientHandler::get_upstream()
|
||||
{
|
||||
return upstream_.get();
|
||||
}
|
||||
Upstream *ClientHandler::get_upstream() { return upstream_.get(); }
|
||||
|
||||
bufferevent* ClientHandler::get_bev() const
|
||||
{
|
||||
return bev_;
|
||||
}
|
||||
bufferevent *ClientHandler::get_bev() const { return bev_; }
|
||||
|
||||
event_base* ClientHandler::get_evbase() const
|
||||
{
|
||||
event_base *ClientHandler::get_evbase() const {
|
||||
return bufferevent_get_base(bev_);
|
||||
}
|
||||
|
||||
void ClientHandler::set_bev_cb
|
||||
(bufferevent_data_cb readcb, bufferevent_data_cb writecb,
|
||||
bufferevent_event_cb eventcb)
|
||||
{
|
||||
void ClientHandler::set_bev_cb(bufferevent_data_cb readcb,
|
||||
bufferevent_data_cb writecb,
|
||||
bufferevent_event_cb eventcb) {
|
||||
bufferevent_setcb(bev_, readcb, writecb, eventcb, this);
|
||||
}
|
||||
|
||||
void ClientHandler::set_upstream_timeouts(const timeval *read_timeout,
|
||||
const timeval *write_timeout)
|
||||
{
|
||||
const timeval *write_timeout) {
|
||||
bufferevent_set_timeouts(bev_, read_timeout, write_timeout);
|
||||
}
|
||||
|
||||
int ClientHandler::validate_next_proto()
|
||||
{
|
||||
int ClientHandler::validate_next_proto() {
|
||||
const unsigned char *next_proto = nullptr;
|
||||
unsigned int next_proto_len;
|
||||
int rv;
|
||||
@ -299,27 +270,27 @@ int ClientHandler::validate_next_proto()
|
||||
// First set callback for catch all cases
|
||||
set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
|
||||
SSL_get0_next_proto_negotiated(ssl_, &next_proto, &next_proto_len);
|
||||
for(int i = 0; i < 2; ++i) {
|
||||
if(next_proto) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
std::string proto(next_proto, next_proto+next_proto_len);
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
if (next_proto) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
std::string proto(next_proto, next_proto + next_proto_len);
|
||||
CLOG(INFO, this) << "The negotiated next protocol: " << proto;
|
||||
}
|
||||
if(!ssl::in_proto_list(get_config()->npn_list,
|
||||
next_proto, next_proto_len)) {
|
||||
if (!ssl::in_proto_list(get_config()->npn_list, next_proto,
|
||||
next_proto_len)) {
|
||||
break;
|
||||
}
|
||||
if(util::check_h2_is_selected(next_proto, next_proto_len)) {
|
||||
if (util::check_h2_is_selected(next_proto, next_proto_len)) {
|
||||
|
||||
set_bev_cb(upstream_http2_connhd_readcb, upstream_writecb,
|
||||
upstream_eventcb);
|
||||
|
||||
auto http2_upstream = util::make_unique<Http2Upstream>(this);
|
||||
|
||||
if(!ssl::check_http2_requirement(ssl_)) {
|
||||
if (!ssl::check_http2_requirement(ssl_)) {
|
||||
rv = http2_upstream->terminate_session(NGHTTP2_INADEQUATE_SECURITY);
|
||||
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@ -330,7 +301,7 @@ int ClientHandler::validate_next_proto()
|
||||
// At this point, input buffer is already filled with some
|
||||
// bytes. The read callback is not called until new data
|
||||
// come. So consume input buffer here.
|
||||
if(on_http2_connhd_read() != 0) {
|
||||
if (on_http2_connhd_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -338,10 +309,10 @@ int ClientHandler::validate_next_proto()
|
||||
} else {
|
||||
#ifdef HAVE_SPDYLAY
|
||||
uint16_t version = spdylay_npn_get_version(next_proto, next_proto_len);
|
||||
if(version) {
|
||||
if (version) {
|
||||
upstream_ = util::make_unique<SpdyUpstream>(version, this);
|
||||
|
||||
switch(version) {
|
||||
switch (version) {
|
||||
case SPDYLAY_PROTO_SPDY2:
|
||||
alpn_ = "spdy/2";
|
||||
break;
|
||||
@ -358,21 +329,21 @@ int ClientHandler::validate_next_proto()
|
||||
// At this point, input buffer is already filled with some
|
||||
// bytes. The read callback is not called until new data
|
||||
// come. So consume input buffer here.
|
||||
if(upstream_->on_read() != 0) {
|
||||
if (upstream_->on_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif // HAVE_SPDYLAY
|
||||
if(next_proto_len == 8 && memcmp("http/1.1", next_proto, 8) == 0) {
|
||||
if (next_proto_len == 8 && memcmp("http/1.1", next_proto, 8) == 0) {
|
||||
upstream_ = util::make_unique<HttpsUpstream>(this);
|
||||
alpn_ = "http/1.1";
|
||||
|
||||
// At this point, input buffer is already filled with some
|
||||
// bytes. The read callback is not called until new data
|
||||
// come. So consume input buffer here.
|
||||
if(upstream_->on_read() != 0) {
|
||||
if (upstream_->on_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -383,12 +354,12 @@ int ClientHandler::validate_next_proto()
|
||||
}
|
||||
#if OPENSSL_VERSION_NUMBER >= 0x10002000L
|
||||
SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
#else // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
break;
|
||||
#endif // OPENSSL_VERSION_NUMBER < 0x10002000L
|
||||
}
|
||||
if(!next_proto) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (!next_proto) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "No protocol negotiated. Fallback to HTTP/1.1";
|
||||
}
|
||||
upstream_ = util::make_unique<HttpsUpstream>(this);
|
||||
@ -397,44 +368,37 @@ int ClientHandler::validate_next_proto()
|
||||
// At this point, input buffer is already filled with some bytes.
|
||||
// The read callback is not called until new data come. So consume
|
||||
// input buffer here.
|
||||
if(upstream_->on_read() != 0) {
|
||||
if (upstream_->on_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "The negotiated protocol is not supported";
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ClientHandler::on_read()
|
||||
{
|
||||
return upstream_->on_read();
|
||||
}
|
||||
int ClientHandler::on_read() { return upstream_->on_read(); }
|
||||
|
||||
int ClientHandler::on_event()
|
||||
{
|
||||
return upstream_->on_event();
|
||||
}
|
||||
int ClientHandler::on_event() { return upstream_->on_event(); }
|
||||
|
||||
int ClientHandler::on_http2_connhd_read()
|
||||
{
|
||||
int ClientHandler::on_http2_connhd_read() {
|
||||
// This callback assumes upstream is Http2Upstream.
|
||||
uint8_t data[NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN];
|
||||
auto input = bufferevent_get_input(bev_);
|
||||
auto readlen = evbuffer_remove(input, data, left_connhd_len_);
|
||||
|
||||
if(readlen == -1) {
|
||||
if (readlen == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE +
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_,
|
||||
data, readlen) != 0) {
|
||||
if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE +
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_,
|
||||
data, readlen) != 0) {
|
||||
// There is no downgrade path here. Just drop the connection.
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "invalid client connection header";
|
||||
}
|
||||
|
||||
@ -443,7 +407,7 @@ int ClientHandler::on_http2_connhd_read()
|
||||
|
||||
left_connhd_len_ -= readlen;
|
||||
|
||||
if(left_connhd_len_ > 0) {
|
||||
if (left_connhd_len_ > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -451,27 +415,26 @@ int ClientHandler::on_http2_connhd_read()
|
||||
|
||||
// Run on_read to process data left in buffer since they are not
|
||||
// notified further
|
||||
if(on_read() != 0) {
|
||||
if (on_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ClientHandler::on_http1_connhd_read()
|
||||
{
|
||||
int ClientHandler::on_http1_connhd_read() {
|
||||
uint8_t data[NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN];
|
||||
auto input = bufferevent_get_input(bev_);
|
||||
auto readlen = evbuffer_copyout(input, data, left_connhd_len_);
|
||||
|
||||
if(readlen == -1) {
|
||||
if (readlen == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE +
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_,
|
||||
data, readlen) != 0) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (memcmp(NGHTTP2_CLIENT_CONNECTION_PREFACE +
|
||||
NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN - left_connhd_len_,
|
||||
data, readlen) != 0) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "This is HTTP/1.1 connection, "
|
||||
<< "but may be upgraded to HTTP/2 later.";
|
||||
}
|
||||
@ -480,24 +443,24 @@ int ClientHandler::on_http1_connhd_read()
|
||||
left_connhd_len_ = NGHTTP2_CLIENT_CONNECTION_PREFACE_LEN;
|
||||
set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
|
||||
|
||||
if(on_read() != 0) {
|
||||
if (on_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(evbuffer_drain(input, readlen) == -1) {
|
||||
if (evbuffer_drain(input, readlen) == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
left_connhd_len_ -= readlen;
|
||||
|
||||
if(left_connhd_len_ > 0) {
|
||||
if (left_connhd_len_ > 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "direct HTTP/2 connection";
|
||||
}
|
||||
|
||||
@ -506,41 +469,34 @@ int ClientHandler::on_http1_connhd_read()
|
||||
|
||||
// Run on_read to process data left in buffer since they are not
|
||||
// notified further
|
||||
if(on_read() != 0) {
|
||||
if (on_read() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const std::string& ClientHandler::get_ipaddr() const
|
||||
{
|
||||
return ipaddr_;
|
||||
}
|
||||
const std::string &ClientHandler::get_ipaddr() const { return ipaddr_; }
|
||||
|
||||
bool ClientHandler::get_should_close_after_write() const
|
||||
{
|
||||
bool ClientHandler::get_should_close_after_write() const {
|
||||
return should_close_after_write_;
|
||||
}
|
||||
|
||||
void ClientHandler::set_should_close_after_write(bool f)
|
||||
{
|
||||
void ClientHandler::set_should_close_after_write(bool f) {
|
||||
should_close_after_write_ = f;
|
||||
}
|
||||
|
||||
void ClientHandler::pool_downstream_connection
|
||||
(std::unique_ptr<DownstreamConnection> dconn)
|
||||
{
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
void ClientHandler::pool_downstream_connection(
|
||||
std::unique_ptr<DownstreamConnection> dconn) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "Pooling downstream connection DCONN:" << dconn.get();
|
||||
}
|
||||
dconn->set_client_handler(nullptr);
|
||||
dconn_pool_->add_downstream_connection(std::move(dconn));
|
||||
}
|
||||
|
||||
void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn)
|
||||
{
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "Removing downstream connection DCONN:" << dconn
|
||||
<< " from pool";
|
||||
}
|
||||
@ -548,19 +504,18 @@ void ClientHandler::remove_downstream_connection(DownstreamConnection *dconn)
|
||||
}
|
||||
|
||||
std::unique_ptr<DownstreamConnection>
|
||||
ClientHandler::get_downstream_connection()
|
||||
{
|
||||
ClientHandler::get_downstream_connection() {
|
||||
auto dconn = dconn_pool_->pop_downstream_connection();
|
||||
|
||||
if(!dconn) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (!dconn) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "Downstream connection pool is empty."
|
||||
<< " Create new one";
|
||||
}
|
||||
|
||||
if(http2session_) {
|
||||
dconn = util::make_unique<Http2DownstreamConnection>
|
||||
(dconn_pool_, http2session_);
|
||||
if (http2session_) {
|
||||
dconn = util::make_unique<Http2DownstreamConnection>(dconn_pool_,
|
||||
http2session_);
|
||||
} else {
|
||||
dconn = util::make_unique<HttpDownstreamConnection>(dconn_pool_);
|
||||
}
|
||||
@ -570,7 +525,7 @@ ClientHandler::get_downstream_connection()
|
||||
|
||||
dconn->set_client_handler(this);
|
||||
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "Reuse downstream connection DCONN:" << dconn.get()
|
||||
<< " from pool";
|
||||
}
|
||||
@ -578,51 +533,39 @@ ClientHandler::get_downstream_connection()
|
||||
return dconn;
|
||||
}
|
||||
|
||||
size_t ClientHandler::get_outbuf_length()
|
||||
{
|
||||
size_t ClientHandler::get_outbuf_length() {
|
||||
return evbuffer_get_length(bufferevent_get_output(bev_));
|
||||
}
|
||||
|
||||
SSL* ClientHandler::get_ssl() const
|
||||
{
|
||||
return ssl_;
|
||||
}
|
||||
SSL *ClientHandler::get_ssl() const { return ssl_; }
|
||||
|
||||
void ClientHandler::set_http2_session(Http2Session *http2session)
|
||||
{
|
||||
void ClientHandler::set_http2_session(Http2Session *http2session) {
|
||||
http2session_ = http2session;
|
||||
}
|
||||
|
||||
Http2Session* ClientHandler::get_http2_session() const
|
||||
{
|
||||
return http2session_;
|
||||
}
|
||||
Http2Session *ClientHandler::get_http2_session() const { return http2session_; }
|
||||
|
||||
void ClientHandler::set_http1_connect_blocker
|
||||
(ConnectBlocker *http1_connect_blocker)
|
||||
{
|
||||
void ClientHandler::set_http1_connect_blocker(
|
||||
ConnectBlocker *http1_connect_blocker) {
|
||||
http1_connect_blocker_ = http1_connect_blocker;
|
||||
}
|
||||
|
||||
ConnectBlocker* ClientHandler::get_http1_connect_blocker() const
|
||||
{
|
||||
ConnectBlocker *ClientHandler::get_http1_connect_blocker() const {
|
||||
return http1_connect_blocker_;
|
||||
}
|
||||
|
||||
void ClientHandler::direct_http2_upgrade()
|
||||
{
|
||||
upstream_= util::make_unique<Http2Upstream>(this);
|
||||
void ClientHandler::direct_http2_upgrade() {
|
||||
upstream_ = util::make_unique<Http2Upstream>(this);
|
||||
// TODO We don't know exact h2 draft version in direct upgrade. We
|
||||
// just use library default for now.
|
||||
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
||||
set_bev_cb(upstream_readcb, upstream_writecb, upstream_eventcb);
|
||||
}
|
||||
|
||||
int ClientHandler::perform_http2_upgrade(HttpsUpstream *http)
|
||||
{
|
||||
int ClientHandler::perform_http2_upgrade(HttpsUpstream *http) {
|
||||
int rv;
|
||||
auto upstream = util::make_unique<Http2Upstream>(this);
|
||||
if(upstream->upgrade_upstream(http) != 0) {
|
||||
if (upstream->upgrade_upstream(http) != 0) {
|
||||
return -1;
|
||||
}
|
||||
// http pointer is now owned by upstream.
|
||||
@ -633,47 +576,36 @@ int ClientHandler::perform_http2_upgrade(HttpsUpstream *http)
|
||||
alpn_ = NGHTTP2_CLEARTEXT_PROTO_VERSION_ID;
|
||||
set_bev_cb(upstream_http2_connhd_readcb, upstream_writecb, upstream_eventcb);
|
||||
static char res[] = "HTTP/1.1 101 Switching Protocols\r\n"
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: " NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "\r\n"
|
||||
"\r\n";
|
||||
"Connection: Upgrade\r\n"
|
||||
"Upgrade: " NGHTTP2_CLEARTEXT_PROTO_VERSION_ID "\r\n"
|
||||
"\r\n";
|
||||
rv = bufferevent_write(bev_, res, sizeof(res) - 1);
|
||||
if(rv != 0) {
|
||||
if (rv != 0) {
|
||||
CLOG(FATAL, this) << "bufferevent_write() faild";
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ClientHandler::get_http2_upgrade_allowed() const
|
||||
{
|
||||
return !ssl_;
|
||||
}
|
||||
bool ClientHandler::get_http2_upgrade_allowed() const { return !ssl_; }
|
||||
|
||||
std::string ClientHandler::get_upstream_scheme() const
|
||||
{
|
||||
if(ssl_) {
|
||||
std::string ClientHandler::get_upstream_scheme() const {
|
||||
if (ssl_) {
|
||||
return "https";
|
||||
} else {
|
||||
return "http";
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::set_tls_handshake(bool f)
|
||||
{
|
||||
tls_handshake_ = f;
|
||||
}
|
||||
void ClientHandler::set_tls_handshake(bool f) { tls_handshake_ = f; }
|
||||
|
||||
bool ClientHandler::get_tls_handshake() const
|
||||
{
|
||||
return tls_handshake_;
|
||||
}
|
||||
bool ClientHandler::get_tls_handshake() const { return tls_handshake_; }
|
||||
|
||||
namespace {
|
||||
void shutdown_cb(evutil_socket_t fd, short what, void *arg)
|
||||
{
|
||||
auto handler = static_cast<ClientHandler*>(arg);
|
||||
void shutdown_cb(evutil_socket_t fd, short what, void *arg) {
|
||||
auto handler = static_cast<ClientHandler *>(arg);
|
||||
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, handler) << "Close connection due to TLS renegotiation";
|
||||
}
|
||||
|
||||
@ -681,10 +613,9 @@ void shutdown_cb(evutil_socket_t fd, short what, void *arg)
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void ClientHandler::set_tls_renegotiation(bool f)
|
||||
{
|
||||
if(tls_renegotiation_ == false) {
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
void ClientHandler::set_tls_renegotiation(bool f) {
|
||||
if (tls_renegotiation_ == false) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
CLOG(INFO, this) << "TLS renegotiation detected. "
|
||||
<< "Start shutdown timer now.";
|
||||
}
|
||||
@ -700,26 +631,22 @@ void ClientHandler::set_tls_renegotiation(bool f)
|
||||
tls_renegotiation_ = f;
|
||||
}
|
||||
|
||||
bool ClientHandler::get_tls_renegotiation() const
|
||||
{
|
||||
return tls_renegotiation_;
|
||||
}
|
||||
bool ClientHandler::get_tls_renegotiation() const { return tls_renegotiation_; }
|
||||
|
||||
namespace {
|
||||
const size_t SHRPX_SMALL_WRITE_LIMIT = 1300;
|
||||
const size_t SHRPX_WARMUP_THRESHOLD = 1 << 20;
|
||||
} // namespace
|
||||
|
||||
ssize_t ClientHandler::get_write_limit()
|
||||
{
|
||||
if(!ssl_) {
|
||||
ssize_t ClientHandler::get_write_limit() {
|
||||
if (!ssl_) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
timeval tv;
|
||||
if(event_base_gettimeofday_cached(get_evbase(), &tv) == 0) {
|
||||
if (event_base_gettimeofday_cached(get_evbase(), &tv) == 0) {
|
||||
auto now = util::to_time64(tv);
|
||||
if(now - last_write_time_ > 1000000) {
|
||||
if (now - last_write_time_ > 1000000) {
|
||||
// Time out, use small record size
|
||||
warmup_writelen_ = 0;
|
||||
return SHRPX_SMALL_WRITE_LIMIT;
|
||||
@ -729,74 +656,62 @@ ssize_t ClientHandler::get_write_limit()
|
||||
// If event_base_gettimeofday_cached() failed, we just skip timer
|
||||
// checking. Don't know how to treat this.
|
||||
|
||||
if(warmup_writelen_ >= SHRPX_WARMUP_THRESHOLD) {
|
||||
if (warmup_writelen_ >= SHRPX_WARMUP_THRESHOLD) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return SHRPX_SMALL_WRITE_LIMIT;
|
||||
}
|
||||
|
||||
void ClientHandler::update_warmup_writelen(size_t n)
|
||||
{
|
||||
if(warmup_writelen_ < SHRPX_WARMUP_THRESHOLD) {
|
||||
void ClientHandler::update_warmup_writelen(size_t n) {
|
||||
if (warmup_writelen_ < SHRPX_WARMUP_THRESHOLD) {
|
||||
warmup_writelen_ += n;
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::update_last_write_time()
|
||||
{
|
||||
void ClientHandler::update_last_write_time() {
|
||||
timeval tv;
|
||||
if(event_base_gettimeofday_cached(get_evbase(), &tv) == 0) {
|
||||
if (event_base_gettimeofday_cached(get_evbase(), &tv) == 0) {
|
||||
last_write_time_ = util::to_time64(tv);
|
||||
}
|
||||
}
|
||||
|
||||
void ClientHandler::write_accesslog(Downstream *downstream)
|
||||
{
|
||||
void ClientHandler::write_accesslog(Downstream *downstream) {
|
||||
LogSpec lgsp = {
|
||||
downstream,
|
||||
ipaddr_.c_str(),
|
||||
downstream->get_request_method().c_str(),
|
||||
downstream, ipaddr_.c_str(), downstream->get_request_method().c_str(),
|
||||
|
||||
downstream->get_request_path().empty() ?
|
||||
downstream->get_request_http2_authority().c_str() :
|
||||
downstream->get_request_path().c_str(),
|
||||
downstream->get_request_path().empty()
|
||||
? downstream->get_request_http2_authority().c_str()
|
||||
: downstream->get_request_path().c_str(),
|
||||
|
||||
alpn_.c_str(),
|
||||
alpn_.c_str(),
|
||||
|
||||
downstream->get_request_start_time(),
|
||||
std::chrono::high_resolution_clock::now(),
|
||||
downstream->get_request_start_time(),
|
||||
std::chrono::high_resolution_clock::now(),
|
||||
|
||||
downstream->get_request_major(),
|
||||
downstream->get_request_minor(),
|
||||
downstream->get_response_http_status(),
|
||||
downstream->get_response_sent_bodylen(),
|
||||
port_.c_str(),
|
||||
get_config()->port,
|
||||
get_config()->pid,
|
||||
downstream->get_request_major(), downstream->get_request_minor(),
|
||||
downstream->get_response_http_status(),
|
||||
downstream->get_response_sent_bodylen(), port_.c_str(),
|
||||
get_config()->port, get_config()->pid,
|
||||
};
|
||||
|
||||
upstream_accesslog(get_config()->accesslog_format, &lgsp);
|
||||
}
|
||||
|
||||
void ClientHandler::write_accesslog(int major, int minor,
|
||||
unsigned int status,
|
||||
int64_t body_bytes_sent)
|
||||
{
|
||||
void ClientHandler::write_accesslog(int major, int minor, unsigned int status,
|
||||
int64_t body_bytes_sent) {
|
||||
LogSpec lgsp = {
|
||||
nullptr,
|
||||
ipaddr_.c_str(),
|
||||
"-", // method
|
||||
"-", // path,
|
||||
alpn_.c_str(),
|
||||
std::chrono::high_resolution_clock::now(), //request_start_time TODO is there a better value?
|
||||
std::chrono::high_resolution_clock::now(), //time_now
|
||||
major, minor, // major, minor
|
||||
status,
|
||||
body_bytes_sent,
|
||||
port_.c_str(),
|
||||
get_config()->port,
|
||||
get_config()->pid,
|
||||
nullptr, ipaddr_.c_str(),
|
||||
"-", // method
|
||||
"-", // path,
|
||||
alpn_.c_str(),
|
||||
std::chrono::high_resolution_clock::now(), // request_start_time TODO is
|
||||
// there a better value?
|
||||
std::chrono::high_resolution_clock::now(), // time_now
|
||||
major, minor, // major, minor
|
||||
status, body_bytes_sent,
|
||||
port_.c_str(), get_config()->port,
|
||||
get_config()->pid,
|
||||
};
|
||||
|
||||
upstream_accesslog(get_config()->accesslog_format, &lgsp);
|
||||
|
@ -47,35 +47,34 @@ struct WorkerStat;
|
||||
class ClientHandler {
|
||||
public:
|
||||
ClientHandler(bufferevent *bev,
|
||||
bufferevent_rate_limit_group *rate_limit_group,
|
||||
int fd, SSL *ssl, const char *ipaddr, const char *port,
|
||||
WorkerStat *worker_stat,
|
||||
DownstreamConnectionPool *dconn_pool);
|
||||
bufferevent_rate_limit_group *rate_limit_group, int fd,
|
||||
SSL *ssl, const char *ipaddr, const char *port,
|
||||
WorkerStat *worker_stat, DownstreamConnectionPool *dconn_pool);
|
||||
~ClientHandler();
|
||||
int on_read();
|
||||
int on_event();
|
||||
bufferevent* get_bev() const;
|
||||
event_base* get_evbase() const;
|
||||
bufferevent *get_bev() const;
|
||||
event_base *get_evbase() const;
|
||||
void set_bev_cb(bufferevent_data_cb readcb, bufferevent_data_cb writecb,
|
||||
bufferevent_event_cb eventcb);
|
||||
void set_upstream_timeouts(const timeval *read_timeout,
|
||||
const timeval *write_timeout);
|
||||
int validate_next_proto();
|
||||
const std::string& get_ipaddr() const;
|
||||
const std::string& get_port() const;
|
||||
const std::string &get_ipaddr() const;
|
||||
const std::string &get_port() const;
|
||||
bool get_should_close_after_write() const;
|
||||
void set_should_close_after_write(bool f);
|
||||
Upstream* get_upstream();
|
||||
Upstream *get_upstream();
|
||||
|
||||
void pool_downstream_connection(std::unique_ptr<DownstreamConnection> dconn);
|
||||
void remove_downstream_connection(DownstreamConnection *dconn);
|
||||
std::unique_ptr<DownstreamConnection> get_downstream_connection();
|
||||
size_t get_outbuf_length();
|
||||
SSL* get_ssl() const;
|
||||
SSL *get_ssl() const;
|
||||
void set_http2_session(Http2Session *http2session);
|
||||
Http2Session* get_http2_session() const;
|
||||
Http2Session *get_http2_session() const;
|
||||
void set_http1_connect_blocker(ConnectBlocker *http1_connect_blocker);
|
||||
ConnectBlocker* get_http1_connect_blocker() const;
|
||||
ConnectBlocker *get_http1_connect_blocker() const;
|
||||
// Call this function when HTTP/2 connection header is received at
|
||||
// the start of the connection.
|
||||
void direct_http2_upgrade();
|
||||
@ -115,6 +114,7 @@ public:
|
||||
// corresponding Downstream object is not available.
|
||||
void write_accesslog(int major, int minor, unsigned int status,
|
||||
int64_t body_bytes_sent);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Upstream> upstream_;
|
||||
std::string ipaddr_;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -133,21 +133,12 @@ union sockaddr_union {
|
||||
sockaddr_in in;
|
||||
};
|
||||
|
||||
enum shrpx_proto {
|
||||
PROTO_HTTP2,
|
||||
PROTO_HTTP
|
||||
};
|
||||
enum shrpx_proto { PROTO_HTTP2, PROTO_HTTP };
|
||||
|
||||
struct AltSvc {
|
||||
AltSvc()
|
||||
: protocol_id(nullptr),
|
||||
host(nullptr),
|
||||
origin(nullptr),
|
||||
protocol_id_len(0),
|
||||
host_len(0),
|
||||
origin_len(0),
|
||||
port(0)
|
||||
{}
|
||||
: protocol_id(nullptr), host(nullptr), origin(nullptr),
|
||||
protocol_id_len(0), host_len(0), origin_len(0), port(0) {}
|
||||
|
||||
char *protocol_id;
|
||||
char *host;
|
||||
@ -208,10 +199,10 @@ struct Config {
|
||||
// list of supported NPN/ALPN protocol strings in the order of
|
||||
// preference. The each element of this list is a NULL-terminated
|
||||
// string.
|
||||
std::vector<char*> npn_list;
|
||||
std::vector<char *> npn_list;
|
||||
// list of supported SSL/TLS protocol strings. The each element of
|
||||
// this list is a NULL-terminated string.
|
||||
std::vector<char*> tls_proto_list;
|
||||
std::vector<char *> tls_proto_list;
|
||||
// Path to file containing CA certificate solely used for client
|
||||
// certificate validation
|
||||
std::unique_ptr<char[]> verify_client_cacert;
|
||||
@ -285,8 +276,8 @@ struct Config {
|
||||
bool no_location_rewrite;
|
||||
};
|
||||
|
||||
const Config* get_config();
|
||||
Config* mod_config();
|
||||
const Config *get_config();
|
||||
Config *mod_config();
|
||||
void create_config();
|
||||
|
||||
// Parses option name |opt| and value |optarg|. The results are
|
||||
@ -310,12 +301,12 @@ std::string read_passwd_from_file(const char *filename);
|
||||
// |s| and the caller must leave it as is after this call. This
|
||||
// function copies |s| and first element in the return value points to
|
||||
// it. It is caller's responsibility to deallocate its memory.
|
||||
std::vector<char*> parse_config_str_list(const char *s);
|
||||
std::vector<char *> parse_config_str_list(const char *s);
|
||||
|
||||
// Clears all elements of |list|, which is returned by
|
||||
// parse_config_str_list(). If list is not empty, list[0] is freed by
|
||||
// free(2). After this call, list.empty() must be true.
|
||||
void clear_config_str_list(std::vector<char*>& list);
|
||||
void clear_config_str_list(std::vector<char *> &list);
|
||||
|
||||
// Parses header field in |optarg|. We expect header field is formed
|
||||
// like "NAME: VALUE". We require that NAME is non empty string. ":"
|
||||
@ -333,15 +324,15 @@ std::unique_ptr<char[]> strcopy(const char *val);
|
||||
std::unique_ptr<char[]> strcopy(const char *val, size_t n);
|
||||
|
||||
// Returns a copy of val.c_str().
|
||||
std::unique_ptr<char[]> strcopy(const std::string& val);
|
||||
std::unique_ptr<char[]> strcopy(const std::string &val);
|
||||
|
||||
// Returns string for syslog |facility|.
|
||||
const char* str_syslog_facility(int facility);
|
||||
const char *str_syslog_facility(int facility);
|
||||
|
||||
// Returns integer value of syslog |facility| string.
|
||||
int int_syslog_facility(const char *strfacility);
|
||||
|
||||
FILE* open_file_for_write(const char *filename);
|
||||
FILE *open_file_for_write(const char *filename);
|
||||
|
||||
} // namespace shrpx
|
||||
|
||||
|
@ -30,8 +30,7 @@
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
void test_shrpx_config_parse_config_str_list(void)
|
||||
{
|
||||
void test_shrpx_config_parse_config_str_list(void) {
|
||||
auto res = parse_config_str_list("a");
|
||||
CU_ASSERT(1 == res.size());
|
||||
CU_ASSERT(0 == strcmp("a", res[0]));
|
||||
@ -64,8 +63,7 @@ void test_shrpx_config_parse_config_str_list(void)
|
||||
clear_config_str_list(res);
|
||||
}
|
||||
|
||||
void test_shrpx_config_parse_header(void)
|
||||
{
|
||||
void test_shrpx_config_parse_header(void) {
|
||||
auto p = parse_header("a: b");
|
||||
CU_ASSERT("a" == p.first);
|
||||
CU_ASSERT("b" == p.second);
|
||||
@ -90,8 +88,7 @@ void test_shrpx_config_parse_header(void)
|
||||
CU_ASSERT("bravo charlie" == p.second);
|
||||
}
|
||||
|
||||
void test_shrpx_config_parse_log_format(void)
|
||||
{
|
||||
void test_shrpx_config_parse_log_format(void) {
|
||||
auto res = parse_log_format("$remote_addr - $remote_user [$time_local] "
|
||||
"\"$request\" $status $body_bytes_sent "
|
||||
"\"$http_referer\" \"$http_user_agent\"");
|
||||
|
@ -30,50 +30,39 @@ namespace {
|
||||
const int INITIAL_SLEEP = 2;
|
||||
} // namespace
|
||||
|
||||
ConnectBlocker::ConnectBlocker()
|
||||
: timerev_(nullptr),
|
||||
sleep_(INITIAL_SLEEP)
|
||||
{}
|
||||
ConnectBlocker::ConnectBlocker() : timerev_(nullptr), sleep_(INITIAL_SLEEP) {}
|
||||
|
||||
ConnectBlocker::~ConnectBlocker()
|
||||
{
|
||||
if(timerev_) {
|
||||
ConnectBlocker::~ConnectBlocker() {
|
||||
if (timerev_) {
|
||||
event_free(timerev_);
|
||||
}
|
||||
}
|
||||
|
||||
namespace {
|
||||
void connect_blocker_cb(evutil_socket_t sig, short events, void *arg)
|
||||
{
|
||||
if(LOG_ENABLED(INFO)) {
|
||||
void connect_blocker_cb(evutil_socket_t sig, short events, void *arg) {
|
||||
if (LOG_ENABLED(INFO)) {
|
||||
LOG(INFO) << "unblock downstream connection";
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
int ConnectBlocker::init(event_base *evbase)
|
||||
{
|
||||
int ConnectBlocker::init(event_base *evbase) {
|
||||
timerev_ = evtimer_new(evbase, connect_blocker_cb, this);
|
||||
|
||||
if(timerev_ == nullptr) {
|
||||
if (timerev_ == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool ConnectBlocker::blocked() const
|
||||
{
|
||||
bool ConnectBlocker::blocked() const {
|
||||
return evtimer_pending(timerev_, nullptr);
|
||||
}
|
||||
|
||||
void ConnectBlocker::on_success()
|
||||
{
|
||||
sleep_ = INITIAL_SLEEP;
|
||||
}
|
||||
void ConnectBlocker::on_success() { sleep_ = INITIAL_SLEEP; }
|
||||
|
||||
void ConnectBlocker::on_failure()
|
||||
{
|
||||
void ConnectBlocker::on_failure() {
|
||||
int rv;
|
||||
|
||||
sleep_ = std::min(128, sleep_ * 2);
|
||||
@ -84,7 +73,7 @@ void ConnectBlocker::on_failure()
|
||||
|
||||
rv = evtimer_add(timerev_, &t);
|
||||
|
||||
if(rv == -1) {
|
||||
if (rv == -1) {
|
||||
LOG(ERROR) << "evtimer_add for ConnectBlocker timerev_ failed";
|
||||
}
|
||||
}
|
||||
|
@ -45,6 +45,7 @@ public:
|
||||
// Call this function if connect operation failed. This will start
|
||||
// timer and blocks connection establishment for sleep_ seconds.
|
||||
void on_failure();
|
||||
|
||||
private:
|
||||
event *timerev_;
|
||||
int sleep_;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -54,7 +54,7 @@ public:
|
||||
Downstream(Upstream *upstream, int32_t stream_id, int32_t priority);
|
||||
~Downstream();
|
||||
void reset_upstream(Upstream *upstream);
|
||||
Upstream* get_upstream() const;
|
||||
Upstream *get_upstream() const;
|
||||
void set_stream_id(int32_t stream_id);
|
||||
int32_t get_stream_id() const;
|
||||
void set_priority(int32_t pri);
|
||||
@ -66,12 +66,11 @@ public:
|
||||
void set_downstream_stream_id(int32_t stream_id);
|
||||
int32_t get_downstream_stream_id() const;
|
||||
|
||||
int attach_downstream_connection
|
||||
(std::unique_ptr<DownstreamConnection> dconn);
|
||||
int attach_downstream_connection(std::unique_ptr<DownstreamConnection> dconn);
|
||||
void detach_downstream_connection();
|
||||
// Releases dconn_, without freeing it.
|
||||
void release_downstream_connection();
|
||||
DownstreamConnection* get_downstream_connection();
|
||||
DownstreamConnection *get_downstream_connection();
|
||||
// Returns dconn_ and nullifies dconn_.
|
||||
std::unique_ptr<DownstreamConnection> pop_downstream_connection();
|
||||
|
||||
@ -93,12 +92,12 @@ public:
|
||||
// Returns true if the request is HTTP Upgrade for HTTP/2
|
||||
bool get_http2_upgrade_request() const;
|
||||
// Returns the value of HTTP2-Settings request header field.
|
||||
const std::string& get_http2_settings() const;
|
||||
const std::string &get_http2_settings() const;
|
||||
// downstream request API
|
||||
const Headers& get_request_headers() const;
|
||||
const Headers &get_request_headers() const;
|
||||
void crumble_request_cookie();
|
||||
void assemble_request_cookie();
|
||||
const std::string& get_assembled_request_cookie() const;
|
||||
const std::string &get_assembled_request_cookie() const;
|
||||
// Makes key lowercase and sort headers by name using <
|
||||
void normalize_request_headers();
|
||||
// Returns iterator pointing to the request header with the name
|
||||
@ -106,14 +105,13 @@ public:
|
||||
// occurrence from the beginning. If no such header is found,
|
||||
// returns std::end(get_request_headers()). This function must be
|
||||
// called after calling normalize_request_headers().
|
||||
Headers::const_iterator get_norm_request_header
|
||||
(const std::string& name) const;
|
||||
Headers::const_iterator
|
||||
get_norm_request_header(const std::string &name) const;
|
||||
// Returns iterator pointing to the request header with the name
|
||||
// |name|. This function acts like get_norm_request_header(), but
|
||||
// if request_headers_ was not normalized, use linear search to find
|
||||
// the header. Otherwise, get_norm_request_header() is used.
|
||||
Headers::const_iterator get_request_header
|
||||
(const std::string& name) const;
|
||||
Headers::const_iterator get_request_header(const std::string &name) const;
|
||||
bool get_request_headers_normalized() const;
|
||||
void add_request_header(std::string name, std::string value);
|
||||
void set_last_request_header_value(std::string value);
|
||||
@ -131,19 +129,21 @@ public:
|
||||
size_t get_request_headers_sum() const;
|
||||
|
||||
void set_request_method(std::string method);
|
||||
const std::string& get_request_method() const;
|
||||
const std::string &get_request_method() const;
|
||||
void set_request_path(std::string path);
|
||||
void set_request_start_time(std::chrono::high_resolution_clock::time_point time);
|
||||
const std::chrono::high_resolution_clock::time_point& get_request_start_time() const;
|
||||
void
|
||||
set_request_start_time(std::chrono::high_resolution_clock::time_point time);
|
||||
const std::chrono::high_resolution_clock::time_point &
|
||||
get_request_start_time() const;
|
||||
void append_request_path(const char *data, size_t len);
|
||||
// Returns request path. For HTTP/1.1, this is request-target. For
|
||||
// HTTP/2, this is :path header field value.
|
||||
const std::string& get_request_path() const;
|
||||
const std::string &get_request_path() const;
|
||||
// Returns HTTP/2 :scheme header field value.
|
||||
const std::string& get_request_http2_scheme() const;
|
||||
const std::string &get_request_http2_scheme() const;
|
||||
void set_request_http2_scheme(std::string scheme);
|
||||
// Returns HTTP/2 :authority header field value.
|
||||
const std::string& get_request_http2_authority() const;
|
||||
const std::string &get_request_http2_authority() const;
|
||||
void set_request_http2_authority(std::string authority);
|
||||
void set_request_major(int major);
|
||||
void set_request_minor(int minor);
|
||||
@ -175,7 +175,7 @@ public:
|
||||
void set_request_state(int state);
|
||||
int get_request_state() const;
|
||||
// downstream response API
|
||||
const Headers& get_response_headers() const;
|
||||
const Headers &get_response_headers() const;
|
||||
// Makes key lowercase and sort headers by name using <
|
||||
void normalize_response_headers();
|
||||
// Returns iterator pointing to the response header with the name
|
||||
@ -183,14 +183,13 @@ public:
|
||||
// occurrence from the beginning. If no such header is found,
|
||||
// returns std::end(get_response_headers()). This function must be
|
||||
// called after calling normalize_response_headers().
|
||||
Headers::const_iterator get_norm_response_header
|
||||
(const std::string& name) const;
|
||||
Headers::const_iterator
|
||||
get_norm_response_header(const std::string &name) const;
|
||||
// Rewrites the location response header field. This function must
|
||||
// be called after calling normalize_response_headers() and
|
||||
// normalize_request_headers().
|
||||
void rewrite_norm_location_response_header
|
||||
(const std::string& upstream_scheme,
|
||||
uint16_t upstream_port);
|
||||
void rewrite_norm_location_response_header(const std::string &upstream_scheme,
|
||||
uint16_t upstream_port);
|
||||
void add_response_header(std::string name, std::string value);
|
||||
void set_last_response_header_value(std::string value);
|
||||
|
||||
@ -220,7 +219,7 @@ public:
|
||||
void set_response_state(int state);
|
||||
int get_response_state() const;
|
||||
int init_response_body_buf();
|
||||
evbuffer* get_response_body_buf();
|
||||
evbuffer *get_response_body_buf();
|
||||
void add_response_bodylen(size_t amount);
|
||||
int64_t get_response_bodylen() const;
|
||||
void add_response_sent_bodylen(size_t amount);
|
||||
@ -282,6 +281,7 @@ public:
|
||||
|
||||
// Returns true if accesslog can be written for this downstream.
|
||||
bool accesslog_ready() const;
|
||||
|
||||
private:
|
||||
Headers request_headers_;
|
||||
Headers response_headers_;
|
||||
|
@ -30,33 +30,22 @@
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
DownstreamConnection::DownstreamConnection
|
||||
(DownstreamConnectionPool *dconn_pool)
|
||||
: dconn_pool_(dconn_pool),
|
||||
client_handler_(nullptr),
|
||||
downstream_(nullptr)
|
||||
{}
|
||||
DownstreamConnection::DownstreamConnection(DownstreamConnectionPool *dconn_pool)
|
||||
: dconn_pool_(dconn_pool), client_handler_(nullptr), downstream_(nullptr) {}
|
||||
|
||||
DownstreamConnection::~DownstreamConnection()
|
||||
{}
|
||||
DownstreamConnection::~DownstreamConnection() {}
|
||||
|
||||
void DownstreamConnection::set_client_handler(ClientHandler *handler)
|
||||
{
|
||||
void DownstreamConnection::set_client_handler(ClientHandler *handler) {
|
||||
client_handler_ = handler;
|
||||
}
|
||||
|
||||
ClientHandler* DownstreamConnection::get_client_handler()
|
||||
{
|
||||
ClientHandler *DownstreamConnection::get_client_handler() {
|
||||
return client_handler_;
|
||||
}
|
||||
|
||||
Downstream* DownstreamConnection::get_downstream()
|
||||
{
|
||||
return downstream_;
|
||||
}
|
||||
Downstream *DownstreamConnection::get_downstream() { return downstream_; }
|
||||
|
||||
DownstreamConnectionPool* DownstreamConnection::get_dconn_pool() const
|
||||
{
|
||||
DownstreamConnectionPool *DownstreamConnection::get_dconn_pool() const {
|
||||
return dconn_pool_;
|
||||
}
|
||||
|
||||
|
@ -61,9 +61,10 @@ public:
|
||||
virtual int on_priority_change(int32_t pri) = 0;
|
||||
|
||||
void set_client_handler(ClientHandler *client_handler);
|
||||
ClientHandler* get_client_handler();
|
||||
Downstream* get_downstream();
|
||||
DownstreamConnectionPool* get_dconn_pool() const;
|
||||
ClientHandler *get_client_handler();
|
||||
Downstream *get_downstream();
|
||||
DownstreamConnectionPool *get_dconn_pool() const;
|
||||
|
||||
protected:
|
||||
DownstreamConnectionPool *dconn_pool_;
|
||||
ClientHandler *client_handler_;
|
||||
|
@ -27,26 +27,22 @@
|
||||
|
||||
namespace shrpx {
|
||||
|
||||
DownstreamConnectionPool::DownstreamConnectionPool()
|
||||
{}
|
||||
DownstreamConnectionPool::DownstreamConnectionPool() {}
|
||||
|
||||
DownstreamConnectionPool::~DownstreamConnectionPool()
|
||||
{
|
||||
for(auto dconn : pool_) {
|
||||
DownstreamConnectionPool::~DownstreamConnectionPool() {
|
||||
for (auto dconn : pool_) {
|
||||
delete dconn;
|
||||
}
|
||||
}
|
||||
|
||||
void DownstreamConnectionPool::add_downstream_connection
|
||||
(std::unique_ptr<DownstreamConnection> dconn)
|
||||
{
|
||||
void DownstreamConnectionPool::add_downstream_connection(
|
||||
std::unique_ptr<DownstreamConnection> dconn) {
|
||||
pool_.insert(dconn.release());
|
||||
}
|
||||
|
||||
std::unique_ptr<DownstreamConnection>
|
||||
DownstreamConnectionPool::pop_downstream_connection()
|
||||
{
|
||||
if(pool_.empty()) {
|
||||
DownstreamConnectionPool::pop_downstream_connection() {
|
||||
if (pool_.empty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
@ -55,9 +51,8 @@ DownstreamConnectionPool::pop_downstream_connection()
|
||||
return dconn;
|
||||
}
|
||||
|
||||
void DownstreamConnectionPool::remove_downstream_connection
|
||||
(DownstreamConnection *dconn)
|
||||
{
|
||||
void DownstreamConnectionPool::remove_downstream_connection(
|
||||
DownstreamConnection *dconn) {
|
||||
pool_.erase(dconn);
|
||||
delete dconn;
|
||||
}
|
||||
|
@ -42,8 +42,9 @@ public:
|
||||
void add_downstream_connection(std::unique_ptr<DownstreamConnection> dconn);
|
||||
std::unique_ptr<DownstreamConnection> pop_downstream_connection();
|
||||
void remove_downstream_connection(DownstreamConnection *dconn);
|
||||
|
||||
private:
|
||||
std::set<DownstreamConnection*> pool_;
|
||||
std::set<DownstreamConnection *> pool_;
|
||||
};
|
||||
|
||||
} // namespace shrpx
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user