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