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