summaryrefslogtreecommitdiffstats
path: root/base/tps/src/httpClient
diff options
context:
space:
mode:
Diffstat (limited to 'base/tps/src/httpClient')
-rw-r--r--base/tps/src/httpClient/Cache.cpp496
-rw-r--r--base/tps/src/httpClient/engine.cpp775
-rw-r--r--base/tps/src/httpClient/http.cpp307
-rw-r--r--base/tps/src/httpClient/httpClient.cpp130
-rw-r--r--base/tps/src/httpClient/nscperror.cpp358
-rw-r--r--base/tps/src/httpClient/request.cpp431
-rw-r--r--base/tps/src/httpClient/response.cpp1115
7 files changed, 3612 insertions, 0 deletions
diff --git a/base/tps/src/httpClient/Cache.cpp b/base/tps/src/httpClient/Cache.cpp
new file mode 100644
index 000000000..2ea628f8c
--- /dev/null
+++ b/base/tps/src/httpClient/Cache.cpp
@@ -0,0 +1,496 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ */
+/** BEGIN COPYRIGHT BLOCK
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/**
+ * Simple cache implementation
+ */
+#include <string.h>
+#include <time.h>
+
+// NSS includes
+#include "pk11func.h"
+#include "hasht.h"
+
+// NSPR includes
+#include "nspr.h"
+#include "plhash.h"
+#include "plstr.h"
+#include "plbase64.h"
+
+// Always before PSCommonLib.h
+#define COMMON_LIB_DLL
+#include "httpClient/httpc/PSCommonLib.h"
+#include "httpClient/httpc/Defines.h"
+//-- #include "httpClient/httpc/PSError.h"
+#include "httpClient/httpc/Iterator.h"
+#include "httpClient/httpc/Cache.h"
+//-- #include "httpClient/httpc/DebugLogger.h"
+//-- #include "httpClient/httpc/ErrorLogger.h"
+
+#include "engine/RA.h"
+#include "main/Memory.h"
+
+//-- static const char *DEBUG_MODULE = NULL;
+//-- static const char *DEBUG_CLASS_NAME = "StringKeyCache";
+
+// From the NSPR implementation of hashtables
+/* Compute the number of buckets in ht */
+#define NBUCKETS(ht) (1 << (PL_HASH_BITS - (ht)->shift))
+
+
+/**
+ * Called from the destructor
+ */
+extern "C" {
+static PRIntn onCacheRelease( PLHashEntry* he, PRIntn index, void* arg );
+/**
+ * Called to allocate and return copies of keys
+ */
+static PRIntn getKeys( PLHashEntry* he, PRIntn index, void* arg );
+}
+
+/**
+ * Constructor
+ *
+ * @param key Pointer to the key being cached
+ * @param data Pointer to the data being cached
+ */
+CacheEntry::CacheEntry( const char* key, void *data ) {
+ if( key != NULL ) {
+ m_key = strdup( key );
+ } else {
+ m_key = NULL;
+ }
+ m_data = data;
+ // NSPR counts in microseconds
+ m_startTime = (time_t)(PR_Now() / 1000000);
+}
+
+/**
+ * Destructor
+ */
+CacheEntry::~CacheEntry() {
+ if( m_key != NULL ) {
+ free( m_key );
+ m_key = NULL;
+ }
+}
+
+/**
+ * Returns a pointer to the cached key
+ *
+ * @return A pointer to the cached key
+ */
+const char *CacheEntry::GetKey() {
+ return m_key;
+}
+
+/**
+ * Returns a pointer to the cached data
+ *
+ * @return A pointer to the cached data
+ */
+void *CacheEntry::GetData() {
+ return m_data;
+}
+
+
+/**
+ * Returns the time when the entry was created
+ *
+ * @return The time when the entry was created
+ */
+long CacheEntry::GetStartTime() {
+ return (long)m_startTime;
+}
+
+
+/**
+ * Default constructor
+ */
+Cache::Cache() {
+ m_cache = NULL;
+ m_cacheLock = NULL;
+}
+
+/**
+ * Constructor
+ *
+ * @param name of the cache
+ * @param ttl Time to live of each cache entry
+ * @param implicitLock true if the Cache is to do locking internally
+ * when required; false if the caller will take responsibility
+ */
+Cache::Cache( const char *name, int ttl, bool implicitLock ) {
+
+ Initialize( name, ttl, implicitLock );
+}
+
+/**
+ * Destructor
+ */
+Cache::~Cache() {
+
+ if( m_cacheLock ) {
+ PR_DestroyRWLock( m_cacheLock );
+ m_cacheLock = NULL;
+ }
+ if( m_cache ) {
+ PL_HashTableEnumerateEntries( m_cache, onCacheRelease, NULL );
+ PL_HashTableDestroy( m_cache );
+ m_cache = NULL;
+ }
+
+}
+
+/**
+ * Initializes the object - to be called from the constructor
+ *
+ * @param name of the cache
+ * @param ttl Time to live of each cache entry
+ * @param implicitLock true if the Cache is to do locking internally
+ * when required; false if the caller will take responsibility
+ */
+void Cache::Initialize( const char *name, int ttl, bool implicitLock ) {
+
+ if ( !m_cache ) {
+ m_implicitLock = implicitLock;
+ m_ttl = ttl;
+ m_cache = PL_NewHashTable( 0,
+ PL_HashString,
+ PL_CompareStrings,
+ PL_CompareValues,
+ NULL,
+ NULL
+ );
+ m_cacheLock = PR_NewRWLock( PR_RWLOCK_RANK_NONE, name );
+ m_name = name;
+ }
+
+}
+
+/**
+ * Acquires a read lock on the cache. Multiple threads may simultaneously
+ * have a read lock, but attempts to acquire a read lock will block
+ * if another thread already has a write lock. It is illegal to request
+ * a read lock if the thread already has one.
+ */
+void Cache::ReadLock() {
+ PR_RWLock_Rlock( m_cacheLock );
+}
+
+/**
+ * Acquires a write lock on the cache. Only one thread may have a write
+ * lock at any given time; attempts to acquire a write lock will block
+ * if another thread already has one. It is illegal to request
+ * a write lock if the thread already has one.
+ */
+void Cache::WriteLock() {
+ PR_RWLock_Wlock( m_cacheLock );
+}
+
+/**
+ * Releases a read or write lock that the thread has on the cache
+ */
+void Cache::Unlock() {
+ PR_RWLock_Unlock( m_cacheLock );
+}
+
+/**
+ * Returns the number of entries in the cache
+ *
+ * @return The number of entries in the cache
+ */
+int Cache::GetCount() {
+ int nKeys = 0;
+ if ( m_implicitLock ) {
+ ReadLock();
+ }
+ nKeys = m_cache->nentries;
+ if ( m_implicitLock ) {
+ Unlock();
+ }
+ return nKeys;
+}
+
+class KeyIterator : public Iterator {
+public:
+ /**
+ * Constructor
+ *
+ * @param ht A hashtable to iterate on
+ * @param cacheLock Lock for accessing the hashtable
+ * @param implictLock true if hashtable locking is to be done
+ * internally
+ */
+ KeyIterator( PLHashTable *ht, PRRWLock *cacheLock, bool implicitLock ) {
+ m_table = ht;
+ m_bucketIndex = 0;
+ m_entry = m_table->buckets[m_bucketIndex];
+ m_cacheLock = cacheLock;
+ m_implicitLock = implicitLock;
+ }
+
+ /**
+ * Destructor
+ */
+ virtual ~KeyIterator() {
+ }
+
+ /**
+ * Returns true if there is at least one more key
+ *
+ * @return true if there is at least one more key
+ */
+ bool HasMore() {
+ if ( NULL == m_entry ) {
+ Next();
+ }
+ return ( NULL != m_entry );
+ }
+
+ /**
+ * Returns the next key, if any; the key is deallocated by the Iterator
+ * in its destructor
+ *
+ * @return The next key, if any, or NULL
+ */
+ void *Next() {
+ PLHashEntry *he = m_entry;
+ m_entry = (m_entry != NULL) ? m_entry->next : NULL;
+ int nBuckets = NBUCKETS(m_table);
+ if ( m_implicitLock ) {
+ PR_RWLock_Rlock( m_cacheLock );
+ }
+ while ( (NULL == m_entry) && (m_bucketIndex < (nBuckets-1)) ) {
+ m_bucketIndex++;
+ m_entry = m_table->buckets[m_bucketIndex];
+ }
+ if ( m_implicitLock ) {
+ PR_RWLock_Unlock( m_cacheLock );
+ }
+ return ( he != NULL ) ? (void *)he->key : NULL;
+ }
+
+private:
+ PLHashTable *m_table;
+ PLHashEntry *m_entry;
+ int m_bucketIndex;
+ PRRWLock* m_cacheLock;
+ bool m_implicitLock;
+};
+
+/**
+ * Constructor
+ *
+ * @param name of the cache
+ * @param ttl Time to live of each cache entry
+ * @param implicitLock true if the Cache is to do locking internally
+ * when required; false if the caller will take responsibility
+ */
+StringKeyCache::StringKeyCache( const char *name, int ttl,
+ bool implicitLock ) {
+
+ Initialize( name, ttl, implicitLock );
+
+}
+
+/**
+ * Destructor
+ */
+StringKeyCache::~StringKeyCache() {
+}
+
+/**
+ * Returns a cache entry
+ *
+ * @param key The name of the cache entry
+ * @return The corresponding cache entry, or NULL if not found
+ */
+CacheEntry *StringKeyCache::Get( const char *key ) {
+ // Avoid recursion when the debug log is starting up
+
+ if ( m_implicitLock ) {
+ ReadLock();
+ }
+ CacheEntry *entry =
+ (CacheEntry *)PL_HashTableLookupConst( m_cache, key );
+ if ( m_implicitLock ) {
+ Unlock();
+ }
+ if ( entry && m_ttl ) {
+ // Check if the cache entry has expired
+ // NSPR counts in microseconds
+ time_t now = (time_t)(PR_Now() / 1000000);
+ if ( ((long)now - entry->GetStartTime()) > m_ttl ) {
+ if( key != NULL ) {
+ Remove( key );
+ key = NULL;
+ }
+ if( entry != NULL ) {
+ delete entry;
+ entry = NULL;
+ }
+ // Avoid recursion when the debug log is starting up
+ if ( PL_strcasecmp( m_name, "DebugLogModuleCache" ) ) {
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+//-- logger->Log( LOGLEVEL_FINER, DEBUG_CLASS_NAME,
+//-- "Get",
+ RA::Debug( LL_PER_PDU,
+ "StringKeyCache::Get: ",
+ "Entry %s expired from cache %s",
+ key,
+ m_name );
+ }
+ }
+ }
+
+ return entry;
+}
+
+/**
+ * Adds a cache entry
+ *
+ * @param key The name of the cache entry; an internal copy is made
+ * @param value The value of the cache entry
+ * @return The corresponding cache entry, or NULL if it couldn't be added
+ */
+CacheEntry *StringKeyCache::Put( const char *key, void *value ) {
+ CacheEntry *entry = new CacheEntry( key, value );
+ if ( m_implicitLock ) {
+ WriteLock();
+ }
+ PL_HashTableAdd( m_cache, entry->GetKey(), entry );
+ if ( m_implicitLock ) {
+ Unlock();
+ }
+
+ return entry;
+}
+
+/**
+ * Removes a cache entry; does not free the entry object
+ *
+ * @param key The name of the cache entry
+ * @return The corresponding cache entry, or NULL if not found
+ */
+CacheEntry *StringKeyCache::Remove( const char *key ) {
+
+ if ( m_implicitLock ) {
+ WriteLock();
+ }
+ CacheEntry *entry =
+ (CacheEntry *)PL_HashTableLookupConst( m_cache, key );
+ if( entry ) {
+ PL_HashTableRemove( m_cache, key );
+ }
+ if ( m_implicitLock ) {
+ Unlock();
+ }
+
+ return entry;
+}
+
+class KeyArray {
+public:
+ KeyArray( int nKeys ) {
+ m_nKeys = nKeys;
+ m_keys = new char *[m_nKeys];
+ m_currentKey = 0;
+ }
+ virtual ~KeyArray() {
+ }
+ int m_currentKey;
+ int m_nKeys;
+ char **m_keys;
+};
+
+/**
+ * Returns an iterator over keys in the cache
+ *
+ * @return An iterator over keys in the cache
+ */
+Iterator *StringKeyCache::GetKeyIterator() {
+ return new KeyIterator( m_cache, m_cacheLock, m_implicitLock );
+}
+
+/**
+ * Allocates and returns a list of keys in the cache
+ *
+ * @param keys Returns an array of names; each name and also the
+ * array itself are to be freed by the caller with delete
+ * @return The number of keys found
+ */
+int StringKeyCache::GetKeys( char ***keys ) {
+
+ int nKeys = GetCount();
+ if ( m_implicitLock ) {
+ ReadLock();
+ }
+ KeyArray keyArray( nKeys );
+ PL_HashTableEnumerateEntries( m_cache, getKeys, &keyArray );
+ if ( m_implicitLock ) {
+ Unlock();
+ }
+ if( ( keyArray.m_nKeys < 1 ) && keyArray.m_keys ) {
+ delete [] keyArray.m_keys;
+ keyArray.m_keys = NULL;
+ }
+ *keys = keyArray.m_keys;
+
+ return keyArray.m_nKeys;
+}
+
+/**
+ * Adds cache entry keys to an accumulator
+ */
+extern "C" {
+static PRIntn getKeys( PLHashEntry* he, PRIntn index, void* arg ) {
+ PRIntn result = HT_ENUMERATE_NEXT;
+ if ( he != NULL ) {
+ if ( he->key ) {
+ KeyArray *keys = (KeyArray *)arg;
+ int len = strlen( (char *)he->key );
+ int i = keys->m_currentKey;
+ keys->m_keys[i] = new char[len+1];
+ strcpy( keys->m_keys[i], (char *)he->key );
+ keys->m_currentKey++;
+ }
+ }
+ return result;
+}
+
+/**
+ * Frees keys of entries in cache; does not free values
+ */
+static PRIntn onCacheRelease( PLHashEntry* he, PRIntn index, void* arg ) {
+ PRIntn result = HT_ENUMERATE_NEXT;
+ if( he != NULL ) {
+ if( he->key != NULL ) {
+ free( (char *) he->key );
+ he->key = NULL;
+ result = HT_ENUMERATE_REMOVE;
+ }
+ }
+ return result;
+}
+} // extern "C"
diff --git a/base/tps/src/httpClient/engine.cpp b/base/tps/src/httpClient/engine.cpp
new file mode 100644
index 000000000..621a37244
--- /dev/null
+++ b/base/tps/src/httpClient/engine.cpp
@@ -0,0 +1,775 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/** BEGIN COPYRIGHT BLOCK
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include "nspr.h"
+#include "sslproto.h"
+#include "prerror.h"
+
+#include "ssl.h"
+#include "nss.h"
+#include "pk11func.h"
+#include "cert.h"
+#include "certt.h"
+#include "sslerr.h"
+#include "secerr.h"
+
+#include "httpClient/httpc/engine.h"
+#include "httpClient/httpc/http.h"
+#include "httpClient/httpc/PSPRUtil.h"
+#include "httpClient/httpc/Defines.h"
+//-- #include "httpClient/httpc/DebugLogger.h"
+#include "engine/RA.h"
+#include "main/Memory.h"
+
+char* certName = NULL;
+char* password = NULL;
+int ciphers[32];
+int cipherCount = 0;
+int _doVerifyServerCert = 1;
+
+//-- static const char *DEBUG_MODULE = "httpclient";
+//-- static const char *DEBUG_CLASS_NAME = "HttpEngine";
+
+PRIntervalTime Engine::globaltimeout = PR_TicksPerSecond()*30;
+
+static char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) {
+ if (!retry) {
+ if( password != NULL ) {
+ return PL_strdup(password);
+ } else {
+ return PL_strdup( "httptest" );
+ }
+ } else {
+ return NULL;
+ }
+}
+
+/**
+ * Function: SECStatus myBadCertHandler()
+ * <BR>
+ * Purpose: This callback is called when the incoming certificate is not
+ * valid. We define a certain set of parameters that still cause the
+ * certificate to be "valid" for this session, and return SECSuccess to cause
+ * the server to continue processing the request when any of these conditions
+ * are met. Otherwise, SECFailure is return and the server rejects the
+ * request.
+ */
+SECStatus myBadCertHandler( void *arg, PRFileDesc *socket ) {
+
+ SECStatus secStatus = SECFailure;
+ PRErrorCode err;
+
+ /* log invalid cert here */
+
+ if ( !arg ) {
+ return secStatus;
+ }
+
+ *(PRErrorCode *)arg = err = PORT_GetError();
+
+ /* If any of the cases in the switch are met, then we will proceed */
+ /* with the processing of the request anyway. Otherwise, the default */
+ /* case will be reached and we will reject the request. */
+
+ switch (err) {
+ case SEC_ERROR_INVALID_AVA:
+ case SEC_ERROR_INVALID_TIME:
+ case SEC_ERROR_BAD_SIGNATURE:
+ case SEC_ERROR_EXPIRED_CERTIFICATE:
+ case SEC_ERROR_UNKNOWN_ISSUER:
+ case SEC_ERROR_UNTRUSTED_CERT:
+ case SEC_ERROR_CERT_VALID:
+ case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE:
+ case SEC_ERROR_CRL_EXPIRED:
+ case SEC_ERROR_CRL_BAD_SIGNATURE:
+ case SEC_ERROR_EXTENSION_VALUE_INVALID:
+ case SEC_ERROR_CA_CERT_INVALID:
+ case SEC_ERROR_CERT_USAGES_INVALID:
+ case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION:
+ case SEC_ERROR_EXTENSION_NOT_FOUND: // Added by Rob 5/21/2002
+ secStatus = SECSuccess;
+ break;
+ default:
+ secStatus = SECFailure;
+ break;
+ }
+
+ return secStatus;
+}
+
+
+PRBool __EXPORT InitSecurity(char* certDir, char* certname, char* certpassword, char *prefix,int verify ) {
+ if (certpassword) {
+ password = PL_strdup(certpassword);
+ } else {
+ password = PL_strdup( "httptest" );
+ }
+ if (certname) {
+ certName = PL_strdup(certname);
+ }
+
+ SECStatus stat;
+ PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0 );
+ if (!NSS_IsInitialized()) {
+ stat = NSS_Initialize( certDir, prefix, prefix,"secmod.db",
+ NSS_INIT_READONLY);
+ } else {
+ stat = SECSuccess;
+ RA::Debug( LL_PER_PDU,
+ "initSecurity: ",
+ "NSS Already initialized" );
+
+ }
+
+ if (SECSuccess != stat) {
+ // int err = PR_GetError();
+ return PR_FAILURE;
+ }
+ PK11_SetPasswordFunc(ownPasswd);
+
+ stat = NSS_SetDomesticPolicy();
+ SSL_CipherPrefSetDefault( SSL_RSA_WITH_NULL_MD5, PR_TRUE );
+
+ _doVerifyServerCert = verify;
+
+
+ return PR_TRUE;
+}
+
+
+int ssl2Suites[] = {
+ SSL_EN_RC4_128_WITH_MD5, /* A */
+ SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */
+ SSL_EN_RC2_128_CBC_WITH_MD5, /* C */
+ SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */
+ SSL_EN_DES_64_CBC_WITH_MD5, /* E */
+ SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */
+ 0
+};
+
+int ssl3Suites[] = {
+ SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */
+ SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, /* b */
+ SSL_RSA_WITH_RC4_128_MD5, /* c */
+ SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */
+ SSL_RSA_WITH_DES_CBC_SHA, /* e */
+ SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */
+ SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */
+ SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* h */
+ SSL_RSA_WITH_NULL_MD5, /* i */
+ SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */
+ SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */
+ TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */
+ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */
+ 0
+};
+
+int tlsSuites[] = {
+// TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+// TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+// TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+// TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+// TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+// TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA
+};
+
+void disableAllCiphersOnSocket(PRFileDesc* sock) {
+ int i;
+ int numsuites = SSL_NumImplementedCiphers;
+
+ /* disable all the cipher suites for that socket */
+ for (i = 0; i<numsuites; i++) {
+ SSL_CipherPrefSet(sock, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
+ }
+}
+
+void __EXPORT EnableAllSSL3Ciphers(PRFileDesc* sock) {
+ int i =0;
+ while (ssl3Suites[i]) {
+ SSL_CipherPrefSet(sock, ssl3Suites[i], SSL_ALLOWED);
+ }
+}
+
+void __EXPORT EnableAllTLSCiphers(PRFileDesc* sock) {
+ int i =0;
+ while (tlsSuites[i]) {
+ SSL_CipherPrefSet(sock, tlsSuites[i++], SSL_ALLOWED);
+ }
+}
+
+PRBool __EXPORT EnableCipher(const char* cipherString) {
+ int ndx;
+
+ if (!cipherString) {
+ return PR_FALSE;
+ }
+
+ while (0 != (ndx = *cipherString++)) {
+ int* cptr;
+ int cipher;
+
+ if (! isalpha(ndx)) {
+ continue;
+ }
+ cptr = islower(ndx) ? ssl3Suites : ssl2Suites;
+ for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) {
+ /* do nothing */;
+ }
+ ciphers[cipherCount++] = cipher;
+ }
+
+ return PR_TRUE;
+}
+
+SECStatus certcallback (
+ void *arg,
+ PRFileDesc *fd,
+ PRBool checksig,
+ PRBool isServer) {
+ return SECSuccess; // always succeed
+}
+
+/**
+ * Function: SECStatus myAuthCertificate()
+ * <BR>
+ * Purpose: This function is our custom certificate authentication handler.
+ * <BR>
+ * Note: This implementation is essentially the same as the default
+ * SSL_AuthCertificate().
+ */
+extern "C" {
+
+static SECStatus myAuthCertificate( void *arg,
+ PRFileDesc *socket,
+ PRBool checksig,
+ PRBool isServer ) {
+
+ SECCertUsage certUsage;
+ CERTCertificate * cert;
+ void * pinArg;
+ char * hostName = NULL;
+ SECStatus secStatus = SECSuccess;
+//-- static const char *DEBUG_METHOD_NAME = "myAuthCertificate";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( "httpclient");
+
+ if ( !arg || !socket ) {
+ return SECFailure;
+ }
+
+ /* Define how the cert is being used based upon the isServer flag. */
+
+ certUsage = isServer ? certUsageSSLClient : certUsageSSLServer;
+
+ cert = SSL_PeerCertificate( socket );
+
+ pinArg = SSL_RevealPinArg( socket );
+
+ // Skip the server cert verification fconditionally, because our test
+ // servers do not have a valid root CA cert.
+ if ( _doVerifyServerCert ) {
+
+ PRLock *verify_lock = RA::GetVerifyLock();
+ if (verify_lock == NULL) {
+ return SECFailure;
+ }
+ PR_Lock(verify_lock);
+ /* This function is not thread-safe. So we need to use a global lock */
+ secStatus = CERT_VerifyCertNow( (CERTCertDBHandle *)arg,
+ cert,
+ checksig,
+ certUsage,
+ pinArg);
+ PR_Unlock(verify_lock);
+
+ if( SECSuccess != secStatus ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ if (cert == NULL) {
+ RA::Debug( LL_PER_PDU,
+ "myAuthCertificate: ",
+ "Server Certificate Not Found" );
+ } else {
+ if (cert->subjectName == NULL) {
+ RA::Debug( LL_PER_PDU,
+ "myAuthCertificate: ",
+ "Untrusted server certificate" );
+ } else {
+ RA::Debug( LL_PER_PDU,
+ "myAuthCertificate: ",
+ "Untrusted server certificate error=%d subject='%s'", PORT_GetError(), cert->subjectName );
+ }
+ }
+ }
+ }
+
+ /* If this is a server, we're finished. */
+ if (isServer || secStatus != SECSuccess) {
+ return secStatus;
+ }
+
+ /* Certificate is OK. Since this is the client side of an SSL
+ * connection, we need to verify that the name field in the cert
+ * matches the desired hostname. This is our defense against
+ * man-in-the-middle attacks.
+ */
+
+ /* SSL_RevealURL returns a hostName, not an URL. */
+ hostName = SSL_RevealURL( socket );
+
+ if (hostName && hostName[0]) {
+ secStatus = CERT_VerifyCertName( cert, hostName );
+ if( SECSuccess != secStatus ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "myAuthCertificate: ",
+ "Server name does not match that in certificate" );
+ }
+ } else {
+ secStatus = SECFailure;
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "myAuthCertificate: ",
+ "server name has been specified" );
+ }
+
+ if( hostName != NULL ) {
+ PR_Free( hostName );
+ hostName = NULL;
+ }
+
+ return secStatus;
+}
+
+
+/* Function: SECStatus ownGetClientAuthData()
+ *
+ * Purpose: This callback is used by SSL to pull client certificate
+ * information upon server request.
+ */
+static SECStatus ownGetClientAuthData(void *arg, PRFileDesc *socket,
+ CERTDistNames *caNames,
+ CERTCertificate **pRetCert,/*return */
+ SECKEYPrivateKey **pRetKey) {
+ CERTCertificate * cert = NULL;
+ SECKEYPrivateKey * privKey = NULL;
+ void * proto_win = NULL;
+ SECStatus rv = SECFailure;
+ char * localNickName = (char *)arg;
+
+ proto_win = SSL_RevealPinArg(socket);
+
+ if (localNickName) {
+ RA::Debug( LL_PER_PDU,
+ "ownGetClientAuthData: ",
+ "ownGetClientAuthData looking for nickname=%s",
+ localNickName );
+ cert = PK11_FindCertFromNickname(localNickName, proto_win);
+ if (cert) {
+ RA::Debug( LL_PER_PDU,
+ "ownGetClientAuthData: ",
+ "ownGetClientAuthData found cert" );
+ privKey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if (privKey) {
+ RA::Debug( LL_PER_PDU,
+ "ownGetClientAuthData: ",
+ "ownGetClientAuthData found priv key for cert" );
+ rv = SECSuccess;
+ } else {
+ if( cert != NULL ) {
+ CERT_DestroyCertificate( cert );
+ cert = NULL;
+ }
+ }
+ }
+ else {
+ RA::Debug( LL_PER_PDU,
+ "ownGetClientAuthData: ",
+ "ownGetClientAuthData did NOT find cert" );
+ }
+
+ if (rv == SECSuccess) {
+ *pRetCert = cert;
+ *pRetKey = privKey;
+ }
+
+ // if( localNickName != NULL ) {
+ // free( localNickName );
+ // localNickName = NULL;
+ // }
+ return rv;
+ }
+ else {
+ RA::Debug( LL_PER_PDU,
+ "ownGetClientAuthData: ",
+ "ownGetClientAuthData does not have nickname" );
+ }
+
+ char* chosenNickName = certName ? (char *)PL_strdup(certName) : NULL;
+ if (chosenNickName) {
+ cert = PK11_FindCertFromNickname(chosenNickName, proto_win);
+ if (cert) {
+ privKey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if (privKey) {
+ rv = SECSuccess;
+ } else {
+ if( cert != NULL ) {
+ CERT_DestroyCertificate( cert );
+ cert = NULL;
+ }
+ }
+ }
+ } else {
+ /* no nickname given, automatically find the right cert */
+ CERTCertNicknames * names;
+ int i;
+
+ names = CERT_GetCertNicknames( CERT_GetDefaultCertDB(),
+ SEC_CERT_NICKNAMES_USER,
+ proto_win);
+
+ if (names != NULL) {
+ for( i=0; i < names->numnicknames; i++ ) {
+ cert = PK11_FindCertFromNickname(names->nicknames[i],
+ proto_win);
+ if (!cert) {
+ continue;
+ }
+
+ /* Only check unexpired certs */
+ if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) !=
+ secCertTimeValid) {
+ if( cert != NULL ) {
+ CERT_DestroyCertificate( cert );
+ cert = NULL;
+ }
+ continue;
+ }
+
+ rv = NSS_CmpCertChainWCANames(cert, caNames);
+
+ if (rv == SECSuccess) {
+ privKey = PK11_FindKeyByAnyCert(cert, proto_win);
+ if (privKey) {
+ // got the key
+ break;
+ }
+
+ // cert database password was probably wrong
+ rv = SECFailure;
+ break;
+ };
+ } /* for loop */
+ CERT_FreeNicknames(names);
+ } // names
+ } // no nickname chosen
+
+ if (rv == SECSuccess) {
+ *pRetCert = cert;
+ *pRetKey = privKey;
+ }
+
+ if( chosenNickName != NULL ) {
+ free( chosenNickName );
+ chosenNickName = NULL;
+ }
+
+ return rv;
+}
+} // extern "C"
+
+void nodelay(PRFileDesc* fd) {
+ PRSocketOptionData opt;
+ PRStatus rv;
+
+ opt.option = PR_SockOpt_NoDelay;
+ opt.value.no_delay = PR_FALSE;
+
+ rv = PR_GetSocketOption(fd, &opt);
+ if (rv == PR_FAILURE) {
+ return;
+ }
+
+ opt.option = PR_SockOpt_NoDelay;
+ opt.value.no_delay = PR_TRUE;
+ rv = PR_SetSocketOption(fd, &opt);
+ if (rv == PR_FAILURE) {
+ return;
+ }
+
+ return;
+}
+
+
+void __EXPORT setDefaultAllTLSCiphers() {
+ int i =0;
+ char alg[256];
+ while (tlsSuites[i]) {
+ PR_snprintf((char *)alg, 256, "%x", tlsSuites[i]);
+ RA::Debug( LL_PER_PDU,
+ "setDefaultAllTLSCiphers",
+ alg);
+ SSL_CipherPrefSetDefault(tlsSuites[i++], PR_TRUE);
+ }
+}
+
+/**
+ * Returns a file descriptor for I/O if the HTTP connection is successful
+ * @param addr PRnetAddr structure which points to the server to connect to
+ * @param SSLOn boo;elan to state if this is an SSL client
+ */
+PRFileDesc * Engine::_doConnect(PRNetAddr *addr, PRBool SSLOn,
+ const PRInt32* cipherSuite,
+ PRInt32 count, const char *nickName,
+ PRBool handshake,
+ /*const SecurityProtocols& secprots,*/
+ const char *serverName, PRIntervalTime timeout) {
+//-- static const char *DEBUG_METHOD_NAME = "doConnect";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( "httpclient");
+ PRFileDesc *tcpsock = NULL;
+ PRFileDesc *sock = NULL;
+
+ SSL_CipherPrefSetDefault(0xC005 /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA */, PR_TRUE);
+ setDefaultAllTLSCiphers();
+
+ tcpsock = PR_OpenTCPSocket(addr->raw.family);
+
+ if (nickName != NULL)
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "_doConnect has nickname=%s",
+ nickName );
+ else
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "_doConnect has nickname=NULL" );
+
+ if (!tcpsock) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+//XXXX log NSPR error code
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "PR_OpenTCPSocket returned NULL" );
+ return NULL;
+ }
+
+ nodelay(tcpsock);
+
+ if (PR_TRUE == SSLOn) {
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "SSL is ON" );
+ sock=SSL_ImportFD(NULL, tcpsock);
+ if (!sock) {
+ //xxx log
+ if( tcpsock != NULL ) {
+ PR_Close( tcpsock );
+ tcpsock = NULL;
+ }
+ return NULL;
+ }
+
+ int error = 0;
+ PRBool rv = SSL_OptionSet(sock, SSL_SECURITY, 1);
+ if ( SECSuccess == rv ) {
+ rv = SSL_OptionSet(sock, SSL_HANDSHAKE_AS_CLIENT, 1);
+ }
+ if ( SECSuccess == rv ) {
+ rv = SSL_OptionSet(sock, SSL_ENABLE_SSL3, PR_TRUE);
+ }
+ if ( SECSuccess == rv ) {
+ rv = SSL_OptionSet(sock, SSL_ENABLE_TLS, PR_TRUE);
+ }
+ if ( SECSuccess != rv ) {
+ error = PORT_GetError();
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "SSL_OptionSet error: %d",
+ error );
+ return NULL;
+ }
+
+ rv = SSL_GetClientAuthDataHook( sock,
+ ownGetClientAuthData,
+ (void*)nickName);
+ if ( SECSuccess != rv ) {
+ error = PORT_GetError();
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "SSL_GetClientAuthDataHook error: %d",
+ error );
+ return NULL;
+ }
+
+ rv = SSL_AuthCertificateHook(sock,
+ (SSLAuthCertificate)myAuthCertificate,
+ (void *)CERT_GetDefaultCertDB());
+
+ if (rv != SECSuccess ) {
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+ return NULL;
+ }
+
+ PRErrorCode errCode = 0;
+
+ rv = SSL_BadCertHook( sock,
+ (SSLBadCertHandler)myBadCertHandler,
+ &errCode );
+ rv = SSL_SetURL( sock, serverName );
+
+ if (rv != SECSuccess ) {
+ error = PORT_GetError();
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "SSL_SetURL error: %d",
+ error );
+ return NULL;
+ }
+
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "end SSL is ON" );
+ //EnableAllTLSCiphers( sock);
+ //EnableAllSSL3Ciphers( sock);
+ } else {
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "SSL is OFF" );
+ sock = tcpsock;
+ }
+
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "about to call PR_Connect, timeout =%d",
+ timeout );
+
+ if ( PR_Connect(sock, addr, timeout) == PR_FAILURE ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "Engine::_doConnect: ",
+ "PR_Connect error: %d Msg=%s",
+ PR_GetError(),
+ "XXX" );
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+ return NULL;
+ }
+
+ return (sock);
+}
+
+/**
+ * Called from higher level to connect, sends a request
+ * and gets a response as an HttpResponse object
+ *
+ * @param request Contains the entire request url + headers etc
+ * @param server Has the host, port, protocol info
+ * @param timeout Time in seconds to wait for a response
+ * @return The response body and headers
+ */
+PSHttpResponse * HttpEngine::makeRequest( PSHttpRequest &request,
+ const PSHttpServer& server,
+ int timeout, PRBool expectChunked ) {
+ PRNetAddr addr;
+ PRFileDesc *sock = NULL;
+ PSHttpResponse *resp = NULL;
+
+ PRBool response_code = 0;
+
+ server.getAddr(&addr);
+
+ char *nickName = request.getCertNickName();
+
+ char *serverName = (char *)server.getAddr();
+ sock = _doConnect( &addr, request.isSSL(), 0, 0,nickName, 0, serverName );
+
+ if ( sock != NULL) {
+ PRBool status = request.send( sock );
+ if ( status ) {
+ resp = new PSHttpResponse( sock, &request, timeout, expectChunked );
+ response_code = resp->processResponse();
+
+ RA::Debug( LL_PER_PDU,
+ "HttpEngine::makeRequest: ",
+ "makeRequest response %d",
+ response_code );
+
+ if(!response_code)
+ {
+ RA::Debug( LL_PER_PDU,
+ "HttpEngine::makeRequest: ",
+ "Deleting response because of FALSE return, returning NULL." );
+ if( resp != NULL ) {
+ delete resp;
+ resp = NULL;
+ }
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+
+ return NULL;
+
+ }
+ }
+ if( sock != NULL ) {
+ PR_Close( sock );
+ sock = NULL;
+ }
+ }
+
+ return resp;
+}
diff --git a/base/tps/src/httpClient/http.cpp b/base/tps/src/httpClient/http.cpp
new file mode 100644
index 000000000..60ca48bf5
--- /dev/null
+++ b/base/tps/src/httpClient/http.cpp
@@ -0,0 +1,307 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/** BEGIN COPYRIGHT BLOCK
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+
+#include "httpClient/httpc/http.h"
+#include "httpClient/httpc/engine.h"
+#include "httpClient/httpc/request.h"
+#include "httpClient/httpc/response.h"
+//-- #include "httpClient/httpc/DebugLogger.h"
+//-- #include "httpClient/httpc/ErrorLogger.h"
+#include "httpClient/httpc/PSPRUtil.h"
+#include "httpClient/httpc/Defines.h"
+#include "engine/RA.h"
+#include "main/Memory.h"
+
+
+//-- static const char *DEBUG_MODULE = "httpclient";
+//-- static const char *DEBUG_CLASS_NAME = "PSHttpServer";
+
+/**
+ * Constructor
+ * @param addr The hostname:port of the server to connect to. The default
+ * port is 80
+ * @param af The protocol family like PR_AF_INET
+ */
+PSHttpServer::PSHttpServer(const char *addr, PRUint16 af) {
+ SSLOn = PR_FALSE;
+ PRUint16 port = 80;
+//-- static const char *DEBUG_METHOD_NAME = "Constructor";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+
+ char *pPort;
+
+
+ _addr = NULL;
+// if( _addr != NULL ) {
+// PL_strfree( _addr );
+// _addr = NULL;
+// }
+
+ if (addr) {
+ _addr = PL_strdup(addr);
+ }
+
+ pPort = PL_strchr(_addr, ':');
+ if (pPort) {
+ *pPort = '\0';
+ port = (PRUint16) atoi(++pPort);
+ }
+
+ /* kludge for doing IPv6 tests on localhost */
+ if (!PL_strcmp(_addr, "ip6-localhost") && (af == PR_AF_INET6)) {
+ PL_strcpy(_addr, "::1");
+ }
+
+// PR_InitializeNetAddr(PR_IpAddrNull, port, &_netAddr);
+
+ if (PR_StringToNetAddr(_addr, &_netAddr) == PR_FAILURE) {
+ char buf[2000];
+ PRHostEnt ent;
+
+ RA::Debug( LL_PER_PDU,
+ "PSHttpServer::PSHttpServer ",
+ " host %s port %d ",_addr,port );
+ PR_InitializeNetAddr(PR_IpAddrNull, port, &_netAddr);
+ if (PR_GetIPNodeByName(_addr, af, PR_AI_DEFAULT,
+ buf, sizeof(buf), &ent) == PR_SUCCESS) {
+ PR_EnumerateHostEnt(0, &ent, port, &_netAddr);
+ } else {
+//-- ErrorLogger::GetErrorLogger()->Log(
+//-- LOGLEVEL_SEVERE, PR_GetError(),
+ RA::Debug( LL_PER_PDU,
+ "PSHttpServer::PSHttpServer: ",
+ "PR_GetIPNodeByName returned error %d [%s] for "
+ "address %s",
+ PR_GetError (),
+ "XXX",
+ addr );
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpServer::PSHttpServer: ",
+ "PR_GetIPNodeByName returned error %d [%s] for "
+ "address %s",
+ PR_GetError(),
+ "XXX",
+ addr );
+ }
+ }
+}
+
+/**
+ * Destructor of the Httpserver class
+ */
+PSHttpServer::~PSHttpServer() {
+ if( _addr != NULL ) {
+ PL_strfree( _addr );
+ _addr = NULL;
+ }
+}
+
+/**
+ * Turns SSL on or off for the connection
+ * @param SSLstate PR_TRUE to make an SSL connection
+ */
+void PSHttpServer::setSSL(PRBool SSLstate) {
+ SSLOn = SSLstate;
+}
+
+/**
+ * Returns the current SSL state for this PSHttpServer object
+ * @return PR_TRUE if SSL is enabled else PR_FALSE
+ */
+PRBool PSHttpServer::isSSL() const {
+ return SSLOn;
+}
+
+/**
+ * Returns the IP address of the HTTP server
+ * @return IP address of the server as a long
+ */
+
+long PSHttpServer::getIp() const {
+ return _netAddr.inet.ip;
+}
+
+/**
+ * Returns the port for the HTTP server
+ * @return port of the server
+ */
+
+long PSHttpServer::getPort() const {
+ return (long) PR_ntohs(_netAddr.inet.port);
+}
+
+/**
+ * Returns the server IP address as a string
+ * @return server address as string
+*/
+const char * PSHttpServer::getAddr() const {
+ return _addr;
+}
+
+/**
+ * Gets the server addr as a PR_NetAddr structure
+ * @param addr PR_netaddr struct in which server address is returned
+ */
+void PSHttpServer::getAddr(PRNetAddr *addr) const {
+ memcpy(addr, &_netAddr, sizeof(_netAddr));
+}
+
+/**
+ * Fets the protocol as string: "HTTP/1.0" "HTTP/1.1" etc
+ * @return Protocol string
+ */
+const char *HttpProtocolToString(HttpProtocol proto) {
+ switch(proto) {
+ case HTTP09:
+ return "";
+ case HTTP10:
+ return "HTTP/1.0";
+ case HTTP11:
+ return "HTTP/1.1";
+ case HTTPBOGUS:
+ return "BOGO-PROTO";
+ case HTTPNA:
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/**
+* Constructor for HttpMessage. This is a base class for PSHttpRequest
+*/
+HttpMessage :: HttpMessage(long len, const char* buf) {
+ firstline = NULL;
+ cl = 0;
+ proto = HTTPNA;
+
+ // search for the first line
+ int counter=0;
+ PRBool found = PR_FALSE;
+ while ( ( (counter++<len) && (PR_FALSE == found) ) ) {
+ if (buf[counter] != '\n') {
+ continue;
+ }
+ found = PR_TRUE;
+ }
+
+ // extract the first line
+ if (PR_TRUE == found) {
+ firstline=new char[counter+1];
+ memcpy(firstline, buf, counter);
+ firstline[counter] = '\0';
+ }
+}
+
+HttpMessage :: ~HttpMessage() {
+ if( firstline != NULL ) {
+ delete firstline;
+ firstline = NULL;
+ }
+}
+
+/*SecurityProtocols :: SecurityProtocols(PRBool s2, PRBool s3, PRBool t)
+{
+ ssl2 = s2;
+ ssl3 = s3;
+ tls = t;
+};
+
+const SecurityProtocols& SecurityProtocols :: operator = (const RWTPtrSlist<char>& protlist)
+{
+ ssl2 = PR_FALSE;
+ ssl3 = PR_FALSE;
+ tls = PR_FALSE;
+ PRInt32 i;
+ for (i = 0;i<protlist.entries();i++)
+ {
+ if (0 == strcmp(protlist.at(i), "SSL2"))
+ {
+ ssl2 = PR_TRUE;
+ };
+ if (0 == strcmp(protlist.at(i), "SSL3"))
+ {
+ ssl3 = PR_TRUE;
+ };
+ if (0 == strcmp(protlist.at(i), "TLS"))
+ {
+ tls = PR_TRUE;
+ };
+ };
+ return *this;
+};
+
+const SecurityProtocols& SecurityProtocols :: operator = (const SecurityProtocols& rhs)
+{
+ ssl2 = rhs.ssl2;
+ ssl3 = rhs.ssl3;
+ tls = rhs.tls;
+ return *this;
+};
+*/
+
+
+PRBool PSHttpServer::putFile(const char* localFile,
+ const char* remoteUri) const {
+ PSHttpRequest request(this, remoteUri, HTTP10, Engine::globaltimeout);
+ request.setMethod("PUT");
+ request.useLocalFileAsBody(localFile);
+
+ PRBool rv = _putFile(request);
+ return rv;
+}
+
+PRBool PSHttpServer::putFile(const char *uri, int size) const {
+ PSHttpRequest request(this, uri, HTTP10, Engine::globaltimeout);
+ request.setMethod("PUT");
+ request.addRandomBody(size);
+
+ PRBool rv = _putFile(request);;
+ return rv;
+}
+
+PRBool PSHttpServer::_putFile(PSHttpRequest& request) const {
+ HttpEngine engine;
+ PRBool rv = PR_TRUE;
+
+ PSHttpResponse* response = engine.makeRequest(request, *this);
+
+ if (response) {
+ int status = response->getStatus();
+ if (status == 200 || status == 201 || status == 204) {
+ rv = PR_TRUE;
+ } else {
+ rv = PR_FALSE;
+ }
+ if( response != NULL ) {
+ delete response;
+ response = NULL;
+ }
+ } else {
+ rv = PR_FALSE;
+ }
+ return rv;
+}
+
diff --git a/base/tps/src/httpClient/httpClient.cpp b/base/tps/src/httpClient/httpClient.cpp
new file mode 100644
index 000000000..7f4e9fff3
--- /dev/null
+++ b/base/tps/src/httpClient/httpClient.cpp
@@ -0,0 +1,130 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation;
+// version 2.1 of the License.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301 USA
+//
+// Copyright (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+#include "nspr.h"
+#include <sys/types.h>
+
+#include <stdio.h>
+#ifndef XP_WIN32
+#include <unistd.h> /* sleep */
+#else /* XP_WIN32 */
+#include <windows.h>
+#endif /* XP_WIN32 */
+
+#include "main/Base.h"
+#include "httpClient/httpc/http.h"
+#include "httpClient/httpc/request.h"
+#include "httpClient/httpc/response.h"
+#include "httpClient/httpc/engine.h"
+
+#include "engine/RA.h"
+#include "main/Memory.h"
+
+/*
+ * httpSend: sends to an HTTP server
+ * host_port should be in the for "host:port"
+ * e.g. ca.fedora.redhat.com:1027
+ * uri should contain uri including parameter values
+ * e.g. https://ca.fedora.redhat.com:1027/ca/profileSubmitSSLClient?profileId=userKey&screenname=user1&publickey=YWJjMTIzCg
+ * method has to be "GET" or "POST"
+ * body is the HTTP body. Can have nothing.
+ */
+PSHttpResponse *httpSend(char *host_port, char *uri, char *method, char *body)
+{
+ const char* nickname;
+ nickname = RA::GetConfigStore()->GetConfigAsString("ra.clientNickname", "");
+
+ char *pPort = NULL;
+ char *pPortActual = NULL;
+
+
+ char hostName[512];
+
+ /*
+ * Isolate the host name, account for IPV6 numeric addresses.
+ *
+ */
+
+ if(host_port)
+ strncpy(hostName,host_port,512);
+
+ pPort = hostName;
+ while(1) {
+ pPort = strchr(pPort, ':');
+ if (pPort) {
+ pPortActual = pPort;
+ pPort++;
+ } else
+ break;
+ }
+
+ if(pPortActual)
+ *pPortActual = '\0';
+
+
+ /*
+ * Rifle through the values for the host
+ */
+
+ PRAddrInfo *ai;
+ void *iter;
+ PRNetAddr addr;
+ int family = PR_AF_INET;
+
+ ai = PR_GetAddrInfoByName(hostName, PR_AF_UNSPEC, PR_AI_ADDRCONFIG);
+ if (ai) {
+ printf("%s\n", PR_GetCanonNameFromAddrInfo(ai));
+ iter = NULL;
+ while ((iter = PR_EnumerateAddrInfo(iter, ai, 0, &addr)) != NULL) {
+ char buf[512];
+ PR_NetAddrToString(&addr, buf, sizeof buf);
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::httpSend: ",
+ "Sending addr -- Msg='%s'\n",
+ buf );
+ family = PR_NetAddrFamily(&addr);
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::httpSend: ",
+ "Sending family -- Msg='%d'\n",
+ family );
+ break;
+ }
+ PR_FreeAddrInfo(ai);
+
+ }
+
+ PSHttpServer server(host_port, family);
+ server.setSSL(PR_TRUE);
+ // use "HTTP10" if no chunking
+ PSHttpRequest request( &server, uri, HTTP11, 0 );
+ request.setSSL(PR_TRUE);
+ request.setCertNickName(nickname);
+ request.setMethod(method);
+ if (body != NULL)
+ request.setBody( strlen(body), body);
+
+ // use with "POST" only
+ request.addHeader( "Content-Type", "text/xml" );
+ request.addHeader( "Connection", "keep-alive" );
+ HttpEngine engine;
+ PSHttpResponse *resp = engine.makeRequest( request, server, 120 /*_timeout*/ , PR_TRUE /* expect chunked*/);
+
+ return resp;
+}
diff --git a/base/tps/src/httpClient/nscperror.cpp b/base/tps/src/httpClient/nscperror.cpp
new file mode 100644
index 000000000..38c722de2
--- /dev/null
+++ b/base/tps/src/httpClient/nscperror.cpp
@@ -0,0 +1,358 @@
+// --- BEGIN COPYRIGHT BLOCK ---
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation;
+// version 2.1 of the License.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 51 Franklin Street, Fifth Floor,
+// Boston, MA 02110-1301 USA
+//
+// Copyright (C) 2007 Red Hat, Inc.
+// All rights reserved.
+// --- END COPYRIGHT BLOCK ---
+
+/* nscperrors.c
+ * Very crude error handling for nspr and libsec.
+ */
+
+#include "prerror.h"
+
+#define NSCP_NSPR_ERROR_BASE (PR_NSPR_ERROR_BASE)
+#define NSCP_NSPR_MAX_ERROR ((PR_MAX_ERROR) - 1)
+#define NSCP_LIBSEC_ERROR_BASE (-8192)
+#define NSCP_LIBSEC_MAX_ERROR (NSCP_LIBSEC_ERROR_BASE + 118)
+#define NSCP_LIBSSL_ERROR_BASE (-12288)
+#define NSCP_LIBSSL_MAX_ERROR (NSCP_LIBSSL_ERROR_BASE + 89)
+
+typedef struct nscp_error_t {
+ int errorNumber;
+ const char *errorString;
+} nscp_error_t;
+
+nscp_error_t nscp_nspr_errors[] = {
+ { 0, "Out of memory" },
+ { 1, "Bad file descriptor" },
+ { 2, "Data temporarily not available" },
+ { 3, "Access fault" },
+ { 4, "Invalid method" },
+ { 5, "Illegal access" },
+ { 6, "Unknown error" },
+ { 7, "Pending interrupt" },
+ { 8, "Not implemented" },
+ { 9, "IO error" },
+ { 10, "IO timeout error" },
+ { 11, "IO already pending error" },
+ { 12, "Directory open error" },
+ { 13, "Invalid Argument" },
+ { 14, "Address not available" },
+ { 15, "Address not supported" },
+ { 16, "Already connected" },
+ { 17, "Bad address" },
+ { 18, "Address already in use" },
+ { 19, "Connection refused" },
+ { 20, "Network unreachable" },
+ { 21, "Connection timed out" },
+ { 22, "Not connected" },
+ { 23, "Load library error" },
+ { 24, "Unload library error" },
+ { 25, "Find symbol error" },
+ { 26, "Insufficient resources" },
+ { 27, "Directory lookup error" },
+ { 28, "Invalid thread private data key" },
+ { 29, "PR_PROC_DESC_TABLE_FULL_ERROR" },
+ { 30, "PR_SYS_DESC_TABLE_FULL_ERROR" },
+ { 31, "Descriptor is not a socket" },
+ { 32, "Descriptor is not a TCP socket" },
+ { 33, "Socket address is already bound" },
+ { 34, "No access rights" },
+ { 35, "Operation not supported" },
+ { 36, "Protocol not supported" },
+ { 37, "Remote file error" },
+ { 38, "Buffer overflow error" },
+ { 39, "Connection reset by peer" },
+ { 40, "Range error" },
+ { 41, "Deadlock error" },
+ { 42, "File is locked" },
+ { 43, "File is too big" },
+ { 44, "No space on device" },
+ { 45, "Pipe error" },
+ { 46, "No seek on device" },
+ { 47, "File is a directory" },
+ { 48, "Loop error" },
+ { 49, "Name too long" },
+ { 50, "File not found" },
+ { 51, "File is not a directory" },
+ { 52, "Read-only filesystem" },
+ { 53, "Directory not empty" },
+ { 54, "Filesystem mounted" },
+ { 55, "Not same device" },
+ { 56, "Directory corrupted" },
+ { 57, "File exists" },
+ { 58, "Maximum directory entries" },
+ { 59, "Invalid device state" },
+ { 60, "Device is locked" },
+ { 61, "No more files" },
+ { 62, "End of file" },
+ { 63, "File seek error" },
+ { 64, "File is busy" },
+ { 65, "NSPR error 65" },
+ { 66, "In progress error" },
+ { 67, "Already initiated" },
+ { 68, "Group empty" },
+ { 69, "Invalid state" },
+ { 70, "Network down" },
+ { 71, "Socket shutdown" },
+ { 72, "Connect aborted" },
+ { 73, "Host unreachable" }
+};
+
+#if (PR_MAX_ERROR - PR_NSPR_ERROR_BASE) > 74
+// cfu temporarily get rid of the "#error NSPR error table is too small" error
+//#error NSPR error table is too small
+#endif
+
+nscp_error_t nscp_libsec_errors[] = {
+ { 0, "SEC_ERROR_IO - I/O Error" },
+ { 1, "SEC_ERROR_LIBRARY_FAILURE - Library Failure" },
+ { 2, "SEC_ERROR_BAD_DATA - Bad data was received" },
+ { 3, "SEC_ERROR_OUTPUT_LEN" },
+ { 4, "SEC_ERROR_INPUT_LEN" },
+ { 5, "SEC_ERROR_INVALID_ARGS" },
+ { 6, "SEC_ERROR_INVALID_ALGORITHM - Certificate contains invalid encryption or signature algorithm" },
+ { 7, "SEC_ERROR_INVALID_AVA" },
+ { 8, "SEC_ERROR_INVALID_TIME - Certificate contains an invalid time value" },
+ { 9, "SEC_ERROR_BAD_DER - Certificate is improperly DER encoded" },
+ { 10, "SEC_ERROR_BAD_SIGNATURE - Certificate has invalid signature" },
+ { 11, "SEC_ERROR_EXPIRED_CERTIFICATE - Certificate has expired" },
+ { 12, "SEC_ERROR_REVOKED_CERTIFICATE - Certificate has been revoked" },
+ { 13, "SEC_ERROR_UNKNOWN_ISSUER - Certificate is signed by an unknown issuer" },
+ { 14, "SEC_ERROR_BAD_KEY - Invalid public key in certificate." },
+ { 15, "SEC_ERROR_BAD_PASSWORD" },
+ { 16, "SEC_ERROR_UNUSED" },
+ { 17, "SEC_ERROR_NO_NODELOCK" },
+ { 18, "SEC_ERROR_BAD_DATABASE - Problem using certificate or key database" },
+ { 19, "SEC_ERROR_NO_MEMORY - Out of Memory" },
+ { 20, "SEC_ERROR_UNTRUSTED_ISSUER - Certificate is signed by an untrusted issuer" },
+ { 21, "SEC_ERROR_UNTRUSTED_CERT" },
+ { 22, "SEC_ERROR_DUPLICATE_CERT" },
+ { 23, "SEC_ERROR_DUPLICATE_CERT_TIME" },
+ { 24, "SEC_ERROR_ADDING_CERT" },
+ { 25, "SEC_ERROR_FILING_KEY" },
+ { 26, "SEC_ERROR_NO_KEY" },
+ { 27, "SEC_ERROR_CERT_VALID" },
+ { 28, "SEC_ERROR_CERT_NOT_VALID" },
+ { 29, "SEC_ERROR_CERT_NO_RESPONSE" },
+ { 30, "SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE" },
+ { 31, "SEC_ERROR_CRL_EXPIRED" },
+ { 32, "SEC_ERROR_CRL_BAD_SIGNATURE" },
+ { 33, "SEC_ERROR_CRL_INVALID" },
+ { 34, "SEC_ERROR_EXTENSION_VALUE_INVALID" },
+ { 35, "SEC_ERROR_EXTENSION_NOT_FOUND" },
+ { 36, "SEC_ERROR_CA_CERT_INVALID" },
+ { 37, "SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID" },
+ { 38, "SEC_ERROR_CERT_USAGES_INVALID" },
+ { 39, "SEC_INTERNAL_ONLY" },
+ { 40, "SEC_ERROR_INVALID_KEY" },
+ { 41, "SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION" },
+ { 42, "SEC_ERROR_OLD_CRL" },
+ { 43, "SEC_ERROR_NO_EMAIL_CERT" },
+ { 44, "SEC_ERROR_NO_RECIPIENT_CERTS_QUERY" },
+ { 45, "SEC_ERROR_NOT_A_RECIPIENT" },
+ { 46, "SEC_ERROR_PKCS7_KEYALG_MISMATCH" },
+ { 47, "SEC_ERROR_PKCS7_BAD_SIGNATURE" },
+ { 48, "SEC_ERROR_UNSUPPORTED_KEYALG" },
+ { 49, "SEC_ERROR_DECRYPTION_DISALLOWED" },
+ { 50, "XP_SEC_FORTEZZA_BAD_CARD" },
+ { 51, "XP_SEC_FORTEZZA_NO_CARD" },
+ { 52, "XP_SEC_FORTEZZA_NONE_SELECTED" },
+ { 53, "XP_SEC_FORTEZZA_MORE_INFO" },
+ { 54, "XP_SEC_FORTEZZA_PERSON_NOT_FOUND" },
+ { 55, "XP_SEC_FORTEZZA_NO_MORE_INFO" },
+ { 56, "XP_SEC_FORTEZZA_BAD_PIN" },
+ { 57, "XP_SEC_FORTEZZA_PERSON_ERROR" },
+ { 58, "SEC_ERROR_NO_KRL" },
+ { 59, "SEC_ERROR_KRL_EXPIRED" },
+ { 60, "SEC_ERROR_KRL_BAD_SIGNATURE" },
+ { 61, "SEC_ERROR_REVOKED_KEY" },
+ { 62, "SEC_ERROR_KRL_INVALID" },
+ { 63, "SEC_ERROR_NEED_RANDOM" },
+ { 64, "SEC_ERROR_NO_MODULE" },
+ { 65, "SEC_ERROR_NO_TOKEN" },
+ { 66, "SEC_ERROR_READ_ONLY" },
+ { 67, "SEC_ERROR_NO_SLOT_SELECTED" },
+ { 68, "SEC_ERROR_CERT_NICKNAME_COLLISION" },
+ { 69, "SEC_ERROR_KEY_NICKNAME_COLLISION" },
+ { 70, "SEC_ERROR_SAFE_NOT_CREATED" },
+ { 71, "SEC_ERROR_BAGGAGE_NOT_CREATED" },
+ { 72, "XP_JAVA_REMOVE_PRINCIPAL_ERROR" },
+ { 73, "XP_JAVA_DELETE_PRIVILEGE_ERROR" },
+ { 74, "XP_JAVA_CERT_NOT_EXISTS_ERROR" },
+ { 75, "SEC_ERROR_BAD_EXPORT_ALGORITHM" },
+ { 76, "SEC_ERROR_EXPORTING_CERTIFICATES" },
+ { 77, "SEC_ERROR_IMPORTING_CERTIFICATES" },
+ { 78, "SEC_ERROR_PKCS12_DECODING_PFX" },
+ { 79, "SEC_ERROR_PKCS12_INVALID_MAC" },
+ { 80, "SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM" },
+ { 81, "SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE" },
+ { 82, "SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE" },
+ { 83, "SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM" },
+ { 84, "SEC_ERROR_PKCS12_UNSUPPORTED_VERSION" },
+ { 85, "SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT" },
+ { 86, "SEC_ERROR_PKCS12_CERT_COLLISION" },
+ { 87, "SEC_ERROR_USER_CANCELLED" },
+ { 88, "SEC_ERROR_PKCS12_DUPLICATE_DATA" },
+ { 89, "SEC_ERROR_MESSAGE_SEND_ABORTED" },
+ { 90, "SEC_ERROR_INADEQUATE_KEY_USAGE" },
+ { 91, "SEC_ERROR_INADEQUATE_CERT_TYPE" },
+ { 92, "SEC_ERROR_CERT_ADDR_MISMATCH" },
+ { 93, "SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY" },
+ { 94, "SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN" },
+ { 95, "SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME" },
+ { 96, "SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY" },
+ { 97, "SEC_ERROR_PKCS12_UNABLE_TO_WRITE" },
+ { 98, "SEC_ERROR_PKCS12_UNABLE_TO_READ" },
+ { 99, "SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED" },
+ { 100, "SEC_ERROR_KEYGEN_FAIL" },
+ { 101, "SEC_ERROR_INVALID_PASSWORD" },
+ { 102, "SEC_ERROR_RETRY_OLD_PASSWORD" },
+ { 103, "SEC_ERROR_BAD_NICKNAME" },
+ { 104, "SEC_ERROR_NOT_FORTEZZA_ISSUER" },
+ { 105, "unused error" },
+ { 106, "SEC_ERROR_JS_INVALID_MODULE_NAME" },
+ { 107, "SEC_ERROR_JS_INVALID_DLL" },
+ { 108, "SEC_ERROR_JS_ADD_MOD_FAILURE" },
+ { 109, "SEC_ERROR_JS_DEL_MOD_FAILURE" },
+ { 110, "SEC_ERROR_OLD_KRL" },
+ { 111, "SEC_ERROR_CKL_CONFLICT" },
+ { 112, "SEC_ERROR_CERT_NOT_IN_NAME_SPACE" },
+ { 113, "SEC_ERROR_KRL_NOT_YET_VALID" },
+ { 114, "SEC_ERROR_CRL_NOT_YET_VALID" },
+ { 115, "SEC_ERROR_CERT_STATUS_SERVER_ERROR" },
+ { 116, "SEC_ERROR_CERT_STATUS_UNKNOWN" },
+ { 117, "SEC_ERROR_CERT_REVOKED_SINCE" },
+ { 118, "SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE" }
+};
+
+nscp_error_t nscp_libssl_errors[] = {
+ { 0, "SSL_ERROR_EXPORT_ONLY_SERVER - client does not support high-grade encryption." },
+ { 1, "SSL_ERROR_US_ONLY_SERVER - client requires high-grade encryption which is not supported." },
+ { 2, "SSL_ERROR_NO_CYPHER_OVERLAP - no common encryption algorithm(s) with client." },
+ { 3, "SSL_ERROR_NO_CERTIFICATE - unable to find the certificate or key necessary for authentication." },
+ { 4, "SSL_ERROR_BAD_CERTIFICATE - unable to communicate securely wih peer: peer's certificate was rejected." },
+ { 5, "unused SSL error #5" },
+ { 6, "SSL_ERROR_BAD_CLIENT - protocol error." },
+ { 7, "SSL_ERROR_BAD_SERVER - protocol error." },
+ { 8, "SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE - unsupported certificate type." },
+ { 9, "SSL_ERROR_UNSUPPORTED_VERSION - client is using unsupported SSL version." },
+ { 10, "unused SSL error #10" },
+ { 11, "SSL_ERROR_WRONG_CERTIFICATE - the public key in the server's own certificate does not match its private key" },
+ { 12, "SSL_ERROR_BAD_CERT_DOMAIN - requested domain name does not match the server's certificate." },
+ { 13, "SSL_ERROR_POST_WARNING" },
+ { 14, "SSL_ERROR_SSL2_DISABLED - peer only supports SSL version 2, which is locally disabled" },
+ { 15, "SSL_ERROR_BAD_MAC_READ - SSL has received a record with an incorrect Message Authentication Code." },
+ { 16, "SSL_ERROR_BAD_MAC_ALERT - SSL has received an error indicating an incorrect Message Authentication Code." },
+ { 17, "SSL_ERROR_BAD_CERT_ALERT - SSL client cannot verify your certificate." },
+ { 18, "SSL_ERROR_REVOKED_CERT_ALERT - the server has rejected your certificate as revoked." },
+ { 19, "SSL_ERROR_EXPIRED_CERT_ALERT - the server has rejected your certificate as expired." },
+ { 20, "SSL_ERROR_SSL_DISABLED - cannot connect: SSL is disabled." },
+ { 21, "SSL_ERROR_FORTEZZA_PQG - cannot connect: SSL peer is in another Fortezza domain" },
+ { 22, "SSL_ERROR_UNKNOWN_CIPHER_SUITE - an unknown SSL cipher suite has been requested" },
+ { 23, "SSL_ERROR_NO_CIPHERS_SUPPORTED - no cipher suites are present and enabled in this program" },
+ { 24, "SSL_ERROR_BAD_BLOCK_PADDING" },
+ { 25, "SSL_ERROR_RX_RECORD_TOO_LONG" },
+ { 26, "SSL_ERROR_TX_RECORD_TOO_LONG" },
+ { 27, "SSL_ERROR_RX_MALFORMED_HELLO_REQUEST" },
+ { 28, "SSL_ERROR_RX_MALFORMED_CLIENT_HELLO" },
+ { 29, "SSL_ERROR_RX_MALFORMED_SERVER_HELLO" },
+ { 30, "SSL_ERROR_RX_MALFORMED_CERTIFICATE" },
+ { 31, "SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH" },
+ { 32, "SSL_ERROR_RX_MALFORMED_CERT_REQUEST" },
+ { 33, "SSL_ERROR_RX_MALFORMED_HELLO_DONE" },
+ { 34, "SSL_ERROR_RX_MALFORMED_CERT_VERIFY" },
+ { 35, "SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH" },
+ { 36, "SSL_ERROR_RX_MALFORMED_FINISHED" },
+ { 37, "SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER" },
+ { 38, "SSL_ERROR_RX_MALFORMED_ALERT" },
+ { 39, "SSL_ERROR_RX_MALFORMED_HANDSHAKE" },
+ { 40, "SSL_ERROR_RX_MALFORMED_APPLICATION_DATA" },
+ { 41, "SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST" },
+ { 42, "SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO" },
+ { 43, "SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO" },
+ { 44, "SSL_ERROR_RX_UNEXPECTED_CERTIFICATE" },
+ { 45, "SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH" },
+ { 46, "SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST" },
+ { 47, "SSL_ERROR_RX_UNEXPECTED_HELLO_DONE" },
+ { 48, "SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY" },
+ { 49, "SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH" },
+ { 50, "SSL_ERROR_RX_UNEXPECTED_FINISHED" },
+ { 51, "SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER" },
+ { 52, "SSL_ERROR_RX_UNEXPECTED_ALERT" },
+ { 53, "SSL_ERROR_RX_UNEXPECTED_HANDSHAKE" },
+ { 54, "SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA" },
+ { 55, "SSL_ERROR_RX_UNKNOWN_RECORD_TYPE" },
+ { 56, "SSL_ERROR_RX_UNKNOWN_HANDSHAKE" },
+ { 57, "SSL_ERROR_RX_UNKNOWN_ALERT" },
+ { 58, "SSL_ERROR_CLOSE_NOTIFY_ALERT - SSL peer has closed the connection" },
+ { 59, "SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT" },
+ { 60, "SSL_ERROR_DECOMPRESSION_FAILURE_ALERT" },
+ { 61, "SSL_ERROR_HANDSHAKE_FAILURE_ALERT" },
+ { 62, "SSL_ERROR_ILLEGAL_PARAMETER_ALERT" },
+ { 63, "SSL_ERROR_UNSUPPORTED_CERT_ALERT" },
+ { 64, "SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT" },
+ { 65, "SSL_ERROR_GENERATE_RANDOM_FAILURE" },
+ { 66, "SSL_ERROR_SIGN_HASHES_FAILURE" },
+ { 67, "SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE" },
+ { 68, "SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE" },
+ { 69, "SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE" },
+ { 70, "SSL_ERROR_ENCRYPTION_FAILURE" },
+ { 71, "SSL_ERROR_DECRYPTION_FAILURE" },
+ { 72, "SSL_ERROR_SOCKET_WRITE_FAILURE" },
+ { 73, "SSL_ERROR_MD5_DIGEST_FAILURE" },
+ { 74, "SSL_ERROR_SHA_DIGEST_FAILURE" },
+ { 75, "SSL_ERROR_MAC_COMPUTATION_FAILURE" },
+ { 76, "SSL_ERROR_SYM_KEY_CONTEXT_FAILURE" },
+ { 77, "SSL_ERROR_SYM_KEY_UNWRAP_FAILURE" },
+ { 78, "SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED" },
+ { 79, "SSL_ERROR_IV_PARAM_FAILURE" },
+ { 80, "SSL_ERROR_INIT_CIPHER_SUITE_FAILURE" },
+ { 81, "SSL_ERROR_SESSION_KEY_GEN_FAILURE" },
+ { 82, "SSL_ERROR_NO_SERVER_KEY_FOR_ALG" },
+ { 83, "SSL_ERROR_TOKEN_INSERTION_REMOVAL" },
+ { 84, "SSL_ERROR_TOKEN_SLOT_NOT_FOUND" },
+ { 85, "SSL_ERROR_NO_COMPRESSION_OVERLAP" },
+ { 86, "SSL_ERROR_HANDSHAKE_NOT_COMPLETED" },
+ { 87, "SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE" },
+ { 88, "SSL_ERROR_CERT_KEA_MISMATCH" },
+ { 89, "SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA - the CA that signed the client certificate is not trusted locally" }
+};
+
+#ifdef WIN32
+#define __EXPORT __declspec(dllexport)
+#else
+#define __EXPORT
+#endif
+
+__EXPORT const char* nscperror_lookup(int error)
+{
+ const char *errmsg;
+
+ if ((error >= NSCP_NSPR_ERROR_BASE) && (error <= NSCP_NSPR_MAX_ERROR)) {
+ errmsg = nscp_nspr_errors[error-NSCP_NSPR_ERROR_BASE].errorString;
+ return errmsg;
+ } else if ((error >= NSCP_LIBSEC_ERROR_BASE) &&
+ (error <= NSCP_LIBSEC_MAX_ERROR)) {
+ return nscp_libsec_errors[error-NSCP_LIBSEC_ERROR_BASE].errorString;
+ } else if ((error >= NSCP_LIBSSL_ERROR_BASE) &&
+ (error <= NSCP_LIBSSL_MAX_ERROR)) {
+ return nscp_libssl_errors[error-NSCP_LIBSSL_ERROR_BASE].errorString;
+ } else {
+ return (const char *)NULL;
+ }
+}
diff --git a/base/tps/src/httpClient/request.cpp b/base/tps/src/httpClient/request.cpp
new file mode 100644
index 000000000..629f74821
--- /dev/null
+++ b/base/tps/src/httpClient/request.cpp
@@ -0,0 +1,431 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ */
+/** BEGIN COPYRIGHT BLOCK
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+#include <string.h>
+#include "httpClient/httpc/request.h"
+#include "httpClient/httpc/engine.h"
+#include "httpClient/httpc/PSPRUtil.h"
+#include "engine/RA.h"
+#include "main/Memory.h"
+
+//-- static const char *DEBUG_MODULE = "httpclient";
+//-- static const char *DEBUG_CLASS_NAME = "PSHttpRequest";
+
+/**
+ * Constructor
+ * @param server The server to send request to
+ * @param uri The uri representing the request e.g /presence/start
+ * @param prot HTTP10 or HTTP11 .
+ * @param to Timeout ... ignore for now
+ */
+
+PSHttpRequest::PSHttpRequest(const PSHttpServer* server,
+ const char *uri,
+ HttpProtocol prot,
+ PRIntervalTime to) : NetRequest(server) {
+ //timeout = to;
+ timeout = PR_INTERVAL_NO_TIMEOUT;
+ _method = PL_strdup("GET");
+ _uri = PL_strdup(uri);
+ _proto = prot;
+ _body = NULL;
+ _bodyLength = -1;
+ _expectedResponseLength = -1;
+ _expectStandardBody = PR_FALSE;
+ _expectDynamicBody = PR_FALSE;
+ _hangupOk = PR_FALSE;
+ _fileFd = NULL;
+ nickName = NULL;
+ _headers = new StringKeyCache("request",10*60);
+}
+
+/**
+ * Destructor
+ *
+ */
+
+PSHttpRequest::~PSHttpRequest() {
+ if( _method != NULL ) {
+ PL_strfree( _method );
+ _method = NULL;
+ }
+ if( _uri != NULL ) {
+ PL_strfree( _uri );
+ _uri = NULL;
+ }
+ if( nickName != NULL ) {
+ PL_strfree( nickName );
+ nickName = NULL;
+ }
+ if( _fileFd != NULL ) {
+ PR_Close( _fileFd );
+ _fileFd = NULL;
+ }
+ if( _headers != NULL ) {
+ delete _headers;
+ _headers = NULL;
+ }
+}
+
+/**
+ * sets the request method for Http protocol
+ * @param method GET /POST etc
+ *
+ */
+
+PRBool PSHttpRequest::setMethod(const char *method) {
+ if( _method != NULL ) {
+ free( _method );
+ _method = NULL;
+ }
+ _method = PL_strdup(method);
+ return PR_TRUE;
+}
+
+void PSHttpRequest::setExpectedResponseLength(int size) {
+ _expectedResponseLength = size;
+}
+
+void PSHttpRequest::setExpectStandardBody() {
+ _expectStandardBody = PR_TRUE;
+}
+
+void PSHttpRequest::setExpectDynamicBody() {
+ _expectDynamicBody = PR_TRUE;
+}
+
+PRBool PSHttpRequest::getExpectStandardBody() {
+ return _expectStandardBody;
+}
+
+PRBool PSHttpRequest::getExpectDynamicBody() {
+ return _expectDynamicBody;
+}
+
+int PSHttpRequest::getExpectedResponseLength() {
+ return _expectedResponseLength;
+}
+
+/**
+ * Returns the method to use
+ *
+ * @return GET /POST etc
+ */
+
+char * PSHttpRequest::getMethod() {
+ return _method;
+}
+
+/**
+ * Returns HTTP0 or HTTP11
+ */
+HttpProtocol HttpMessage::getProtocol() const {
+ return proto;
+}
+
+/**
+ * Adds an HTTP header to the request
+ *
+ * @param name header name
+ * @param value header value
+ */
+PRBool PSHttpRequest::addHeader(const char *name, const char *value) {
+ char *dvalue = PL_strdup(value);
+ CacheEntry *entry = _headers->Put(name,dvalue);
+ if (entry == NULL ) {
+ if( dvalue != NULL ) {
+ PL_strfree( dvalue );
+ dvalue = NULL;
+ }
+ return PR_FALSE;
+ } else {
+ return PR_TRUE;
+ }
+}
+
+/**
+ * Gets the value for a header for this HTTP request object
+ *
+ * @param name Name of the header
+ * @return The value of the header in the request object
+ */
+
+const char * PSHttpRequest::getHeader(const char *name) {
+ CacheEntry *entry = _headers->Get(name);
+ return entry ? (char *)entry->GetData() : NULL;
+}
+
+/**
+ * Sets the body of a POST message
+ *
+ * @param size Content length
+ * @param body Content of the message; it is not copied
+ * @return PR_TRUE if the Content-length header can be set
+ */
+PRBool PSHttpRequest::setBody(int size, const char* body) {
+ char byteStr[12];
+
+ sprintf(byteStr, "%d", size);
+ if (!addHeader("Content-length", byteStr)) {
+ return PR_FALSE;
+ }
+
+ _bodyLength = size;
+ _body = (char *)body;
+
+ return PR_TRUE;
+}
+
+PRBool PSHttpRequest::addRandomBody(int size) {
+ char byteStr[12];
+
+ sprintf(byteStr, "%d", size);
+ if (!addHeader("Content-length", byteStr)) {
+ return PR_FALSE;
+ }
+
+ _bodyLength = size;
+
+ return PR_TRUE;
+}
+
+PRBool PSHttpRequest::useLocalFileAsBody(const char* fileName) {
+ PRBool res = PR_FALSE;
+ PRFileInfo finfo;
+ if (PR_GetFileInfo(fileName, &finfo) == PR_SUCCESS) {
+ res = PR_TRUE;
+ char byteStr[25];
+ sprintf(byteStr, "%d", finfo.size);
+ if (!addHeader("Content-length", byteStr)) {
+ return PR_FALSE;
+ }
+ _bodyLength = finfo.size;
+ _fileFd = PR_Open(fileName, PR_RDONLY, 0);
+ if (!_fileFd) {
+ return PR_FALSE;
+ }
+ }
+
+ return PR_TRUE;
+}
+
+/**
+ * This function sends the HTTP request to the server.
+ * @param sock - the connection onto which the request is to be sent
+ */
+
+PRBool PSHttpRequest::send( PRFileDesc *sock ) {
+ const char *hostname;
+//-- static const char *DEBUG_METHOD_NAME = "send";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+
+ PRBool rv = PR_FALSE;
+ if (!sock) {
+ return rv;
+ }
+
+ char *data = NULL;
+
+ if (_proto == HTTP11) {
+ hostname = getHeader("Host");
+
+ if (hostname == NULL) {
+ // long port = _server->getPort();
+
+ char address[100];
+ PR_snprintf(address, 100, "%s:%d", _server->getAddr(),
+ _server->getPort());
+ addHeader("Host", address);
+ }
+ }
+
+ // create the HTTP string "GET /presence/stop HTTP/1.0"
+ char *path = strstr( _uri, "//" );
+ if ( path ) {
+ path = strchr( path + 2, '/' );
+ }
+ if ( !path ) {
+ path = _uri;
+ }
+ data = PR_smprintf( "%s %s %s\r\n", _method, path,
+ HttpProtocolToString(_proto) );
+
+ // Send HTTP headers
+ char **keys;
+ char *headerValue = NULL;
+ int nKeys = _headers->GetKeys( &keys );
+ for ( int i = 0 ; i < nKeys; i++ ) {
+ CacheEntry *entry = _headers->Get( keys[i] );
+ if (entry) {
+ headerValue = (char *)entry->GetData();
+ //adds the headers name: value
+ data = PR_sprintf_append(data,"%s: %s\r\n",keys[i],headerValue);
+ if( headerValue != NULL ) {
+ PL_strfree( headerValue );
+ headerValue = NULL;
+ }
+ }
+ entry = _headers->Remove(keys[i]);
+ if( entry != NULL ) {
+ delete entry;
+ entry = NULL;
+ }
+ if( keys[i] != NULL ) {
+ delete [] ( keys[i] );
+ keys[i] = NULL;
+ }
+ }
+ if( keys != NULL ) {
+ delete [] keys;
+ keys = NULL;
+ }
+
+ // Send terminator
+ data = PR_sprintf_append(data,"\r\n");
+
+ int len = PL_strlen(data);
+ //send the data ..
+ int bytes = PR_Send(sock, data, len, 0, timeout);
+ if( data != NULL ) {
+ PR_smprintf_free( data );
+ data = NULL;
+ }
+ if ( bytes != len ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpRequest::send: ",
+ "Error sending request -- PR_Send returned(%d) Msg=%s\n",
+ PR_GetError(),
+ "XXX" );
+ return PR_FALSE;
+ }
+
+ if ( _fileFd ) {
+ // Send body from file
+ PRInt32 bytesSent = PR_TransmitFile(sock, _fileFd, 0, 0,
+ PR_TRANSMITFILE_KEEP_OPEN,
+ timeout);
+ if ( bytesSent < 0 ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpRequest::send: ",
+ "Error sending request\n" );
+ return PR_FALSE;
+ }
+ } else if (_bodyLength > 0) {
+ // Send internally stored body
+ char *allocated = NULL;
+ if ( !_body ) {
+ // Send a generated pattern
+ _body = allocated = new char[_bodyLength];
+ for ( int index = 0; index < _bodyLength; index++ ) {
+ _body[index] = (unsigned char)(index %256);
+ }
+ }
+ int sentBytes = 0;
+ char *toSend = _body;
+ for ( int i = _bodyLength; i > 0; i -= sentBytes ) {
+ sentBytes = PR_Send( sock, toSend, i, 0, timeout );
+ if ( sentBytes < 0 ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpRequest::send: ",
+ "Error sending request in PR_Send\n" );
+ return PR_FALSE;
+ }
+ toSend += sentBytes;
+ }
+ if ( allocated ) {
+ if( _body != NULL ) {
+ delete [] _body;
+ _body = NULL;
+ }
+ }
+ }
+
+ return PR_TRUE;
+}
+
+/**
+ * Sets the nickname for the client cert to be send to the server
+ * @param certName Nickname of the cert in the cert db
+ */
+void PSHttpRequest::setCertNickName(const char *certName) {
+ nickName = PL_strdup(certName);
+}
+
+/**
+ * Gets the nickname for the client cert
+ * @return certName Nickname of the cert in the cert db
+ */
+char * PSHttpRequest::getCertNickName() {
+ return nickName;
+}
+
+void PSHttpRequest::setHangupOk() {
+ _hangupOk = PR_TRUE;
+}
+
+PRBool PSHttpRequest::isHangupOk() {
+ return(_hangupOk);
+}
+
+
+/**
+ * returns PR_TRUE if ssl is enabled for this request
+ */
+PRBool NetRequest::isSSL() const {
+ return SSLOn;
+}
+
+/**
+ * enable/disable SSL for the request
+ */
+void NetRequest::setSSL(PRBool SSLstate) {
+ SSLOn=SSLstate;
+}
+
+/**
+* Constructor for NetRequest class. This is a superclass of httprequest class
+* @param server The server to which the request is to be send
+*/
+NetRequest :: NetRequest(const PSHttpServer* server) {
+ _server = server;
+ timeout = Engine::globaltimeout;
+ SSLOn=PR_FALSE;
+ if (server)
+ SSLOn=server->isSSL();
+ handshake = PR_FALSE;
+ cipherCount = 0;
+ cipherSet = NULL;
+
+}
+
+/**
+* Returns the current configured timeout
+*/
+PRIntervalTime NetRequest :: getTimeout() const {
+ return timeout;
+}
diff --git a/base/tps/src/httpClient/response.cpp b/base/tps/src/httpClient/response.cpp
new file mode 100644
index 000000000..89b900492
--- /dev/null
+++ b/base/tps/src/httpClient/response.cpp
@@ -0,0 +1,1115 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/** BEGIN COPYRIGHT BLOCK
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * Copyright (C) 2007 Red Hat, Inc.
+ * All rights reserved.
+ * END COPYRIGHT BLOCK **/
+
+/**
+ * HTTP response handler
+ */
+
+#include <ctype.h>
+#include <string.h>
+#include <math.h>
+
+#include "nspr.h"
+#include "engine/RA.h"
+#include "main/Util.h"
+#include "httpClient/httpc/response.h"
+#include "httpClient/httpc/engine.h"
+//-- #include "httpClient/httpc/DebugLogger.h"
+#include "httpClient/httpc/PSPRUtil.h"
+#include "main/Memory.h"
+
+//-- static const char *DEBUG_MODULE = "httpclient";
+//-- static const char *DEBUG_CLASS_NAME = "PSHttpResponse";
+void printBuf(int , char* );
+
+/**
+ * Constructor. This class is used by the HttpResponse class for reading and
+ * processing data from the socket
+ * @param socket The NSPR socket from which the response is expected
+ * @param size The size of the internal buffer to hold data
+ * @param timeout Timeout in seconds on receiving a response
+ */
+
+RecvBuf::RecvBuf( const PRFileDesc *socket, int size, int timeout ) {
+ _socket = socket;
+ _allocSize = size;
+ _buf = (char *)PR_Malloc(size);
+ _curPos = 0;
+ _curSize = 0;
+ _chunkedMode = PR_FALSE;
+ _currentChunkSize = _currentChunkBytesRead = 0;
+ _timeout = PR_TicksPerSecond() * timeout;
+ _content = NULL;
+}
+
+/**
+ * Destructor
+ */
+RecvBuf::~RecvBuf() {
+ if( _buf != NULL ) {
+ PR_Free( _buf );
+ _buf = NULL;
+ }
+}
+
+/**
+ * Reads the specified number of bytes from the socket and place it into the buffer
+ *
+ * @param socket The NSPR socket from which the response is expected
+ * @param size The size of the buffer
+ * @return PR_TRUE on success, otherwise PR_FALSE
+ */
+PRBool RecvBuf::_getBytes(int size) {
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+ PRErrorCode pec;
+ _curPos = 0;
+
+ int num =1;
+ int i =0;
+ PRBool endChunk= PR_FALSE;
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::_getBytes: ",
+ "Start RecvBuf::_getBytes" );
+ // actual reading from the socket happens here
+ do {
+ num = PR_Recv( (PRFileDesc*)_socket,
+ &_buf[_curSize],
+ _allocSize-_curSize,
+ 0,
+ _timeout );
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::_getBytes: ",
+ "num of bytes read from the socket=%d",
+ num );
+ /*
+ * in chunked mode, ending chunk contains a 0 to begin
+ * loop through to see if it contains just 0 (skip carriage returns
+ * endChunk indicates possible end chunk.
+ */
+ if ((_chunkedMode == PR_TRUE) && (num < 10)) {
+ endChunk = PR_FALSE;
+
+ for (i=0; i< num; i++) {
+ if (endChunk == PR_TRUE) {
+ if ((_buf[_curSize+i] == 13) || (_buf[_curSize+i] == 10))
+ continue;
+ else {
+ endChunk = PR_FALSE;
+ break; // not an endChunk
+ }
+ } else { // endChunk==PR_FALSE
+ if (_buf[_curSize+i] == '0') {
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::_getBytes: ",
+ "may be chunked mode end chunk" );
+ endChunk = PR_TRUE;
+ } else if ((_buf[_curSize+i] == 13) || (_buf[_curSize+i] == 10))
+ continue;
+ else {
+ endChunk = PR_FALSE;
+ break; // not an endChunk
+ }
+ }
+ } // for
+ }
+
+ if (num >0)
+ _curSize = _curSize+num;
+
+ if (_chunkedMode == PR_FALSE) {
+ if (getAllContent()) {
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::_getBytes: ",
+ "Already got all the content, no need to call PR_Recv again." );
+ break;
+ }
+ }
+
+ if (endChunk == PR_TRUE)
+ break;
+ } while (num > 0);
+
+ if (num <0) {
+ pec = PR_GetError();
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::_getBytes: ",
+ "error in pr_recv, err=%d",
+ pec );
+ }
+
+ if ( _curSize <= 0 ) {
+ return PR_FALSE;
+ }
+
+ _buf[_curSize] = '\0';
+//-- logger->Log( LOGLEVEL_FINEST, DEBUG_CLASS_NAME,
+//-- "getBytes",
+
+ _content = (char *) PR_Malloc(_curSize+1);
+ if (_content == NULL) {
+ return PR_FALSE;
+ }
+ memcpy((char*) _content, (const char *)_buf, _curSize+1);
+ _contentSize = _curSize +1;
+
+ RA::Debug(LL_PER_PDU, "RecvBuf::_getBytes",
+ "buffer received with size %d follows:", _contentSize);
+ printBuf(_contentSize, _content);
+
+ return PR_TRUE;
+}
+
+int RecvBuf::getAllContent() {
+ //int result[10];
+ //int j=0;
+ //int k=0;
+ int number = 0;
+ for (int i=0; i<_curSize; i++) {
+ if (_buf[i] == '\r') {
+ if (i < (_curSize-3)) {
+ if (_buf[i+1] == '\n' && _buf[i+2] == '\r'
+ && _buf[i+3] == '\n') {
+ // find content length
+// strcasestr may not be supported by Solaris
+// char *clen = strcasestr(_buf, "Content-length:");
+ char *clen = strstr(_buf, "Content-Length:");
+ if (clen != NULL) {
+ clen = &clen[16];
+ number = atoi(clen);
+/*
+ while (1) {
+ if ((number=Util::ascii2numeric(clen[j++])) >= 0) {
+ result[k++] = number;
+ } else {
+ break;
+ }
+ }
+
+ number = 0;
+ for (int l=0; l<k; l++)
+ number = (int)(number + result[l]*(float)pow((float)10, (float)k-l-1));
+*/
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::getAllContent: ",
+ "content length number=%d",
+ number );
+ }
+ int remainingBytes = _curSize - (i+4);
+ RA::Debug( LL_PER_PDU,
+ "RecvBuf::getAllContent: ",
+ "remainingbytes=%d",
+ remainingBytes );
+ if (remainingBytes == number)
+ return 1;
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+void printBuf(int len, char* buf) {
+ RA::Debug(LL_PER_PDU, "response:printBuf",
+ "Buffer print begins");
+ RA::Debug(LL_PER_PDU, "response::printBuf",
+ "%s", buf);
+ RA::Debug(LL_PER_PDU, "response:printBuf",
+ "Buffer print end");
+ /*
+ int times = len/256;
+ if (len%256)
+ times++;
+ RA::Debug("response:printBuf",
+ "%d times", times);
+ RA::Debug("response:printBuf",
+ "attempting to print the whole buffer:");
+
+ int i;
+
+ for (i = 0; i< times; i++) {
+ char *temp;
+ temp = PL_strdup((char *)buf+i*256);
+ RA::Debug("response:printBuf",
+ "%s", temp);
+ }
+ */
+}
+
+/**
+ * gets the next char from the buffer. If all the data in the buffer is read,
+ * read a chunk to the buffer
+ * @returns - the next char from the data
+ */
+char RecvBuf::_getChar() {
+ if (_curPos >= _curSize) {
+ if (!_getBytes(_allocSize)) {
+ /* bugscape #55624: Solaris RA exited
+ with a signal ABRT if we raised exception
+ without handling it */
+ return -1;
+ /* throw RecvBuf::EndOfFile(); */
+ }
+ }
+
+ return _buf[_curPos++];
+}
+
+
+/**
+ * gets the next char from the buffer. If all the data in the buffer is read ,
+ * read a chunk to the buffer
+ * @returns - the next char from the data
+ */
+char RecvBuf::getChar() {
+ if (!_chunkedMode)
+ return _getChar();
+
+ else
+ {
+ if (_currentChunkSize == 0)
+ {
+ // read the chunk header
+ char ch, chunkStr[20];
+ int index = 0;
+
+ while (!isspace(ch = _getChar()) )
+ chunkStr[index++] = ch;
+ chunkStr[index] = '\0';
+
+ sscanf((char *)chunkStr, "%x", (unsigned int *)(&_currentChunkSize));
+
+ if (ch != '\n')
+ {
+ char ch2 = _getChar();
+ if (ch != '\r' || ch2 != '\n')
+ {
+ printf( "did not find CRLF after chunk");
+ }
+ }
+
+ if (_currentChunkSize == 0)
+ return -1;
+
+ _currentChunkBytesRead = 1;
+ return _buf[_curPos++];
+ }
+ else
+ if (_currentChunkBytesRead < _currentChunkSize)
+ {
+ // read a byte from the chunk
+ _currentChunkBytesRead++;
+ return _getChar();
+ }
+ else
+ {
+ // read the chunk trailer
+ char ch1 = _getChar();
+ char ch2 = _getChar();
+ if (ch1 != '\r' || ch2 != '\n')
+ {
+ printf( "did not find CRLF after chunk");
+ };
+ _currentChunkSize = _currentChunkBytesRead = 0;
+ return getChar();
+ };
+ };
+
+}
+
+char *RecvBuf::get_content() {
+ return _content;
+}
+
+int RecvBuf::get_contentSize() {
+ return _contentSize;
+}
+
+/**
+ * Decrements the pointer to the internal buffer so that the next read would
+ * retrieve the last data again
+ */
+void RecvBuf::putBack() {
+ if (_curPos > 0) {
+ _curPos--;
+ if (_chunkedMode) {
+ _currentChunkBytesRead--;
+ }
+ }
+}
+
+/**
+ * Sets the chunked mode for reading data
+ * Not used now..
+ */
+void RecvBuf::setChunkedMode() {
+ _chunkedMode = PR_TRUE;
+ _currentChunkSize = _currentChunkBytesRead = 0;
+}
+
+/**
+ * Gets the timeout in seconds for reading
+ *
+ * @return The timeout in seconds for reading
+ */
+int RecvBuf::getTimeout() {
+ return _timeout / PR_TicksPerSecond();
+}
+
+
+Response::Response(const PRFileDesc *sock, NetRequest *request) {
+ _socket = sock;
+ _request = request;
+}
+
+/**
+ * Constructor
+ */
+
+PSHttpResponse::PSHttpResponse( const PRFileDesc *sock,
+ PSHttpRequest *request,
+ int timeout , PRBool expectChunked):
+ Response(sock, request) {
+ _request = request;
+ _proto = HTTPNA;
+ _protocol = NULL;
+ retcode =0 ;
+ _statusNum = NULL;
+ _statusString = NULL;
+ _keepAlive = -1;
+ _connectionClosed = 0;
+ _bodyLength = -1;
+ _content = NULL;
+
+ _headers = new StringKeyCache("response",10*60);
+ _expectChunked = expectChunked;
+ _chunkedResponse = PR_FALSE;
+ _timeout = timeout;
+}
+
+PSHttpResponse::~PSHttpResponse() {
+ if( _protocol != NULL ) {
+ PL_strfree( _protocol );
+ _protocol = NULL;
+ }
+ if( _statusString != NULL ) {
+ PL_strfree( _statusString );
+ _statusString = NULL;
+ }
+ if( _statusNum != NULL ) {
+ PL_strfree( _statusNum );
+ _statusNum = NULL;
+ }
+ if (_headers) {
+ Iterator* iterator = _headers->GetKeyIterator();
+ while ( iterator->HasMore() ) {
+ const char* name = (const char*)iterator->Next();
+ CacheEntry* entry = _headers->Remove( name );
+ if ( entry ) {
+ char* value = (char*)entry->GetData();
+ if( value != NULL ) {
+ PL_strfree( value );
+ value = NULL;
+ }
+ if( entry != NULL ) {
+ delete entry;
+ entry = NULL;
+ }
+ }
+ }
+ if( iterator != NULL ) {
+ delete iterator;
+ iterator = NULL;
+ }
+ if( _headers != NULL ) {
+ delete _headers;
+ _headers = NULL;
+ }
+ }
+ _socket = 0;
+}
+
+long PSHttpResponse::getStatus() {
+ return _statusNum ? atoi(_statusNum) : 0;
+}
+
+int PSHttpResponse::getReturnCode() {
+ return retcode;
+}
+
+char * PSHttpResponse::getStatusString() {
+ return _statusString?_statusString:(char*)"";
+}
+
+HttpProtocol PSHttpResponse::getProtocol() {
+ // first check the response protocol
+ if (_proto == HTTPNA) {
+ if (_protocol) {
+ int major, minor;
+
+ sscanf(_protocol, "HTTP/%d.%d", &major, &minor);
+
+ switch(major) {
+ case 1:
+ switch(minor) {
+ case 0:
+ _proto = HTTP10;
+ break;
+ case 1:
+ _proto = HTTP11;
+ break;
+ }
+ break;
+ }
+ } else {
+ _proto = HTTP09;
+ }
+ }
+
+ if (_proto == HTTP11) {
+ // A 1.1 compliant server response shows the protocol as HTTP/1.1 even
+ // for a HTTP/1.0 request, but it promises to only use HTTP/1.0 syntax.
+ if (_request->getProtocol() == HTTP10) {
+ _proto = HTTP10;
+ }
+ }
+
+ return _proto;
+};
+
+char * PSHttpResponse::getHeader(const char *name) {
+ CacheEntry *entry = _headers->Get(name);
+ return entry ? (char *)entry->GetData() : NULL;
+}
+
+int PSHttpResponse::getHeaders(char ***keys) {
+
+ return _headers->GetKeys( keys );
+
+}
+
+long PSHttpResponse::getBodyLength() {
+ return _bodyLength;
+}
+
+char * PSHttpResponse::getContent() {
+ return _content;
+}
+
+void PSHttpResponse::freeContent() {
+ if( _content != NULL ) {
+ PR_Free( _content );
+ _content = NULL;
+ }
+}
+
+int PSHttpResponse::getContentSize() {
+
+ return _contentSize;
+}
+
+char *PSHttpResponse::toString() {
+ char *resp = (char *)"";
+ char **keys;
+ char *headerBuf = NULL;
+ int nHeaders = getHeaders( &keys );
+ if ( nHeaders > 0 ) {
+ char **values = new char*[nHeaders];
+ int len = 0;
+ int *keyLengths = new int[nHeaders];
+ int *valueLengths = new int[nHeaders];
+ int i;
+ for( i = 0; i < nHeaders; i++ ) {
+ keyLengths[i] = strlen( keys[i] );
+ len += keyLengths[i] + 1;
+ values[i] = getHeader(keys[i]);
+ valueLengths[i] = strlen( values[i] );
+ len += valueLengths[i] + 1;
+ }
+ headerBuf = new char[len + nHeaders * 2];
+ char *p = headerBuf;
+ for( i = 0; i < nHeaders; i++ ) {
+ strcpy( p, keys[i] );
+ p += keyLengths[i];
+ *p++ = ':';
+ strcpy( p, values[i] );
+ p += valueLengths[i];
+ *p++ = ',';
+ }
+ *p = 0;
+ for( i = 0; i < nHeaders; i++ ) {
+ if( keys[i] != NULL ) {
+ delete [] keys[i];
+ keys[i] = NULL;
+ }
+ }
+ if( keys != NULL ) {
+ delete [] keys;
+ keys = NULL;
+ }
+ if( values != NULL ) {
+ delete [] values;
+ values = NULL;
+ }
+ if( keyLengths != NULL ) {
+ delete [] keyLengths;
+ keyLengths = NULL;
+ }
+ if( valueLengths != NULL ) {
+ delete [] valueLengths;
+ valueLengths = NULL;
+ }
+ }
+
+ char *s = NULL;
+ if ( headerBuf ) {
+ s = PR_smprintf( "PSHttpResponse [%s\nbody bytes:%d]",
+ headerBuf, _bodyLength );
+ } else {
+ s = PR_smprintf( "PSHttpResponse [body bytes:%d]", _bodyLength );
+ }
+ resp = new char[strlen(s) + 1];
+ strcpy( resp, s );
+ if( s != NULL ) {
+ PR_smprintf_free( s );
+ s = NULL;
+ }
+ return resp;
+}
+
+PRBool PSHttpResponse::checkKeepAlive() {
+ HttpProtocol proto;
+ const char *connectionHeader;
+//-- static const char *DEBUG_METHOD_NAME = "checkKeepAlive";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+
+ if (_keepAlive < 0) {
+ proto = getProtocol();
+ if (proto == HTTP11) {
+ // default is connection: keep-alive
+ _keepAlive = 1;
+ } else {
+ // default is connection: close
+ // _keepAlive = 0;
+ //CMS needs keepalive with HTTP10 (so no chunked encoding)
+ _keepAlive=1;
+ }
+
+ connectionHeader = _request->getHeader("connection");
+ if (connectionHeader) {
+ if (!PL_strcasecmp(connectionHeader, "keep-alive")) {
+ _keepAlive = 1;
+ } else if (!PL_strcasecmp(connectionHeader, "close")) {
+ _keepAlive = 0;
+ } else {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::checkKeepAlive: ",
+ "Unknown connection header" );
+ }
+ }
+ }
+
+ return (_keepAlive == 0?PR_FALSE:PR_TRUE);
+}
+
+PRBool PSHttpResponse::checkConnection() {
+ // return true if the connection is OPEN
+ return (_connectionClosed == 0?PR_TRUE:PR_FALSE);
+}
+
+
+int PSHttpResponse::_verifyStandardBody(RecvBuf &buf,
+ int expectedBytes,
+ PRBool check) {
+ int bytesRead = 0;
+ int curPos = 0;
+ char ch;
+//-- static const char *DEBUG_METHOD_NAME = "_verifyStandardBody";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+
+ while(expectedBytes > 0 ) {
+ ch = buf.getChar();
+ if (ch < 0 ) {
+ break;
+ }
+ // if check is true, we think we know what the content looks like
+ if ( check ) {
+ if (ch != (char) curPos%256) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_verifyStandardBody: ",
+ "Response data corrupt at byte %d (%d, %d)",
+ curPos,
+ ch,
+ ( curPos % 256 ) );
+ check = PR_FALSE;
+ break;
+ }
+ curPos++;
+ }
+
+ bytesRead++;
+
+ if (expectedBytes > 0) {
+ expectedBytes--;
+ }
+ }
+
+ return bytesRead;
+}
+
+
+PRBool PSHttpResponse::_handleBody( RecvBuf &buf ) {
+ char *clHeader; // content length header
+ char *teHeader; // transfer-encoding header
+ int expected_cl=-1; // expected content length
+//-- static const char *DEBUG_METHOD_NAME = "_handleBody";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+
+ teHeader = getHeader("transfer-encoding");
+ if (teHeader && !PL_strcasecmp(teHeader, "chunked")) {
+ _chunkedResponse = PR_TRUE;
+ buf.setChunkedMode();
+ } else {
+ _chunkedResponse = PR_FALSE;
+ clHeader = getHeader("Content-length");
+ if (clHeader) {
+ expected_cl = atoi(clHeader);
+ }
+ }
+
+ if (_request->getExpectStandardBody()) {
+ _bodyLength = _verifyStandardBody(buf, expected_cl, PR_TRUE);
+
+ } else {
+ _bodyLength = _verifyStandardBody(buf, expected_cl, PR_FALSE);
+ }
+
+ if (expected_cl >= 0) {
+ if (_bodyLength != expected_cl) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_handleBody: ",
+ "Content length was incorrect (%d/%d bytes)",
+ _bodyLength,
+ expected_cl );
+ }
+ }
+
+ return PR_TRUE;
+}
+
+/**
+ * Reads until the first space character
+ *
+ * @param buf Receive buffer to read from
+ * @param headerBuf Array to read header into
+ * @param len Size of headerBuf
+ * @return Number of characters read, or -1 if too many
+ */
+static int readHeader( RecvBuf& buf, char* headerBuf, int len ) {
+ int index = 0;
+
+ do {
+ char ch = buf.getChar();
+
+ if ( ch != -1 && !isspace(ch) ) {
+ headerBuf[index++] = ch;
+ if ( index >= (len-1) ) {
+ return -1;
+ }
+ } else {
+ headerBuf[index] = '\0';
+ break;
+ }
+ } while( true );
+ // RA::Debug( LL_PER_PDU,
+ // "readHeader: ",
+ // "headerBuf = %s",
+ // headerBuf );
+
+ return index;
+}
+
+
+PRBool PSHttpResponse::processResponse() {
+ RecvBuf buf( _socket, 8192, _timeout );
+
+ if (_expectChunked) {
+ buf.setChunkedMode();
+ }
+
+//-- static const char *DEBUG_METHOD_NAME = "processResponse";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Entered processResponse()" );
+
+ try {
+ char tmp[2048];
+ int tmpLen = sizeof(tmp);
+
+ // Get protocol string
+ int nRead = readHeader( buf, tmp, tmpLen );
+
+ if ( nRead < 0 ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Returned more than expected bytes %d "
+ "in protocol header",
+ sizeof( tmp ) );
+ return PR_FALSE;
+ }
+
+ _protocol = PL_strdup(tmp);
+//-- logger->Log( LOGLEVEL_FINER, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Protocol header: %s",
+ _protocol );
+
+ // Get status num
+ nRead = readHeader( buf, tmp, tmpLen );
+ if ( nRead < 0 ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Returned more than expected bytes %d "
+ "in status header",
+ tmpLen );
+ return PR_FALSE;
+ }
+
+ _statusNum = PL_strdup( tmp );
+
+//-- logger->Log( LOGLEVEL_FINER, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Status header: %s",
+ _statusNum );
+ retcode = atoi( tmp );
+
+ // Get status string
+ int index = 0;
+ do {
+ char ch = buf.getChar();
+ if ( ch != -1 && ch != '\r' ) {
+ tmp[index++] = ch;
+ if ( index >= (tmpLen-2) ) {
+ tmp[index] = 0;
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Returned more than expected bytes %d "
+ "in protocol header:\n%s",
+ tmpLen,
+ tmp );
+ return PR_FALSE;
+ }
+ } else {
+ break;
+ }
+ } while (true);
+ tmp[index] = '\0';
+ _statusString = PL_strdup( tmp );
+
+ // Skip CRLF
+ (void)buf.getChar();
+
+ // loop over response headers
+ index = 0;
+#ifdef CHECK
+ PRBool doneParsing = PR_FALSE;
+ PRBool atEOL = PR_FALSE;
+ PRBool inName = PR_TRUE;
+ char name[2048];
+ int nameLen = sizeof(name);
+
+ while ( !doneParsing ) {
+ char value[2048];
+ int valueLen = sizeof(value);
+ char ch = buf.getChar();
+
+ switch( ch ) {
+ case ':':
+ if ( inName ) {
+ name[index] = '\0';
+ index = 0;
+ inName = PR_FALSE;
+
+ nRead = readHeader( buf, value, valueLen );
+ if ( nRead < 0 ) {
+//-- logger->Log( LOGLEVEL_SEVERE,
+//-- DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Name %s in header does not "
+ "have a value",
+ name );
+ // return PR_FALSE;
+ } else {
+ value[index++] = ch;
+ if ( index >= (int)(sizeof(value) - 1 ) ) {
+//-- logger->Log( LOGLEVEL_SEVERE,
+//-- DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Name %s in header does not "
+ "have a value",
+ name );
+ // return PR_FALSE;
+ }
+ }
+ break;
+ case '\r':
+ if ( inName && !atEOL ) {
+ name[index] = '\0';
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Name %s in header does not "
+ "have a value",
+ name );
+ // return PR_FALSE;
+ }
+ break;
+ case '\n':
+ if ( atEOL ) {
+ doneParsing = PR_TRUE;
+ break;
+ }
+ if ( inName ) {
+ name[index] = '\0';
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Name %s in header does not "
+ "have a value",
+ name );
+ // return PR_FALSE;
+ }
+ value[index] = '\0';
+ index = 0;
+ inName = PR_TRUE;
+ _headers->Put(name, PL_strdup(value));
+ atEOL = PR_TRUE;
+ break;
+ default:
+ atEOL = PR_FALSE;
+ if (inName) {
+ name[index++] = ch;
+ } else {
+ value[index++] = ch;
+ }
+ if ( inName && (index >= (nameLen-2)) ) {
+ name[index] = '\0';
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Name %s in header exceeds the expected "
+ "%d max characters",
+ name,
+ nameLen );
+ // return PR_FALSE;
+ } else if ( !inName && (index >= (valueLen-1)) ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Name %s in header does not "
+ "have a value",
+ name );
+ // return PR_FALSE;
+ }
+ break;
+ }
+ }
+
+ } //while
+#endif //CHECK
+ } catch ( RecvBuf::EndOfFile & ) {
+ if ( !_request->isHangupOk() ) {
+
+ int errCode = PR_GetError();
+ if ( PR_IO_TIMEOUT_ERROR == errCode ) {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Timed out reading response (%d seconds)",
+ buf.getTimeout() );
+ } else {
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Received unexpected end of file from server\n%s",
+ "XXX" );
+ }
+ }
+ return PR_FALSE;
+ }
+
+ // Read the body (HEAD requests don't have bodies)
+ // jpierre 1xx, 204 and 304 don't have bodies either
+ if ( PL_strcmp(_request->getMethod(), "HEAD") &&
+ (!((retcode>=100) && (retcode<200))) &&
+ (retcode!=204) &&
+ (retcode!=304) ) {
+ if ( _handleBody(buf) == PR_FALSE ) {
+ return PR_FALSE;
+ }
+ }
+
+ if ( checkConnection() && !checkKeepAlive() ) {
+ // if connection is still open, and we didn't expect a keepalive,
+ // read another byte to see if the connection has closed.
+ try {
+ char ch;
+ ch = buf.getChar();
+ buf.putBack();
+ // conflict!
+//-- logger->Log( LOGLEVEL_SEVERE, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "Connection kept alive when it shouldn't" );
+ } catch (RecvBuf::EndOfFile &) {
+ _connectionClosed = 1;
+ }
+ }
+
+ _checkResponseSanity();
+ _content = (char *)buf.get_content();
+ _contentSize = buf.get_contentSize();
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "processed Buffer contentSize=%d",
+ getContentSize() );
+ if (_content != NULL) {
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::processResponse: ",
+ "processed Buffer content=%s",
+ _content );
+ }
+ // char * yo = getContent();
+
+ return PR_TRUE;
+}
+
+void PSHttpResponse::_checkResponseSanity() {
+ char *clHeader = getHeader("Content-length");
+ char *teHeader = getHeader("Transfer-encoding");
+//-- static const char *DEBUG_METHOD_NAME = "checkResponseSanity";
+//-- DebugLogger *logger = DebugLogger::GetDebugLogger( DEBUG_MODULE );
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "in _checkResponseSanity" );
+
+ ///////////////////////////////////////////////////
+ // Check items relevant to HTTP/1.0 and HTTP/1.1 //
+ ///////////////////////////////////////////////////
+
+ // check for both content-length and chunked
+ if ( clHeader && teHeader ) {
+//-- logger->Log( LOGLEVEL_FINER, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "Response contains both content-length and "
+ "transfer-encoding" );
+ }
+
+ // check for basic headers
+ if ( !getHeader("Date") ) {
+//-- logger->Log( LOGLEVEL_WARNING, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "Response does not contain a date header" );
+ }
+ if ( !getHeader("Server") ) {
+//-- logger->Log( LOGLEVEL_WARNING, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "Response does not contain a server header" );
+ }
+
+ int expectedLength;
+ if ((expectedLength = _request->getExpectedResponseLength()) > 0) {
+ if (expectedLength != _bodyLength) {
+//-- logger->Log( LOGLEVEL_INFO, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "Response body length does not match expected "
+ "response length (%d/%d)",
+ _bodyLength,
+ expectedLength );
+ }
+ }
+
+ ///////////////////////////////////////
+ // Check items relevant to HTTP/1.0 //
+ ///////////////////////////////////////
+ if ( getProtocol() == HTTP10 ) {
+ if ( _chunkedResponse ) {
+//-- logger->Log( LOGLEVEL_INFO, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "Server sent a chunked HTTP/1.0 response" );
+ }
+ }
+
+ ///////////////////////////////////////
+ // Check items relevant to HTTP/1.1 //
+ ///////////////////////////////////////
+ if ( getProtocol() == HTTP11 ) {
+ if ( (!clHeader && !_chunkedResponse) &&
+ (!((retcode>=100) && (retcode<200))) &&
+ (retcode!=204) &&
+ (retcode!=304) ) {
+//-- logger->Log( LOGLEVEL_INFO, DEBUG_CLASS_NAME,
+//-- DEBUG_METHOD_NAME,
+ RA::Debug( LL_PER_PDU,
+ "PSHttpResponse::_checkResponseSanity: ",
+ "Server responded with a HTTP/1.1 response without "
+ "content-length or chunked encoding" );
+ }
+ }
+}