From 5370afc58bb3493afb31edc2a9013c24eb8b89f4 Mon Sep 17 00:00:00 2001 From: Scott Cantor Date: Fri, 8 Jan 2010 00:50:38 +0000 Subject: [PATCH] Add cache handling to SOAP transport layer. --- xmltooling/soap/SOAPTransport.h | 18 +++++++++++++++++ xmltooling/soap/impl/CURLSOAPTransport.cpp | 31 +++++++++++++++++++++++++++++- xmltooling/soap/impl/SOAPClient.cpp | 24 ++++++++++++++++------- 3 files changed, 65 insertions(+), 8 deletions(-) diff --git a/xmltooling/soap/SOAPTransport.h b/xmltooling/soap/SOAPTransport.h index 3a5c345..cf5cb41 100644 --- a/xmltooling/soap/SOAPTransport.h +++ b/xmltooling/soap/SOAPTransport.h @@ -24,6 +24,8 @@ #define __xmltooling_soaptrans_h__ #include + +#include #include namespace xmltooling { @@ -156,6 +158,15 @@ namespace xmltooling { #endif /** + * Installs (or clears) a pointer to an object used for cache management of the + * content being accessed. The lifetime of the object must be longer than the lifetime + * of this object. + * + * @param cacheTag optional pointer to string used for cache management + */ + virtual bool setCacheTag(std::string* cacheTag=NULL); + + /** * Sets an implementation-specific transport provider option. * *

Requires knowledge of the underlying SOAPTransport implementation. @@ -211,6 +222,13 @@ namespace xmltooling { * @return MIME type of response, or an empty string */ virtual std::string getContentType() const=0; + + /** + * Returns the status code of the response. + * + * @return transport status code, or 0 if unknown + */ + virtual long getStatusCode() const; }; #ifndef XMLTOOLING_NO_XMLSEC diff --git a/xmltooling/soap/impl/CURLSOAPTransport.cpp b/xmltooling/soap/impl/CURLSOAPTransport.cpp index af06fbb..e7a1b1e 100644 --- a/xmltooling/soap/impl/CURLSOAPTransport.cpp +++ b/xmltooling/soap/impl/CURLSOAPTransport.cpp @@ -72,7 +72,7 @@ namespace xmltooling { #ifndef XMLTOOLING_NO_XMLSEC m_cred(NULL), m_trustEngine(NULL), m_peerResolver(NULL), m_mandatory(false), #endif - m_ssl_callback(NULL), m_ssl_userptr(NULL), m_chunked(true), m_authenticated(false) { + m_ssl_callback(NULL), m_ssl_userptr(NULL), m_chunked(true), m_authenticated(false), m_cacheTag(NULL) { m_handle = g_CURLPool->get(addr); curl_easy_setopt(m_handle,CURLOPT_URL,addr.m_endpoint); curl_easy_setopt(m_handle,CURLOPT_CONNECTTIMEOUT,15); @@ -147,6 +147,11 @@ namespace xmltooling { return true; } + bool setCacheTag(string* cacheTag) { + m_cacheTag = cacheTag; + return true; + } + bool setProviderOption(const char* provider, const char* option, const char* value) { if (!provider || strcmp(provider, "CURL")) return false; @@ -196,6 +201,7 @@ namespace xmltooling { } string getContentType() const; + long getStatusCode() const; bool setRequestHeader(const char* name, const char* val) { string temp(name); @@ -231,6 +237,7 @@ namespace xmltooling { void* m_ssl_userptr; bool m_chunked; bool m_authenticated; + string* m_cacheTag; 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); @@ -428,6 +435,14 @@ string CURLSOAPTransport::getContentType() const return content_type ? content_type : ""; } +long CURLSOAPTransport::getStatusCode() const +{ + long code=200; + if (curl_easy_getinfo(m_handle, CURLINFO_RESPONSE_CODE, &code) != CURLE_OK) + code = 200; + return code; +} + void CURLSOAPTransport::send(istream* in) { #ifdef _DEBUG @@ -475,6 +490,13 @@ void CURLSOAPTransport::send(istream* in) if (log_curl.isDebugEnabled()) curl_easy_setopt(m_handle,CURLOPT_VERBOSE,1); + // Check for cache tag. + if (m_cacheTag && !m_cacheTag->empty()) { + string hdr("If-None-Match: "); + hdr += *m_cacheTag; + m_headers = curl_slist_append(m_headers, hdr.c_str()); + } + // Set request headers. curl_easy_setopt(m_handle,CURLOPT_HTTPHEADER,m_headers); @@ -505,6 +527,13 @@ void CURLSOAPTransport::send(istream* in) string("CURLSOAPTransport failed while contacting SOAP endpoint (") + m_endpoint + "): " + (curl_errorbuf[0] ? curl_errorbuf : "no further information available")); } + + // Check for outgoing cache tag. + if (m_cacheTag) { + const vector& tags = getResponseHeader("ETag"); + if (!tags.empty()) + *m_cacheTag = tags.front(); + } } // callback to buffer headers from server diff --git a/xmltooling/soap/impl/SOAPClient.cpp b/xmltooling/soap/impl/SOAPClient.cpp index 1978e28..a3898a5 100644 --- a/xmltooling/soap/impl/SOAPClient.cpp +++ b/xmltooling/soap/impl/SOAPClient.cpp @@ -50,6 +50,23 @@ bool SOAPTransport::setProviderOption(const char* provider, const char* option, return false; } +bool SOAPTransport::setCacheTag(string* cacheTag) +{ + return false; +} + +void SOAPTransport::send(istream* in) +{ + if (!in) + throw IOException("SOAP transport does not support an empty request body."); + return send(*in); +} + +long SOAPTransport::getStatusCode() const +{ + return 0; +} + HTTPSOAPTransport::HTTPSOAPTransport() { } @@ -78,13 +95,6 @@ void SOAPClient::reset() m_transport=NULL; } -void SOAPTransport::send(istream* in) -{ - if (!in) - throw IOException("SOAP transport does not support an empty request body."); - return send(*in); -} - void SOAPClient::send(const Envelope& env, const SOAPTransport::Address& addr) { // Prepare a transport object. -- 2.1.4