2020//
2121//
2222#include < utility>
23- #include < iostream>
2423#include < string>
24+ #include < fstream>
2525#include < sstream>
26+ #include < filesystem>
2627
2728#include " ts/ts.h"
29+ #include " tscore/Layout.h"
2830
2931#include " parser.h"
3032
@@ -50,7 +52,7 @@ Parser::parse_line(const std::string &original_line)
5052 state = PARSER_DEFAULT;
5153 } else if (!std::isspace (line[i])) {
5254 // we got a standalone =, > or <
53- _tokens.push_back ( std::string ( 1 , line[i]) );
55+ _tokens.emplace_back ( 1 , line[i]);
5456 }
5557 } else if ((state != PARSER_IN_QUOTE) && (line[i] == ' /' )) {
5658 // Deal with regexes, nothing gets escaped / quoted in here
@@ -115,7 +117,7 @@ Parser::parse_line(const std::string &original_line)
115117
116118 if ((line[i] == ' =' ) || (line[i] == ' +' )) {
117119 // These are always a separate token
118- _tokens.push_back ( std::string ( 1 , line[i]) );
120+ _tokens.emplace_back ( 1 , line[i]);
119121 continue ;
120122 }
121123
@@ -278,9 +280,8 @@ Parser::cond_is_hook(TSHttpHookID &hook) const
278280 return false ;
279281}
280282
281- HRWSimpleTokenizer::HRWSimpleTokenizer (const std::string &original_line )
283+ HRWSimpleTokenizer::HRWSimpleTokenizer (const std::string &line )
282284{
283- std::string line = original_line;
284285 ParserState state = PARSER_DEFAULT;
285286 bool extracting_token = false ;
286287 off_t cur_token_start = 0 ;
@@ -325,3 +326,95 @@ HRWSimpleTokenizer::HRWSimpleTokenizer(const std::string &original_line)
325326 _tokens.push_back (line.substr (cur_token_start));
326327 }
327328}
329+
330+ // This is the universal configuration reader, which can read both
331+ // a raw file, as well as executing an external compiler (hrw4u) to parse
332+ // the configuration file.
333+ namespace
334+ {
335+ void
336+ _log_stderr (int fd)
337+ {
338+ char buffer[512 ];
339+ std::string partial;
340+
341+ while (ssize_t n = read (fd, buffer, sizeof (buffer))) {
342+ if (n <= 0 ) {
343+ break ;
344+ }
345+ partial.append (buffer, n);
346+ size_t pos = 0 ;
347+ while ((pos = partial.find (' \n ' )) != std::string::npos) {
348+ std::string line = partial.substr (0 , pos);
349+ TSError (" [header_rewrite: hrw4u] %s" , line.c_str ());
350+ partial.erase (0 , pos + 1 );
351+ }
352+ }
353+
354+ if (!partial.empty ()) {
355+ TSError (" [hrw4u] stderr: %s" , partial.c_str ());
356+ }
357+
358+ close (fd);
359+ }
360+ } // namespace
361+
362+ std::optional<ConfReader>
363+ openConfig (const std::string &filename)
364+ {
365+ namespace fs = std::filesystem;
366+ const std::string suffix = " .hrw4u" ;
367+ std::string hrw4u = Layout::get ()->bindir + " /traffic_hrw4u" ;
368+
369+ static const bool has_compiler = [hrw4u]() {
370+ fs::path path (hrw4u);
371+ std::error_code ec;
372+ auto status = fs::status (path, ec);
373+ auto perms = status.permissions ();
374+ return fs::exists (path, ec) && fs::is_regular_file (path, ec) && (perms & fs::perms::owner_exec) != fs::perms::none;
375+ }();
376+
377+ if (filename.ends_with (suffix) && has_compiler) {
378+ int pipe_fds[2 ];
379+ int stderr_pipe[2 ];
380+
381+ if (pipe (pipe_fds) != 0 || pipe (stderr_pipe) != 0 ) {
382+ TSError (" [header_rewrite] failed to create pipe for hrw4u compiler: %s" , strerror (errno));
383+ return std::nullopt ;
384+ }
385+
386+ pid_t pid = fork ();
387+ if (pid < 0 ) {
388+ TSError (" [header_rewrite] failed to fork for hrw4u compiler: %s" , strerror (errno));
389+ return std::nullopt ;
390+ } else if (pid == 0 ) {
391+ dup2 (pipe_fds[1 ], STDOUT_FILENO);
392+ dup2 (stderr_pipe[1 ], STDERR_FILENO);
393+ close (pipe_fds[0 ]);
394+ close (stderr_pipe[0 ]);
395+
396+ const char *argv[] = {hrw4u.c_str (), filename.c_str (), nullptr };
397+ execvp (argv[0 ], const_cast <char **>(argv));
398+ _exit (127 ); // child exec failed
399+ }
400+
401+ // Parent
402+ close (pipe_fds[1 ]);
403+ close (stderr_pipe[1 ]);
404+
405+ _log_stderr (stderr_pipe[0 ]);
406+
407+ auto pipebuf = std::make_shared<HRW4UPipe>(fdopen (pipe_fds[0 ], " r" ));
408+ pipebuf->set_pid (pid);
409+ auto stream = std::make_unique<std::istream>(pipebuf.get ());
410+
411+ return ConfReader{.stream = std::move (stream), .pipebuf = std::move (pipebuf)};
412+ } else {
413+ auto file = std::make_unique<std::ifstream>(filename);
414+ if (!file->is_open ()) {
415+ return std::nullopt ;
416+ }
417+
418+ return ConfReader{.stream = std::move (file), .pipebuf = nullptr };
419+ }
420+ }
0 commit comments