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