2121#include < dirent.h>
2222#include < algorithm>
2323#include < sstream>
24+ #include < regex>
2425
2526namespace swoole {
2627namespace http_server {
@@ -101,7 +102,9 @@ bool StaticHandler::get_absolute_path() {
101102 return true ;
102103}
103104
104- bool StaticHandler::hit () {
105+ bool StaticHandler::try_serve () {
106+ serv->apply_rewrite_rules (this );
107+
105108 char *p = filename;
106109 const char *url = request_url.c_str ();
107110 size_t url_length = request_url.length ();
@@ -189,7 +192,7 @@ bool StaticHandler::hit() {
189192 return true ;
190193}
191194
192- bool StaticHandler::hit_index_file () {
195+ bool StaticHandler::try_serve_index_file () {
193196 if (serv->http_index_files && !serv->http_index_files ->empty () && is_dir ()) {
194197 if (!get_dir_files ()) {
195198 return false ;
@@ -441,6 +444,25 @@ void StaticHandler::parse_range(const char *range, const char *if_range) {
441444 }
442445}
443446} // namespace http_server
447+
448+ void Server::add_rewrite_rule (const std::string &pattern, const std::string &replacement) {
449+ if (rewrite_rules == nullptr ) {
450+ rewrite_rules = std::make_shared<std::vector<http_server::RewriteRule>>();
451+ }
452+
453+ http_server::RewriteRule rule;
454+ rule.replacement = replacement;
455+
456+ if (pattern.length () >= 2 && pattern.at (0 ) == ' ~' && pattern.at (pattern.length () - 1 ) == ' ~' ) {
457+ rule.pattern = pattern.substr (1 , pattern.length () - 2 );
458+ rule.is_regex = true ;
459+ } else {
460+ rule.pattern = pattern;
461+ rule.is_regex = false ;
462+ }
463+ rewrite_rules->emplace_back (rule);
464+ }
465+
444466void Server::add_static_handler_location (const std::string &location) {
445467 if (locations == nullptr ) {
446468 locations = std::make_shared<std::unordered_set<std::string>>();
@@ -464,7 +486,7 @@ bool Server::select_static_handler(const http_server::Request *request, const Co
464486 size_t url_length = request->url_length_ ;
465487
466488 http_server::StaticHandler handler (this , url, url_length);
467- if (!handler.hit ()) {
489+ if (!handler.try_serve ()) {
468490 return false ;
469491 }
470492
@@ -515,7 +537,7 @@ bool Server::select_static_handler(const http_server::Request *request, const Co
515537 * if http_index_files is enabled, need to search the index file first.
516538 * if the index file is found, set filename to index filename.
517539 */
518- if (!handler.hit_index_file ()) {
540+ if (!handler.try_serve_index_file ()) {
519541 return false ;
520542 }
521543
@@ -638,4 +660,42 @@ bool Server::select_static_handler(const http_server::Request *request, const Co
638660
639661 return true ;
640662}
663+
664+ bool Server::apply_rewrite_rules (http_server::StaticHandler *handler) {
665+ if (!rewrite_rules || rewrite_rules->empty ()) {
666+ return false ;
667+ }
668+
669+ bool rewritten = false ;
670+ auto current_url = handler->get_request_url ();
671+
672+ for (const auto &rule : *rewrite_rules) {
673+ if (rule.is_regex ) {
674+ try {
675+ std::regex pattern (rule.pattern );
676+ std::string rewritten_url;
677+
678+ if (std::regex_search (current_url, pattern)) {
679+ rewritten_url = std::regex_replace (current_url, pattern, rule.replacement );
680+ if (rewritten_url != current_url) {
681+ handler->set_request_url (rewritten_url);
682+ rewritten = true ;
683+ break ;
684+ }
685+ }
686+ } catch (const std::regex_error &e) {
687+ continue ;
688+ }
689+ } else {
690+ if (starts_with (current_url, rule.pattern )) {
691+ std::string rewritten_url = rule.replacement + current_url.substr (rule.pattern .length ());
692+ handler->set_request_url (rewritten_url);
693+ rewritten = true ;
694+ break ;
695+ }
696+ }
697+ }
698+
699+ return rewritten;
700+ }
641701} // namespace swoole
0 commit comments