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