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