1 /*
2 * nghttp2 - HTTP/2 C Library
3 *
4 * Copyright (c) 2013 Tatsuhiro Tsujikawa
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining
7 * a copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sublicense, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be
15 * included in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 */
25 #include "HttpServer.h"
26
27 #include <sys/stat.h>
28 #ifdef HAVE_SYS_SOCKET_H
29 # include <sys/socket.h>
30 #endif // HAVE_SYS_SOCKET_H
31 #ifdef HAVE_NETDB_H
32 # include <netdb.h>
33 #endif // HAVE_NETDB_H
34 #ifdef HAVE_UNISTD_H
35 # include <unistd.h>
36 #endif // HAVE_UNISTD_H
37 #ifdef HAVE_FCNTL_H
38 # include <fcntl.h>
39 #endif // HAVE_FCNTL_H
40 #ifdef HAVE_NETINET_IN_H
41 # include <netinet/in.h>
42 #endif // HAVE_NETINET_IN_H
43 #include <netinet/tcp.h>
44 #ifdef HAVE_ARPA_INET_H
45 # include <arpa/inet.h>
46 #endif // HAVE_ARPA_INET_H
47
48 #include <cassert>
49 #include <set>
50 #include <iostream>
51 #include <thread>
52 #include <mutex>
53 #include <deque>
54
55 #include "ssl_compat.h"
56
57 #include <openssl/err.h>
58 #include <openssl/dh.h>
59 #if OPENSSL_3_0_0_API
60 # include <openssl/decoder.h>
61 #endif // OPENSSL_3_0_0_API
62
63 #include <zlib.h>
64
65 #include "app_helper.h"
66 #include "http2.h"
67 #include "util.h"
68 #include "tls.h"
69 #include "template.h"
70
71 #ifndef O_BINARY
72 # define O_BINARY (0)
73 #endif // O_BINARY
74
75 using namespace std::chrono_literals;
76
77 namespace nghttp2 {
78
79 namespace {
80 // TODO could be constexpr
81 constexpr auto DEFAULT_HTML = "index.html"_sr;
82 constexpr auto NGHTTPD_SERVER = "nghttpd nghttp2/" NGHTTP2_VERSION ""_sr;
83 } // namespace
84
85 namespace {
delete_handler(Http2Handler * handler)86 void delete_handler(Http2Handler *handler) {
87 handler->remove_self();
88 delete handler;
89 }
90 } // namespace
91
92 namespace {
print_session_id(int64_t id)93 void print_session_id(int64_t id) { std::cout << "[id=" << id << "] "; }
94 } // namespace
95
Config()96 Config::Config()
97 : mime_types_file("/etc/mime.types"),
98 stream_read_timeout(1_min),
99 stream_write_timeout(1_min),
100 data_ptr(nullptr),
101 padding(0),
102 num_worker(1),
103 max_concurrent_streams(100),
104 header_table_size(-1),
105 encoder_header_table_size(-1),
106 window_bits(-1),
107 connection_window_bits(-1),
108 port(0),
109 verbose(false),
110 daemon(false),
111 verify_client(false),
112 no_tls(false),
113 error_gzip(false),
114 early_response(false),
115 hexdump(false),
116 echo_upload(false),
117 no_content_length(false),
118 ktls(false),
119 no_rfc7540_pri(false) {}
120
~Config()121 Config::~Config() {}
122
123 namespace {
stream_timeout_cb(struct ev_loop * loop,ev_timer * w,int revents)124 void stream_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
125 int rv;
126 auto stream = static_cast<Stream *>(w->data);
127 auto hd = stream->handler;
128 auto config = hd->get_config();
129
130 ev_timer_stop(hd->get_loop(), &stream->rtimer);
131 ev_timer_stop(hd->get_loop(), &stream->wtimer);
132
133 if (config->verbose) {
134 print_session_id(hd->session_id());
135 print_timer();
136 std::cout << " timeout stream_id=" << stream->stream_id << std::endl;
137 }
138
139 hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
140
141 rv = hd->on_write();
142 if (rv == -1) {
143 delete_handler(hd);
144 }
145 }
146 } // namespace
147
148 namespace {
add_stream_read_timeout(Stream * stream)149 void add_stream_read_timeout(Stream *stream) {
150 auto hd = stream->handler;
151 ev_timer_again(hd->get_loop(), &stream->rtimer);
152 }
153 } // namespace
154
155 namespace {
add_stream_read_timeout_if_pending(Stream * stream)156 void add_stream_read_timeout_if_pending(Stream *stream) {
157 auto hd = stream->handler;
158 if (ev_is_active(&stream->rtimer)) {
159 ev_timer_again(hd->get_loop(), &stream->rtimer);
160 }
161 }
162 } // namespace
163
164 namespace {
add_stream_write_timeout(Stream * stream)165 void add_stream_write_timeout(Stream *stream) {
166 auto hd = stream->handler;
167 ev_timer_again(hd->get_loop(), &stream->wtimer);
168 }
169 } // namespace
170
171 namespace {
remove_stream_read_timeout(Stream * stream)172 void remove_stream_read_timeout(Stream *stream) {
173 auto hd = stream->handler;
174 ev_timer_stop(hd->get_loop(), &stream->rtimer);
175 }
176 } // namespace
177
178 namespace {
remove_stream_write_timeout(Stream * stream)179 void remove_stream_write_timeout(Stream *stream) {
180 auto hd = stream->handler;
181 ev_timer_stop(hd->get_loop(), &stream->wtimer);
182 }
183 } // namespace
184
185 namespace {
186 void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config);
187 } // namespace
188
189 namespace {
190 constexpr ev_tstamp RELEASE_FD_TIMEOUT = 2.;
191 } // namespace
192
193 namespace {
194 void release_fd_cb(struct ev_loop *loop, ev_timer *w, int revents);
195 } // namespace
196
197 namespace {
198 constexpr auto FILE_ENTRY_MAX_AGE = 10s;
199 } // namespace
200
201 namespace {
202 constexpr size_t FILE_ENTRY_EVICT_THRES = 2048;
203 } // namespace
204
205 namespace {
need_validation_file_entry(const FileEntry * ent,const std::chrono::steady_clock::time_point & now)206 bool need_validation_file_entry(
207 const FileEntry *ent, const std::chrono::steady_clock::time_point &now) {
208 return ent->last_valid + FILE_ENTRY_MAX_AGE < now;
209 }
210 } // namespace
211
212 namespace {
validate_file_entry(FileEntry * ent,const std::chrono::steady_clock::time_point & now)213 bool validate_file_entry(FileEntry *ent,
214 const std::chrono::steady_clock::time_point &now) {
215 struct stat stbuf;
216 int rv;
217
218 rv = fstat(ent->fd, &stbuf);
219 if (rv != 0) {
220 ent->stale = true;
221 return false;
222 }
223
224 if (stbuf.st_nlink == 0 || ent->mtime != stbuf.st_mtime) {
225 ent->stale = true;
226 return false;
227 }
228
229 ent->mtime = stbuf.st_mtime;
230 ent->last_valid = now;
231
232 return true;
233 }
234 } // namespace
235
236 class Sessions {
237 public:
Sessions(HttpServer * sv,struct ev_loop * loop,const Config * config,SSL_CTX * ssl_ctx)238 Sessions(HttpServer *sv, struct ev_loop *loop, const Config *config,
239 SSL_CTX *ssl_ctx)
240 : sv_(sv),
241 loop_(loop),
242 config_(config),
243 ssl_ctx_(ssl_ctx),
244 callbacks_(nullptr),
245 option_(nullptr),
246 next_session_id_(1),
247 tstamp_cached_(ev_now(loop)),
248 cached_date_(util::http_date(tstamp_cached_)) {
249 nghttp2_session_callbacks_new(&callbacks_);
250
251 fill_callback(callbacks_, config_);
252
253 nghttp2_option_new(&option_);
254
255 if (config_->encoder_header_table_size != -1) {
256 nghttp2_option_set_max_deflate_dynamic_table_size(
257 option_, config_->encoder_header_table_size);
258 }
259
260 ev_timer_init(&release_fd_timer_, release_fd_cb, 0., RELEASE_FD_TIMEOUT);
261 release_fd_timer_.data = this;
262 }
~Sessions()263 ~Sessions() {
264 ev_timer_stop(loop_, &release_fd_timer_);
265 for (auto handler : handlers_) {
266 delete handler;
267 }
268 nghttp2_option_del(option_);
269 nghttp2_session_callbacks_del(callbacks_);
270 }
add_handler(Http2Handler * handler)271 void add_handler(Http2Handler *handler) { handlers_.insert(handler); }
remove_handler(Http2Handler * handler)272 void remove_handler(Http2Handler *handler) {
273 handlers_.erase(handler);
274 if (handlers_.empty() && !fd_cache_.empty()) {
275 ev_timer_again(loop_, &release_fd_timer_);
276 }
277 }
get_ssl_ctx() const278 SSL_CTX *get_ssl_ctx() const { return ssl_ctx_; }
ssl_session_new(int fd)279 SSL *ssl_session_new(int fd) {
280 SSL *ssl = SSL_new(ssl_ctx_);
281 if (!ssl) {
282 std::cerr << "SSL_new() failed" << std::endl;
283 return nullptr;
284 }
285 if (SSL_set_fd(ssl, fd) == 0) {
286 std::cerr << "SSL_set_fd() failed" << std::endl;
287 SSL_free(ssl);
288 return nullptr;
289 }
290 return ssl;
291 }
get_config() const292 const Config *get_config() const { return config_; }
get_loop() const293 struct ev_loop *get_loop() const { return loop_; }
get_next_session_id()294 int64_t get_next_session_id() {
295 auto session_id = next_session_id_;
296 if (next_session_id_ == std::numeric_limits<int64_t>::max()) {
297 next_session_id_ = 1;
298 } else {
299 ++next_session_id_;
300 }
301 return session_id;
302 }
get_callbacks() const303 const nghttp2_session_callbacks *get_callbacks() const { return callbacks_; }
get_option() const304 const nghttp2_option *get_option() const { return option_; }
accept_connection(int fd)305 void accept_connection(int fd) {
306 util::make_socket_nodelay(fd);
307 SSL *ssl = nullptr;
308 if (ssl_ctx_) {
309 ssl = ssl_session_new(fd);
310 if (!ssl) {
311 close(fd);
312 return;
313 }
314 }
315 auto handler =
316 std::make_unique<Http2Handler>(this, fd, ssl, get_next_session_id());
317 if (!ssl) {
318 if (handler->connection_made() != 0) {
319 return;
320 }
321 }
322 add_handler(handler.release());
323 }
update_cached_date()324 void update_cached_date() { cached_date_ = util::http_date(tstamp_cached_); }
get_cached_date()325 const std::string &get_cached_date() {
326 auto t = ev_now(loop_);
327 if (t != tstamp_cached_) {
328 tstamp_cached_ = t;
329 update_cached_date();
330 }
331 return cached_date_;
332 }
get_cached_fd(const std::string & path)333 FileEntry *get_cached_fd(const std::string &path) {
334 auto range = fd_cache_.equal_range(path);
335 if (range.first == range.second) {
336 return nullptr;
337 }
338
339 auto now = std::chrono::steady_clock::now();
340
341 for (auto it = range.first; it != range.second;) {
342 auto &ent = (*it).second;
343 if (ent->stale) {
344 ++it;
345 continue;
346 }
347 if (need_validation_file_entry(ent.get(), now) &&
348 !validate_file_entry(ent.get(), now)) {
349 if (ent->usecount == 0) {
350 fd_cache_lru_.remove(ent.get());
351 close(ent->fd);
352 it = fd_cache_.erase(it);
353 continue;
354 }
355 ++it;
356 continue;
357 }
358
359 fd_cache_lru_.remove(ent.get());
360 fd_cache_lru_.append(ent.get());
361
362 ++ent->usecount;
363 return ent.get();
364 }
365 return nullptr;
366 }
cache_fd(const std::string & path,const FileEntry & ent)367 FileEntry *cache_fd(const std::string &path, const FileEntry &ent) {
368 #ifdef HAVE_STD_MAP_EMPLACE
369 auto rv = fd_cache_.emplace(path, std::make_unique<FileEntry>(ent));
370 #else // !HAVE_STD_MAP_EMPLACE
371 // for gcc-4.7
372 auto rv = fd_cache_.insert(
373 std::make_pair(path, std::make_unique<FileEntry>(ent)));
374 #endif // !HAVE_STD_MAP_EMPLACE
375 auto &res = (*rv).second;
376 res->it = rv;
377 fd_cache_lru_.append(res.get());
378
379 while (fd_cache_.size() > FILE_ENTRY_EVICT_THRES) {
380 auto ent = fd_cache_lru_.head;
381 if (ent->usecount) {
382 break;
383 }
384 fd_cache_lru_.remove(ent);
385 close(ent->fd);
386 fd_cache_.erase(ent->it);
387 }
388
389 return res.get();
390 }
release_fd(FileEntry * target)391 void release_fd(FileEntry *target) {
392 --target->usecount;
393
394 if (target->usecount == 0 && target->stale) {
395 fd_cache_lru_.remove(target);
396 close(target->fd);
397 fd_cache_.erase(target->it);
398 return;
399 }
400
401 // We use timer to close file descriptor and delete the entry from
402 // cache. The timer will be started when there is no handler.
403 }
release_unused_fd()404 void release_unused_fd() {
405 for (auto i = std::begin(fd_cache_); i != std::end(fd_cache_);) {
406 auto &ent = (*i).second;
407 if (ent->usecount != 0) {
408 ++i;
409 continue;
410 }
411
412 fd_cache_lru_.remove(ent.get());
413 close(ent->fd);
414 i = fd_cache_.erase(i);
415 }
416 }
get_server() const417 const HttpServer *get_server() const { return sv_; }
handlers_empty() const418 bool handlers_empty() const { return handlers_.empty(); }
419
420 private:
421 std::set<Http2Handler *> handlers_;
422 // cache for file descriptors to read file.
423 std::multimap<std::string, std::unique_ptr<FileEntry>> fd_cache_;
424 DList<FileEntry> fd_cache_lru_;
425 HttpServer *sv_;
426 struct ev_loop *loop_;
427 const Config *config_;
428 SSL_CTX *ssl_ctx_;
429 nghttp2_session_callbacks *callbacks_;
430 nghttp2_option *option_;
431 ev_timer release_fd_timer_;
432 int64_t next_session_id_;
433 ev_tstamp tstamp_cached_;
434 std::string cached_date_;
435 };
436
437 namespace {
release_fd_cb(struct ev_loop * loop,ev_timer * w,int revents)438 void release_fd_cb(struct ev_loop *loop, ev_timer *w, int revents) {
439 auto sessions = static_cast<Sessions *>(w->data);
440
441 ev_timer_stop(loop, w);
442
443 if (!sessions->handlers_empty()) {
444 return;
445 }
446
447 sessions->release_unused_fd();
448 }
449 } // namespace
450
Stream(Http2Handler * handler,int32_t stream_id)451 Stream::Stream(Http2Handler *handler, int32_t stream_id)
452 : balloc(1024, 1024),
453 header{},
454 handler(handler),
455 file_ent(nullptr),
456 body_length(0),
457 body_offset(0),
458 header_buffer_size(0),
459 stream_id(stream_id),
460 echo_upload(false) {
461 auto config = handler->get_config();
462 ev_timer_init(&rtimer, stream_timeout_cb, 0., config->stream_read_timeout);
463 ev_timer_init(&wtimer, stream_timeout_cb, 0., config->stream_write_timeout);
464 rtimer.data = this;
465 wtimer.data = this;
466 }
467
~Stream()468 Stream::~Stream() {
469 if (file_ent != nullptr) {
470 auto sessions = handler->get_sessions();
471 sessions->release_fd(file_ent);
472 }
473
474 auto &rcbuf = header.rcbuf;
475 nghttp2_rcbuf_decref(rcbuf.method);
476 nghttp2_rcbuf_decref(rcbuf.scheme);
477 nghttp2_rcbuf_decref(rcbuf.authority);
478 nghttp2_rcbuf_decref(rcbuf.host);
479 nghttp2_rcbuf_decref(rcbuf.path);
480 nghttp2_rcbuf_decref(rcbuf.ims);
481 nghttp2_rcbuf_decref(rcbuf.expect);
482
483 auto loop = handler->get_loop();
484 ev_timer_stop(loop, &rtimer);
485 ev_timer_stop(loop, &wtimer);
486 }
487
488 namespace {
on_session_closed(Http2Handler * hd,int64_t session_id)489 void on_session_closed(Http2Handler *hd, int64_t session_id) {
490 if (hd->get_config()->verbose) {
491 print_session_id(session_id);
492 print_timer();
493 std::cout << " closed" << std::endl;
494 }
495 }
496 } // namespace
497
498 namespace {
settings_timeout_cb(struct ev_loop * loop,ev_timer * w,int revents)499 void settings_timeout_cb(struct ev_loop *loop, ev_timer *w, int revents) {
500 int rv;
501 auto hd = static_cast<Http2Handler *>(w->data);
502 hd->terminate_session(NGHTTP2_SETTINGS_TIMEOUT);
503 rv = hd->on_write();
504 if (rv == -1) {
505 delete_handler(hd);
506 }
507 }
508 } // namespace
509
510 namespace {
readcb(struct ev_loop * loop,ev_io * w,int revents)511 void readcb(struct ev_loop *loop, ev_io *w, int revents) {
512 int rv;
513 auto handler = static_cast<Http2Handler *>(w->data);
514
515 rv = handler->on_read();
516 if (rv == -1) {
517 delete_handler(handler);
518 }
519 }
520 } // namespace
521
522 namespace {
writecb(struct ev_loop * loop,ev_io * w,int revents)523 void writecb(struct ev_loop *loop, ev_io *w, int revents) {
524 int rv;
525 auto handler = static_cast<Http2Handler *>(w->data);
526
527 rv = handler->on_write();
528 if (rv == -1) {
529 delete_handler(handler);
530 }
531 }
532 } // namespace
533
Http2Handler(Sessions * sessions,int fd,SSL * ssl,int64_t session_id)534 Http2Handler::Http2Handler(Sessions *sessions, int fd, SSL *ssl,
535 int64_t session_id)
536 : session_id_(session_id),
537 session_(nullptr),
538 sessions_(sessions),
539 ssl_(ssl),
540 data_pending_(nullptr),
541 data_pendinglen_(0),
542 fd_(fd) {
543 ev_timer_init(&settings_timerev_, settings_timeout_cb, 10., 0.);
544 ev_io_init(&wev_, writecb, fd, EV_WRITE);
545 ev_io_init(&rev_, readcb, fd, EV_READ);
546
547 settings_timerev_.data = this;
548 wev_.data = this;
549 rev_.data = this;
550
551 auto loop = sessions_->get_loop();
552 ev_io_start(loop, &rev_);
553
554 if (ssl) {
555 SSL_set_accept_state(ssl);
556 read_ = &Http2Handler::tls_handshake;
557 write_ = &Http2Handler::tls_handshake;
558 } else {
559 read_ = &Http2Handler::read_clear;
560 write_ = &Http2Handler::write_clear;
561 }
562 }
563
~Http2Handler()564 Http2Handler::~Http2Handler() {
565 on_session_closed(this, session_id_);
566 nghttp2_session_del(session_);
567 if (ssl_) {
568 SSL_set_shutdown(ssl_, SSL_get_shutdown(ssl_) | SSL_RECEIVED_SHUTDOWN);
569 ERR_clear_error();
570 SSL_shutdown(ssl_);
571 }
572 auto loop = sessions_->get_loop();
573 ev_timer_stop(loop, &settings_timerev_);
574 ev_io_stop(loop, &rev_);
575 ev_io_stop(loop, &wev_);
576 if (ssl_) {
577 SSL_free(ssl_);
578 }
579 shutdown(fd_, SHUT_WR);
580 close(fd_);
581 }
582
remove_self()583 void Http2Handler::remove_self() { sessions_->remove_handler(this); }
584
get_loop() const585 struct ev_loop *Http2Handler::get_loop() const { return sessions_->get_loop(); }
586
get_wb()587 Http2Handler::WriteBuf *Http2Handler::get_wb() { return &wb_; }
588
start_settings_timer()589 void Http2Handler::start_settings_timer() {
590 ev_timer_start(sessions_->get_loop(), &settings_timerev_);
591 }
592
fill_wb()593 int Http2Handler::fill_wb() {
594 if (data_pending_) {
595 auto n = std::min(wb_.wleft(), data_pendinglen_);
596 wb_.write(data_pending_, n);
597 if (n < data_pendinglen_) {
598 data_pending_ += n;
599 data_pendinglen_ -= n;
600 return 0;
601 }
602
603 data_pending_ = nullptr;
604 data_pendinglen_ = 0;
605 }
606
607 for (;;) {
608 const uint8_t *data;
609 auto datalen = nghttp2_session_mem_send2(session_, &data);
610
611 if (datalen < 0) {
612 std::cerr << "nghttp2_session_mem_send2() returned error: "
613 << nghttp2_strerror(datalen) << std::endl;
614 return -1;
615 }
616 if (datalen == 0) {
617 break;
618 }
619 auto n = wb_.write(data, datalen);
620 if (n < static_cast<decltype(n)>(datalen)) {
621 data_pending_ = data + n;
622 data_pendinglen_ = datalen - n;
623 break;
624 }
625 }
626 return 0;
627 }
628
read_clear()629 int Http2Handler::read_clear() {
630 int rv;
631 std::array<uint8_t, 8_k> buf;
632
633 ssize_t nread;
634 while ((nread = read(fd_, buf.data(), buf.size())) == -1 && errno == EINTR)
635 ;
636 if (nread == -1) {
637 if (errno == EAGAIN || errno == EWOULDBLOCK) {
638 return write_(*this);
639 }
640 return -1;
641 }
642 if (nread == 0) {
643 return -1;
644 }
645
646 if (get_config()->hexdump) {
647 util::hexdump(stdout, buf.data(), nread);
648 }
649
650 rv = nghttp2_session_mem_recv2(session_, buf.data(), nread);
651 if (rv < 0) {
652 if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
653 std::cerr << "nghttp2_session_mem_recv2() returned error: "
654 << nghttp2_strerror(rv) << std::endl;
655 }
656 return -1;
657 }
658
659 return write_(*this);
660 }
661
write_clear()662 int Http2Handler::write_clear() {
663 auto loop = sessions_->get_loop();
664 for (;;) {
665 if (wb_.rleft() > 0) {
666 ssize_t nwrite;
667 while ((nwrite = write(fd_, wb_.pos, wb_.rleft())) == -1 &&
668 errno == EINTR)
669 ;
670 if (nwrite == -1) {
671 if (errno == EAGAIN || errno == EWOULDBLOCK) {
672 ev_io_start(loop, &wev_);
673 return 0;
674 }
675 return -1;
676 }
677 wb_.drain(nwrite);
678 continue;
679 }
680 wb_.reset();
681 if (fill_wb() != 0) {
682 return -1;
683 }
684 if (wb_.rleft() == 0) {
685 break;
686 }
687 }
688
689 if (wb_.rleft() == 0) {
690 ev_io_stop(loop, &wev_);
691 } else {
692 ev_io_start(loop, &wev_);
693 }
694
695 if (nghttp2_session_want_read(session_) == 0 &&
696 nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
697 return -1;
698 }
699
700 return 0;
701 }
702
tls_handshake()703 int Http2Handler::tls_handshake() {
704 ev_io_stop(sessions_->get_loop(), &wev_);
705
706 ERR_clear_error();
707
708 auto rv = SSL_do_handshake(ssl_);
709
710 if (rv <= 0) {
711 auto err = SSL_get_error(ssl_, rv);
712 switch (err) {
713 case SSL_ERROR_WANT_READ:
714 return 0;
715 case SSL_ERROR_WANT_WRITE:
716 ev_io_start(sessions_->get_loop(), &wev_);
717 return 0;
718 default:
719 return -1;
720 }
721 }
722
723 if (sessions_->get_config()->verbose) {
724 std::cerr << "SSL/TLS handshake completed" << std::endl;
725 }
726
727 if (verify_alpn_result() != 0) {
728 return -1;
729 }
730
731 read_ = &Http2Handler::read_tls;
732 write_ = &Http2Handler::write_tls;
733
734 if (connection_made() != 0) {
735 return -1;
736 }
737
738 if (sessions_->get_config()->verbose) {
739 if (SSL_session_reused(ssl_)) {
740 std::cerr << "SSL/TLS session reused" << std::endl;
741 }
742 }
743
744 return 0;
745 }
746
read_tls()747 int Http2Handler::read_tls() {
748 std::array<uint8_t, 8_k> buf;
749
750 ERR_clear_error();
751
752 for (;;) {
753 auto rv = SSL_read(ssl_, buf.data(), buf.size());
754
755 if (rv <= 0) {
756 auto err = SSL_get_error(ssl_, rv);
757 switch (err) {
758 case SSL_ERROR_WANT_READ:
759 return write_(*this);
760 case SSL_ERROR_WANT_WRITE:
761 // renegotiation started
762 return -1;
763 default:
764 return -1;
765 }
766 }
767
768 auto nread = rv;
769
770 if (get_config()->hexdump) {
771 util::hexdump(stdout, buf.data(), nread);
772 }
773
774 rv = nghttp2_session_mem_recv2(session_, buf.data(), nread);
775 if (rv < 0) {
776 if (rv != NGHTTP2_ERR_BAD_CLIENT_MAGIC) {
777 std::cerr << "nghttp2_session_mem_recv2() returned error: "
778 << nghttp2_strerror(rv) << std::endl;
779 }
780 return -1;
781 }
782
783 if (SSL_pending(ssl_) == 0) {
784 break;
785 }
786 }
787
788 return write_(*this);
789 }
790
write_tls()791 int Http2Handler::write_tls() {
792 auto loop = sessions_->get_loop();
793
794 ERR_clear_error();
795
796 for (;;) {
797 if (wb_.rleft() > 0) {
798 auto rv = SSL_write(ssl_, wb_.pos, wb_.rleft());
799
800 if (rv <= 0) {
801 auto err = SSL_get_error(ssl_, rv);
802 switch (err) {
803 case SSL_ERROR_WANT_READ:
804 // renegotiation started
805 return -1;
806 case SSL_ERROR_WANT_WRITE:
807 ev_io_start(sessions_->get_loop(), &wev_);
808 return 0;
809 default:
810 return -1;
811 }
812 }
813
814 wb_.drain(rv);
815 continue;
816 }
817 wb_.reset();
818 if (fill_wb() != 0) {
819 return -1;
820 }
821 if (wb_.rleft() == 0) {
822 break;
823 }
824 }
825
826 if (wb_.rleft() == 0) {
827 ev_io_stop(loop, &wev_);
828 } else {
829 ev_io_start(loop, &wev_);
830 }
831
832 if (nghttp2_session_want_read(session_) == 0 &&
833 nghttp2_session_want_write(session_) == 0 && wb_.rleft() == 0) {
834 return -1;
835 }
836
837 return 0;
838 }
839
on_read()840 int Http2Handler::on_read() { return read_(*this); }
841
on_write()842 int Http2Handler::on_write() { return write_(*this); }
843
connection_made()844 int Http2Handler::connection_made() {
845 int r;
846
847 r = nghttp2_session_server_new2(&session_, sessions_->get_callbacks(), this,
848 sessions_->get_option());
849
850 if (r != 0) {
851 return r;
852 }
853
854 auto config = sessions_->get_config();
855 std::array<nghttp2_settings_entry, 4> entry;
856 size_t niv = 1;
857
858 entry[0].settings_id = NGHTTP2_SETTINGS_MAX_CONCURRENT_STREAMS;
859 entry[0].value = config->max_concurrent_streams;
860
861 if (config->header_table_size >= 0) {
862 entry[niv].settings_id = NGHTTP2_SETTINGS_HEADER_TABLE_SIZE;
863 entry[niv].value = config->header_table_size;
864 ++niv;
865 }
866
867 if (config->window_bits != -1) {
868 entry[niv].settings_id = NGHTTP2_SETTINGS_INITIAL_WINDOW_SIZE;
869 entry[niv].value = (1 << config->window_bits) - 1;
870 ++niv;
871 }
872
873 if (config->no_rfc7540_pri) {
874 entry[niv].settings_id = NGHTTP2_SETTINGS_NO_RFC7540_PRIORITIES;
875 entry[niv].value = 1;
876 ++niv;
877 }
878
879 r = nghttp2_submit_settings(session_, NGHTTP2_FLAG_NONE, entry.data(), niv);
880 if (r != 0) {
881 return r;
882 }
883
884 if (config->connection_window_bits != -1) {
885 r = nghttp2_session_set_local_window_size(
886 session_, NGHTTP2_FLAG_NONE, 0,
887 (1 << config->connection_window_bits) - 1);
888 if (r != 0) {
889 return r;
890 }
891 }
892
893 if (ssl_ && !nghttp2::tls::check_http2_requirement(ssl_)) {
894 terminate_session(NGHTTP2_INADEQUATE_SECURITY);
895 }
896
897 return on_write();
898 }
899
verify_alpn_result()900 int Http2Handler::verify_alpn_result() {
901 const unsigned char *next_proto = nullptr;
902 unsigned int next_proto_len;
903 // Check the negotiated protocol in ALPN
904 SSL_get0_alpn_selected(ssl_, &next_proto, &next_proto_len);
905 if (next_proto) {
906 auto proto = StringRef{next_proto, next_proto_len};
907 if (sessions_->get_config()->verbose) {
908 std::cout << "The negotiated protocol: " << proto << std::endl;
909 }
910 if (util::check_h2_is_selected(proto)) {
911 return 0;
912 }
913 }
914 if (sessions_->get_config()->verbose) {
915 std::cerr << "Client did not advertise HTTP/2 protocol."
916 << " (nghttp2 expects " << NGHTTP2_PROTO_VERSION_ID << ")"
917 << std::endl;
918 }
919 return -1;
920 }
921
submit_file_response(const StringRef & status,Stream * stream,time_t last_modified,off_t file_length,const std::string * content_type,nghttp2_data_provider2 * data_prd)922 int Http2Handler::submit_file_response(const StringRef &status, Stream *stream,
923 time_t last_modified, off_t file_length,
924 const std::string *content_type,
925 nghttp2_data_provider2 *data_prd) {
926 std::string last_modified_str;
927 auto nva = std::to_array({
928 http2::make_field(":status"_sr, status),
929 http2::make_field("server"_sr, NGHTTPD_SERVER),
930 http2::make_field("cache-control"_sr, "max-age=3600"_sr),
931 http2::make_field_v("date"_sr, sessions_->get_cached_date()),
932 {},
933 {},
934 {},
935 {},
936 });
937 size_t nvlen = 4;
938 if (!get_config()->no_content_length) {
939 nva[nvlen++] = http2::make_field(
940 "content-length"_sr,
941 util::make_string_ref_uint(stream->balloc, file_length));
942 }
943 if (last_modified != 0) {
944 last_modified_str = util::http_date(last_modified);
945 nva[nvlen++] = http2::make_field_v("last-modified"_sr, last_modified_str);
946 }
947 if (content_type) {
948 nva[nvlen++] = http2::make_field_v("content-type"_sr, *content_type);
949 }
950 auto &trailer_names = get_config()->trailer_names;
951 if (!trailer_names.empty()) {
952 nva[nvlen++] = http2::make_field("trailer"_sr, trailer_names);
953 }
954 return nghttp2_submit_response2(session_, stream->stream_id, nva.data(),
955 nvlen, data_prd);
956 }
957
submit_response(const StringRef & status,int32_t stream_id,const HeaderRefs & headers,nghttp2_data_provider2 * data_prd)958 int Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
959 const HeaderRefs &headers,
960 nghttp2_data_provider2 *data_prd) {
961 auto nva = std::vector<nghttp2_nv>();
962 nva.reserve(4 + headers.size());
963 nva.push_back(http2::make_field(":status"_sr, status));
964 nva.push_back(http2::make_field("server"_sr, NGHTTPD_SERVER));
965 nva.push_back(http2::make_field_v("date"_sr, sessions_->get_cached_date()));
966
967 if (data_prd) {
968 auto &trailer_names = get_config()->trailer_names;
969 if (!trailer_names.empty()) {
970 nva.push_back(http2::make_field("trailer"_sr, trailer_names));
971 }
972 }
973
974 for (auto &nv : headers) {
975 nva.push_back(
976 http2::make_field(nv.name, nv.value, http2::no_index(nv.no_index)));
977 }
978 int r = nghttp2_submit_response2(session_, stream_id, nva.data(), nva.size(),
979 data_prd);
980 return r;
981 }
982
submit_response(const StringRef & status,int32_t stream_id,nghttp2_data_provider2 * data_prd)983 int Http2Handler::submit_response(const StringRef &status, int32_t stream_id,
984 nghttp2_data_provider2 *data_prd) {
985 auto nva = std::to_array({
986 http2::make_field(":status"_sr, status),
987 http2::make_field("server"_sr, NGHTTPD_SERVER),
988 http2::make_field_v("date"_sr, sessions_->get_cached_date()),
989 {},
990 });
991 size_t nvlen = 3;
992
993 if (data_prd) {
994 auto &trailer_names = get_config()->trailer_names;
995 if (!trailer_names.empty()) {
996 nva[nvlen++] = http2::make_field("trailer"_sr, trailer_names);
997 }
998 }
999
1000 return nghttp2_submit_response2(session_, stream_id, nva.data(), nvlen,
1001 data_prd);
1002 }
1003
submit_non_final_response(const std::string & status,int32_t stream_id)1004 int Http2Handler::submit_non_final_response(const std::string &status,
1005 int32_t stream_id) {
1006 auto nva = std::to_array({http2::make_field_v(":status"_sr, status)});
1007 return nghttp2_submit_headers(session_, NGHTTP2_FLAG_NONE, stream_id, nullptr,
1008 nva.data(), nva.size(), nullptr);
1009 }
1010
submit_push_promise(Stream * stream,const StringRef & push_path)1011 int Http2Handler::submit_push_promise(Stream *stream,
1012 const StringRef &push_path) {
1013 auto authority = stream->header.authority;
1014
1015 if (authority.empty()) {
1016 authority = stream->header.host;
1017 }
1018
1019 auto scheme = get_config()->no_tls ? "http"_sr : "https"_sr;
1020
1021 auto nva = std::to_array({http2::make_field(":method"_sr, "GET"_sr),
1022 http2::make_field(":path"_sr, push_path),
1023 http2::make_field(":scheme"_sr, scheme),
1024 http2::make_field(":authority"_sr, authority)});
1025
1026 auto promised_stream_id = nghttp2_submit_push_promise(
1027 session_, NGHTTP2_FLAG_END_HEADERS, stream->stream_id, nva.data(),
1028 nva.size(), nullptr);
1029
1030 if (promised_stream_id < 0) {
1031 return promised_stream_id;
1032 }
1033
1034 auto promised_stream = std::make_unique<Stream>(this, promised_stream_id);
1035
1036 auto &promised_header = promised_stream->header;
1037 promised_header.method = "GET"_sr;
1038 promised_header.path = push_path;
1039 promised_header.scheme = scheme;
1040 promised_header.authority =
1041 make_string_ref(promised_stream->balloc, authority);
1042
1043 add_stream(promised_stream_id, std::move(promised_stream));
1044
1045 return 0;
1046 }
1047
submit_rst_stream(Stream * stream,uint32_t error_code)1048 int Http2Handler::submit_rst_stream(Stream *stream, uint32_t error_code) {
1049 remove_stream_read_timeout(stream);
1050 remove_stream_write_timeout(stream);
1051
1052 return nghttp2_submit_rst_stream(session_, NGHTTP2_FLAG_NONE,
1053 stream->stream_id, error_code);
1054 }
1055
add_stream(int32_t stream_id,std::unique_ptr<Stream> stream)1056 void Http2Handler::add_stream(int32_t stream_id,
1057 std::unique_ptr<Stream> stream) {
1058 id2stream_[stream_id] = std::move(stream);
1059 }
1060
remove_stream(int32_t stream_id)1061 void Http2Handler::remove_stream(int32_t stream_id) {
1062 id2stream_.erase(stream_id);
1063 }
1064
get_stream(int32_t stream_id)1065 Stream *Http2Handler::get_stream(int32_t stream_id) {
1066 auto itr = id2stream_.find(stream_id);
1067 if (itr == std::end(id2stream_)) {
1068 return nullptr;
1069 } else {
1070 return (*itr).second.get();
1071 }
1072 }
1073
session_id() const1074 int64_t Http2Handler::session_id() const { return session_id_; }
1075
get_sessions() const1076 Sessions *Http2Handler::get_sessions() const { return sessions_; }
1077
get_config() const1078 const Config *Http2Handler::get_config() const {
1079 return sessions_->get_config();
1080 }
1081
remove_settings_timer()1082 void Http2Handler::remove_settings_timer() {
1083 ev_timer_stop(sessions_->get_loop(), &settings_timerev_);
1084 }
1085
terminate_session(uint32_t error_code)1086 void Http2Handler::terminate_session(uint32_t error_code) {
1087 nghttp2_session_terminate_session(session_, error_code);
1088 }
1089
file_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)1090 nghttp2_ssize file_read_callback(nghttp2_session *session, int32_t stream_id,
1091 uint8_t *buf, size_t length,
1092 uint32_t *data_flags,
1093 nghttp2_data_source *source, void *user_data) {
1094 int rv;
1095 auto hd = static_cast<Http2Handler *>(user_data);
1096 auto stream = hd->get_stream(stream_id);
1097
1098 auto nread = std::min(stream->body_length - stream->body_offset,
1099 static_cast<int64_t>(length));
1100
1101 *data_flags |= NGHTTP2_DATA_FLAG_NO_COPY;
1102
1103 if (nread == 0 || stream->body_length == stream->body_offset + nread) {
1104 *data_flags |= NGHTTP2_DATA_FLAG_EOF;
1105
1106 auto config = hd->get_config();
1107 if (!config->trailer.empty()) {
1108 std::vector<nghttp2_nv> nva;
1109 nva.reserve(config->trailer.size());
1110 for (auto &kv : config->trailer) {
1111 nva.push_back(http2::make_field_nv(kv.name, kv.value,
1112 http2::no_index(kv.no_index)));
1113 }
1114 rv = nghttp2_submit_trailer(session, stream_id, nva.data(), nva.size());
1115 if (rv != 0) {
1116 if (nghttp2_is_fatal(rv)) {
1117 return NGHTTP2_ERR_CALLBACK_FAILURE;
1118 }
1119 } else {
1120 *data_flags |= NGHTTP2_DATA_FLAG_NO_END_STREAM;
1121 }
1122 }
1123
1124 if (nghttp2_session_get_stream_remote_close(session, stream_id) == 0) {
1125 remove_stream_read_timeout(stream);
1126 remove_stream_write_timeout(stream);
1127
1128 hd->submit_rst_stream(stream, NGHTTP2_NO_ERROR);
1129 }
1130 }
1131
1132 return nread;
1133 }
1134
1135 namespace {
prepare_status_response(Stream * stream,Http2Handler * hd,int status)1136 void prepare_status_response(Stream *stream, Http2Handler *hd, int status) {
1137 auto sessions = hd->get_sessions();
1138 auto status_page = sessions->get_server()->get_status_page(status);
1139 auto file_ent = &status_page->file_ent;
1140
1141 // we don't set stream->file_ent since we don't want to expire it.
1142 stream->body_length = file_ent->length;
1143 nghttp2_data_provider2 data_prd;
1144 data_prd.source.fd = file_ent->fd;
1145 data_prd.read_callback = file_read_callback;
1146
1147 HeaderRefs headers;
1148 headers.reserve(2);
1149 headers.emplace_back("content-type"_sr, "text/html; charset=UTF-8"_sr);
1150 headers.emplace_back(
1151 "content-length"_sr,
1152 util::make_string_ref_uint(stream->balloc, file_ent->length));
1153 hd->submit_response(StringRef{status_page->status}, stream->stream_id,
1154 headers, &data_prd);
1155 }
1156 } // namespace
1157
1158 namespace {
prepare_echo_response(Stream * stream,Http2Handler * hd)1159 void prepare_echo_response(Stream *stream, Http2Handler *hd) {
1160 auto length = lseek(stream->file_ent->fd, 0, SEEK_END);
1161 if (length == -1) {
1162 hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
1163 return;
1164 }
1165 stream->body_length = length;
1166 if (lseek(stream->file_ent->fd, 0, SEEK_SET) == -1) {
1167 hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
1168 return;
1169 }
1170 nghttp2_data_provider2 data_prd;
1171 data_prd.source.fd = stream->file_ent->fd;
1172 data_prd.read_callback = file_read_callback;
1173
1174 HeaderRefs headers;
1175 headers.emplace_back("nghttpd-response"_sr, "echo"_sr);
1176 if (!hd->get_config()->no_content_length) {
1177 headers.emplace_back("content-length"_sr,
1178 util::make_string_ref_uint(stream->balloc, length));
1179 }
1180
1181 hd->submit_response("200"_sr, stream->stream_id, headers, &data_prd);
1182 }
1183 } // namespace
1184
1185 namespace {
prepare_upload_temp_store(Stream * stream,Http2Handler * hd)1186 bool prepare_upload_temp_store(Stream *stream, Http2Handler *hd) {
1187 auto sessions = hd->get_sessions();
1188
1189 char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
1190 auto fd = mkstemp(tempfn);
1191 if (fd == -1) {
1192 return false;
1193 }
1194 unlink(tempfn);
1195 // Ordinary request never start with "echo:". The length is 0 for
1196 // now. We will update it when we get whole request body.
1197 auto path = std::string("echo:") + tempfn;
1198 stream->file_ent =
1199 sessions->cache_fd(path, FileEntry(path, 0, 0, fd, nullptr, {}, true));
1200 stream->echo_upload = true;
1201 return true;
1202 }
1203 } // namespace
1204
1205 namespace {
prepare_redirect_response(Stream * stream,Http2Handler * hd,const StringRef & path,int status)1206 void prepare_redirect_response(Stream *stream, Http2Handler *hd,
1207 const StringRef &path, int status) {
1208 auto scheme = stream->header.scheme;
1209
1210 auto authority = stream->header.authority;
1211 if (authority.empty()) {
1212 authority = stream->header.host;
1213 }
1214
1215 auto location =
1216 concat_string_ref(stream->balloc, scheme, "://"_sr, authority, path);
1217
1218 auto headers = HeaderRefs{{"location"_sr, location}};
1219
1220 auto sessions = hd->get_sessions();
1221 auto status_page = sessions->get_server()->get_status_page(status);
1222
1223 hd->submit_response(StringRef{status_page->status}, stream->stream_id,
1224 headers, nullptr);
1225 }
1226 } // namespace
1227
1228 namespace {
prepare_response(Stream * stream,Http2Handler * hd,bool allow_push=true)1229 void prepare_response(Stream *stream, Http2Handler *hd,
1230 bool allow_push = true) {
1231 int rv;
1232 auto reqpath = stream->header.path;
1233 if (reqpath.empty()) {
1234 prepare_status_response(stream, hd, 405);
1235 return;
1236 }
1237
1238 auto ims = stream->header.ims;
1239
1240 time_t last_mod = 0;
1241 bool last_mod_found = false;
1242 if (!ims.empty()) {
1243 last_mod_found = true;
1244 last_mod = util::parse_http_date(ims);
1245 }
1246
1247 StringRef raw_path, raw_query;
1248 auto query_pos = std::find(std::begin(reqpath), std::end(reqpath), '?');
1249 if (query_pos != std::end(reqpath)) {
1250 // Do not response to this request to allow clients to test timeouts.
1251 if ("nghttpd_do_not_respond_to_req=yes"_sr ==
1252 StringRef{query_pos, std::end(reqpath)}) {
1253 return;
1254 }
1255 raw_path = StringRef{std::begin(reqpath), query_pos};
1256 raw_query = StringRef{query_pos, std::end(reqpath)};
1257 } else {
1258 raw_path = reqpath;
1259 }
1260
1261 auto sessions = hd->get_sessions();
1262
1263 StringRef path;
1264 if (std::find(std::begin(raw_path), std::end(raw_path), '%') ==
1265 std::end(raw_path)) {
1266 path = raw_path;
1267 } else {
1268 path = util::percent_decode(stream->balloc, raw_path);
1269 }
1270
1271 path = http2::path_join(stream->balloc, StringRef{}, StringRef{}, path,
1272 StringRef{});
1273
1274 if (std::find(std::begin(path), std::end(path), '\\') != std::end(path)) {
1275 if (stream->file_ent) {
1276 sessions->release_fd(stream->file_ent);
1277 stream->file_ent = nullptr;
1278 }
1279 prepare_status_response(stream, hd, 404);
1280 return;
1281 }
1282
1283 if (!hd->get_config()->push.empty()) {
1284 auto push_itr = hd->get_config()->push.find(std::string{path});
1285 if (allow_push && push_itr != std::end(hd->get_config()->push)) {
1286 for (auto &push_path : (*push_itr).second) {
1287 rv = hd->submit_push_promise(stream, StringRef{push_path});
1288 if (rv != 0) {
1289 std::cerr << "nghttp2_submit_push_promise() returned error: "
1290 << nghttp2_strerror(rv) << std::endl;
1291 }
1292 }
1293 }
1294 }
1295
1296 std::string file_path;
1297 {
1298 auto len = hd->get_config()->htdocs.size() + path.size();
1299
1300 auto trailing_slash = path[path.size() - 1] == '/';
1301 if (trailing_slash) {
1302 len += DEFAULT_HTML.size();
1303 }
1304
1305 file_path.resize(len);
1306
1307 auto p = &file_path[0];
1308
1309 auto &htdocs = hd->get_config()->htdocs;
1310 p = std::copy(std::begin(htdocs), std::end(htdocs), p);
1311 p = std::copy(std::begin(path), std::end(path), p);
1312 if (trailing_slash) {
1313 std::copy(std::begin(DEFAULT_HTML), std::end(DEFAULT_HTML), p);
1314 }
1315 }
1316
1317 if (stream->echo_upload) {
1318 assert(stream->file_ent);
1319 prepare_echo_response(stream, hd);
1320 return;
1321 }
1322
1323 auto file_ent = sessions->get_cached_fd(file_path);
1324
1325 if (file_ent == nullptr) {
1326 int file = open(file_path.c_str(), O_RDONLY | O_BINARY);
1327 if (file == -1) {
1328 prepare_status_response(stream, hd, 404);
1329
1330 return;
1331 }
1332
1333 struct stat buf;
1334
1335 if (fstat(file, &buf) == -1) {
1336 close(file);
1337 prepare_status_response(stream, hd, 404);
1338
1339 return;
1340 }
1341
1342 if (buf.st_mode & S_IFDIR) {
1343 close(file);
1344
1345 auto reqpath =
1346 concat_string_ref(stream->balloc, raw_path, "/"_sr, raw_query);
1347
1348 prepare_redirect_response(stream, hd, reqpath, 301);
1349
1350 return;
1351 }
1352
1353 const std::string *content_type = nullptr;
1354
1355 auto ext = file_path.c_str() + file_path.size() - 1;
1356 for (; file_path.c_str() < ext && *ext != '.' && *ext != '/'; --ext)
1357 ;
1358 if (*ext == '.') {
1359 ++ext;
1360
1361 const auto &mime_types = hd->get_config()->mime_types;
1362 auto content_type_itr = mime_types.find(ext);
1363 if (content_type_itr != std::end(mime_types)) {
1364 content_type = &(*content_type_itr).second;
1365 }
1366 }
1367
1368 file_ent = sessions->cache_fd(
1369 file_path, FileEntry(file_path, buf.st_size, buf.st_mtime, file,
1370 content_type, std::chrono::steady_clock::now()));
1371 }
1372
1373 stream->file_ent = file_ent;
1374
1375 if (last_mod_found && file_ent->mtime <= last_mod) {
1376 hd->submit_response("304"_sr, stream->stream_id, nullptr);
1377
1378 return;
1379 }
1380
1381 auto method = stream->header.method;
1382 if (method == "HEAD"_sr) {
1383 hd->submit_file_response("200"_sr, stream, file_ent->mtime,
1384 file_ent->length, file_ent->content_type, nullptr);
1385 return;
1386 }
1387
1388 stream->body_length = file_ent->length;
1389
1390 nghttp2_data_provider2 data_prd;
1391
1392 data_prd.source.fd = file_ent->fd;
1393 data_prd.read_callback = file_read_callback;
1394
1395 hd->submit_file_response("200"_sr, stream, file_ent->mtime, file_ent->length,
1396 file_ent->content_type, &data_prd);
1397 }
1398 } // namespace
1399
1400 namespace {
on_header_callback2(nghttp2_session * session,const nghttp2_frame * frame,nghttp2_rcbuf * name,nghttp2_rcbuf * value,uint8_t flags,void * user_data)1401 int on_header_callback2(nghttp2_session *session, const nghttp2_frame *frame,
1402 nghttp2_rcbuf *name, nghttp2_rcbuf *value,
1403 uint8_t flags, void *user_data) {
1404 auto hd = static_cast<Http2Handler *>(user_data);
1405
1406 auto namebuf = nghttp2_rcbuf_get_buf(name);
1407 auto valuebuf = nghttp2_rcbuf_get_buf(value);
1408
1409 if (hd->get_config()->verbose) {
1410 print_session_id(hd->session_id());
1411 verbose_on_header_callback(session, frame, namebuf.base, namebuf.len,
1412 valuebuf.base, valuebuf.len, flags, user_data);
1413 }
1414 if (frame->hd.type != NGHTTP2_HEADERS ||
1415 frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
1416 return 0;
1417 }
1418 auto stream = hd->get_stream(frame->hd.stream_id);
1419 if (!stream) {
1420 return 0;
1421 }
1422
1423 if (stream->header_buffer_size + namebuf.len + valuebuf.len > 64_k) {
1424 hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
1425 return 0;
1426 }
1427
1428 stream->header_buffer_size += namebuf.len + valuebuf.len;
1429
1430 auto token = http2::lookup_token(StringRef{namebuf.base, namebuf.len});
1431
1432 auto &header = stream->header;
1433
1434 switch (token) {
1435 case http2::HD__METHOD:
1436 header.method = StringRef{valuebuf.base, valuebuf.len};
1437 header.rcbuf.method = value;
1438 nghttp2_rcbuf_incref(value);
1439 break;
1440 case http2::HD__SCHEME:
1441 header.scheme = StringRef{valuebuf.base, valuebuf.len};
1442 header.rcbuf.scheme = value;
1443 nghttp2_rcbuf_incref(value);
1444 break;
1445 case http2::HD__AUTHORITY:
1446 header.authority = StringRef{valuebuf.base, valuebuf.len};
1447 header.rcbuf.authority = value;
1448 nghttp2_rcbuf_incref(value);
1449 break;
1450 case http2::HD_HOST:
1451 header.host = StringRef{valuebuf.base, valuebuf.len};
1452 header.rcbuf.host = value;
1453 nghttp2_rcbuf_incref(value);
1454 break;
1455 case http2::HD__PATH:
1456 header.path = StringRef{valuebuf.base, valuebuf.len};
1457 header.rcbuf.path = value;
1458 nghttp2_rcbuf_incref(value);
1459 break;
1460 case http2::HD_IF_MODIFIED_SINCE:
1461 header.ims = StringRef{valuebuf.base, valuebuf.len};
1462 header.rcbuf.ims = value;
1463 nghttp2_rcbuf_incref(value);
1464 break;
1465 case http2::HD_EXPECT:
1466 header.expect = StringRef{valuebuf.base, valuebuf.len};
1467 header.rcbuf.expect = value;
1468 nghttp2_rcbuf_incref(value);
1469 break;
1470 }
1471
1472 return 0;
1473 }
1474 } // namespace
1475
1476 namespace {
on_begin_headers_callback(nghttp2_session * session,const nghttp2_frame * frame,void * user_data)1477 int on_begin_headers_callback(nghttp2_session *session,
1478 const nghttp2_frame *frame, void *user_data) {
1479 auto hd = static_cast<Http2Handler *>(user_data);
1480
1481 if (frame->hd.type != NGHTTP2_HEADERS ||
1482 frame->headers.cat != NGHTTP2_HCAT_REQUEST) {
1483 return 0;
1484 }
1485
1486 auto stream = std::make_unique<Stream>(hd, frame->hd.stream_id);
1487
1488 add_stream_read_timeout(stream.get());
1489
1490 hd->add_stream(frame->hd.stream_id, std::move(stream));
1491
1492 return 0;
1493 }
1494 } // namespace
1495
1496 namespace {
hd_on_frame_recv_callback(nghttp2_session * session,const nghttp2_frame * frame,void * user_data)1497 int hd_on_frame_recv_callback(nghttp2_session *session,
1498 const nghttp2_frame *frame, void *user_data) {
1499 auto hd = static_cast<Http2Handler *>(user_data);
1500 if (hd->get_config()->verbose) {
1501 print_session_id(hd->session_id());
1502 verbose_on_frame_recv_callback(session, frame, user_data);
1503 }
1504 switch (frame->hd.type) {
1505 case NGHTTP2_DATA: {
1506 // TODO Handle POST
1507 auto stream = hd->get_stream(frame->hd.stream_id);
1508 if (!stream) {
1509 return 0;
1510 }
1511
1512 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1513 remove_stream_read_timeout(stream);
1514 if (stream->echo_upload || !hd->get_config()->early_response) {
1515 prepare_response(stream, hd);
1516 }
1517 } else {
1518 add_stream_read_timeout(stream);
1519 }
1520
1521 break;
1522 }
1523 case NGHTTP2_HEADERS: {
1524 auto stream = hd->get_stream(frame->hd.stream_id);
1525 if (!stream) {
1526 return 0;
1527 }
1528
1529 if (frame->headers.cat == NGHTTP2_HCAT_REQUEST) {
1530
1531 auto expect100 = stream->header.expect;
1532
1533 if (util::strieq("100-continue"_sr, expect100)) {
1534 hd->submit_non_final_response("100", frame->hd.stream_id);
1535 }
1536
1537 auto method = stream->header.method;
1538 if (hd->get_config()->echo_upload &&
1539 (method == "POST"_sr || method == "PUT"_sr)) {
1540 if (!prepare_upload_temp_store(stream, hd)) {
1541 hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
1542 return 0;
1543 }
1544 } else if (hd->get_config()->early_response) {
1545 prepare_response(stream, hd);
1546 }
1547 }
1548
1549 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1550 remove_stream_read_timeout(stream);
1551 if (stream->echo_upload || !hd->get_config()->early_response) {
1552 prepare_response(stream, hd);
1553 }
1554 } else {
1555 add_stream_read_timeout(stream);
1556 }
1557
1558 break;
1559 }
1560 case NGHTTP2_SETTINGS:
1561 if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
1562 hd->remove_settings_timer();
1563 }
1564 break;
1565 default:
1566 break;
1567 }
1568 return 0;
1569 }
1570 } // namespace
1571
1572 namespace {
hd_on_frame_send_callback(nghttp2_session * session,const nghttp2_frame * frame,void * user_data)1573 int hd_on_frame_send_callback(nghttp2_session *session,
1574 const nghttp2_frame *frame, void *user_data) {
1575 auto hd = static_cast<Http2Handler *>(user_data);
1576
1577 if (hd->get_config()->verbose) {
1578 print_session_id(hd->session_id());
1579 verbose_on_frame_send_callback(session, frame, user_data);
1580 }
1581
1582 switch (frame->hd.type) {
1583 case NGHTTP2_DATA:
1584 case NGHTTP2_HEADERS: {
1585 auto stream = hd->get_stream(frame->hd.stream_id);
1586
1587 if (!stream) {
1588 return 0;
1589 }
1590
1591 if (frame->hd.flags & NGHTTP2_FLAG_END_STREAM) {
1592 remove_stream_write_timeout(stream);
1593 } else if (std::min(nghttp2_session_get_stream_remote_window_size(
1594 session, frame->hd.stream_id),
1595 nghttp2_session_get_remote_window_size(session)) <= 0) {
1596 // If stream is blocked by flow control, enable write timeout.
1597 add_stream_read_timeout_if_pending(stream);
1598 add_stream_write_timeout(stream);
1599 } else {
1600 add_stream_read_timeout_if_pending(stream);
1601 remove_stream_write_timeout(stream);
1602 }
1603
1604 break;
1605 }
1606 case NGHTTP2_SETTINGS: {
1607 if (frame->hd.flags & NGHTTP2_FLAG_ACK) {
1608 return 0;
1609 }
1610
1611 hd->start_settings_timer();
1612
1613 break;
1614 }
1615 case NGHTTP2_PUSH_PROMISE: {
1616 auto promised_stream_id = frame->push_promise.promised_stream_id;
1617 auto promised_stream = hd->get_stream(promised_stream_id);
1618 auto stream = hd->get_stream(frame->hd.stream_id);
1619
1620 if (!stream || !promised_stream) {
1621 return 0;
1622 }
1623
1624 add_stream_read_timeout_if_pending(stream);
1625 add_stream_write_timeout(stream);
1626
1627 prepare_response(promised_stream, hd, /*allow_push */ false);
1628 }
1629 }
1630 return 0;
1631 }
1632 } // namespace
1633
1634 namespace {
send_data_callback(nghttp2_session * session,nghttp2_frame * frame,const uint8_t * framehd,size_t length,nghttp2_data_source * source,void * user_data)1635 int send_data_callback(nghttp2_session *session, nghttp2_frame *frame,
1636 const uint8_t *framehd, size_t length,
1637 nghttp2_data_source *source, void *user_data) {
1638 auto hd = static_cast<Http2Handler *>(user_data);
1639 auto wb = hd->get_wb();
1640 auto padlen = frame->data.padlen;
1641 auto stream = hd->get_stream(frame->hd.stream_id);
1642
1643 if (wb->wleft() < 9 + length + padlen) {
1644 return NGHTTP2_ERR_WOULDBLOCK;
1645 }
1646
1647 int fd = source->fd;
1648
1649 auto p = wb->last;
1650
1651 p = std::copy_n(framehd, 9, p);
1652
1653 if (padlen) {
1654 *p++ = padlen - 1;
1655 }
1656
1657 while (length) {
1658 ssize_t nread;
1659 while ((nread = pread(fd, p, length, stream->body_offset)) == -1 &&
1660 errno == EINTR)
1661 ;
1662
1663 if (nread == -1) {
1664 remove_stream_read_timeout(stream);
1665 remove_stream_write_timeout(stream);
1666
1667 return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
1668 }
1669
1670 stream->body_offset += nread;
1671 length -= nread;
1672 p += nread;
1673 }
1674
1675 if (padlen) {
1676 std::fill(p, p + padlen - 1, 0);
1677 p += padlen - 1;
1678 }
1679
1680 wb->last = p;
1681
1682 return 0;
1683 }
1684 } // namespace
1685
1686 namespace {
select_padding_callback(nghttp2_session * session,const nghttp2_frame * frame,size_t max_payload,void * user_data)1687 nghttp2_ssize select_padding_callback(nghttp2_session *session,
1688 const nghttp2_frame *frame,
1689 size_t max_payload, void *user_data) {
1690 auto hd = static_cast<Http2Handler *>(user_data);
1691 return std::min(max_payload, frame->hd.length + hd->get_config()->padding);
1692 }
1693 } // namespace
1694
1695 namespace {
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)1696 int on_data_chunk_recv_callback(nghttp2_session *session, uint8_t flags,
1697 int32_t stream_id, const uint8_t *data,
1698 size_t len, void *user_data) {
1699 auto hd = static_cast<Http2Handler *>(user_data);
1700 auto stream = hd->get_stream(stream_id);
1701
1702 if (!stream) {
1703 return 0;
1704 }
1705
1706 if (stream->echo_upload) {
1707 assert(stream->file_ent);
1708 while (len) {
1709 ssize_t n;
1710 while ((n = write(stream->file_ent->fd, data, len)) == -1 &&
1711 errno == EINTR)
1712 ;
1713 if (n == -1) {
1714 hd->submit_rst_stream(stream, NGHTTP2_INTERNAL_ERROR);
1715 return 0;
1716 }
1717 len -= n;
1718 data += n;
1719 }
1720 }
1721 // TODO Handle POST
1722
1723 add_stream_read_timeout(stream);
1724
1725 return 0;
1726 }
1727 } // namespace
1728
1729 namespace {
on_stream_close_callback(nghttp2_session * session,int32_t stream_id,uint32_t error_code,void * user_data)1730 int on_stream_close_callback(nghttp2_session *session, int32_t stream_id,
1731 uint32_t error_code, void *user_data) {
1732 auto hd = static_cast<Http2Handler *>(user_data);
1733 hd->remove_stream(stream_id);
1734 if (hd->get_config()->verbose) {
1735 print_session_id(hd->session_id());
1736 print_timer();
1737 printf(" stream_id=%d closed\n", stream_id);
1738 fflush(stdout);
1739 }
1740 return 0;
1741 }
1742 } // namespace
1743
1744 namespace {
fill_callback(nghttp2_session_callbacks * callbacks,const Config * config)1745 void fill_callback(nghttp2_session_callbacks *callbacks, const Config *config) {
1746 nghttp2_session_callbacks_set_on_stream_close_callback(
1747 callbacks, on_stream_close_callback);
1748
1749 nghttp2_session_callbacks_set_on_frame_recv_callback(
1750 callbacks, hd_on_frame_recv_callback);
1751
1752 nghttp2_session_callbacks_set_on_frame_send_callback(
1753 callbacks, hd_on_frame_send_callback);
1754
1755 if (config->verbose) {
1756 nghttp2_session_callbacks_set_on_invalid_frame_recv_callback(
1757 callbacks, verbose_on_invalid_frame_recv_callback);
1758
1759 nghttp2_session_callbacks_set_error_callback2(callbacks,
1760 verbose_error_callback);
1761 }
1762
1763 nghttp2_session_callbacks_set_on_data_chunk_recv_callback(
1764 callbacks, on_data_chunk_recv_callback);
1765
1766 nghttp2_session_callbacks_set_on_header_callback2(callbacks,
1767 on_header_callback2);
1768
1769 nghttp2_session_callbacks_set_on_begin_headers_callback(
1770 callbacks, on_begin_headers_callback);
1771
1772 nghttp2_session_callbacks_set_send_data_callback(callbacks,
1773 send_data_callback);
1774
1775 if (config->padding) {
1776 nghttp2_session_callbacks_set_select_padding_callback2(
1777 callbacks, select_padding_callback);
1778 }
1779 }
1780 } // namespace
1781
1782 struct ClientInfo {
1783 int fd;
1784 };
1785
1786 struct Worker {
1787 std::unique_ptr<Sessions> sessions;
1788 ev_async w;
1789 // protects q
1790 std::mutex m;
1791 std::deque<ClientInfo> q;
1792 };
1793
1794 namespace {
worker_acceptcb(struct ev_loop * loop,ev_async * w,int revents)1795 void worker_acceptcb(struct ev_loop *loop, ev_async *w, int revents) {
1796 auto worker = static_cast<Worker *>(w->data);
1797 auto &sessions = worker->sessions;
1798
1799 std::deque<ClientInfo> q;
1800 {
1801 std::lock_guard<std::mutex> lock(worker->m);
1802 q.swap(worker->q);
1803 }
1804
1805 for (const auto &c : q) {
1806 sessions->accept_connection(c.fd);
1807 }
1808 }
1809 } // namespace
1810
1811 namespace {
run_worker(Worker * worker)1812 void run_worker(Worker *worker) {
1813 auto loop = worker->sessions->get_loop();
1814
1815 ev_run(loop, 0);
1816 }
1817 } // namespace
1818
1819 namespace {
get_ev_loop_flags()1820 int get_ev_loop_flags() {
1821 if (ev_supported_backends() & ~ev_recommended_backends() & EVBACKEND_KQUEUE) {
1822 return ev_recommended_backends() | EVBACKEND_KQUEUE;
1823 }
1824
1825 return 0;
1826 }
1827 } // namespace
1828
1829 class AcceptHandler {
1830 public:
AcceptHandler(HttpServer * sv,Sessions * sessions,const Config * config)1831 AcceptHandler(HttpServer *sv, Sessions *sessions, const Config *config)
1832 : sessions_(sessions), config_(config), next_worker_(0) {
1833 if (config_->num_worker == 1) {
1834 return;
1835 }
1836 for (size_t i = 0; i < config_->num_worker; ++i) {
1837 if (config_->verbose) {
1838 std::cerr << "spawning thread #" << i << std::endl;
1839 }
1840 auto worker = std::make_unique<Worker>();
1841 auto loop = ev_loop_new(get_ev_loop_flags());
1842 worker->sessions = std::make_unique<Sessions>(sv, loop, config_,
1843 sessions_->get_ssl_ctx());
1844 ev_async_init(&worker->w, worker_acceptcb);
1845 worker->w.data = worker.get();
1846 ev_async_start(loop, &worker->w);
1847
1848 auto t = std::thread(run_worker, worker.get());
1849 t.detach();
1850 workers_.push_back(std::move(worker));
1851 }
1852 }
accept_connection(int fd)1853 void accept_connection(int fd) {
1854 if (config_->num_worker == 1) {
1855 sessions_->accept_connection(fd);
1856 return;
1857 }
1858
1859 // Dispatch client to the one of the worker threads, in a round
1860 // robin manner.
1861 auto &worker = workers_[next_worker_];
1862 if (next_worker_ == config_->num_worker - 1) {
1863 next_worker_ = 0;
1864 } else {
1865 ++next_worker_;
1866 }
1867 {
1868 std::lock_guard<std::mutex> lock(worker->m);
1869 worker->q.push_back({fd});
1870 }
1871 ev_async_send(worker->sessions->get_loop(), &worker->w);
1872 }
1873
1874 private:
1875 std::vector<std::unique_ptr<Worker>> workers_;
1876 Sessions *sessions_;
1877 const Config *config_;
1878 // In multi threading mode, this points to the next thread that
1879 // client will be dispatched.
1880 size_t next_worker_;
1881 };
1882
1883 namespace {
1884 void acceptcb(struct ev_loop *loop, ev_io *w, int revents);
1885 } // namespace
1886
1887 class ListenEventHandler {
1888 public:
ListenEventHandler(Sessions * sessions,int fd,std::shared_ptr<AcceptHandler> acceptor)1889 ListenEventHandler(Sessions *sessions, int fd,
1890 std::shared_ptr<AcceptHandler> acceptor)
1891 : acceptor_(std::move(acceptor)), sessions_(sessions), fd_(fd) {
1892 ev_io_init(&w_, acceptcb, fd, EV_READ);
1893 w_.data = this;
1894 ev_io_start(sessions_->get_loop(), &w_);
1895 }
accept_connection()1896 void accept_connection() {
1897 for (;;) {
1898 #ifdef HAVE_ACCEPT4
1899 auto fd = accept4(fd_, nullptr, nullptr, SOCK_NONBLOCK);
1900 #else // !HAVE_ACCEPT4
1901 auto fd = accept(fd_, nullptr, nullptr);
1902 #endif // !HAVE_ACCEPT4
1903 if (fd == -1) {
1904 break;
1905 }
1906 #ifndef HAVE_ACCEPT4
1907 util::make_socket_nonblocking(fd);
1908 #endif // !HAVE_ACCEPT4
1909 acceptor_->accept_connection(fd);
1910 }
1911 }
1912
1913 private:
1914 ev_io w_;
1915 std::shared_ptr<AcceptHandler> acceptor_;
1916 Sessions *sessions_;
1917 int fd_;
1918 };
1919
1920 namespace {
acceptcb(struct ev_loop * loop,ev_io * w,int revents)1921 void acceptcb(struct ev_loop *loop, ev_io *w, int revents) {
1922 auto handler = static_cast<ListenEventHandler *>(w->data);
1923 handler->accept_connection();
1924 }
1925 } // namespace
1926
1927 namespace {
make_status_body(int status,uint16_t port)1928 FileEntry make_status_body(int status, uint16_t port) {
1929 BlockAllocator balloc(1024, 1024);
1930
1931 auto status_string = http2::stringify_status(balloc, status);
1932 auto reason_pharase = http2::get_reason_phrase(status);
1933
1934 std::string body;
1935 body = "<html><head><title>";
1936 body += status_string;
1937 body += ' ';
1938 body += reason_pharase;
1939 body += "</title></head><body><h1>";
1940 body += status_string;
1941 body += ' ';
1942 body += reason_pharase;
1943 body += "</h1><hr><address>";
1944 body += NGHTTPD_SERVER;
1945 body += " at port ";
1946 body += util::utos(port);
1947 body += "</address>";
1948 body += "</body></html>";
1949
1950 char tempfn[] = "/tmp/nghttpd.temp.XXXXXX";
1951 int fd = mkstemp(tempfn);
1952 if (fd == -1) {
1953 auto error = errno;
1954 std::cerr << "Could not open status response body file: errno=" << error;
1955 assert(0);
1956 }
1957 unlink(tempfn);
1958 ssize_t nwrite;
1959 while ((nwrite = write(fd, body.c_str(), body.size())) == -1 &&
1960 errno == EINTR)
1961 ;
1962 if (nwrite == -1) {
1963 auto error = errno;
1964 std::cerr << "Could not write status response body into file: errno="
1965 << error;
1966 assert(0);
1967 }
1968
1969 return FileEntry(util::utos(status), nwrite, 0, fd, nullptr, {});
1970 }
1971 } // namespace
1972
1973 // index into HttpServer::status_pages_
1974 enum {
1975 IDX_200,
1976 IDX_301,
1977 IDX_400,
1978 IDX_404,
1979 IDX_405,
1980 };
1981
HttpServer(const Config * config)1982 HttpServer::HttpServer(const Config *config) : config_(config) {
1983 status_pages_ = std::vector<StatusPage>{
1984 {"200", make_status_body(200, config_->port)},
1985 {"301", make_status_body(301, config_->port)},
1986 {"400", make_status_body(400, config_->port)},
1987 {"404", make_status_body(404, config_->port)},
1988 {"405", make_status_body(405, config_->port)},
1989 };
1990 }
1991
1992 namespace {
verify_callback(int preverify_ok,X509_STORE_CTX * ctx)1993 int verify_callback(int preverify_ok, X509_STORE_CTX *ctx) {
1994 // We don't verify the client certificate. Just request it for the
1995 // testing purpose.
1996 return 1;
1997 }
1998 } // namespace
1999
2000 namespace {
start_listen(HttpServer * sv,struct ev_loop * loop,Sessions * sessions,const Config * config)2001 int start_listen(HttpServer *sv, struct ev_loop *loop, Sessions *sessions,
2002 const Config *config) {
2003 int r;
2004 bool ok = false;
2005 const char *addr = nullptr;
2006
2007 std::shared_ptr<AcceptHandler> acceptor;
2008 auto service = util::utos(config->port);
2009
2010 addrinfo hints{};
2011 hints.ai_family = AF_UNSPEC;
2012 hints.ai_socktype = SOCK_STREAM;
2013 hints.ai_flags = AI_PASSIVE;
2014 #ifdef AI_ADDRCONFIG
2015 hints.ai_flags |= AI_ADDRCONFIG;
2016 #endif // AI_ADDRCONFIG
2017
2018 if (!config->address.empty()) {
2019 addr = config->address.c_str();
2020 }
2021
2022 addrinfo *res, *rp;
2023 r = getaddrinfo(addr, service.c_str(), &hints, &res);
2024 if (r != 0) {
2025 std::cerr << "getaddrinfo() failed: " << gai_strerror(r) << std::endl;
2026 return -1;
2027 }
2028
2029 for (rp = res; rp; rp = rp->ai_next) {
2030 int fd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
2031 if (fd == -1) {
2032 continue;
2033 }
2034 int val = 1;
2035 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &val,
2036 static_cast<socklen_t>(sizeof(val))) == -1) {
2037 close(fd);
2038 continue;
2039 }
2040 (void)util::make_socket_nonblocking(fd);
2041 #ifdef IPV6_V6ONLY
2042 if (rp->ai_family == AF_INET6) {
2043 if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &val,
2044 static_cast<socklen_t>(sizeof(val))) == -1) {
2045 close(fd);
2046 continue;
2047 }
2048 }
2049 #endif // IPV6_V6ONLY
2050 if (bind(fd, rp->ai_addr, rp->ai_addrlen) == 0 && listen(fd, 1000) == 0) {
2051 if (!acceptor) {
2052 acceptor = std::make_shared<AcceptHandler>(sv, sessions, config);
2053 }
2054 new ListenEventHandler(sessions, fd, acceptor);
2055
2056 if (config->verbose) {
2057 std::string s = util::numeric_name(rp->ai_addr, rp->ai_addrlen);
2058 std::cout << (rp->ai_family == AF_INET ? "IPv4" : "IPv6") << ": listen "
2059 << s << ":" << config->port << std::endl;
2060 }
2061 ok = true;
2062 continue;
2063 } else {
2064 std::cerr << strerror(errno) << std::endl;
2065 }
2066 close(fd);
2067 }
2068 freeaddrinfo(res);
2069
2070 if (!ok) {
2071 return -1;
2072 }
2073 return 0;
2074 }
2075 } // namespace
2076
2077 namespace {
alpn_select_proto_cb(SSL * ssl,const unsigned char ** out,unsigned char * outlen,const unsigned char * in,unsigned int inlen,void * arg)2078 int alpn_select_proto_cb(SSL *ssl, const unsigned char **out,
2079 unsigned char *outlen, const unsigned char *in,
2080 unsigned int inlen, void *arg) {
2081 auto config = static_cast<HttpServer *>(arg)->get_config();
2082 if (config->verbose) {
2083 std::cout << "[ALPN] client offers:" << std::endl;
2084 }
2085 if (config->verbose) {
2086 for (unsigned int i = 0; i < inlen; i += in[i] + 1) {
2087 std::cout << " * ";
2088 std::cout.write(reinterpret_cast<const char *>(&in[i + 1]), in[i]);
2089 std::cout << std::endl;
2090 }
2091 }
2092 if (!util::select_h2(out, outlen, in, inlen)) {
2093 return SSL_TLSEXT_ERR_NOACK;
2094 }
2095 return SSL_TLSEXT_ERR_OK;
2096 }
2097 } // namespace
2098
run()2099 int HttpServer::run() {
2100 SSL_CTX *ssl_ctx = nullptr;
2101 std::vector<unsigned char> next_proto;
2102
2103 if (!config_->no_tls) {
2104 ssl_ctx = SSL_CTX_new(TLS_server_method());
2105 if (!ssl_ctx) {
2106 std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2107 return -1;
2108 }
2109
2110 auto ssl_opts = (SSL_OP_ALL & ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS) |
2111 SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 | SSL_OP_NO_COMPRESSION |
2112 SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION |
2113 SSL_OP_SINGLE_ECDH_USE | SSL_OP_NO_TICKET |
2114 SSL_OP_CIPHER_SERVER_PREFERENCE;
2115
2116 #ifdef SSL_OP_ENABLE_KTLS
2117 if (config_->ktls) {
2118 ssl_opts |= SSL_OP_ENABLE_KTLS;
2119 }
2120 #endif // SSL_OP_ENABLE_KTLS
2121
2122 SSL_CTX_set_options(ssl_ctx, ssl_opts);
2123 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_AUTO_RETRY);
2124 SSL_CTX_set_mode(ssl_ctx, SSL_MODE_RELEASE_BUFFERS);
2125
2126 if (nghttp2::tls::ssl_ctx_set_proto_versions(
2127 ssl_ctx, nghttp2::tls::NGHTTP2_TLS_MIN_VERSION,
2128 nghttp2::tls::NGHTTP2_TLS_MAX_VERSION) != 0) {
2129 std::cerr << "Could not set TLS versions" << std::endl;
2130 return -1;
2131 }
2132
2133 if (SSL_CTX_set_cipher_list(ssl_ctx, tls::DEFAULT_CIPHER_LIST.data()) ==
2134 0) {
2135 std::cerr << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2136 return -1;
2137 }
2138
2139 const unsigned char sid_ctx[] = "nghttpd";
2140 SSL_CTX_set_session_id_context(ssl_ctx, sid_ctx, sizeof(sid_ctx) - 1);
2141 SSL_CTX_set_session_cache_mode(ssl_ctx, SSL_SESS_CACHE_SERVER);
2142
2143 #ifndef OPENSSL_NO_EC
2144 if (SSL_CTX_set1_curves_list(ssl_ctx, "P-256") != 1) {
2145 std::cerr << "SSL_CTX_set1_curves_list failed: "
2146 << ERR_error_string(ERR_get_error(), nullptr);
2147 return -1;
2148 }
2149 #endif // OPENSSL_NO_EC
2150
2151 if (!config_->dh_param_file.empty()) {
2152 // Read DH parameters from file
2153 auto bio = BIO_new_file(config_->dh_param_file.c_str(), "rb");
2154 if (bio == nullptr) {
2155 std::cerr << "BIO_new_file() failed: "
2156 << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2157 return -1;
2158 }
2159
2160 #if OPENSSL_3_0_0_API
2161 EVP_PKEY *dh = nullptr;
2162 auto dctx = OSSL_DECODER_CTX_new_for_pkey(
2163 &dh, "PEM", nullptr, "DH", OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS,
2164 nullptr, nullptr);
2165
2166 if (!OSSL_DECODER_from_bio(dctx, bio)) {
2167 std::cerr << "OSSL_DECODER_from_bio() failed: "
2168 << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2169 return -1;
2170 }
2171
2172 if (SSL_CTX_set0_tmp_dh_pkey(ssl_ctx, dh) != 1) {
2173 std::cerr << "SSL_CTX_set0_tmp_dh_pkey failed: "
2174 << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2175 return -1;
2176 }
2177 #else // !OPENSSL_3_0_0_API
2178 auto dh = PEM_read_bio_DHparams(bio, nullptr, nullptr, nullptr);
2179
2180 if (dh == nullptr) {
2181 std::cerr << "PEM_read_bio_DHparams() failed: "
2182 << ERR_error_string(ERR_get_error(), nullptr) << std::endl;
2183 return -1;
2184 }
2185
2186 SSL_CTX_set_tmp_dh(ssl_ctx, dh);
2187 DH_free(dh);
2188 #endif // !OPENSSL_3_0_0_API
2189 BIO_free(bio);
2190 }
2191
2192 if (SSL_CTX_use_PrivateKey_file(ssl_ctx, config_->private_key_file.c_str(),
2193 SSL_FILETYPE_PEM) != 1) {
2194 std::cerr << "SSL_CTX_use_PrivateKey_file failed." << std::endl;
2195 return -1;
2196 }
2197 if (SSL_CTX_use_certificate_chain_file(ssl_ctx,
2198 config_->cert_file.c_str()) != 1) {
2199 std::cerr << "SSL_CTX_use_certificate_file failed." << std::endl;
2200 return -1;
2201 }
2202 if (SSL_CTX_check_private_key(ssl_ctx) != 1) {
2203 std::cerr << "SSL_CTX_check_private_key failed." << std::endl;
2204 return -1;
2205 }
2206 if (config_->verify_client) {
2207 SSL_CTX_set_verify(ssl_ctx,
2208 SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE |
2209 SSL_VERIFY_FAIL_IF_NO_PEER_CERT,
2210 verify_callback);
2211 }
2212
2213 next_proto = util::get_default_alpn();
2214
2215 // ALPN selection callback
2216 SSL_CTX_set_alpn_select_cb(ssl_ctx, alpn_select_proto_cb, this);
2217
2218 #if defined(NGHTTP2_OPENSSL_IS_BORINGSSL) && defined(HAVE_LIBBROTLI)
2219 if (!SSL_CTX_add_cert_compression_alg(
2220 ssl_ctx, nghttp2::tls::CERTIFICATE_COMPRESSION_ALGO_BROTLI,
2221 nghttp2::tls::cert_compress, nghttp2::tls::cert_decompress)) {
2222 std::cerr << "SSL_CTX_add_cert_compression_alg failed." << std::endl;
2223 return -1;
2224 }
2225 #endif // NGHTTP2_OPENSSL_IS_BORINGSSL && HAVE_LIBBROTLI
2226 }
2227
2228 auto loop = EV_DEFAULT;
2229
2230 Sessions sessions(this, loop, config_, ssl_ctx);
2231 if (start_listen(this, loop, &sessions, config_) != 0) {
2232 std::cerr << "Could not listen" << std::endl;
2233 if (ssl_ctx) {
2234 SSL_CTX_free(ssl_ctx);
2235 }
2236 return -1;
2237 }
2238
2239 ev_run(loop, 0);
2240
2241 SSL_CTX_free(ssl_ctx);
2242
2243 return 0;
2244 }
2245
get_config() const2246 const Config *HttpServer::get_config() const { return config_; }
2247
get_status_page(int status) const2248 const StatusPage *HttpServer::get_status_page(int status) const {
2249 switch (status) {
2250 case 200:
2251 return &status_pages_[IDX_200];
2252 case 301:
2253 return &status_pages_[IDX_301];
2254 case 400:
2255 return &status_pages_[IDX_400];
2256 case 404:
2257 return &status_pages_[IDX_404];
2258 case 405:
2259 return &status_pages_[IDX_405];
2260 default:
2261 assert(0);
2262 }
2263 return nullptr;
2264 }
2265
2266 } // namespace nghttp2
2267