mirror of
https://github.com/pocoproject/poco.git
synced 2025-04-01 09:24:55 +02:00
Merge branch 'develop' of https://github.com/pocoproject/poco into develop
This commit is contained in:
commit
599c4cb3aa
@ -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;
|
||||
};
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
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);
|
||||
}
|
||||
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{
|
||||
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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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,10 +195,23 @@ 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)
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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();
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ public:
|
||||
void testEncodeDecode();
|
||||
void testOther();
|
||||
void testFromPath();
|
||||
void testQueryParameters();
|
||||
|
||||
void setUp();
|
||||
void tearDown();
|
||||
|
@ -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);
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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");
|
||||
|
||||
bool found = false;
|
||||
while (!found && it != response.end() && icompare(it->first, header) == 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
else throw InvalidArgumentException("Invalid authentication scheme", header);
|
||||
++it;
|
||||
}
|
||||
if (!found) throw NotAuthenticatedException("No Basic or Digest authentication header found");
|
||||
}
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
{
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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();
|
||||
}
|
||||
|
||||
|
||||
|
@ -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);
|
||||
|
@ -51,7 +51,7 @@ void TCPServerParams::setMaxThreads(int count)
|
||||
|
||||
void TCPServerParams::setMaxQueued(int count)
|
||||
{
|
||||
poco_assert (count > 0);
|
||||
poco_assert (count >= 0);
|
||||
|
||||
_maxQueued = count;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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();
|
||||
|
@ -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);
|
||||
|
||||
if (n > 0 && !_pConfig->has("application.configDir"))
|
||||
{
|
||||
if (!confPath.isAbsolute())
|
||||
_pConfig->setString("application.configDir", confPath.absolute().parent().toString());
|
||||
else
|
||||
throw Poco::InvalidArgumentException("Unsupported configuration file type", ext);
|
||||
_pConfig->setString("application.configDir", confPath.parent().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user