Add nghttpd and 24 bytes client connection header support

This commit is contained in:
Tatsuhiro Tsujikawa 2013-07-22 21:30:40 +09:00
parent 6bc7e7bd0b
commit 9e9a7fb160
6 changed files with 1366 additions and 3 deletions

View File

@ -52,6 +52,9 @@ typedef struct nghttp2_session nghttp2_session;
#define NGHTTP2_PRI_DEFAULT (1 << 30) #define NGHTTP2_PRI_DEFAULT (1 << 30)
#define NGHTTP2_PRI_LOWEST ((1U << 31) - 1) #define NGHTTP2_PRI_LOWEST ((1U << 31) - 1)
#define NGHTTP2_CLIENT_CONNECTION_HEADER "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
#define NGHTTP2_CLIENT_CONNECTION_HEADER_LEN 24
/** /**
* @enum * @enum
* *

1024
src/HttpServer.cc Normal file

File diff suppressed because it is too large Load Diff

147
src/HttpServer.h Normal file
View File

@ -0,0 +1,147 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2013 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of 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.
*/
#ifndef HTTP_SERVER_H
#define HTTP_SERVER_H
#include "nghttp2_config.h"
#include <stdint.h>
#include <sys/types.h>
#include <cstdlib>
#include <string>
#include <vector>
#include <map>
#include <memory>
#include <openssl/ssl.h>
#include <event2/bufferevent.h>
#include <nghttp2/nghttp2.h>
namespace nghttp2 {
struct Config {
std::string htdocs;
bool verbose;
bool daemon;
std::string host;
uint16_t port;
std::string private_key_file;
std::string cert_file;
nghttp2_on_request_recv_callback on_request_recv_callback;
void *data_ptr;
bool verify_client;
bool no_tls;
size_t output_upper_thres;
Config();
};
class Sessions;
struct Request {
int32_t stream_id;
std::vector<std::pair<std::string, std::string>> headers;
int file;
std::pair<std::string, size_t> response_body;
Request(int32_t stream_id);
~Request();
};
class Sessions;
class Http2Handler {
public:
Http2Handler(Sessions *sessions, int fd, SSL *ssl, int64_t session_id);
~Http2Handler();
void remove_self();
int setup_bev();
int on_read();
int on_write();
int on_connect();
int verify_npn_result();
int sendcb(const uint8_t *data, size_t len);
int recvcb(uint8_t *buf, size_t len);
int submit_file_response(const std::string& status,
int32_t stream_id,
time_t last_modified,
off_t file_length,
nghttp2_data_provider *data_prd);
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 std::vector<std::pair<std::string, std::string>>& headers,
nghttp2_data_provider *data_prd);
void add_stream(int32_t stream_id, std::unique_ptr<Request> req);
void remove_stream(int32_t stream_id);
Request* get_stream(int32_t stream_id);
int64_t session_id() const;
Sessions* get_sessions() const;
const Config* get_config() const;
size_t get_left_connhd_len() const;
private:
nghttp2_session *session_;
Sessions *sessions_;
bufferevent *bev_;
int fd_;
SSL* ssl_;
int64_t session_id_;
uint8_t io_flags_;
std::map<int32_t, std::unique_ptr<Request>> id2req_;
size_t left_connhd_len_;
};
class HttpServer {
public:
HttpServer(const Config* config);
~HttpServer();
int listen();
int run();
private:
const Config *config_;
int sfd_[2];
};
void htdocs_on_request_recv_callback
(nghttp2_session *session, int32_t stream_id, 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
#endif // HTTP_SERVER_H

View File

@ -35,7 +35,7 @@ AM_CXXFLAGS = -std=c++11
LDADD = $(top_builddir)/lib/libnghttp2.la LDADD = $(top_builddir)/lib/libnghttp2.la
bin_PROGRAMS += spdycat nghttp bin_PROGRAMS += spdycat nghttp nghttpd
if ENABLE_SPDYD if ENABLE_SPDYD
bin_PROGRAMS += spdyd bin_PROGRAMS += spdyd
@ -76,6 +76,9 @@ nghttp_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttp.cc \
${HTML_PARSER_OBJECTS} ${HTML_PARSER_HFILES} \ ${HTML_PARSER_OBJECTS} ${HTML_PARSER_HFILES} \
http-parser/http_parser.c http-parser/http_parser.h http-parser/http_parser.c http-parser/http_parser.h
nghttpd_SOURCES = ${HELPER_OBJECTS} ${HELPER_HFILES} nghttpd.cc \
HttpServer.cc HttpServer.h
if ENABLE_SPDYD if ENABLE_SPDYD
SPDY_SERVER_OBJECTS = SpdyServer.cc SPDY_SERVER_OBJECTS = SpdyServer.cc
SPDY_SERVER_HFILES = SpdyServer.h SPDY_SERVER_HFILES = SpdyServer.h

View File

@ -449,7 +449,10 @@ struct HttpClient {
if(rv != 0) { if(rv != 0) {
return -1; return -1;
} }
// TODO Send connection header here // Send connection header here
bufferevent_write(bev, NGHTTP2_CLIENT_CONNECTION_HEADER,
NGHTTP2_CLIENT_CONNECTION_HEADER_LEN);
nghttp2_settings_entry iv[1]; nghttp2_settings_entry iv[1];
size_t niv = 0; size_t niv = 0;
if(config.window_bits != -1) { if(config.window_bits != -1) {
@ -464,7 +467,7 @@ struct HttpClient {
for(auto& req : reqvec) { for(auto& req : reqvec) {
submit_request(this, config.headers, req.get()); submit_request(this, config.headers, req.get());
} }
return 0; return on_write();
} }
int on_read() int on_read()

183
src/nghttpd.cc Normal file
View File

@ -0,0 +1,183 @@
/*
* nghttp2 - HTTP/2.0 C Library
*
* Copyright (c) 2012 Tatsuhiro Tsujikawa
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of 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.
*/
#include <unistd.h>
#include <signal.h>
#include <getopt.h>
#include <cstdlib>
#include <cstring>
#include <cassert>
#include <string>
#include <iostream>
#include <string>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <nghttp2/nghttp2.h>
#include "nghttp2_ssl.h"
#include "HttpServer.h"
namespace nghttp2 {
extern bool ssl_debug;
namespace {
void print_usage(std::ostream& out)
{
out << "Usage: nghttpd [-DVhv] [-d <PATH>] [--no-tls] <PORT> [<PRIVATE_KEY> <CERT>]"
<< std::endl;
}
} // namespace
namespace {
void print_help(std::ostream& out)
{
print_usage(out);
out << "\n"
<< "OPTIONS:\n"
<< " -D, --daemon Run in a background. If -D is used, the\n"
<< " current working directory is changed to '/'.\n"
<< " Therefore if this option is used, -d option\n"
<< " must be specified.\n"
<< " -V, --verify-client\n"
<< " The server sends a client certificate\n"
<< " request. If the client did not return a\n"
<< " certificate, the handshake is terminated.\n"
<< " Currently, this option just requests a\n"
<< " client certificate and does not verify it.\n"
<< " -d, --htdocs=<PATH>\n"
<< " Specify document root. If this option is\n"
<< " not specified, the document root is the\n"
<< " current working directory.\n"
<< " -v, --verbose Print debug information such as reception/\n"
<< " transmission of frames and name/value pairs.\n"
<< " --no-tls Disable SSL/TLS.\n"
<< " -h, --help Print this help.\n"
<< std::endl;
}
} // namespace
int main(int argc, char **argv)
{
Config config;
while(1) {
int flag;
static option long_options[] = {
{"daemon", no_argument, 0, 'D' },
{"htdocs", required_argument, 0, 'd' },
{"help", no_argument, 0, 'h' },
{"verbose", no_argument, 0, 'v' },
{"verify-client", no_argument, 0, 'V' },
{"no-tls", no_argument, &flag, 1 },
{0, 0, 0, 0 }
};
int option_index = 0;
int c = getopt_long(argc, argv, "DVd:hv", long_options, &option_index);
if(c == -1) {
break;
}
switch(c) {
case 'D':
config.daemon = true;
break;
case 'V':
config.verify_client = true;
break;
case 'd':
config.htdocs = optarg;
break;
case 'h':
print_help(std::cout);
exit(EXIT_SUCCESS);
case 'v':
config.verbose = true;
break;
case '?':
exit(EXIT_FAILURE);
case 0:
switch(flag) {
case 1:
// no-tls option
config.no_tls = true;
break;
}
break;
default:
break;
}
}
if(argc - optind < (config.no_tls ? 1 : 3)) {
print_usage(std::cerr);
std::cerr << "Too few arguments" << std::endl;
exit(EXIT_FAILURE);
}
config.port = strtol(argv[optind++], nullptr, 10);
if(!config.no_tls) {
config.private_key_file = argv[optind++];
config.cert_file = argv[optind++];
}
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) {
perror("daemon");
exit(EXIT_FAILURE);
}
}
if(config.htdocs.empty()) {
config.htdocs = "./";
}
set_color_output(isatty(fileno(stdout)));
struct sigaction act;
memset(&act, 0, sizeof(struct sigaction));
act.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &act, nullptr);
OpenSSL_add_all_algorithms();
SSL_load_error_strings();
SSL_library_init();
reset_timer();
config.on_request_recv_callback = htdocs_on_request_recv_callback;
ssl_debug = config.verbose;
HttpServer server(&config);
server.run();
return 0;
}
} // namespace nghttp2
int main(int argc, char **argv)
{
return nghttp2::main(argc, argv);
}