From: cantor Date: Wed, 2 Jul 2008 18:53:28 +0000 (+0000) Subject: Support GET requests when input stream is empty. X-Git-Tag: 1.4.1~322 X-Git-Url: http://www.project-moonshot.org/gitweb/?p=shibboleth%2Fxmltooling.git;a=commitdiff_plain;h=4218453693c50a7c9e68ff543f05824a60caaf1c Support GET requests when input stream is empty. git-svn-id: https://svn.middleware.georgetown.edu/cpp-xmltooling/branches/REL_1@507 de75baf8-a10c-0410-a50a-987c0e22f00f --- diff --git a/.cproject b/.cproject index 8474fe4..2473079 100644 --- a/.cproject +++ b/.cproject @@ -60,6 +60,7 @@ + @@ -69,6 +70,7 @@ + diff --git a/xmltooling/soap/SOAPTransport.h b/xmltooling/soap/SOAPTransport.h index 55ec9e0..ec6ed9c 100644 --- a/xmltooling/soap/SOAPTransport.h +++ b/xmltooling/soap/SOAPTransport.h @@ -1,6 +1,6 @@ /* * Copyright 2001-2007 Internet2 - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,7 +16,7 @@ /** * @file xmltooling/soap/SOAPTransport.h - * + * * Encapsulates a transport layer protocol for sending/receiving messages. */ @@ -27,15 +27,15 @@ #include namespace xmltooling { - + class XMLTOOL_API Credential; class XMLTOOL_API CredentialCriteria; class XMLTOOL_API CredentialResolver; class XMLTOOL_API X509TrustEngine; - + /** * Encapsulates a transport layer protocol for sending/receiving messages. - * + * * Most of the methods are const, meaning they don't affect the transport * layer until the data is sent. */ @@ -73,27 +73,27 @@ namespace xmltooling { /** * Indicates whether transport provides confidentiality. - * + * * @return true iff transport layer provides confidentiality */ virtual bool isConfidential() const=0; - + /** * Sets the connection timeout. - * + * * @param timeout time to wait for connection to server in seconds, or -1 for no timeout * @return true iff the transport supports connection timeouts */ virtual bool setConnectTimeout(long timeout)=0; - + /** * Sets the request timeout. - * + * * @param timeout time to wait for a response in seconds, or -1 for no timeout * @return true iff the transport supports request/response timeouts */ virtual bool setTimeout(long timeout)=0; - + /** * Common types of transport authentication that may be supported. */ @@ -104,10 +104,10 @@ namespace xmltooling { transport_auth_ntlm = 3, transport_auth_gss = 4 }; - + /** * Sets a particular form of transport authentication and credentials. - * + * * @param authType type of transport authentication to use * @param username username for transport authentication * @param password simple password/credential for transport authentication @@ -119,18 +119,18 @@ namespace xmltooling { * Determines whether TLS/SSL connections include a check of the server's certificate * against the expected hostname or address. Defaults to true, and has no effect for * insecure protocols. - * + * * @param verify true iff the hostname should be verified against the server's certificate * @return true iff the transport supports hostname verification */ virtual bool setVerifyHost(bool verify)=0; - + #ifndef XMLTOOLING_NO_XMLSEC /** * Supplies transport credentials. * *

