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