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