The lifetime of the credential must be longer than the lifetime of this object. - * + * * @param credential a Credential instance, or NULL * @return true iff the transport supports the use of the Credential */ @@ -139,7 +139,7 @@ namespace xmltooling { /** * Provides an X509TrustEngine to the transport to authenticate the transport peer. * The lifetime of the engine must be longer than the lifetime of this object. - * + * * @param trustEngine an X509TrustEngine instance, or NULL * @param credResolver a CredentialResolver to supply the peer's trusted credentials, or NULL * @param criteria optional criteria for selecting peer credentials @@ -157,10 +157,10 @@ namespace xmltooling { /** * Sets an implementation-specific transport provider option. - * + * *

Requires knowledge of the underlying SOAPTransport implementation. * Without the proper knowledge and inputs, crashes may result. - * + * * @param provider name of the SOAPTransport class the caller believes is in use * @param option implementation-specific string containing the option to set * @param value implementation- and option-specific string to use @@ -169,33 +169,36 @@ namespace xmltooling { virtual bool setProviderOption(const char* provider, const char* option, const char* value) { return false; } - + /** * Sends a stream of data over the transport. The function may return without * having received any data, depending on the nature of the transport. - * + * + *

If the stream is empty, a request may be issued with no body if the transport + * supports that feature. + * * @param in input stream to send - */ + */ virtual void send(std::istream& in)=0; - + /** * Returns reference to response stream. The resulting stream must be * checked directly to determine whether data is available. - * + * * @return reference to a stream containing the response, if any */ virtual std::istream& receive()=0; - + /** * Returns result of authenticating transport peer. - * + * * @return true iff TrustEngine or other mechanism successfully authenticated the peer */ virtual bool isAuthenticated() const=0; /** * Returns the MIME type of the response, if any. - * + * * @return MIME type of response, or an empty string */ virtual std::string getContentType() const=0; @@ -206,14 +209,14 @@ namespace xmltooling { * Registers SOAPTransport classes into the runtime. */ void XMLTOOL_API registerSOAPTransports(); - + /** - * Notifies transport infrastructure to initialize. + * Notifies transport infrastructure to initialize. */ void XMLTOOL_API initSOAPTransports(); - + /** - * Notifies transport infrastructure to shutdown. + * Notifies transport infrastructure to shutdown. */ void XMLTOOL_API termSOAPTransports(); #endif diff --git a/xmltooling/soap/impl/CURLSOAPTransport.cpp b/xmltooling/soap/impl/CURLSOAPTransport.cpp index 811bde5..4b278e3 100644 --- a/xmltooling/soap/impl/CURLSOAPTransport.cpp +++ b/xmltooling/soap/impl/CURLSOAPTransport.cpp @@ -1,6 +1,6 @@ /* * Copyright 2001-2007 Internet2 - * + * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -16,7 +16,7 @@ /** * CURLSOAPTransport.cpp - * + * * libcurl-based SOAPTransport implementation */ @@ -48,11 +48,11 @@ namespace xmltooling { CURLPool() : m_size(0), m_lock(Mutex::create()), m_log(Category::getInstance(XMLTOOLING_LOGCAT".SOAPTransport.CURL")) {} ~CURLPool(); - + CURL* get(const SOAPTransport::Address& addr); void put(const char* from, const char* to, const char* endpoint, CURL* handle); - - private: + + private: typedef map > poolmap_t; poolmap_t m_bindingMap; list< vector* > m_pools; @@ -60,9 +60,9 @@ namespace xmltooling { Mutex* m_lock; Category& m_log; }; - + static XMLTOOL_DLLLOCAL CURLPool* g_CURLPool = NULL; - + class XMLTOOL_DLLLOCAL CURLSOAPTransport : public HTTPSOAPTransport, public OpenSSLSOAPTransport { public: @@ -83,7 +83,7 @@ namespace xmltooling { curl_easy_setopt(m_handle,CURLOPT_HEADERDATA,this); m_headers=curl_slist_append(m_headers,"Content-Type: text/xml"); } - + virtual ~CURLSOAPTransport() { curl_slist_free_all(m_headers); curl_easy_setopt(m_handle,CURLOPT_ERRORBUFFER,NULL); @@ -98,17 +98,17 @@ namespace xmltooling { bool setConnectTimeout(long timeout) { return (curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,timeout)==CURLE_OK); } - + bool setTimeout(long timeout) { return (curl_easy_setopt(m_handle,CURLOPT_TIMEOUT,timeout)==CURLE_OK); } - + bool setAuth(transport_auth_t authType, const char* username=NULL, const char* password=NULL); - + bool setVerifyHost(bool verify) { return (curl_easy_setopt(m_handle,CURLOPT_SSL_VERIFYHOST,verify ? 2 : 0)==CURLE_OK); } - + #ifndef XMLTOOLING_NO_XMLSEC bool setCredential(const Credential* cred=NULL) { const OpenSSLCredential* down = dynamic_cast(cred); @@ -119,7 +119,7 @@ namespace xmltooling { m_cred = down; return true; } - + bool setTrustEngine( const X509TrustEngine* trustEngine=NULL, const CredentialResolver* peerResolver=NULL, @@ -139,9 +139,9 @@ namespace xmltooling { m_mandatory = mandatory; return true; } - + #endif - + bool useChunkedEncoding(bool chunked=true) { m_chunked = chunked; return true; @@ -165,13 +165,13 @@ namespace xmltooling { return (curl_easy_setopt(m_handle, opt, value) == CURLE_OK); #endif } - + void send(istream& in); - + istream& receive() { return m_stream; } - + bool isAuthenticated() const { return m_authenticated; } @@ -181,23 +181,23 @@ namespace xmltooling { } string getContentType() const; - + bool setRequestHeader(const char* name, const char* val) { string temp(name); temp=temp + ": " + val; m_headers=curl_slist_append(m_headers,temp.c_str()); return true; } - + const vector& getResponseHeader(const char* val) const; - + bool setSSLCallback(ssl_ctx_callback_fn fn, void* userptr=NULL) { m_ssl_callback=fn; m_ssl_userptr=userptr; return true; } - private: + private: // per-call state string m_sender,m_peerName,m_endpoint,m_simplecreds; CURL* m_handle; @@ -215,7 +215,7 @@ namespace xmltooling { void* m_ssl_userptr; bool m_chunked; bool m_authenticated; - + friend size_t XMLTOOL_DLLLOCAL curl_header_hook(void* ptr, size_t size, size_t nmemb, void* stream); friend CURLcode XMLTOOL_DLLLOCAL xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* userptr); friend int XMLTOOL_DLLLOCAL verify_callback(X509_STORE_CTX* x509_ctx, void* arg); @@ -277,12 +277,12 @@ CURL* CURLPool::get(const SOAPTransport::Address& addr) key = key + '|' + addr.m_to; m_lock->lock(); poolmap_t::iterator i=m_bindingMap.find(key); - + if (i!=m_bindingMap.end()) { // Move this pool to the front of the list. m_pools.remove(&(i->second)); m_pools.push_front(&(i->second)); - + // If a free connection exists, return it. if (!(i->second.empty())) { CURL* handle=i->second.back(); @@ -293,10 +293,10 @@ CURL* CURLPool::get(const SOAPTransport::Address& addr) return handle; } } - + m_lock->unlock(); m_log.debug("nothing free in pool, returning new connection handle"); - + // Create a new connection and set non-varying options. CURL* handle=curl_easy_init(); if (!handle) @@ -328,7 +328,7 @@ void CURLPool::put(const char* from, const char* to, const char* endpoint, CURL* m_pools.push_front(&(m_bindingMap.insert(poolmap_t::value_type(key,vector(1,handle))).first->second)); else i->second.push_back(handle); - + CURL* killit=NULL; if (++m_size > 256) { // Kick a handle out from the back of the bus. @@ -340,7 +340,7 @@ void CURLPool::put(const char* from, const char* to, const char* endpoint, CURL* m_size--; break; } - + // Move an empty pool up to the front so we don't keep hitting it. m_pools.pop_back(); m_pools.push_front(corpse); @@ -384,7 +384,7 @@ const vector& CURLSOAPTransport::getResponseHeader(const char* name) con map >::const_iterator i=m_response_headers.find(name); if (i!=m_response_headers.end()) return i->second; - + for (map >::const_iterator j=m_response_headers.begin(); j!=m_response_headers.end(); j++) { #ifdef HAVE_STRCASECMP if (!strcasecmp(j->first.c_str(), name)) @@ -393,7 +393,7 @@ const vector& CURLSOAPTransport::getResponseHeader(const char* name) con #endif return j->second; } - + return emptyVector; } @@ -420,22 +420,26 @@ void CURLSOAPTransport::send(istream& in) // Setup standard per-call curl properties. curl_easy_setopt(m_handle,CURLOPT_DEBUGDATA,&log_curl); curl_easy_setopt(m_handle,CURLOPT_FILE,&m_stream); - curl_easy_setopt(m_handle,CURLOPT_POST,1); - if (m_chunked) { + if (m_chunked && in) { + curl_easy_setopt(m_handle,CURLOPT_POST,1); m_headers=curl_slist_append(m_headers,"Transfer-Encoding: chunked"); curl_easy_setopt(m_handle,CURLOPT_READFUNCTION,&curl_read_hook); curl_easy_setopt(m_handle,CURLOPT_READDATA,&in); } - else { + else if (in) { char buf[1024]; while (in) { in.read(buf,1024); msg.append(buf,in.gcount()); } + curl_easy_setopt(m_handle,CURLOPT_POST,1); curl_easy_setopt(m_handle,CURLOPT_READFUNCTION,NULL); curl_easy_setopt(m_handle,CURLOPT_POSTFIELDS,msg.c_str()); curl_easy_setopt(m_handle,CURLOPT_POSTFIELDSIZE,msg.length()); } + else { + curl_easy_setopt(m_handle,CURLOPT_HTTPGET,1); + } char curl_errorbuf[CURL_ERROR_SIZE]; curl_errorbuf[0]=0; @@ -465,7 +469,7 @@ void CURLSOAPTransport::send(istream& in) curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_FUNCTION,NULL); curl_easy_setopt(m_handle,CURLOPT_SSL_CTX_DATA,NULL); } - + // Make the call. log.debug("sending SOAP message to %s", m_endpoint.c_str()); if (curl_easy_perform(m_handle) != CURLE_OK) { @@ -562,14 +566,14 @@ int xmltooling::verify_callback(X509_STORE_CTX* x509_ctx, void* arg) cc.setUsage(Credential::TLS_CREDENTIAL); success = ctx->m_trustEngine->validate(x509_ctx->cert,x509_ctx->untrusted,*(ctx->m_peerResolver),&cc); } - + if (!success) { log.error("supplied TrustEngine failed to validate SSL/TLS server certificate"); x509_ctx->error=X509_V_ERR_APPLICATION_VERIFICATION; // generic error, check log for plugin specifics ctx->setAuthenticated(false); return ctx->m_mandatory ? 0 : 1; } - + // Signal success. Hopefully it doesn't matter what's actually in the structure now. ctx->setAuthenticated(true); return 1; @@ -599,9 +603,9 @@ CURLcode xmltooling::xml_ssl_ctx_callback(CURL* curl, SSL_CTX* ssl_ctx, void* us #endif } #endif - + if (conf->m_ssl_callback && !conf->m_ssl_callback(conf, ssl_ctx, conf->m_ssl_userptr)) return CURLE_SSL_CERTPROBLEM; - + return CURLE_OK; }