Merge branch 'master' of https://opensourceprojects.eu/git/p/recoll1/code
This commit is contained in:
@@ -415,6 +415,7 @@ int ConfSimple::i_set(const std::string& nm, const std::string& value,
|
||||
// During the initial construction, just append:
|
||||
CONFDEB("ConfSimple::i_set: init true: append\n");
|
||||
m_order.push_back(ConfLine(ConfLine::CFL_VAR, nm));
|
||||
m_order.back().m_value = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ public:
|
||||
enum Kind {CFL_COMMENT, CFL_SK, CFL_VAR, CFL_VARCOMMENT};
|
||||
Kind m_kind;
|
||||
std::string m_data;
|
||||
std::string m_value;
|
||||
std::string m_aux;
|
||||
ConfLine(Kind k, const std::string& d, std::string a = std::string())
|
||||
: m_kind(k), m_data(d), m_aux(a) {
|
||||
|
||||
+16
-378
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2004 J.F.Dockes
|
||||
/* Copyright (C) 2004-2018 J.F.Dockes
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -14,7 +14,6 @@
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
#ifndef TEST_EXECMD
|
||||
#ifdef BUILDING_RECOLL
|
||||
#include "autoconfig.h"
|
||||
#else
|
||||
@@ -74,6 +73,7 @@ public:
|
||||
ExecCmdProvide *m_provide{0};
|
||||
bool m_killRequest{false};
|
||||
int m_timeoutMs{1000};
|
||||
int m_killTimeoutMs{2000};
|
||||
int m_rlimit_as_mbytes{0};
|
||||
string m_stderrFile;
|
||||
// Pipe for data going to the command
|
||||
@@ -122,6 +122,10 @@ void ExecCmd::setTimeout(int mS)
|
||||
m->m_timeoutMs = mS;
|
||||
}
|
||||
}
|
||||
void ExecCmd::setKillTimeout(int mS)
|
||||
{
|
||||
m->m_killTimeoutMs = mS;
|
||||
}
|
||||
void ExecCmd::setStderr(const std::string& stderrFile)
|
||||
{
|
||||
m->m_stderrFile = stderrFile;
|
||||
@@ -276,17 +280,23 @@ public:
|
||||
", SIGTERM)\n");
|
||||
int ret = killpg(grp, SIGTERM);
|
||||
if (ret == 0) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
msleep(i == 0 ? 5 : (i == 1 ? 100 : 2000));
|
||||
int ms_slept{0};
|
||||
for (int i = 0; ; i++) {
|
||||
int tosleep = i == 0 ? 5 : (i == 1 ? 100 : 1000);
|
||||
msleep(tosleep);
|
||||
ms_slept += tosleep;
|
||||
int status;
|
||||
(void)waitpid(m_parent->m_pid, &status, WNOHANG);
|
||||
if (kill(m_parent->m_pid, 0) != 0) {
|
||||
break;
|
||||
}
|
||||
if (i == 2) {
|
||||
LOGDEB("ExecCmd: killpg(" << (grp) << ", SIGKILL)\n");
|
||||
// killtimeout == -1 -> never KILL
|
||||
if (m_parent->m_killTimeoutMs >= 0 &&
|
||||
ms_slept >= m_parent->m_killTimeoutMs) {
|
||||
LOGDEB("ExecCmd: killpg(" << grp << ", SIGKILL)\n");
|
||||
killpg(grp, SIGKILL);
|
||||
(void)waitpid(m_parent->m_pid, &status, WNOHANG);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -1144,375 +1154,3 @@ void ReExec::reexec()
|
||||
argv[i] = 0;
|
||||
execvp(m_argv[0].c_str(), (char *const*)argv);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
#else // TEST
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include <string>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
|
||||
#include "log.h"
|
||||
|
||||
#include "execmd.h"
|
||||
#ifdef BUILDING_RECOLL
|
||||
#include "smallut.h"
|
||||
#include "cancelcheck.h"
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef BUILDING_RECOLL
|
||||
// Testing the rclexecm protocol outside of recoll. Here we use the
|
||||
// rcldoc.py filter, you can try with rclaudio too, adjust the file arg
|
||||
// accordingly
|
||||
bool exercise_mhexecm(const string& cmdstr, const string& mimetype,
|
||||
vector<string>& files)
|
||||
{
|
||||
ExecCmd cmd;
|
||||
|
||||
vector<string> myparams;
|
||||
|
||||
if (cmd.startExec(cmdstr, myparams, 1, 1) < 0) {
|
||||
cerr << "startExec " << cmdstr << " failed. Missing command?\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
for (vector<string>::const_iterator it = files.begin();
|
||||
it != files.end(); it++) {
|
||||
// Build request message
|
||||
ostringstream obuf;
|
||||
obuf << "Filename: " << (*it).length() << "\n" << (*it);
|
||||
obuf << "Mimetype: " << mimetype.length() << "\n" << mimetype;
|
||||
// Bogus parameter should be skipped by filter
|
||||
obuf << "BogusParam: " << string("bogus").length() << "\n" << "bogus";
|
||||
obuf << "\n";
|
||||
cerr << "SENDING: [" << obuf.str() << "]\n";
|
||||
// Send it
|
||||
if (cmd.send(obuf.str()) < 0) {
|
||||
// The real code calls zapchild here, but we don't need it as
|
||||
// this will be handled by ~ExecCmd
|
||||
//cmd.zapChild();
|
||||
cerr << "send error\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read answer
|
||||
for (int loop = 0;; loop++) {
|
||||
string name, data;
|
||||
|
||||
// Code from mh_execm.cpp: readDataElement
|
||||
string ibuf;
|
||||
// Read name and length
|
||||
if (cmd.getline(ibuf) <= 0) {
|
||||
cerr << "getline error\n";
|
||||
return false;
|
||||
}
|
||||
// Empty line (end of message)
|
||||
if (!ibuf.compare("\n")) {
|
||||
cerr << "Got empty line\n";
|
||||
name.clear();
|
||||
break;
|
||||
}
|
||||
|
||||
// Filters will sometimes abort before entering the real
|
||||
// protocol, ie if a module can't be loaded. Check the
|
||||
// special filter error first word:
|
||||
if (ibuf.find("RECFILTERROR ") == 0) {
|
||||
cerr << "Got RECFILTERROR\n";
|
||||
return false;
|
||||
}
|
||||
|
||||
// We're expecting something like Name: len\n
|
||||
vector<string> tokens;
|
||||
stringToTokens(ibuf, tokens);
|
||||
if (tokens.size() != 2) {
|
||||
cerr << "bad line in filter output: [" << ibuf << "]\n";
|
||||
return false;
|
||||
}
|
||||
vector<string>::iterator it = tokens.begin();
|
||||
name = *it++;
|
||||
string& slen = *it;
|
||||
int len;
|
||||
if (sscanf(slen.c_str(), "%d", &len) != 1) {
|
||||
cerr << "bad line in filter output (no len): [" <<
|
||||
ibuf << "]\n";
|
||||
return false;
|
||||
}
|
||||
// Read element data
|
||||
data.erase();
|
||||
if (len > 0 && cmd.receive(data, len) != len) {
|
||||
cerr << "MHExecMultiple: expected " << len <<
|
||||
" bytes of data, got " << data.length() << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Empty element: end of message
|
||||
if (name.empty()) {
|
||||
break;
|
||||
}
|
||||
cerr << "Got name: [" << name << "] data [" << data << "]\n";
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
static char *thisprog;
|
||||
static char usage [] =
|
||||
"trexecmd [-c -r -i -o] cmd [arg1 arg2 ...]\n"
|
||||
" -c : test cancellation (ie: trexecmd -c sleep 1000)\n"
|
||||
" -r : run reexec. Must be separate option.\n"
|
||||
" -i : command takes input\n"
|
||||
" -o : command produces output\n"
|
||||
" If -i is set, we send /etc/group contents to whatever command is run\n"
|
||||
" If -o is set, we print whatever comes out\n"
|
||||
"trexecmd -m <filter> <mimetype> <file> [file ...]: test execm:\n"
|
||||
" <filter> should be the path to an execm filter\n"
|
||||
" <mimetype> the type of the file parameters\n"
|
||||
"trexecmd -w cmd : do the 'which' thing\n"
|
||||
"trexecmd -l cmd test getline\n"
|
||||
;
|
||||
|
||||
static void Usage(void)
|
||||
{
|
||||
fprintf(stderr, "%s: usage:\n%s", thisprog, usage);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static int op_flags;
|
||||
#define OPT_MOINS 0x1
|
||||
#define OPT_i 0x4
|
||||
#define OPT_w 0x8
|
||||
#define OPT_c 0x10
|
||||
#define OPT_r 0x20
|
||||
#define OPT_m 0x40
|
||||
#define OPT_o 0x80
|
||||
#define OPT_l 0x100
|
||||
|
||||
// Data sink for data coming out of the command. We also use it to set
|
||||
// a cancellation after a moment.
|
||||
class MEAdv : public ExecCmdAdvise {
|
||||
public:
|
||||
void newData(int cnt) {
|
||||
if (op_flags & OPT_c) {
|
||||
#ifdef BUILDING_RECOLL
|
||||
static int callcnt;
|
||||
if (callcnt++ == 10) {
|
||||
// Just sets the cancellation flag
|
||||
CancelCheck::instance().setCancel();
|
||||
// Would be called from somewhere else and throws an
|
||||
// exception. We call it here for simplicity
|
||||
CancelCheck::instance().checkCancel();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
cerr << "newData(" << cnt << ")" << endl;
|
||||
}
|
||||
};
|
||||
|
||||
// Data provider, used if the -i flag is set
|
||||
class MEPv : public ExecCmdProvide {
|
||||
public:
|
||||
FILE *m_fp;
|
||||
string *m_input;
|
||||
MEPv(string *i)
|
||||
: m_input(i) {
|
||||
m_fp = fopen("/etc/group", "r");
|
||||
}
|
||||
~MEPv() {
|
||||
if (m_fp) {
|
||||
fclose(m_fp);
|
||||
}
|
||||
}
|
||||
void newData() {
|
||||
char line[1024];
|
||||
if (m_fp && fgets(line, 1024, m_fp)) {
|
||||
m_input->assign((const char *)line);
|
||||
} else {
|
||||
m_input->erase();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
ReExec reexec;
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
reexec.init(argc, argv);
|
||||
|
||||
if (0) {
|
||||
// Disabled: For testing reexec arg handling
|
||||
vector<string> newargs;
|
||||
newargs.push_back("newarg");
|
||||
newargs.push_back("newarg1");
|
||||
newargs.push_back("newarg2");
|
||||
newargs.push_back("newarg3");
|
||||
newargs.push_back("newarg4");
|
||||
reexec.insertArgs(newargs, 2);
|
||||
}
|
||||
|
||||
thisprog = argv[0];
|
||||
argc--;
|
||||
argv++;
|
||||
|
||||
while (argc > 0 && **argv == '-') {
|
||||
(*argv)++;
|
||||
if (!(**argv))
|
||||
/* Cas du "adb - core" */
|
||||
{
|
||||
Usage();
|
||||
}
|
||||
while (**argv)
|
||||
switch (*(*argv)++) {
|
||||
case 'c':
|
||||
op_flags |= OPT_c;
|
||||
break;
|
||||
case 'r':
|
||||
op_flags |= OPT_r;
|
||||
break;
|
||||
case 'w':
|
||||
op_flags |= OPT_w;
|
||||
break;
|
||||
#ifdef BUILDING_RECOLL
|
||||
case 'm':
|
||||
op_flags |= OPT_m;
|
||||
break;
|
||||
#endif
|
||||
case 'i':
|
||||
op_flags |= OPT_i;
|
||||
break;
|
||||
case 'l':
|
||||
op_flags |= OPT_l;
|
||||
break;
|
||||
case 'o':
|
||||
op_flags |= OPT_o;
|
||||
break;
|
||||
default:
|
||||
Usage();
|
||||
break;
|
||||
}
|
||||
argc--;
|
||||
argv++;
|
||||
}
|
||||
|
||||
if (argc < 1) {
|
||||
Usage();
|
||||
}
|
||||
|
||||
string arg1 = *argv++;
|
||||
argc--;
|
||||
vector<string> l;
|
||||
while (argc > 0) {
|
||||
l.push_back(*argv++);
|
||||
argc--;
|
||||
}
|
||||
|
||||
#ifdef BUILDING_RECOLL
|
||||
DebugLog::getdbl()->setloglevel(DEBDEB1);
|
||||
DebugLog::setfilename("stderr");
|
||||
#endif
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (op_flags & OPT_r) {
|
||||
// Test reexec. Normally only once, next time we fall through
|
||||
// because we remove the -r option (only works if it was isolated, not like -rc
|
||||
chdir("/");
|
||||
argv[0] = strdup("");
|
||||
sleep(1);
|
||||
cerr << "Calling reexec\n";
|
||||
// We remove the -r arg from list, otherwise we are going to
|
||||
// loop (which you can try by commenting out the following
|
||||
// line)
|
||||
reexec.removeArg("-r");
|
||||
reexec.reexec();
|
||||
}
|
||||
|
||||
if (op_flags & OPT_w) {
|
||||
// Test "which" method
|
||||
string path;
|
||||
if (ExecCmd::which(arg1, path)) {
|
||||
cout << path << endl;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
#ifdef BUILDING_RECOLL
|
||||
} else if (op_flags & OPT_m) {
|
||||
if (l.size() < 2) {
|
||||
Usage();
|
||||
}
|
||||
string mimetype = l[0];
|
||||
l.erase(l.begin());
|
||||
return exercise_mhexecm(arg1, mimetype, l) ? 0 : 1;
|
||||
#endif
|
||||
} else if (op_flags & OPT_l) {
|
||||
ExecCmd mexec;
|
||||
|
||||
if (mexec.startExec(arg1, l, false, true) < 0) {
|
||||
cerr << "Startexec failed\n";
|
||||
exit(1);
|
||||
}
|
||||
string output;
|
||||
int ret = mexec.getline(output, 2);
|
||||
cerr << "Got ret " << ret << " output " << output << endl;
|
||||
cerr << "Waiting\n";
|
||||
int status = mexec.wait();
|
||||
cerr << "Got status " << status << endl;
|
||||
exit(status);
|
||||
} else {
|
||||
// Default: execute command line arguments
|
||||
ExecCmd mexec;
|
||||
|
||||
// Set callback to be called whenever there is new data
|
||||
// available and at a periodic interval, to check for
|
||||
// cancellation
|
||||
MEAdv adv;
|
||||
mexec.setAdvise(&adv);
|
||||
mexec.setTimeout(5);
|
||||
|
||||
// Stderr output goes there
|
||||
mexec.setStderr("/tmp/trexecStderr");
|
||||
|
||||
// A few environment variables. Check with trexecmd env
|
||||
mexec.putenv("TESTVARIABLE1=TESTVALUE1");
|
||||
mexec.putenv("TESTVARIABLE2=TESTVALUE2");
|
||||
mexec.putenv("TESTVARIABLE3=TESTVALUE3");
|
||||
|
||||
string input, output;
|
||||
MEPv pv(&input);
|
||||
|
||||
string *ip = 0;
|
||||
if (op_flags & OPT_i) {
|
||||
ip = &input;
|
||||
mexec.setProvide(&pv);
|
||||
}
|
||||
string *op = 0;
|
||||
if (op_flags & OPT_o) {
|
||||
op = &output;
|
||||
}
|
||||
|
||||
int status = -1;
|
||||
try {
|
||||
status = mexec.doexec(arg1, l, ip, op);
|
||||
} catch (...) {
|
||||
cerr << "CANCELLED" << endl;
|
||||
}
|
||||
|
||||
fprintf(stderr, "Status: 0x%x\n", status);
|
||||
if (op_flags & OPT_o) {
|
||||
cout << output;
|
||||
}
|
||||
exit(status >> 8);
|
||||
}
|
||||
}
|
||||
#endif // TEST
|
||||
|
||||
|
||||
+12
-1
@@ -1,4 +1,4 @@
|
||||
/* Copyright (C) 2004 J.F.Dockes
|
||||
/* Copyright (C) 2004-2018 J.F.Dockes
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
@@ -117,6 +117,17 @@ public:
|
||||
*/
|
||||
void setStderr(const std::string& stderrFile);
|
||||
|
||||
/**
|
||||
* Set kill wait timeout. This is the maximum time we'll wait for
|
||||
* the command after sending a SIGTERM, before sending a SIGKILL.
|
||||
|
||||
* @param mS the maximum number of mS to wait. Note that values
|
||||
* below 1000 mS make no sense as the program will sleep for
|
||||
* longer time before retrying the waitpid(). Use -1 for
|
||||
* forever (bad idea), 0 for absolutely no pity.
|
||||
*/
|
||||
void setKillTimeout(int mS);
|
||||
|
||||
/**
|
||||
* Execute command.
|
||||
*
|
||||
|
||||
@@ -26,20 +26,6 @@
|
||||
|
||||
using std::string;
|
||||
|
||||
// Debug only
|
||||
#ifdef PATHHASH_HEX
|
||||
static void md5hexprint(const unsigned char hash[16], string &out)
|
||||
{
|
||||
out.erase();
|
||||
out.reserve(33);
|
||||
static const char hex[]="0123456789abcdef";
|
||||
for (int i = 0; i < 16; i++) {
|
||||
out.append(1, hex[hash[i] >> 4]);
|
||||
out.append(1, hex[hash[i] & 0x0f]);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Size of the hashed result (base64 of 16 bytes of md5, minus 2 pad chars)
|
||||
#define HASHLEN 22
|
||||
|
||||
@@ -66,12 +52,6 @@ void pathHash(const std::string &path, std::string &phash, unsigned int maxlen)
|
||||
path.length() - (maxlen - HASHLEN));
|
||||
MD5Final(chash, &ctx);
|
||||
|
||||
#ifdef PATHHASH_HEX
|
||||
string hex;
|
||||
md5hexprint(chash, hex);
|
||||
printf("hex [%s]\n", hex.c_str());
|
||||
#endif
|
||||
|
||||
// Encode it to ascii. This shouldn't be strictly necessary as
|
||||
// xapian terms can be binary
|
||||
string hash;
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
#ifndef _LOG_H_X_INCLUDED_
|
||||
#define _LOG_H_X_INCLUDED_
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -191,4 +193,17 @@ private:
|
||||
#endif
|
||||
#define LOGFATAL LOGFAT
|
||||
|
||||
#if (_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
|
||||
#define LOGSYSERR(who, what, arg) { \
|
||||
char buf[200]; buf[0] = 0; strerror_r(errno, buf, 200); \
|
||||
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
|
||||
": " << buf << std::endl); \
|
||||
}
|
||||
#else
|
||||
#define LOGSYSERR(who, what, arg) { \
|
||||
char buf[200]; buf[0] = 0; \
|
||||
LOGERR(who << ": " << what << "(" << arg << "): errno " << errno << \
|
||||
": " << strerror_r(errno, buf, 200) << std::endl); \
|
||||
}
|
||||
#endif
|
||||
#endif /* _LOG_H_X_INCLUDED_ */
|
||||
|
||||
+10
-3
@@ -72,10 +72,11 @@ using namespace std;
|
||||
static const int one = 1;
|
||||
static const int zero = 0;
|
||||
|
||||
#ifndef LOGSYSERR
|
||||
#define LOGSYSERR(who, call, spar) \
|
||||
LOGERR(who << ": " << call << "(" << spar << ") errno " << \
|
||||
errno << " (" << strerror(errno) << ")\n")
|
||||
|
||||
#endif
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
#endif
|
||||
@@ -700,7 +701,10 @@ void NetconData::cancelReceive()
|
||||
{
|
||||
if (m_wkfds[1] >= 0) {
|
||||
LOGDEB2("NetconData::cancelReceive: writing to " << m_wkfds[1] << endl);
|
||||
::write(m_wkfds[1], "!", 1);
|
||||
// We can't do a thing about the ::write return value, the
|
||||
// following nonsense is for cancelling warnings
|
||||
int ret = ::write(m_wkfds[1], "!", 1);
|
||||
ret = ret;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,7 +753,10 @@ int NetconData::receive(char *buf, int cnt, int timeo)
|
||||
|
||||
if (cancellable && FD_ISSET(m_wkfds[0], &rd)) {
|
||||
char b[100];
|
||||
read(m_wkfds[0], b, 100);
|
||||
// We can't do a thing about the return value, the
|
||||
// following nonsense is for cancelling warnings
|
||||
int ret = ::read(m_wkfds[0], b, 100);
|
||||
ret = ret;
|
||||
return Cancelled;
|
||||
}
|
||||
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include <stack>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
||||
#include "pathut.h"
|
||||
#include "smallut.h"
|
||||
@@ -761,6 +762,96 @@ bool urlisfileurl(const string& url)
|
||||
return url.find("file://") == 0;
|
||||
}
|
||||
|
||||
static std::regex
|
||||
re_uriparse("^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\\?([^#]*))?(#(.*))?",
|
||||
std::regex::extended);
|
||||
|
||||
ParsedUri::ParsedUri(std::string uri)
|
||||
{
|
||||
std::smatch mr;
|
||||
parsed = regex_match(uri, mr, re_uriparse);
|
||||
if (!parsed)
|
||||
return;
|
||||
// cf http://www.ietf.org/rfc/rfc2396.txt
|
||||
// scheme = $2
|
||||
// authority = $4
|
||||
// path = $5
|
||||
// query = $7
|
||||
// fragment = $9
|
||||
if (mr[2].matched) {
|
||||
scheme = mr[2].str();
|
||||
}
|
||||
if (mr[4].matched) {
|
||||
string auth = mr[4].str();
|
||||
// user:pass@host, user@host
|
||||
string::size_type at = auth.find_first_of('@');
|
||||
if (at != string::npos) {
|
||||
host = auth.substr(at+1);
|
||||
string::size_type colon = auth.find_first_of(':');
|
||||
if (colon != string::npos && colon < at) {
|
||||
user = auth.substr(0, colon);
|
||||
pass = auth.substr(colon+1, at-colon-1);
|
||||
} else {
|
||||
user = auth.substr(0, at);
|
||||
}
|
||||
} else {
|
||||
host.swap(auth);
|
||||
}
|
||||
string::size_type pc = host.find_first_of(':');
|
||||
if (pc != string::npos) {
|
||||
port = host.substr(pc+1);
|
||||
host = host.substr(0, pc);
|
||||
}
|
||||
}
|
||||
if (mr[5].matched) {
|
||||
path = mr[5].str();
|
||||
}
|
||||
if (mr[7].matched) {
|
||||
query = mr[7].str();
|
||||
string::size_type pos=0, amp, eq;
|
||||
string nm, val;
|
||||
for (;;) {
|
||||
nm.clear();
|
||||
val.clear();
|
||||
amp = query.find_first_of('&', pos);
|
||||
//cerr << "pos " << pos << " amp " << amp << endl;
|
||||
if (amp > pos && amp != string::npos) {
|
||||
eq = query.find_first_of('=', pos);
|
||||
if (eq > amp || eq == string::npos) {
|
||||
nm = query.substr(pos, amp-pos);
|
||||
} else {
|
||||
nm = query.substr(pos, eq-pos);
|
||||
val = query.substr(eq+1, amp-eq-1);
|
||||
}
|
||||
pos = amp + 1;
|
||||
} else if (amp == string::npos) {
|
||||
if (pos < query.size()-1) {
|
||||
eq = query.find_first_of('=', pos);
|
||||
if (eq == string::npos) {
|
||||
nm = query.substr(pos);
|
||||
} else {
|
||||
nm = query.substr(pos, eq-pos);
|
||||
val = query.substr(eq+1);
|
||||
}
|
||||
}
|
||||
pos = query.size()-1;
|
||||
} else {
|
||||
pos++;
|
||||
}
|
||||
if (!nm.empty()) {
|
||||
parsedquery.push_back(pair<string,string>(nm, val));
|
||||
}
|
||||
if (pos >= query.size()-1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
if (mr[9].matched) {
|
||||
fragment = mr[9].str();
|
||||
}
|
||||
}
|
||||
|
||||
bool readdir(const string& dir, string& reason, set<string>& entries)
|
||||
{
|
||||
struct stat st;
|
||||
|
||||
@@ -120,6 +120,22 @@ extern bool path_isdesc(const std::string& top, const std::string& sub);
|
||||
/// Turn absolute path into file:// url
|
||||
extern std::string path_pathtofileurl(const std::string& path);
|
||||
|
||||
/// URI parser, loosely from rfc2396.txt
|
||||
class ParsedUri {
|
||||
public:
|
||||
ParsedUri(std::string uri);
|
||||
bool parsed{false};
|
||||
std::string scheme;
|
||||
std::string user;
|
||||
std::string pass;
|
||||
std::string host;
|
||||
std::string port;
|
||||
std::string path;
|
||||
std::string query;
|
||||
std::vector<std::pair<std::string,std::string>> parsedquery;
|
||||
std::string fragment;
|
||||
};
|
||||
|
||||
#ifdef _WIN32
|
||||
/// Convert \ separators to /
|
||||
void path_slashize(std::string& s);
|
||||
|
||||
+49
-3
@@ -43,6 +43,7 @@
|
||||
#include "wipedir.h"
|
||||
#include "transcode.h"
|
||||
#include "md5ut.h"
|
||||
#include "log.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -281,8 +282,51 @@ bool maketmpdir(string& tdir, string& reason)
|
||||
return true;
|
||||
}
|
||||
|
||||
TempFileInternal::TempFileInternal(const string& suffix)
|
||||
: m_noremove(false)
|
||||
|
||||
class TempFile::Internal {
|
||||
public:
|
||||
Internal(const std::string& suffix);
|
||||
~Internal();
|
||||
friend class TempFile;
|
||||
private:
|
||||
std::string m_filename;
|
||||
std::string m_reason;
|
||||
bool m_noremove{false};
|
||||
};
|
||||
|
||||
TempFile::TempFile(const string& suffix)
|
||||
: m(new Internal(suffix))
|
||||
{
|
||||
}
|
||||
|
||||
TempFile::TempFile()
|
||||
{
|
||||
m = std::shared_ptr<Internal>();
|
||||
}
|
||||
|
||||
const char *TempFile::filename() const
|
||||
{
|
||||
return m ? m->m_filename.c_str() : "";
|
||||
}
|
||||
|
||||
const std::string& TempFile::getreason() const
|
||||
{
|
||||
static string fatal{"fatal error"};
|
||||
return m ? m->m_reason : fatal;
|
||||
}
|
||||
|
||||
void TempFile::setnoremove(bool onoff)
|
||||
{
|
||||
if (m)
|
||||
m->m_noremove = onoff;
|
||||
}
|
||||
|
||||
bool TempFile::ok() const
|
||||
{
|
||||
return m ? !m->m_filename.empty() : false;
|
||||
}
|
||||
|
||||
TempFile::Internal::Internal(const string& suffix)
|
||||
{
|
||||
// Because we need a specific suffix, can't use mkstemp
|
||||
// well. There is a race condition between name computation and
|
||||
@@ -322,7 +366,7 @@ TempFileInternal::TempFileInternal(const string& suffix)
|
||||
}
|
||||
}
|
||||
|
||||
TempFileInternal::~TempFileInternal()
|
||||
TempFile::Internal::~Internal()
|
||||
{
|
||||
if (!m_filename.empty() && !m_noremove) {
|
||||
unlink(m_filename.c_str());
|
||||
@@ -335,11 +379,13 @@ TempDir::TempDir()
|
||||
m_dirname.erase();
|
||||
return;
|
||||
}
|
||||
LOGDEB("TempDir::TempDir: -> " << m_dirname << endl);
|
||||
}
|
||||
|
||||
TempDir::~TempDir()
|
||||
{
|
||||
if (!m_dirname.empty()) {
|
||||
LOGDEB("TempDir::~TempDir: erasing " << m_dirname << endl);
|
||||
(void)wipedir(m_dirname, true, true);
|
||||
m_dirname.erase();
|
||||
}
|
||||
|
||||
+9
-20
@@ -48,30 +48,19 @@ extern const std::string& tmplocation();
|
||||
extern bool maketmpdir(std::string& tdir, std::string& reason);
|
||||
|
||||
/// Temporary file class
|
||||
class TempFileInternal {
|
||||
class TempFile {
|
||||
public:
|
||||
TempFileInternal(const std::string& suffix);
|
||||
~TempFileInternal();
|
||||
const char *filename() {
|
||||
return m_filename.c_str();
|
||||
}
|
||||
const std::string& getreason() {
|
||||
return m_reason;
|
||||
}
|
||||
void setnoremove(bool onoff) {
|
||||
m_noremove = onoff;
|
||||
}
|
||||
bool ok() {
|
||||
return !m_filename.empty();
|
||||
}
|
||||
TempFile(const std::string& suffix);
|
||||
TempFile();
|
||||
const char *filename() const;
|
||||
const std::string& getreason() const;
|
||||
void setnoremove(bool onoff);
|
||||
bool ok() const;
|
||||
class Internal;
|
||||
private:
|
||||
std::string m_filename;
|
||||
std::string m_reason;
|
||||
bool m_noremove;
|
||||
std::shared_ptr<Internal> m;
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<TempFileInternal> TempFile;
|
||||
|
||||
/// Temporary directory class. Recursively deleted by destructor.
|
||||
class TempDir {
|
||||
public:
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
#ifndef _REFCNTR_H_
|
||||
#define _REFCNTR_H_
|
||||
/* Copyright (C) 2014 J.F.Dockes
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the
|
||||
* Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
// See Stroustrup C++ 3rd ed, p. 783
|
||||
// This is only used if std::shared_ptr is not available
|
||||
template <class X> class RefCntr {
|
||||
X *rep;
|
||||
int *pcount;
|
||||
public:
|
||||
RefCntr()
|
||||
: rep(0), pcount(0)
|
||||
{}
|
||||
explicit RefCntr(X *pp)
|
||||
: rep(pp), pcount(new int(1))
|
||||
{}
|
||||
RefCntr(const RefCntr &r)
|
||||
: rep(r.rep), pcount(r.pcount)
|
||||
{
|
||||
if (pcount)
|
||||
(*pcount)++;
|
||||
}
|
||||
RefCntr& operator=(const RefCntr& r)
|
||||
{
|
||||
if (rep == r.rep)
|
||||
return *this;
|
||||
if (pcount && --(*pcount) == 0) {
|
||||
delete rep;
|
||||
delete pcount;
|
||||
}
|
||||
rep = r.rep;
|
||||
pcount = r.pcount;
|
||||
if (pcount)
|
||||
(*pcount)++;
|
||||
return *this;
|
||||
}
|
||||
void reset() {
|
||||
if (pcount && --(*pcount) == 0) {
|
||||
delete rep;
|
||||
delete pcount;
|
||||
}
|
||||
rep = 0;
|
||||
pcount = 0;
|
||||
}
|
||||
~RefCntr()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
X *operator->() {return rep;}
|
||||
X *get() const {return rep;}
|
||||
int use_count() const {return pcount ? *pcount : 0;}
|
||||
operator bool() const {return rep != 0;}
|
||||
};
|
||||
|
||||
#endif /*_REFCNTR_H_ */
|
||||
+11
-61
@@ -16,14 +16,10 @@
|
||||
*/
|
||||
|
||||
#include "autoconfig.h"
|
||||
#include "strmatcher.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#ifdef _WIN32
|
||||
#include <regex>
|
||||
#else
|
||||
#include <regex.h>
|
||||
#endif
|
||||
#include <fnmatch.h>
|
||||
|
||||
#include <string>
|
||||
@@ -31,19 +27,19 @@
|
||||
#include "cstr.h"
|
||||
#include "log.h"
|
||||
#include "pathut.h"
|
||||
#include "strmatcher.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
bool StrWildMatcher::match(const string& val) const
|
||||
{
|
||||
LOGDEB2("StrWildMatcher::match: [" << (m_sexp) << "] against [" << (val) << "]\n" );
|
||||
LOGDEB2("StrWildMatcher::match ["<< m_sexp<< "] against [" << val << "]\n");
|
||||
int ret = fnmatch(m_sexp.c_str(), val.c_str(), FNM_NOESCAPE);
|
||||
switch (ret) {
|
||||
case 0: return true;
|
||||
case FNM_NOMATCH: return false;
|
||||
default:
|
||||
LOGINFO("StrWildMatcher::match:err: e [" << (m_sexp) << "] s [" << (val) << "] (" << (url_encode(val)) << ") ret " << (ret) << "\n" );
|
||||
LOGINFO("StrWildMatcher::match:err: e [" << m_sexp << "] s [" << val
|
||||
<< "] (" << url_encode(val) << ") ret " << ret << "\n");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -54,68 +50,22 @@ string::size_type StrWildMatcher::baseprefixlen() const
|
||||
}
|
||||
|
||||
StrRegexpMatcher::StrRegexpMatcher(const string& exp)
|
||||
: StrMatcher(exp), m_compiled(0), m_errcode(0)
|
||||
: StrMatcher(exp),
|
||||
m_re(exp, SimpleRegexp::SRE_NOSUB)
|
||||
{
|
||||
setExp(exp);
|
||||
}
|
||||
|
||||
bool StrRegexpMatcher::setExp(const string& exp)
|
||||
{
|
||||
if (m_compiled) {
|
||||
#ifdef _WIN32
|
||||
delete (regex*)m_compiled;
|
||||
#else
|
||||
regfree((regex_t*)m_compiled);
|
||||
delete (regex_t*)m_compiled;
|
||||
#endif
|
||||
}
|
||||
m_compiled = 0;
|
||||
|
||||
#ifdef _WIN32
|
||||
try {
|
||||
m_compiled = new regex(exp, std::regex_constants::nosubs |
|
||||
std::regex_constants::extended);
|
||||
} catch (...) {
|
||||
m_reason = string("StrRegexpMatcher:regcomp failed for ")
|
||||
+ exp + string("syntax error ?");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
m_compiled = new regex_t;
|
||||
if ((m_errcode =
|
||||
regcomp((regex_t*)m_compiled, exp.c_str(), REG_EXTENDED|REG_NOSUB))) {
|
||||
char errbuf[200];
|
||||
regerror(m_errcode, (regex_t*)m_compiled, errbuf, 199);
|
||||
m_reason = string("StrRegexpMatcher:regcomp failed for ")
|
||||
+ exp + string(errbuf);
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
m_sexp = exp;
|
||||
return true;
|
||||
}
|
||||
|
||||
StrRegexpMatcher::~StrRegexpMatcher()
|
||||
{
|
||||
if (m_compiled) {
|
||||
#ifdef _WIN32
|
||||
delete (regex *)m_compiled;
|
||||
#else
|
||||
regfree((regex_t*)m_compiled);
|
||||
delete (regex_t*)m_compiled;
|
||||
#endif
|
||||
}
|
||||
m_re = SimpleRegexp(exp, SimpleRegexp::SRE_NOSUB);
|
||||
return m_re.ok();
|
||||
}
|
||||
|
||||
bool StrRegexpMatcher::match(const string& val) const
|
||||
{
|
||||
if (m_errcode)
|
||||
if (!m_re.ok())
|
||||
return false;
|
||||
#ifdef _WIN32
|
||||
return regex_match(val, *((regex *)m_compiled));
|
||||
#else
|
||||
return regexec((regex_t*)m_compiled, val.c_str(), 0, 0, 0) != REG_NOMATCH;
|
||||
#endif
|
||||
return m_re(val);
|
||||
}
|
||||
|
||||
string::size_type StrRegexpMatcher::baseprefixlen() const
|
||||
@@ -125,6 +75,6 @@ string::size_type StrRegexpMatcher::baseprefixlen() const
|
||||
|
||||
bool StrRegexpMatcher::ok() const
|
||||
{
|
||||
return !m_errcode;
|
||||
return m_re.ok();
|
||||
}
|
||||
|
||||
|
||||
+15
-31
@@ -18,6 +18,7 @@
|
||||
#define _STRMATCHER_H_INCLUDED_
|
||||
|
||||
#include <string>
|
||||
#include "smallut.h"
|
||||
|
||||
// Encapsulating simple wildcard/regexp string matching.
|
||||
|
||||
@@ -25,28 +26,22 @@
|
||||
class StrMatcher {
|
||||
public:
|
||||
StrMatcher(const std::string& exp)
|
||||
: m_sexp(exp)
|
||||
{
|
||||
}
|
||||
: m_sexp(exp) {}
|
||||
virtual ~StrMatcher() {};
|
||||
virtual bool match(const std::string &val) const = 0;
|
||||
virtual std::string::size_type baseprefixlen() const = 0;
|
||||
virtual bool setExp(const std::string& newexp)
|
||||
{
|
||||
virtual bool setExp(const std::string& newexp) {
|
||||
m_sexp = newexp;
|
||||
return true;
|
||||
}
|
||||
virtual bool ok() const
|
||||
{
|
||||
virtual bool ok() const {
|
||||
return true;
|
||||
}
|
||||
virtual const std::string& exp()
|
||||
{
|
||||
virtual const std::string& exp() const {
|
||||
return m_sexp;
|
||||
}
|
||||
virtual StrMatcher *clone() = 0;
|
||||
const string& getreason()
|
||||
{
|
||||
virtual StrMatcher *clone() const = 0;
|
||||
const std::string& getreason() const {
|
||||
return m_reason;
|
||||
}
|
||||
protected:
|
||||
@@ -57,16 +52,11 @@ protected:
|
||||
class StrWildMatcher : public StrMatcher {
|
||||
public:
|
||||
StrWildMatcher(const std::string& exp)
|
||||
: StrMatcher(exp)
|
||||
{
|
||||
}
|
||||
virtual ~StrWildMatcher()
|
||||
{
|
||||
}
|
||||
: StrMatcher(exp) {}
|
||||
virtual ~StrWildMatcher() {}
|
||||
virtual bool match(const std::string& val) const;
|
||||
virtual std::string::size_type baseprefixlen() const;
|
||||
virtual StrWildMatcher *clone()
|
||||
{
|
||||
virtual StrWildMatcher *clone() const {
|
||||
return new StrWildMatcher(m_sexp);
|
||||
}
|
||||
};
|
||||
@@ -74,22 +64,16 @@ public:
|
||||
class StrRegexpMatcher : public StrMatcher {
|
||||
public:
|
||||
StrRegexpMatcher(const std::string& exp);
|
||||
virtual bool setExp(const std::string& newexp);
|
||||
virtual ~StrRegexpMatcher();
|
||||
virtual bool setExp(const std::string& newexp) override;
|
||||
virtual ~StrRegexpMatcher() {};
|
||||
virtual bool match(const std::string& val) const;
|
||||
virtual std::string::size_type baseprefixlen() const;
|
||||
virtual bool ok() const;
|
||||
virtual StrRegexpMatcher *clone()
|
||||
{
|
||||
virtual bool ok() const override;
|
||||
virtual StrRegexpMatcher *clone() const {
|
||||
return new StrRegexpMatcher(m_sexp);
|
||||
}
|
||||
const string& getreason()
|
||||
{
|
||||
return m_reason;
|
||||
}
|
||||
private:
|
||||
void *m_compiled;
|
||||
bool m_errcode;
|
||||
SimpleRegexp m_re;
|
||||
};
|
||||
|
||||
#endif /* _STRMATCHER_H_INCLUDED_ */
|
||||
|
||||
Reference in New Issue
Block a user