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