Merge branch 'develop' of https://github.com/pocoproject/poco into develop

This commit is contained in:
Alex Fabijanic 2014-11-19 22:25:48 -06:00
commit 599c4cb3aa
31 changed files with 491 additions and 152 deletions

View File

@ -22,6 +22,7 @@
#include "Poco/Crypto/Crypto.h"
#include "Poco/Mutex.h"
#include "Poco/AtomicCounter.h"
#include <openssl/crypto.h>
#include <openssl/opensslv.h>
#if defined(OPENSSL_FIPS) && OPENSSL_VERSION_NUMBER < 0x010001000L
@ -82,8 +83,7 @@ protected:
private:
static Poco::FastMutex* _mutexes;
static Poco::FastMutex _mutex;
static int _rc;
static Poco::AtomicCounter _rc;
};

View File

@ -35,8 +35,7 @@ namespace Crypto {
Poco::FastMutex* OpenSSLInitializer::_mutexes(0);
Poco::FastMutex OpenSSLInitializer::_mutex;
int OpenSSLInitializer::_rc(0);
Poco::AtomicCounter OpenSSLInitializer::_rc;
OpenSSLInitializer::OpenSSLInitializer()
@ -60,8 +59,6 @@ OpenSSLInitializer::~OpenSSLInitializer()
void OpenSSLInitializer::initialize()
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (++_rc == 1)
{
#if OPENSSL_VERSION_NUMBER >= 0x0907000L
@ -98,8 +95,6 @@ void OpenSSLInitializer::initialize()
void OpenSSLInitializer::uninitialize()
{
Poco::FastMutex::ScopedLock lock(_mutex);
if (--_rc == 0)
{
EVP_cleanup();
@ -109,6 +104,8 @@ void OpenSSLInitializer::uninitialize()
CRYPTO_set_id_callback(0);
#endif
delete [] _mutexes;
CONF_modules_free();
}
}

View File

@ -13,9 +13,6 @@ ifeq ($(POCO_CONFIG),FreeBSD)
SYSLIBS += -lssl -lcrypto -lz
else
SYSLIBS += -lssl -lcrypto -lz -ldl
ifeq ($(POCO_CONFIG),Linux)
SYSLIBS += -lkrb5
endif
endif
objects = CryptoTestSuite Driver \

View File

@ -164,6 +164,8 @@ void Utility::throwException(int rc, const std::string& addErrMsg)
case SQLITE_ABORT:
throw ExecutionAbortedException(std::string("Callback routine requested an abort"), addErrMsg);
case SQLITE_BUSY:
case SQLITE_BUSY_RECOVERY:
case SQLITE_BUSY_SNAPSHOT:
throw DBLockedException(std::string("The database file is locked"), addErrMsg);
case SQLITE_LOCKED:
throw TableLockedException(std::string("A table in the database is locked"), addErrMsg);

View File

@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.8.7.1. By combining all the individual C code files into this
** version 3.8.7.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@ -231,9 +231,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.8.7.1"
#define SQLITE_VERSION "3.8.7.2"
#define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID "2014-10-29 13:59:56 3b7b72c4685aa5cf5e675c2c47ebec10d9704221"
#define SQLITE_SOURCE_ID "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -9013,7 +9013,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree*, const char *zMaster);
SQLITE_PRIVATE int sqlite3BtreeCommitPhaseTwo(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeCommit(Btree*);
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree*,int,int);
SQLITE_PRIVATE int sqlite3BtreeBeginStmt(Btree*,int);
SQLITE_PRIVATE int sqlite3BtreeCreateTable(Btree*, int*, int flags);
SQLITE_PRIVATE int sqlite3BtreeIsInTrans(Btree*);
@ -9046,7 +9046,7 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *);
SQLITE_PRIVATE int sqlite3BtreeDropTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTable(Btree*, int, int*);
SQLITE_PRIVATE int sqlite3BtreeClearTableOfCursor(BtCursor*);
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree*, int);
SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree*, int, int);
SQLITE_PRIVATE void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue);
SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value);
@ -13062,7 +13062,7 @@ SQLITE_PRIVATE int sqlite3OpenTempDatabase(Parse *);
SQLITE_PRIVATE void sqlite3StrAccumInit(StrAccum*, char*, int, int);
SQLITE_PRIVATE void sqlite3StrAccumAppend(StrAccum*,const char*,int);
SQLITE_PRIVATE void sqlite3StrAccumAppendAll(StrAccum*,const char*);
SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum*,int);
SQLITE_PRIVATE void sqlite3AppendChar(StrAccum*,int,char);
SQLITE_PRIVATE char *sqlite3StrAccumFinish(StrAccum*);
SQLITE_PRIVATE void sqlite3StrAccumReset(StrAccum*);
SQLITE_PRIVATE void sqlite3SelectDestInit(SelectDest*,int,int);
@ -20947,7 +20947,7 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
const et_info *infop; /* Pointer to the appropriate info structure */
char *zOut; /* Rendering buffer */
int nOut; /* Size of the rendering buffer */
char *zExtra; /* Malloced memory used by some conversion */
char *zExtra = 0; /* Malloced memory used by some conversion */
#ifndef SQLITE_OMIT_FLOATING_POINT
int exp, e2; /* exponent of real numbers */
int nsd; /* Number of significant digits returned */
@ -21064,7 +21064,6 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
break;
}
}
zExtra = 0;
/*
** At this point, variables are initialized as follows:
@ -21355,13 +21354,16 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
}else{
c = va_arg(ap,int);
}
buf[0] = (char)c;
if( precision>=0 ){
for(idx=1; idx<precision; idx++) buf[idx] = (char)c;
length = precision;
}else{
length =1;
if( precision>1 ){
width -= precision-1;
if( width>1 && !flag_leftjustify ){
sqlite3AppendChar(pAccum, width-1, ' ');
width = 0;
}
sqlite3AppendChar(pAccum, precision-1, c);
}
length = 1;
buf[0] = c;
bufpt = buf;
break;
case etSTRING:
@ -21462,11 +21464,14 @@ SQLITE_PRIVATE void sqlite3VXPrintf(
** the output.
*/
width -= length;
if( width>0 && !flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
if( width>0 && !flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
sqlite3StrAccumAppend(pAccum, bufpt, length);
if( width>0 && flag_leftjustify ) sqlite3AppendSpace(pAccum, width);
if( width>0 && flag_leftjustify ) sqlite3AppendChar(pAccum, width, ' ');
if( zExtra ) sqlite3_free(zExtra);
if( zExtra ){
sqlite3_free(zExtra);
zExtra = 0;
}
}/* End for loop over the format string */
} /* End of function */
@ -21519,11 +21524,11 @@ static int sqlite3StrAccumEnlarge(StrAccum *p, int N){
}
/*
** Append N space characters to the given string buffer.
** Append N copies of character c to the given string buffer.
*/
SQLITE_PRIVATE void sqlite3AppendSpace(StrAccum *p, int N){
SQLITE_PRIVATE void sqlite3AppendChar(StrAccum *p, int N, char c){
if( p->nChar+N >= p->nAlloc && (N = sqlite3StrAccumEnlarge(p, N))<=0 ) return;
while( (N--)>0 ) p->zText[p->nChar++] = ' ';
while( (N--)>0 ) p->zText[p->nChar++] = c;
}
/*
@ -50636,7 +50641,6 @@ SQLITE_PRIVATE int sqlite3WalUndo(Wal *pWal, int (*xUndo)(void *, Pgno), void *p
}
if( iMax!=pWal->hdr.mxFrame ) walCleanupHash(pWal);
}
assert( rc==SQLITE_OK );
return rc;
}
@ -51715,6 +51719,11 @@ struct CellInfo {
**
** Fields in this structure are accessed under the BtShared.mutex
** found at self->pBt->mutex.
**
** skipNext meaning:
** eState==SKIPNEXT && skipNext>0: Next sqlite3BtreeNext() is no-op.
** eState==SKIPNEXT && skipNext<0: Next sqlite3BtreePrevious() is no-op.
** eState==FAULT: Cursor fault with skipNext as error code.
*/
struct BtCursor {
Btree *pBtree; /* The Btree to which this cursor belongs */
@ -51727,7 +51736,8 @@ struct BtCursor {
void *pKey; /* Saved key that was cursor last known position */
Pgno pgnoRoot; /* The root page of this tree */
int nOvflAlloc; /* Allocated size of aOverflow[] array */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive */
int skipNext; /* Prev() is noop if negative. Next() is noop if positive.
** Error code if eState==CURSOR_FAULT */
u8 curFlags; /* zero or more BTCF_* flags defined below */
u8 eState; /* One of the CURSOR_XXX constants (see below) */
u8 hints; /* As configured by CursorSetHints() */
@ -51773,7 +51783,7 @@ struct BtCursor {
** on a different connection that shares the BtShared cache with this
** cursor. The error has left the cache in an inconsistent state.
** Do nothing else with this cursor. Any attempt to use the cursor
** should return the error code stored in BtCursor.skip
** should return the error code stored in BtCursor.skipNext
*/
#define CURSOR_INVALID 0
#define CURSOR_VALID 1
@ -54355,7 +54365,7 @@ SQLITE_PRIVATE int sqlite3BtreeClose(Btree *p){
** The call to sqlite3BtreeRollback() drops any table-locks held by
** this handle.
*/
sqlite3BtreeRollback(p, SQLITE_OK);
sqlite3BtreeRollback(p, SQLITE_OK, 0);
sqlite3BtreeLeave(p);
/* If there are still other outstanding references to the shared-btree
@ -55648,60 +55658,91 @@ SQLITE_PRIVATE int sqlite3BtreeCommit(Btree *p){
/*
** This routine sets the state to CURSOR_FAULT and the error
** code to errCode for every cursor on BtShared that pBtree
** references.
** code to errCode for every cursor on any BtShared that pBtree
** references. Or if the writeOnly flag is set to 1, then only
** trip write cursors and leave read cursors unchanged.
**
** Every cursor is tripped, including cursors that belong
** to other database connections that happen to be sharing
** the cache with pBtree.
** Every cursor is a candidate to be tripped, including cursors
** that belong to other database connections that happen to be
** sharing the cache with pBtree.
**
** This routine gets called when a rollback occurs.
** All cursors using the same cache must be tripped
** to prevent them from trying to use the btree after
** the rollback. The rollback may have deleted tables
** or moved root pages, so it is not sufficient to
** save the state of the cursor. The cursor must be
** invalidated.
** This routine gets called when a rollback occurs. If the writeOnly
** flag is true, then only write-cursors need be tripped - read-only
** cursors save their current positions so that they may continue
** following the rollback. Or, if writeOnly is false, all cursors are
** tripped. In general, writeOnly is false if the transaction being
** rolled back modified the database schema. In this case b-tree root
** pages may be moved or deleted from the database altogether, making
** it unsafe for read cursors to continue.
**
** If the writeOnly flag is true and an error is encountered while
** saving the current position of a read-only cursor, all cursors,
** including all read-cursors are tripped.
**
** SQLITE_OK is returned if successful, or if an error occurs while
** saving a cursor position, an SQLite error code.
*/
SQLITE_PRIVATE void sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode){
SQLITE_PRIVATE int sqlite3BtreeTripAllCursors(Btree *pBtree, int errCode, int writeOnly){
BtCursor *p;
if( pBtree==0 ) return;
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
sqlite3BtreeClearCursor(p);
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
for(i=0; i<=p->iPage; i++){
releasePage(p->apPage[i]);
p->apPage[i] = 0;
int rc = SQLITE_OK;
assert( (writeOnly==0 || writeOnly==1) && BTCF_WriteFlag==1 );
if( pBtree ){
sqlite3BtreeEnter(pBtree);
for(p=pBtree->pBt->pCursor; p; p=p->pNext){
int i;
if( writeOnly && (p->curFlags & BTCF_WriteFlag)==0 ){
if( p->eState==CURSOR_VALID ){
rc = saveCursorPosition(p);
if( rc!=SQLITE_OK ){
(void)sqlite3BtreeTripAllCursors(pBtree, rc, 0);
break;
}
}
}else{
sqlite3BtreeClearCursor(p);
p->eState = CURSOR_FAULT;
p->skipNext = errCode;
}
for(i=0; i<=p->iPage; i++){
releasePage(p->apPage[i]);
p->apPage[i] = 0;
}
}
sqlite3BtreeLeave(pBtree);
}
sqlite3BtreeLeave(pBtree);
return rc;
}
/*
** Rollback the transaction in progress. All cursors will be
** invalided by this operation. Any attempt to use a cursor
** that was open at the beginning of this operation will result
** in an error.
** Rollback the transaction in progress.
**
** If tripCode is not SQLITE_OK then cursors will be invalidated (tripped).
** Only write cursors are tripped if writeOnly is true but all cursors are
** tripped if writeOnly is false. Any attempt to use
** a tripped cursor will result in an error.
**
** This will release the write lock on the database file. If there
** are no active cursors, it also releases the read lock.
*/
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode){
SQLITE_PRIVATE int sqlite3BtreeRollback(Btree *p, int tripCode, int writeOnly){
int rc;
BtShared *pBt = p->pBt;
MemPage *pPage1;
assert( writeOnly==1 || writeOnly==0 );
assert( tripCode==SQLITE_ABORT_ROLLBACK || tripCode==SQLITE_OK );
sqlite3BtreeEnter(p);
if( tripCode==SQLITE_OK ){
rc = tripCode = saveAllCursors(pBt, 0, 0);
if( rc ) writeOnly = 0;
}else{
rc = SQLITE_OK;
}
if( tripCode ){
sqlite3BtreeTripAllCursors(p, tripCode);
int rc2 = sqlite3BtreeTripAllCursors(p, tripCode, writeOnly);
assert( rc==SQLITE_OK || (writeOnly==0 && rc2==SQLITE_OK) );
if( rc2!=SQLITE_OK ) rc = rc2;
}
btreeIntegrity(p);
@ -56036,13 +56077,9 @@ SQLITE_PRIVATE int sqlite3BtreeCursorIsValid(BtCursor *pCur){
*/
SQLITE_PRIVATE int sqlite3BtreeKeySize(BtCursor *pCur, i64 *pSize){
assert( cursorHoldsMutex(pCur) );
assert( pCur->eState==CURSOR_INVALID || pCur->eState==CURSOR_VALID );
if( pCur->eState!=CURSOR_VALID ){
*pSize = 0;
}else{
getCellInfo(pCur);
*pSize = pCur->info.nKey;
}
assert( pCur->eState==CURSOR_VALID );
getCellInfo(pCur);
*pSize = pCur->info.nKey;
return SQLITE_OK;
}
@ -61466,7 +61503,7 @@ SQLITE_API int sqlite3_backup_finish(sqlite3_backup *p){
}
/* If a transaction is still open on the Btree, roll it back. */
sqlite3BtreeRollback(p->pDest, SQLITE_OK);
sqlite3BtreeRollback(p->pDest, SQLITE_OK, 0);
/* Set the error code of the destination database handle. */
rc = (p->rc==SQLITE_DONE) ? SQLITE_OK : p->rc;
@ -71304,7 +71341,7 @@ case OP_Column: {
pC->payloadSize = pC->szRow = avail = pReg->n;
pC->aRow = (u8*)pReg->z;
}else{
MemSetTypeFlag(pDest, MEM_Null);
sqlite3VdbeMemSetNull(pDest);
goto op_column_out;
}
}else{
@ -71828,11 +71865,18 @@ case OP_Savepoint: {
db->isTransactionSavepoint = 0;
rc = p->rc;
}else{
int isSchemaChange;
iSavepoint = db->nSavepoint - iSavepoint - 1;
if( p1==SAVEPOINT_ROLLBACK ){
isSchemaChange = (db->flags & SQLITE_InternChanges)!=0;
for(ii=0; ii<db->nDb; ii++){
sqlite3BtreeTripAllCursors(db->aDb[ii].pBt, SQLITE_ABORT);
rc = sqlite3BtreeTripAllCursors(db->aDb[ii].pBt,
SQLITE_ABORT_ROLLBACK,
isSchemaChange==0);
if( rc!=SQLITE_OK ) goto abort_due_to_error;
}
}else{
isSchemaChange = 0;
}
for(ii=0; ii<db->nDb; ii++){
rc = sqlite3BtreeSavepoint(db->aDb[ii].pBt, p1, iSavepoint);
@ -71840,7 +71884,7 @@ case OP_Savepoint: {
goto abort_due_to_error;
}
}
if( p1==SAVEPOINT_ROLLBACK && (db->flags&SQLITE_InternChanges)!=0 ){
if( isSchemaChange ){
sqlite3ExpirePreparedStatements(db);
sqlite3ResetAllSchemasOfConnection(db);
db->flags = (db->flags | SQLITE_InternChanges);
@ -72237,7 +72281,7 @@ case OP_OpenWrite: {
|| p->readOnly==0 );
if( p->expired ){
rc = SQLITE_ABORT;
rc = SQLITE_ABORT_ROLLBACK;
break;
}
@ -73404,6 +73448,10 @@ case OP_Rowid: { /* out2-prerelease */
assert( pC->pCursor!=0 );
rc = sqlite3VdbeCursorRestore(pC);
if( rc ) goto abort_due_to_error;
if( pC->nullRow ){
pOut->flags = MEM_Null;
break;
}
rc = sqlite3BtreeKeySize(pC->pCursor, &v);
assert( rc==SQLITE_OK ); /* Always so because of CursorRestore() above */
}
@ -82435,7 +82483,6 @@ SQLITE_PRIVATE int sqlite3CodeSubselect(
assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );
pSelect->iLimit = 0;
testcase( pSelect->selFlags & SF_Distinct );
pSelect->selFlags &= ~SF_Distinct;
testcase( pKeyInfo==0 ); /* Caused by OOM in sqlite3KeyInfoAlloc() */
if( sqlite3Select(pParse, pSelect, &dest) ){
sqlite3KeyInfoUnref(pKeyInfo);
@ -125927,13 +125974,15 @@ SQLITE_PRIVATE void sqlite3LeaveMutexAndCloseZombie(sqlite3 *db){
/*
** Rollback all database files. If tripCode is not SQLITE_OK, then
** any open cursors are invalidated ("tripped" - as in "tripping a circuit
** any write cursors are invalidated ("tripped" - as in "tripping a circuit
** breaker") and made to return tripCode if there are any further
** attempts to use that cursor.
** attempts to use that cursor. Read cursors remain open and valid
** but are "saved" in case the table pages are moved around.
*/
SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
int i;
int inTrans = 0;
int schemaChange;
assert( sqlite3_mutex_held(db->mutex) );
sqlite3BeginBenignMalloc();
@ -125944,6 +125993,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
** the database rollback and schema reset, which can cause false
** corruption reports in some cases. */
sqlite3BtreeEnterAll(db);
schemaChange = (db->flags & SQLITE_InternChanges)!=0 && db->init.busy==0;
for(i=0; i<db->nDb; i++){
Btree *p = db->aDb[i].pBt;
@ -125951,7 +126001,7 @@ SQLITE_PRIVATE void sqlite3RollbackAll(sqlite3 *db, int tripCode){
if( sqlite3BtreeIsInTrans(p) ){
inTrans = 1;
}
sqlite3BtreeRollback(p, tripCode);
sqlite3BtreeRollback(p, tripCode, !schemaChange);
}
}
sqlite3VtabRollback(db);

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.8.7.1"
#define SQLITE_VERSION "3.8.7.2"
#define SQLITE_VERSION_NUMBER 3008007
#define SQLITE_SOURCE_ID "2014-10-29 13:59:56 3b7b72c4685aa5cf5e675c2c47ebec10d9704221"
#define SQLITE_SOURCE_ID "2014-11-18 20:57:56 2ab564bf9655b7c7b97ab85cafc8a48329b27f93"
/*
** CAPI3REF: Run-Time Library Version Numbers

View File

@ -47,6 +47,14 @@ class Foundation_API DateTimeParser
/// additional specifier is supported: %r will parse a year given by either
/// two or four digits. Years 69-00 are interpreted in the 20th century
/// (1969-2000), years 01-68 in the 21th century (2001-2068).
///
/// Note that in the current implementation all characters other than format specifiers in
/// the format string are ignored/not matched against the date/time string. This may
/// lead to non-error results even with nonsense input strings.
/// This may change in a future version to a more strict behavior.
/// If more strict format validation of date/time strings is required, a regular
/// expression could be used for initial validation, before passing the string
/// to DateTimeParser.
{
public:
static void parse(const std::string& fmt, const std::string& str, DateTime& dateTime, int& timeZoneDifferential);

View File

@ -22,6 +22,7 @@
#include "Poco/Foundation.h"
#include <vector>
#include <utility>
namespace Poco {
@ -40,11 +41,13 @@ class Foundation_API URI
///
/// The class automatically performs a few normalizations on
/// all URIs and URI parts passed to it:
/// * scheme identifiers are converted to lower case.
/// * scheme identifiers are converted to lower case
/// * percent-encoded characters are decoded
/// * optionally, dot segments are removed from paths (see normalize())
{
public:
typedef std::vector<std::pair<std::string, std::string> > QueryParameters;
URI();
/// Creates an empty URI.
@ -159,10 +162,30 @@ public:
/// Sets the path part of the URI.
std::string getQuery() const;
/// Returns the query part of the URI.
/// Returns the decoded query part of the URI.
///
/// Note that encoded ampersand characters ('&', "%26")
/// will be decoded, which could cause ambiguities if the query
/// string contains multiple parameters and a parameter name
/// or value contains an ampersand as well.
/// In such a case it's better to use getRawQuery() or
/// getQueryParameters().
void setQuery(const std::string& query);
/// Sets the query part of the URI.
///
/// The query string will be percent-encoded. If the query
/// already contains percent-encoded characters, these
/// will be double-encoded, which is probably not what's
/// intended by the caller. Furthermore, ampersand ('&')
/// characters in the query will not be encoded. This could
/// lead to ambiguity issues if the query string contains multiple
/// name-value parameters separated by ampersand, and if any
/// name or value also contains an ampersand. In such a
/// case, it's better to use setRawQuery() with a properly
/// percent-encoded query string, or use addQueryParameter()
/// or setQueryParameters(), which take care of appropriate
/// percent encoding of parameter names and values.
void addQueryParameter(const std::string& param, const std::string& val = "");
/// Adds "param=val" to the query; "param" may not be empty.
@ -172,11 +195,24 @@ public:
/// if found in param or val.
const std::string& getRawQuery() const;
/// Returns the unencoded query part of the URI.
/// Returns the query string in raw form, which usually
/// means percent encoded.
void setRawQuery(const std::string& query);
/// Sets the query part of the URI.
///
/// The given query string must be properly percent-encoded.
QueryParameters getQueryParameters() const;
/// Returns the decoded query string parameters as a vector
/// of name-value pairs.
void setQueryParameters(const QueryParameters& params);
/// Sets the query part of the URI from a vector
/// of query parameters.
///
/// Calls addQueryParameter() for each parameter name and value.
const std::string& getFragment() const;
/// Returns the fragment part of the URI.
@ -246,6 +282,7 @@ public:
/// URI-decodes the given string by replacing percent-encoded
/// characters with the actual character. The decoded string
/// is appended to decodedStr.
///
/// When plusAsSpace is true, non-encoded plus signs in the query are decoded as spaces.
/// (http://www.w3.org/TR/html401/interact/forms.html#h-17.13.4.1)

View File

@ -392,7 +392,38 @@ void DateTime::computeGregorian(double julianDay)
void DateTime::computeDaytime()
{
Timespan span(_utcTime/10);
_hour = span.hours();
int hour = span.hours();
// Due to double rounding issues, the previous call to computeGregorian()
// may have crossed into the next or previous day. We need to correct that.
if (hour == 23 && _hour == 0)
{
_day--;
if (_day == 0)
{
_month--;
if (_month == 0)
{
_month = 12;
_year--;
}
_day = daysOfMonth(_year, _month);
}
}
else if (hour == 0 && _hour == 23)
{
_day++;
if (_day > daysOfMonth(_year, _month))
{
_month++;
if (_month > 12)
{
_month = 1;
_year++;
}
_day = 1;
}
}
_hour = hour;
_minute = span.minutes();
_second = span.seconds();
_millisecond = span.milliseconds();

View File

@ -228,7 +228,7 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts)
FILETIME ft;
ft.dwLowDateTime = low;
ft.dwHighDateTime = high;
FileHandle fh(_path, FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING);
FileHandle fh(_path, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING);
if (SetFileTime(fh.get(), 0, &ft, &ft) == 0)
handleLastErrorImpl(_path);
}

View File

@ -232,7 +232,7 @@ void FileImpl::setLastModifiedImpl(const Timestamp& ts)
FILETIME ft;
ft.dwLowDateTime = low;
ft.dwHighDateTime = high;
FileHandle fh(_path, _upath, FILE_ALL_ACCESS, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING);
FileHandle fh(_path, _upath, FILE_WRITE_ATTRIBUTES, FILE_SHARE_READ | FILE_SHARE_WRITE, OPEN_EXISTING);
if (SetFileTime(fh.get(), 0, &ft, &ft) == 0)
handleLastErrorImpl(_path);
}

View File

@ -20,6 +20,7 @@
#include "Poco/Pipe.h"
#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/resource.h>
@ -149,6 +150,20 @@ ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const Arg
ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env)
{
// We must not allocated memory after fork(),
// therefore allocate all required buffers first.
std::vector<char> envChars = getEnvironmentVariablesBuffer(env);
std::vector<char*> argv(args.size() + 2);
int i = 0;
argv[i++] = const_cast<char*>(command.c_str());
for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
{
argv[i++] = const_cast<char*>(it->c_str());
}
argv[i] = NULL;
const char* pInitialDirectory = initialDirectory.empty() ? 0 : initialDirectory.c_str();
int pid = fork();
if (pid < 0)
{
@ -156,15 +171,22 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
}
else if (pid == 0)
{
if (!initialDirectory.empty())
if (pInitialDirectory)
{
if (chdir(initialDirectory.c_str()) != 0)
if (chdir(pInitialDirectory) != 0)
{
_exit(72);
}
}
setEnvironmentVariables(env);
// set environment variables
char* p = &envChars[0];
while (*p)
{
putenv(p);
while (*p) ++p;
++p;
}
// setup redirection
if (inPipe)
@ -179,15 +201,11 @@ ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command,
if (errPipe) errPipe->close(Pipe::CLOSE_BOTH);
// close all open file descriptors other than stdin, stdout, stderr
for (int i = 3; i < getdtablesize(); ++i)
{
close(i);
}
char** argv = new char*[args.size() + 2];
int i = 0;
argv[i++] = const_cast<char*>(command.c_str());
for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
argv[i++] = const_cast<char*>(it->c_str());
argv[i] = NULL;
execvp(command.c_str(), argv);
execvp(argv[0], &argv[0]);
_exit(72);
}

View File

@ -26,7 +26,7 @@ namespace Poco {
const std::string URI::RESERVED_PATH = "?#";
const std::string URI::RESERVED_QUERY = "#/";
const std::string URI::RESERVED_QUERY = "?#/";
const std::string URI::RESERVED_FRAGMENT = "";
const std::string URI::ILLEGAL = "%<>{}|\\\"^`";
@ -335,9 +335,9 @@ void URI::addQueryParameter(const std::string& param, const std::string& val)
{
std::string reserved(RESERVED_QUERY);
reserved += "=&";
if (!_query.empty()) _query.append(1, '&');
if (!_query.empty()) _query += '&';
encode(param, reserved, _query);
_query.append(1, '=');
_query += '=';
encode(val, reserved, _query);
}
@ -350,6 +350,56 @@ std::string URI::getQuery() const
}
URI::QueryParameters URI::getQueryParameters() const
{
QueryParameters result;
std::string::const_iterator it(_query.begin());
std::string::const_iterator end(_query.end());
while (it != end)
{
std::string name;
std::string value;
while (it != end && *it != '=' && *it != '&')
{
if (*it == '+')
name += ' ';
else
name += *it;
++it;
}
if (it != end && *it == '=')
{
++it;
while (it != end && *it != '&')
{
if (*it == '+')
value += ' ';
else
value += *it;
++it;
}
}
std::string decodedName;
std::string decodedValue;
URI::decode(name, decodedName);
URI::decode(value, decodedValue);
result.push_back(std::make_pair(decodedName, decodedValue));
if (it != end && *it == '&') ++it;
}
return result;
}
void URI::setQueryParameters(const QueryParameters& params)
{
_query.clear();
for (QueryParameters::const_iterator it = params.begin(); it != params.end(); ++it)
{
addQueryParameter(it->first, it->second);
}
}
void URI::setFragment(const std::string& fragment)
{
_fragment.clear();

View File

@ -18,8 +18,10 @@
#include "Poco/Timespan.h"
#include "Poco/Exception.h"
GCC_DIAG_OFF(unused-variable)
using Poco::Timestamp;
using Poco::DateTime;
using Poco::Timespan;
@ -443,6 +445,28 @@ void DateTimeTest::testArithmetics()
loop_1_assert(line, data[di].month2 == X.month());
loop_1_assert(line, data[di].day2 == X.day());
}
DateTime edgeTime(2014, 9, 16, 0, 0, 0, 0, 10);
edgeTime -= Poco::Timespan(11);
assert (edgeTime.year() == 2014);
assert (edgeTime.month() == 9);
assert (edgeTime.day() == 15);
assert (edgeTime.hour() == 23);
assert (edgeTime.minute() == 59);
assert (edgeTime.second() == 59);
assert (edgeTime.millisecond() == 999);
assert (edgeTime.microsecond() == 999);
edgeTime.assign(2014, 9, 15, 23, 59, 59, 999, 968);
edgeTime += Poco::Timespan(11);
assert (edgeTime.year() == 2014);
assert (edgeTime.month() == 9);
assert (edgeTime.day() == 15);
assert (edgeTime.hour() == 23);
assert (edgeTime.minute() == 59);
assert (edgeTime.second() == 59);
assert (edgeTime.millisecond() == 999);
assert (edgeTime.microsecond() == 979);
}
void DateTimeTest::testIncrementDecrement()

View File

@ -720,6 +720,7 @@ void URITest::testSwap()
assert (uri2.toString() == "http://www.appinf.com/search.cgi?keyword=test%20encoded&scope=all#result");
}
void URITest::testOther()
{
// The search string is "hello%world"; google happens to ignore the '%'
@ -735,6 +736,18 @@ void URITest::testOther()
assert(uri.toString() == "http://google.com/search?q=hello%25world#frag%20ment");
assert(uri.getPathEtc() == "/search?q=hello%25world#frag%20ment");
uri.setQuery("q=foo&bar");
assert(uri.getQuery() == "q=foo&bar");
assert(uri.getRawQuery() == "q=foo&bar");
assert(uri.toString() == "http://google.com/search?q=foo&bar#frag%20ment");
assert(uri.getPathEtc() == "/search?q=foo&bar#frag%20ment");
uri.setQuery("q=foo/bar");
assert(uri.getQuery() == "q=foo/bar");
assert(uri.getRawQuery() == "q=foo%2Fbar");
assert(uri.toString() == "http://google.com/search?q=foo%2Fbar#frag%20ment");
assert(uri.getPathEtc() == "/search?q=foo%2Fbar#frag%20ment");
uri.setQuery("q=goodbye cruel world");
assert(uri.getQuery() == "q=goodbye cruel world");
assert(uri.getRawQuery() == "q=goodbye%20cruel%20world");
@ -753,6 +766,15 @@ void URITest::testOther()
uri.addQueryParameter("pa=ra&m2", "val&ue");
assert(uri.getRawQuery() == "q=pony%7eride&pa%3Dra%26m1=&pa%3Dra%26m2=val%26ue");
assert(uri.getQuery() == "q=pony~ride&pa=ra&m1=&pa=ra&m2=val&ue");
uri = "http://google.com/search?q=hello+world#frag%20ment";
assert(uri.getHost() == "google.com");
assert(uri.getPath() == "/search");
assert(uri.getQuery() == "q=hello+world");
assert(uri.getRawQuery() == "q=hello+world");
assert(uri.getFragment() == "frag ment");
assert(uri.toString() == "http://google.com/search?q=hello+world#frag%20ment");
assert(uri.getPathEtc() == "/search?q=hello+world#frag%20ment");
}
@ -792,6 +814,40 @@ void URITest::testFromPath()
}
void URITest::testQueryParameters()
{
Poco::URI uri("http://google.com/search?q=hello+world&client=safari");
URI::QueryParameters params = uri.getQueryParameters();
assert (params.size() == 2);
assert (params[0].first == "q");
assert (params[0].second == "hello world");
assert (params[1].first == "client");
assert (params[1].second == "safari");
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=hello%20world&client=safari");
uri = "http://google.com/search?q=&client&";
params = uri.getQueryParameters();
assert (params.size() == 2);
assert (params[0].first == "q");
assert (params[0].second == "");
assert (params[1].first == "client");
assert (params[1].second == "");
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=&client=");
params[0].second = "foo/bar?";
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=foo%2Fbar%3F&client=");
params[0].second = "foo&bar";
uri.setQueryParameters(params);
assert (uri.toString() == "http://google.com/search?q=foo%26bar&client=");
}
void URITest::setUp()
{
}
@ -816,6 +872,7 @@ CppUnit::Test* URITest::suite()
CppUnit_addTest(pSuite, URITest, testEncodeDecode);
CppUnit_addTest(pSuite, URITest, testOther);
CppUnit_addTest(pSuite, URITest, testFromPath);
CppUnit_addTest(pSuite, URITest, testQueryParameters);
return pSuite;
}

View File

@ -36,6 +36,7 @@ public:
void testEncodeDecode();
void testOther();
void testFromPath();
void testQueryParameters();
void setUp();
void tearDown();

View File

@ -46,7 +46,7 @@ public:
explicit HTTPAuthenticationParams(const HTTPRequest& request);
/// See fromRequest() documentation.
explicit HTTPAuthenticationParams(const HTTPResponse& response);
HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header = WWW_AUTHENTICATE);
/// See fromResponse() documentation.
virtual ~HTTPAuthenticationParams();
@ -68,7 +68,7 @@ public:
/// Throws a InvalidArgumentException if authentication scheme is
/// unknown or invalid.
void fromResponse(const HTTPResponse& response);
void fromResponse(const HTTPResponse& response, const std::string& header = WWW_AUTHENTICATE);
/// Extracts authentication information from the response and creates
/// HTTPAuthenticationParams by parsing it.
///
@ -91,6 +91,8 @@ public:
/// request or response authentication header.
static const std::string REALM;
static const std::string WWW_AUTHENTICATE;
static const std::string PROXY_AUTHENTICATE;
private:
void parse(std::string::const_iterator first, std::string::const_iterator last);

View File

@ -52,6 +52,9 @@ public:
~HTTPDigestCredentials();
/// Destroys the HTTPDigestCredentials.
void reset();
/// Resets the HTTPDigestCredentials object to a clean state.
void setUsername(const std::string& username);
/// Sets the username.

View File

@ -23,6 +23,7 @@
#include "Poco/Net/Net.h"
#include "Poco/String.h"
#include "Poco/ListMap.h"
#include <cstddef>
namespace Poco {
@ -97,7 +98,7 @@ public:
bool empty() const;
/// Returns true iff the header does not have any content.
int size() const;
std::size_t size() const;
/// Returns the number of name-value pairs in the
/// collection.

View File

@ -68,6 +68,8 @@ namespace Net {
const std::string HTTPAuthenticationParams::REALM("realm");
const std::string HTTPAuthenticationParams::WWW_AUTHENTICATE("WWW-Authenticate");
const std::string HTTPAuthenticationParams::PROXY_AUTHENTICATE("Proxy-Authenticate");
HTTPAuthenticationParams::HTTPAuthenticationParams()
@ -87,9 +89,9 @@ HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPRequest& request)
}
HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response)
HTTPAuthenticationParams::HTTPAuthenticationParams(const HTTPResponse& response, const std::string& header)
{
fromResponse(response);
fromResponse(response, header);
}
@ -126,22 +128,29 @@ void HTTPAuthenticationParams::fromRequest(const HTTPRequest& request)
}
void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response)
void HTTPAuthenticationParams::fromResponse(const HTTPResponse& response, const std::string& header)
{
if (!response.has("WWW-Authenticate"))
NameValueCollection::ConstIterator it = response.find(header);
if (it == response.end())
throw NotAuthenticatedException("HTTP response has no authentication header");
const std::string& header = response.get("WWW-Authenticate");
if (icompare(header, 0, 6, "Basic ") == 0)
bool found = false;
while (!found && it != response.end() && icompare(it->first, header) == 0)
{
parse(header.begin() + 6, header.end());
}
else if (icompare(header, 0, 7, "Digest ") == 0)
{
parse(header.begin() + 7, header.end());
}
else throw InvalidArgumentException("Invalid authentication scheme", header);
const std::string& header = it->second;
if (icompare(header, 0, 6, "Basic ") == 0)
{
parse(header.begin() + 6, header.end());
found = true;
}
else if (icompare(header, 0, 7, "Digest ") == 0)
{
parse(header.begin() + 7, header.end());
found = true;
}
++it;
}
if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found");
}

View File

@ -267,17 +267,13 @@ std::istream& HTTPClientSession::receiveResponse(HTTPResponse& response)
{
response.read(his);
}
catch (MessageException&)
catch (Exception&)
{
close();
if (networkException())
networkException()->rethrow();
else
throw;
}
catch (Exception&)
{
close();
throw;
}
}

View File

@ -57,7 +57,7 @@ void HTTPCredentials::fromUserInfo(const std::string& userInfo)
extractCredentials(userInfo, username, password);
setUsername(username);
setPassword(password);
// TODO: Reset digest state?
_digest.reset();
}
@ -69,13 +69,13 @@ void HTTPCredentials::fromURI(const URI& uri)
extractCredentials(uri, username, password);
setUsername(username);
setPassword(password);
// TODO: Reset digest state?
_digest.reset();
}
void HTTPCredentials::authenticate(HTTPRequest& request, const HTTPResponse& response)
{
for (HTTPResponse::ConstIterator iter = response.find("WWW-Authenticate"); iter != response.end(); ++iter)
for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::WWW_AUTHENTICATE); iter != response.end(); ++iter)
{
if (isBasicCredentials(iter->second))
{
@ -111,7 +111,7 @@ void HTTPCredentials::updateAuthInfo(HTTPRequest& request)
void HTTPCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
{
for (HTTPResponse::ConstIterator iter = response.find("Proxy-Authenticate"); iter != response.end(); ++iter)
for (HTTPResponse::ConstIterator iter = response.find(HTTPAuthenticationParams::PROXY_AUTHENTICATE); iter != response.end(); ++iter)
{
if (isBasicCredentials(iter->second))
{

View File

@ -104,6 +104,13 @@ HTTPDigestCredentials::~HTTPDigestCredentials()
}
void HTTPDigestCredentials::reset()
{
_requestAuthParams.clear();
_nc.clear();
}
void HTTPDigestCredentials::setUsername(const std::string& username)
{
_username = username;
@ -138,7 +145,7 @@ void HTTPDigestCredentials::updateAuthInfo(HTTPRequest& request)
void HTTPDigestCredentials::proxyAuthenticate(HTTPRequest& request, const HTTPResponse& response)
{
proxyAuthenticate(request, HTTPAuthenticationParams(response));
proxyAuthenticate(request, HTTPAuthenticationParams(response, HTTPAuthenticationParams::PROXY_AUTHENTICATE));
}

View File

@ -209,7 +209,6 @@ void HTTPRequest::read(std::istream& istr)
uri.reserve(64);
version.reserve(16);
int ch = istr.get();
if (istr.bad()) throw NetException("Network failure while reading HTTP request header");
if (istr.bad()) throw NetException("Error reading HTTP request header");
if (ch == eof) throw NoMessageException();
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
@ -259,5 +258,4 @@ void HTTPRequest::setCredentials(const std::string& header, const std::string& s
}
} } // namespace Poco::Net

View File

@ -208,6 +208,7 @@ void HTTPResponse::read(std::istream& istr)
std::string reason;
int ch = istr.get();
if (istr.bad()) throw NetException("Error reading HTTP response header");
if (ch == eof) throw NoMessageException();
while (Poco::Ascii::isSpace(ch)) ch = istr.get();
if (ch == eof) throw MessageException("No HTTP response header");

View File

@ -134,9 +134,9 @@ bool NameValueCollection::empty() const
}
int NameValueCollection::size() const
std::size_t NameValueCollection::size() const
{
return (int) _map.size();
return _map.size();
}

View File

@ -196,7 +196,7 @@ void POP3ClientSession::retrieveMessage(int id, MailMessage& message)
{
std::string response;
sendCommand("RETR", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot get message list", response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
message.read(mis);
@ -208,7 +208,7 @@ void POP3ClientSession::retrieveMessage(int id, MailMessage& message, PartHandle
{
std::string response;
sendCommand("RETR", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot get message list", response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
message.read(mis, handler);
@ -220,7 +220,7 @@ void POP3ClientSession::retrieveMessage(int id, std::ostream& ostr)
{
std::string response;
sendCommand("RETR", NumberFormatter::format(id), response);
if (!isPositive(response)) throw POP3Exception("Cannot get message list", response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve message", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
StreamCopier::copyStream(mis, ostr);
@ -231,7 +231,7 @@ void POP3ClientSession::retrieveHeader(int id, MessageHeader& header)
{
std::string response;
sendCommand("TOP", NumberFormatter::format(id), "0", response);
if (!isPositive(response)) throw POP3Exception("Cannot get message list", response);
if (!isPositive(response)) throw POP3Exception("Cannot retrieve header", response);
DialogInputStream sis(_socket);
MailInputStream mis(sis);
header.read(mis);

View File

@ -51,7 +51,7 @@ void TCPServerParams::setMaxThreads(int count)
void TCPServerParams::setMaxQueued(int count)
{
poco_assert (count > 0);
poco_assert (count >= 0);
_maxQueued = count;
}

View File

@ -145,6 +145,19 @@ void HTTPCredentialsTest::testAuthenticationParams()
}
void HTTPCredentialsTest::testAuthenticationParamsMultipleHeaders()
{
HTTPResponse response;
response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\"");
response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
HTTPAuthenticationParams params(response);
assert (params["realm"] == "TestDigest");
assert (params["nonce"] == "212573bb90170538efad012978ab811f%lu");
assert (params.size() == 2);
}
void HTTPCredentialsTest::testDigestCredentials()
{
HTTPDigestCredentials creds("user", "s3cr3t");
@ -231,6 +244,19 @@ void HTTPCredentialsTest::testCredentialsDigest()
}
void HTTPCredentialsTest::testCredentialsDigestMultipleHeaders()
{
HTTPCredentials creds("user", "s3cr3t");
HTTPRequest request(HTTPRequest::HTTP_GET, "/digest/");
HTTPResponse response;
response.add("WWW-Authenticate", "Unsupported realm=\"TestUnsupported\"");
response.add("WWW-Authenticate", "Digest realm=\"TestDigest\", nonce=\"212573bb90170538efad012978ab811f%lu\"");
creds.authenticate(request, response);
std::string auth = request.get("Authorization");
assert (auth == "Digest username=\"user\", nonce=\"212573bb90170538efad012978ab811f%lu\", realm=\"TestDigest\", uri=\"/digest/\", response=\"40e4889cfbd0e561f71e3107a2863bc4\"");
}
void HTTPCredentialsTest::testProxyCredentialsDigest()
{
HTTPCredentials creds("user", "s3cr3t");
@ -299,11 +325,13 @@ CppUnit::Test* HTTPCredentialsTest::suite()
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyBasicCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testBadCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParams);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testAuthenticationParamsMultipleHeaders);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testDigestCredentialsQoP);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsBasic);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsBasic);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigest);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testCredentialsDigestMultipleHeaders);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testProxyCredentialsDigest);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testExtractCredentials);
CppUnit_addTest(pSuite, HTTPCredentialsTest, testVerifyAuthInfo);

View File

@ -30,11 +30,13 @@ public:
void testProxyBasicCredentials();
void testBadCredentials();
void testAuthenticationParams();
void testAuthenticationParamsMultipleHeaders();
void testDigestCredentials();
void testDigestCredentialsQoP();
void testCredentialsBasic();
void testProxyCredentialsBasic();
void testCredentialsDigest();
void testCredentialsDigestMultipleHeaders();
void testProxyCredentialsDigest();
void testExtractCredentials();
void testVerifyAuthInfo();

View File

@ -219,39 +219,39 @@ int Application::loadConfiguration(int priority)
int n = 0;
Path appPath;
getApplicationPath(appPath);
Path cfgPath;
if (findAppConfigFile(appPath.getBaseName(), "properties", cfgPath))
Path confPath;
if (findAppConfigFile(appPath.getBaseName(), "properties", confPath))
{
_pConfig->add(new PropertyFileConfiguration(cfgPath.toString()), priority, false, false);
_pConfig->add(new PropertyFileConfiguration(confPath.toString()), priority, false, false);
++n;
}
#ifndef POCO_UTIL_NO_INIFILECONFIGURATION
if (findAppConfigFile(appPath.getBaseName(), "ini", cfgPath))
if (findAppConfigFile(appPath.getBaseName(), "ini", confPath))
{
_pConfig->add(new IniFileConfiguration(cfgPath.toString()), priority, false, false);
_pConfig->add(new IniFileConfiguration(confPath.toString()), priority, false, false);
++n;
}
#endif
#ifndef POCO_UTIL_NO_JSONCONFIGURATION
if (findAppConfigFile(appPath.getBaseName(), "json", cfgPath))
if (findAppConfigFile(appPath.getBaseName(), "json", confPath))
{
_pConfig->add(new JSONConfiguration(cfgPath.toString()), priority, false, false);
_pConfig->add(new JSONConfiguration(confPath.toString()), priority, false, false);
++n;
}
#endif
#ifndef POCO_UTIL_NO_XMLCONFIGURATION
if (findAppConfigFile(appPath.getBaseName(), "xml", cfgPath))
if (findAppConfigFile(appPath.getBaseName(), "xml", confPath))
{
_pConfig->add(new XMLConfiguration(cfgPath.toString()), priority, false, false);
_pConfig->add(new XMLConfiguration(confPath.toString()), priority, false, false);
++n;
}
#endif
if (n > 0)
{
if (!cfgPath.isAbsolute())
_pConfig->setString("application.configDir", cfgPath.absolute().parent().toString());
if (!confPath.isAbsolute())
_pConfig->setString("application.configDir", confPath.absolute().parent().toString());
else
_pConfig->setString("application.configDir", cfgPath.parent().toString());
_pConfig->setString("application.configDir", confPath.parent().toString());
}
return n;
}
@ -259,24 +259,44 @@ int Application::loadConfiguration(int priority)
void Application::loadConfiguration(const std::string& path, int priority)
{
int n = 0;
Path confPath(path);
std::string ext = confPath.getExtension();
if (icompare(ext, "properties") == 0)
{
_pConfig->add(new PropertyFileConfiguration(confPath.toString()), priority, false, false);
++n;
}
#ifndef POCO_UTIL_NO_INIFILECONFIGURATION
else if (icompare(ext, "ini") == 0)
{
_pConfig->add(new IniFileConfiguration(confPath.toString()), priority, false, false);
++n;
}
#endif
#ifndef POCO_UTIL_NO_JSONCONFIGURATION
else if (icompare(ext, "json") == 0)
{
_pConfig->add(new JSONConfiguration(confPath.toString()), priority, false, false);
++n;
}
#endif
#ifndef POCO_UTIL_NO_XMLCONFIGURATION
else if (icompare(ext, "xml") == 0)
{
_pConfig->add(new XMLConfiguration(confPath.toString()), priority, false, false);
++n;
}
#endif
else
throw Poco::InvalidArgumentException("Unsupported configuration file type", ext);
else throw Poco::InvalidArgumentException("Unsupported configuration file type", ext);
if (n > 0 && !_pConfig->has("application.configDir"))
{
if (!confPath.isAbsolute())
_pConfig->setString("application.configDir", confPath.absolute().parent().toString());
else
_pConfig->setString("application.configDir", confPath.parent().toString());
}
}