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