From bb9bc9051629c3319c56785c2f4ae0e605d76329 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Frings-F=C3=BCrst?= Date: Sat, 21 Nov 2015 14:51:17 +0100 Subject: Initial import of bitz-server version 0.1.6-1 --- lib/icap/Makefile.am | 24 ++ lib/icap/common.h | 41 +++ lib/icap/header.cpp | 223 ++++++++++++++ lib/icap/header.h | 168 +++++++++++ lib/icap/request.cpp | 84 ++++++ lib/icap/request.h | 72 +++++ lib/icap/request_header.cpp | 113 +++++++ lib/icap/request_header.h | 84 ++++++ lib/icap/response.cpp | 81 +++++ lib/icap/response.h | 65 ++++ lib/icap/response_header.cpp | 101 +++++++ lib/icap/response_header.h | 78 +++++ lib/icap/util.cpp | 693 +++++++++++++++++++++++++++++++++++++++++++ lib/icap/util.h | 265 +++++++++++++++++ 14 files changed, 2092 insertions(+) create mode 100644 lib/icap/Makefile.am create mode 100644 lib/icap/common.h create mode 100644 lib/icap/header.cpp create mode 100644 lib/icap/header.h create mode 100644 lib/icap/request.cpp create mode 100644 lib/icap/request.h create mode 100644 lib/icap/request_header.cpp create mode 100644 lib/icap/request_header.h create mode 100644 lib/icap/response.cpp create mode 100644 lib/icap/response.h create mode 100644 lib/icap/response_header.cpp create mode 100644 lib/icap/response_header.h create mode 100644 lib/icap/util.cpp create mode 100644 lib/icap/util.h (limited to 'lib/icap') diff --git a/lib/icap/Makefile.am b/lib/icap/Makefile.am new file mode 100644 index 0000000..02d8bb4 --- /dev/null +++ b/lib/icap/Makefile.am @@ -0,0 +1,24 @@ +## [icap-library] lib/icap/ +AM_CPPFLAGS = -I$(top_srcdir)/lib +libicapincludedir = $(includedir)/icap + +lib_LTLIBRARIES = libicap.la +libicap_la_LIBADD = $(top_builddir)/lib/socket/libsocket.la +libicap_la_LDFLAGS = -version-info @ICAP_LT_VERSION@ -no-undefined +libicap_la_SOURCES = \ + header.cpp \ + request_header.cpp \ + response_header.cpp \ + request.cpp \ + response.cpp \ + util.cpp + +libicapinclude_HEADERS = \ + common.h \ + header.h \ + request_header.h \ + response_header.h \ + request.h \ + response.h \ + util.h + diff --git a/lib/icap/common.h b/lib/icap/common.h new file mode 100644 index 0000000..65c3694 --- /dev/null +++ b/lib/icap/common.h @@ -0,0 +1,41 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_COMMON_H +#define ICAP_COMMON_H + +#include + + +namespace icap { + + /** + * Payload structure common to both requests and responses. + */ + struct payload_t { + std::string req_header; /**< request header */ + std::string req_body; /**< request body */ + std::string res_header; /**< response header */ + std::string res_body; /**< response body */ + bool ieof; /**< boolen flag to store the presence of "ieof" */ + }; + +} /* end of namespace icap */ + +#endif /* !ICAP_COMMON_H */ diff --git a/lib/icap/header.cpp b/lib/icap/header.cpp new file mode 100644 index 0000000..493e659 --- /dev/null +++ b/lib/icap/header.cpp @@ -0,0 +1,223 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "header.h" +#include "util.h" + +#include +#include + + +namespace icap { + + Header::Header() { + + // initialise defaults + _encapsulated["req-hdr"] = -1; + _encapsulated["req-body"] = -1; + _encapsulated["res-hdr"] = -1; + _encapsulated["res-body"] = -1; + _encapsulated["opt-body"] = -1; + _encapsulated["null-body"] = -1; + + } + + Header::~Header() {} + + + const Header::headers_t &Header::headers() const throw() { + return _headers; + } + + + const std::string Header::value( const std::string &key ) throw() { + + std::string value = ""; + Header::headers_index_t idx = _headers.find( key ); + + if ( idx != _headers.end() ) { + value = idx->second; + } + + return value; + + } + + + const int Header::encapsulated_header( const std::string &entity ) throw() { + + Header::encapsulated_header_index_t idx; + + idx = _encapsulated.find( entity ); + if ( idx == _encapsulated.end() ) { + return -1; + } + + return idx->second; + + } + + + void Header::attach( std::string key, std::string value ) throw() { + + // trim + key = util::trim( key ); + value = util::trim( value ); + + // check for 'Encapsulated' headers + if ( key == "Encapsulated" ) { + attach_encapsulated( value ); + } else { + _headers[key] = value; + } + + } + + + bool Header::attach_encapsulated( std::string header_value ) throw() { + + std::vector list_data; + std::vector entity_data; + + encapsulated_header_index_t idx; + bool r_status = true; + + // grab the entity list [ req-hdr=0, null-body=170 ] + list_data = util::split( util::trim( header_value ), "," ); + + for ( size_t i = 0; i < list_data.size(); i++ ) { + + // get entity data [ req-hdr=0 ] + entity_data = util::split( util::trim( list_data.at( i ) ), "=" ); + + if ( entity_data.size() == 2 ) { + + idx = _encapsulated.find( util::trim( entity_data.at( 0 ) ) ); + if ( idx != _encapsulated.end() ) { + idx->second = atoi( util::trim( entity_data.at( 1 ) ).c_str() ); + } + + } else { + r_status = false; + } + } + + return r_status; + + } + + + bool Header::remove( std::string key ) throw() { + return ( (bool) _headers.erase( util::trim( key ) ) ); + } + + + const std::string Header::encapsulated_header_str() throw() { + + /* + * Encapsulated request header grammer: + * REQMOD request encapsulated_list: [reqhdr] reqbody + * REQMOD response encapsulated_list: {[reqhdr] reqbody} | + * {[reshdr] resbody} + * RESPMOD request encapsulated_list: [reqhdr] [reshdr] resbody + * RESPMOD response encapsulated_list: [reshdr] resbody + * OPTIONS response encapsulated_list: optbody + */ + + Header::encapsulated_header_index_t idx; + std::string encaps_header = ""; + + // FIXME: chances are that we will always get the correct order + // but should consider sorting + for ( idx = _encapsulated.begin(); idx != _encapsulated.end(); idx++ ) { + + if ( idx->second > 0 ) { + + if ( encaps_header != "" ) { + encaps_header.append( ", " ); + } + + encaps_header.append( idx->first ).append( "=" ).append( util::itoa( idx->second ) ); + + } + + } + + // sanity check + if ( encaps_header == "" ) { + encaps_header = "null-body=0"; + } + + return encaps_header; + + } + + + void Header::update_encapsulated( const payload_t &payload ) throw() { + + unsigned int data_length = 0; + unsigned int data_offset = 0; + + // request header + if ( payload.req_header.size() > 0 ) { + _encapsulated["req-hdr"] = data_length; + data_offset = data_length; + data_length += payload.req_header.size(); + } + + // request body (POST data) + if ( payload.req_body.size() > 0 ) { + _encapsulated["req-body"] = data_length; + data_offset = data_length; + data_length += payload.req_body.size(); + } + + // response header + if ( payload.res_header.size() > 0 ) { + _encapsulated["res-hdr"] = data_length; + data_offset = data_length; + data_length += payload.res_header.size(); + } + + // response body + if ( payload.res_body.size() > 0 ) { + _encapsulated["res-body"] = data_length; + data_offset = data_length; + data_length += payload.res_body.size(); + } + + // null-body + if ( data_offset == 0 ) { + _encapsulated["null-body"] = data_length; + } + + } + + + std::vector Header::sort_encapsulated_header() { + + std::vector data( _encapsulated.begin(), _encapsulated.end() ); + std::sort(data.begin(), data.end(), encapsulated_header_compare()); + + return data; + + } + +} + diff --git a/lib/icap/header.h b/lib/icap/header.h new file mode 100644 index 0000000..52a8fef --- /dev/null +++ b/lib/icap/header.h @@ -0,0 +1,168 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_HEADER_H +#define ICAP_HEADER_H + +#include "common.h" + +#include +#include +#include +#include + + +namespace icap { + + class Header { + public: + + /* headers data type */ + typedef std::map headers_t; + + /* headers iterator type */ + typedef headers_t::iterator headers_index_t; + + /* encapsulated header type */ + typedef std::map encapsulated_header_t; + + /* encapsulated header iterator type */ + typedef encapsulated_header_t::iterator encapsulated_header_index_t; + + /* encapsulated header data type */ + typedef std::pair encapsulated_header_data_t; + + /** + * Binary compare structure to compare two encapsulated header + * entity (data) values. Used for sorting. + */ + struct encapsulated_header_compare + : std::binary_function { + inline bool operator()( const icap::Header::encapsulated_header_data_t &lhs, const icap::Header::encapsulated_header_data_t &rhs ) { + return lhs.second < rhs.second; + } + }; + + + Header(); + virtual ~Header(); + + /** + * Return headers + * @return headers + */ + const headers_t &headers() const throw(); + + /** + * Returns the header value for the given header key or an empty string + * if the header is not found. + * + * @param key header key + * @return header value + */ + const std::string value( const std::string &key ) throw(); + + /** + * Return Encapsulated header value for the given entity + * or -1 if the given entity is invalid. + * + * @param entity encapsulated header entity + * @return -1 | encapsulated header value + */ + const int encapsulated_header( const std::string &entity ) throw(); + + /** + * Attach header data into the header + * + *
+		*   e.g.
+		*   Host: icap-server.net
+		*   Encapsulated: req-hdr=0, null-body=170
+		*   [key]: [value]
+		*   
+ * + * @param key header key + * @param value header value + */ + virtual void attach( std::string key, std::string value ) throw(); + + /** + * Attach Encapsulated header data. This method should only be used + * when reading a raw request / response. Consider using update_encapsulated() + * method for other scenarios. + * + *
+		*   e.g.
+		*   Encapsulated: req-hdr=0, req-body=412
+		*   Encapsulated: req-hdr=0, res-hdr=822, res-body=1655
+		*   Encapsulated: [header_value]
+		*   
+ * + * @param header_value Encapsulated header value + * @return boolean to denote success or failure + */ + virtual bool attach_encapsulated( std::string header_value ) throw(); + + + /** + * Update Encapsulated header data using the passed in (icap::payload_t) payload. + * When the request / response has been populated with the payload, calling this + * method will update the encapsulated header entities with appropriate values. + * + * This methos will always succeed. + * + * @param payload request or response payload + */ + virtual void update_encapsulated( const payload_t &payload ) throw(); + + /** + * Remove header data from the header instance with the given key + * + * @param key header key + * @return boolean to denote success or failure + */ + virtual bool remove( std::string key ) throw(); + + /** + * Return Encapsulated header as a std::string value. + * @return encapsulated header value (e.g. res-hdr=0, res-body=213) + */ + virtual const std::string encapsulated_header_str() throw(); + + /** + * Sort the encapsulated header data and return a std::vector of + * encapsulated_header_data_t. The actual header data won't be changed. + * + * @return sorted encapsulated header + */ + virtual std::vector sort_encapsulated_header(); + + + protected: + headers_t _headers; + encapsulated_header_t _encapsulated; + + private: + + }; + +} /* end of namespace icap */ + +#endif /* !ICAP_HEADER_H */ + diff --git a/lib/icap/request.cpp b/lib/icap/request.cpp new file mode 100644 index 0000000..bf80e13 --- /dev/null +++ b/lib/icap/request.cpp @@ -0,0 +1,84 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "request.h" + +#include + + +namespace icap { + + Request::Request( RequestHeader * req_header ) { + + _header = req_header; + + // initialise defaults + _payload.req_header = ""; + _payload.req_body = ""; + _payload.res_header = ""; + _payload.res_body = ""; + _payload.ieof = false; + + } + + + Request::~Request() { } + + + RequestHeader * const Request::header() const throw() { + return _header; + } + + + void Request::payload( payload_t payload ) throw() { + + _payload = payload; + + // update encapsulated data + _header->update_encapsulated( _payload ); + + } + + + const payload_t &Request::payload() const throw() { + return _payload; + } + + + const int Request::preview_size() throw() { + + int size = -1; + + // grab the size from request header + std::string s_size = _header->value( "Preview" ); + + // sanity check + if (! s_size.empty() ) { + + // convert string to integer + size = atoi( s_size.c_str() ); + + } + + return size; + + } + +} /* end of namespace icap */ + diff --git a/lib/icap/request.h b/lib/icap/request.h new file mode 100644 index 0000000..d5c4f69 --- /dev/null +++ b/lib/icap/request.h @@ -0,0 +1,72 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_REQUEST_H +#define ICAP_REQUEST_H + +#include "common.h" +#include "request_header.h" + + +namespace icap { + + class Request { + public: + Request( RequestHeader * req_header ); + virtual ~Request(); + + /** + * Return the request header + * @return request header + */ + RequestHeader * const header() const throw(); + + /** + * Set the payload data for this response instance from a + * icap::payload_t data structure + * + * @param payload payload data structure + */ + void payload( payload_t payload ) throw(); + + /** + * Return the payload data for this response instance + * @return payload data + */ + const payload_t &payload() const throw(); + + /** + * Returns the number of preview bytes in the request. If the preview + * header is not present in the request then a minus (-1) value will be + * returned. + * + * @return preview bytes + */ + const int preview_size() throw(); + + private: + RequestHeader * _header; + payload_t _payload; + + }; + +} /* end of namespace icap */ + +#endif /* !ICAP_REQUEST_H */ + diff --git a/lib/icap/request_header.cpp b/lib/icap/request_header.cpp new file mode 100644 index 0000000..a9b42dc --- /dev/null +++ b/lib/icap/request_header.cpp @@ -0,0 +1,113 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "request_header.h" +#include "util.h" + + +namespace icap { + + /* + * sample icap request header: + * REQMOD icap://icap-server.net/server?arg=87 ICAP/1.0 + * Host: icap-server.net + * Encapsulated: req-hdr=0, null-body=170 + * + * [payload] + */ + RequestHeader::RequestHeader( const std::string &raw_data ) : Header() { + + // initialise defaults + _request.method = ""; + _request.uri = ""; + _request.protocol = "ICAP/1.0"; + + // read header + read_header( raw_data ); + + } + + + RequestHeader::~RequestHeader() { } + + + const std::string &RequestHeader::method() const throw() { + return _request.method; + } + + + const std::string &RequestHeader::uri() const throw() { + return _request.uri; + } + + + const std::string &RequestHeader::protocol() const throw() { + return _request.protocol; + } + + + const RequestHeader::request_t &RequestHeader::request() const throw() { + return _request; + } + + + const std::string &RequestHeader::raw_data() const throw() { + return _raw_data; + } + + + void RequestHeader::read_header( const std::string &raw_data ) throw() { + + std::vector data; + + _raw_data = raw_data; + data = util::split( raw_data, "\r\n" ); + + if ( data.size() > 0 ) { + + std::vector header_data; + std::vector request; + + std::string request_data = data.at( 0 ); + request = util::split( util::trim( request_data ) ); + + if ( request.size() == 3 ) { + _request.method = request.at(0); + _request.uri = request.at(1); + _request.protocol = request.at(2); + } else { + // TODO: error, invalid request format + } + + for ( int i = 1; i < data.size(); i++ ) { + header_data = util::split( data.at( i ), ":" ); + + if ( header_data.size() == 2 ) { + this->attach( header_data.at( 0 ), header_data.at( 1 ) ); + } else { + // TODO: error parsing header data + } + } + + } + + } + +} /* end of namespace icap */ + diff --git a/lib/icap/request_header.h b/lib/icap/request_header.h new file mode 100644 index 0000000..47978c1 --- /dev/null +++ b/lib/icap/request_header.h @@ -0,0 +1,84 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_REQUEST_HEADER_H +#define ICAP_REQUEST_HEADER_H + +#include "header.h" + +#include +#include + + +namespace icap { + + class RequestHeader : public Header { + public: + + struct request_t { + std::string method; + std::string uri; + std::string protocol; + }; + + RequestHeader( const std::string &raw_data ); + virtual ~RequestHeader(); + + /** + * Return request method + * @return method + */ + const std::string &method() const throw(); + + /** + * Return request URI + * @return URI + */ + const std::string &uri() const throw(); + + /** + * Return request protocol + * @return protocol + */ + const std::string &protocol() const throw(); + + /** + * Return request + * @return request + */ + const request_t &request() const throw(); + + /** + * Return raw header data + * @return raw request header + */ + const std::string &raw_data() const throw(); + + private: + request_t _request; + std::string _raw_data; + + void read_header( const std::string &raw_data ) throw(); + + }; + +} /* end of namespace icap */ + +#endif /* !ICAP_REQUEST_HEADER_H */ + diff --git a/lib/icap/response.cpp b/lib/icap/response.cpp new file mode 100644 index 0000000..6bd730f --- /dev/null +++ b/lib/icap/response.cpp @@ -0,0 +1,81 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "response.h" + + +namespace icap { + + Response::Response( ResponseHeader * header ) { + + if ( header != NULL ) { + _header = header; + _cleanup_header = false; + } else { + _header = new ResponseHeader( ResponseHeader::SERVER_ERROR ); + _cleanup_header = true; + } + + // initialise defaults + _payload.req_header = ""; + _payload.req_body = ""; + _payload.res_header = ""; + _payload.res_body = ""; + _payload.ieof = false; + + } + + + Response::Response( ResponseHeader::status_t status ) { + _header = new ResponseHeader( status ); + _cleanup_header = true; + } + + + Response::~Response() { + + // cleanup + if ( _cleanup_header ) { + delete _header; + } + + } + + + ResponseHeader * const Response::header() const throw() { + return _header; + } + + + void Response::payload( payload_t payload ) throw() { + + _payload = payload; + + // update encapsulated data + _header->update_encapsulated( _payload ); + + } + + + const payload_t &Response::payload() const throw() { + return _payload; + } + +} /* end of namespace icap */ + diff --git a/lib/icap/response.h b/lib/icap/response.h new file mode 100644 index 0000000..2977c07 --- /dev/null +++ b/lib/icap/response.h @@ -0,0 +1,65 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_RESPONSE_H +#define ICAP_RESPONSE_H + +#include "common.h" +#include "response_header.h" + + +namespace icap { + + class Response { + public: + Response( ResponseHeader * response_header = NULL ); + Response( ResponseHeader::status_t status ); + virtual ~Response(); + + /** + * Return the response header + * @return response header + */ + ResponseHeader * const header() const throw(); + + /** + * Set the payload data for this response instance from a + * icap::payload_t data structure + * + * @param payload payload data structure + */ + void payload( payload_t payload ) throw(); + + /** + * Return the payload data for this response instance + * @return payload data + */ + const payload_t &payload() const throw(); + + private: + ResponseHeader * _header; + payload_t _payload; + bool _cleanup_header; + + }; + +} /* end of namespace icap */ + +#endif /* !ICAP_RESPONSE_H */ + diff --git a/lib/icap/response_header.cpp b/lib/icap/response_header.cpp new file mode 100644 index 0000000..aa29e63 --- /dev/null +++ b/lib/icap/response_header.cpp @@ -0,0 +1,101 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "response_header.h" +#include "util.h" +#include + +#include +#include + + +namespace icap { + + ResponseHeader::ResponseHeader( status_t status ) : Header() { + + // FIXME: protocol shouldn't be hard-coded + _response.protocol = "ICAP/1.0"; + _response.status = status; + + // initialise default headers + init_defaults(); + + } + + ResponseHeader::~ResponseHeader() { } + + + const std::string &ResponseHeader::protocol() const throw() { + return _response.protocol; + } + + + const ResponseHeader::status_t &ResponseHeader::status() const throw() { + return _response.status; + } + + + void ResponseHeader::init_defaults() throw() { + + update_timestamp(); + generate_istag(); + attach( "Server", PACKAGE_STRING ); + + // close connection header + if ( _response.status != ResponseHeader::CONTINUE ) { + attach( "Connection" , "close" ); + } + + } + + + void ResponseHeader::update_timestamp() throw() { + + time_t raw_time; + struct tm * time_info; + char buffer [80]; + + time( &raw_time ); + time_info = localtime( &raw_time ); + + strftime ( buffer, 80, "%c %Z", time_info ); + attach( "Date", buffer ); + + } + + + void ResponseHeader::generate_istag() throw() { + + time_t raw_time; + clock_t clock_time; + std::string istag; + + time( &raw_time ); + clock_time = clock(); + + istag = "BITZ-"; + istag.append( util::itoa( raw_time ) ).append( "-" ); + istag.append( util::itoa( clock_time) ); + + attach( "ISTag", istag.substr( 0, 32 ) ); + + } + +} /* end of namespace icap */ + diff --git a/lib/icap/response_header.h b/lib/icap/response_header.h new file mode 100644 index 0000000..48d9ddd --- /dev/null +++ b/lib/icap/response_header.h @@ -0,0 +1,78 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_RESPONSE_HEADER_H +#define ICAP_RESPONSE_HEADER_H + +#include "header.h" + + +namespace icap { + + class ResponseHeader : public Header { + public: + + enum status_t { + CONTINUE = 100, + OK = 200, + NO_CONTENT = 204, + BAD_REQUEST = 400, + NOT_FOUND = 404, + NOT_ALLOWED = 405, + REQ_TIMEOUT = 408, + SERVER_ERROR = 500, + NOT_IMPLEMENTED = 501, + BAD_GATEWAY = 502, + SERVICE_OVERLOADED = 503, + NOT_SUPPORTED = 505 + }; + + struct response_t { + std::string protocol; + status_t status; + }; + + ResponseHeader( status_t status ); + virtual ~ResponseHeader(); + + /** + * Return the response protocol + * @return protocol + */ + const std::string &protocol() const throw(); + + /** + * Return the response status + * @return status + */ + const status_t &status() const throw(); + + private: + response_t _response; + + void update_timestamp() throw(); + void generate_istag() throw(); + void init_defaults() throw(); + + }; + +} /* end of namespace icap */ + +#endif /* !ICAP_RESPONSE_HEADER_H */ + diff --git a/lib/icap/util.cpp b/lib/icap/util.cpp new file mode 100644 index 0000000..c383261 --- /dev/null +++ b/lib/icap/util.cpp @@ -0,0 +1,693 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include "util.h" + +#include +#include +#include +#include + + +namespace icap { + + namespace util { + + unsigned int hextodec( const std::string &hex ) throw() { + + unsigned int dec; + std::stringstream ss; + + ss << std::hex << hex; + ss >> dec; + + return dec; + + } + + + const std::string dectohex( const unsigned int &dec ) throw() { + + std::string hex; + std::stringstream ss; + + ss << std::hex << dec; + ss >> hex; + + return hex; + + } + + + int read_line( socketlibrary::TCPSocket * socket, char * buf, int buf_length, bool incl_endl ) throw() { + + int i = 0, n; + char c = '\0'; + + while ( i < ( buf_length - 1 ) ) { + + n = socket->recv( &c, 1 ); + + if ( n > 0 ) { + if ( c == '\r' ) { + + if ( incl_endl ) { + buf[i] = c; + i++; + } + + // peak for \n + n = socket->peek( &c, 1 ); + + if ( ( n > 0 ) && ( c == '\n' ) ) { + + n = socket->recv( &c, 1 ); + + if ( incl_endl ) { + buf[i] = c; + i++; + } + + break; // end of line + } + } + + buf[i] = c; + i++; + } else { + break; // nothing read from socket + } + + } + + buf[i] = '\0'; + return i; + + } + + + std::string read_line( socketlibrary::TCPSocket * socket, bool incl_endl ) throw() { + + int n; + std::string line; + char c = '\0'; + + try { + + while ( ( n = socket->recv( &c, 1 ) ) > 0 ) { + + if ( c == '\r' ) { + + if ( incl_endl ) { + line += c; + } + + // peak for \n + n = socket->peek( &c, 1 ); + + if ( ( n > 0 ) && ( c == '\n' ) ) { + + n = socket->recv( &c, 1 ); + + if ( incl_endl ) { + line += c; + } + + break; // end of line + } + } + + line += c; + + } + + } catch ( socketlibrary::SocketException &sex ) { + // TODO: log error? + line = ""; + } + + return line; + + } + + + std::string read_data( socketlibrary::TCPSocket * socket, int size ) throw() { + + char buffer[ICAP_BUFFER_SIZE]; + std::string data = ""; + int n; + + // loop until we have read all the bytes + while ( size > 0 ) { + + try { + + // read from socket + n = socket->recv( buffer, min( size, ICAP_BUFFER_SIZE ) ); + + // sanity check + if ( n == 0 ) { + break; + } + + // append to data + data.append( buffer, n ); + + // update size with remaining bytes + size -= n; + + } catch ( socketlibrary::SocketException &sex ) { + // TODO: log errors ?? + } + + } + + return data; + + } + + + unsigned int read_chunk_size( socketlibrary::TCPSocket * socket ) throw() { + + std::string line; + std::vector chunk_header; + + line = read_line( socket ); + chunk_header = split( line, ";" ); + + return hextodec( chunk_header.at( 0 ) ); + + } + + + void read_chunk_header( socketlibrary::TCPSocket * socket, chunk_t &chunk ) throw() { + + std::string line; + std::vector chunk_header; + + line = read_line( socket ); + chunk_header = split( line, ";" ); + + // sanity check + if ( chunk_header.size() > 0 ) { + + // sanity check + if ( chunk_header.at( 0 ).size() > 0 ) { + chunk.size = hextodec( chunk_header.at( 0 ) ); + } + + // check for chunk-extension + if ( chunk_header.size() == 2 ) { + chunk.extention = trim( chunk_header.at( 1 ) ); + } + } + + return; + + } + + + chunk_t read_chunk( socketlibrary::TCPSocket * socket ) throw() { + + chunk_t chunk; + std::string line; + std::vector chunk_header; + + // initialise chunk + chunk.size = 0; + chunk.extention = ""; + chunk.data = ""; + + // read chunk header + read_chunk_header( socket, chunk ); + + // read chunk data + if ( chunk.size > 0 ) { + chunk.data = read_data( socket, chunk.size ); + } + + // read \r\n ending for the chunk + read_data( socket, 2 ); + + return chunk; + + } + + + std::string read_chunked( socketlibrary::TCPSocket * socket ) throw() { + + unsigned int chunk_size = 0; + unsigned int offset = 0; + std::string chunked_data = ""; + + while ( ( chunk_size = read_chunk_size( socket ) ) > 0 ) { + + offset = chunked_data.size(); + + // read chunk-data + chunked_data.append( read_data( socket, chunk_size ) ); + + // sanity check + if ( ( chunked_data.size() - offset ) != chunk_size ) { + // something went wrong + break; + } + + // extra \r\n + read_data( socket, 2 ); + + } + + // read until the end of chunked data + while ( read_line( socket, true ).size() > 2 ) ; + + return chunked_data; + + } + + + bool read_chunked_payload( socketlibrary::TCPSocket * socket, std::string &payload ) throw() { + + chunk_t chunk; + bool ieof = false; + + do { + + // read chunk + chunk = read_chunk( socket ); + + // append to payload + payload.append( chunk.data ); + + // sanity check + if ( chunk.data.size() != chunk.size ) { + // something went wrong + break; + } + + } while( chunk.size > 0 ); + + // check for ieof + if ( chunk.extention == "ieof" ) { + ieof = true; + } + + return ieof; + + } + + + bool send_line( const std::string &line, socketlibrary::TCPSocket * socket ) throw() { + + try { + socket->send( line.c_str(), line.length() ); + socket->send( "\r\n", 2 ); + } catch ( socketlibrary::SocketException &sex ) { + // TODO: log errors + return false; + } + + return true; + + } + + + bool send_data( const std::string &data, socketlibrary::TCPSocket * socket ) throw() { + + try { + socket->send( data.c_str(), data.size() ); + } catch( socketlibrary::SocketException &sex ) { + // TODO: log errors + return false; + } + + return true; + + } + + + bool send_chunked( const std::string &data, socketlibrary::TCPSocket * socket ) throw() { + + std::string chunked_data = ""; + unsigned int offset = 0; + int chunks = 0; + + // calculate the number of chunks we need + if ( data.size() > ICAP_BUFFER_SIZE ) { + chunks = ( data.size() / ICAP_BUFFER_SIZE ); + } + + try { + + do { + + // prepare data for this chunk + chunked_data = data.substr( offset, ICAP_BUFFER_SIZE ); + + // sanity check + if ( chunked_data.size() <= 0 ) { + // we shouldn't get here + break; + } + + // update offset + offset += chunked_data.size(); + + // send chunk size + if (! send_line( dectohex( chunked_data.size() ), socket ) ) { + return false; + } + + // send chunk + if (! send_data( chunked_data, socket ) ) { + return false; + } + + chunks--; + + } while ( chunks > 0 ); + + // end of chunk + if (! send_data( "\r\n0\r\n\r\n", socket ) ) { + return false; + } + + } catch ( socketlibrary::SocketException &sex ) { + // TODO: log errors ?? + return false; + } + + return true; + + } + + + std::vector split( const std::string &str, const std::string &delimiter ) throw() { + + std::vector result; + size_t current; + size_t next = -1; + + do { + current = next + 1; + next = str.find_first_of( delimiter, current ); + result.push_back( str.substr( current, ( next - current ) ) ); + } while ( next != std::string::npos ); + + return result; + + } + + + std::string <rim( std::string &str ) throw() { + str.erase( str.begin(), std::find_if( str.begin(), str.end(), std::not1( std::ptr_fun( std::isspace ) ) ) ); + return str; + } + + + std::string &rtrim( std::string &str ) throw() { + str.erase( std::find_if( str.rbegin(), str.rend(), std::not1( std::ptr_fun( std::isspace ) ) ).base(), str.end() ); + return str; + } + + + std::string &trim( std::string &str ) throw() { + return ltrim( rtrim( str ) ); + } + + + icap::RequestHeader * read_req_header( socketlibrary::TCPSocket * socket ) throw() { + + char buffer[ICAP_BUFFER_SIZE]; + int n = 0; + std::string data = ""; + + while ( ( n = read_line( socket, buffer, ICAP_BUFFER_SIZE, true ) ) > 2 ) { + data.append( buffer ); + } + + icap::RequestHeader * req_header = new icap::RequestHeader( data ); + return req_header; + + } + + + bool read_req_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw() { + + int data_offset = 0; + int data_length = 0; + int data_read = 0; + std::vector sorted_encaps_header; + std::vector::iterator sorted_idx; + + // payload + icap::payload_t payload; + payload.req_header = ""; + payload.req_body = ""; + payload.res_header = ""; + payload.res_body = ""; + payload.ieof = false; + + // header + icap::Header * header = request->header(); + sorted_encaps_header = header->sort_encapsulated_header(); + + // loop through the sorted header + for ( sorted_idx = sorted_encaps_header.begin(); sorted_idx != sorted_encaps_header.end(); sorted_idx++ ) { + + // don't want to read negative headers + if ( sorted_idx->second < 0 ) { + continue; + } + + // if this is the last header entity then check for chunked content + if ( sorted_idx == ( sorted_encaps_header.end() - 1 ) ) { + + if ( sorted_idx->first == "req-body" ) { + payload.ieof = read_chunked_payload( socket, payload.req_body ); + } else if ( sorted_idx->first == "res-body" ) { + payload.ieof = read_chunked_payload( socket, payload.res_body ); + } else { + /* + * null-body is the only other legal possibility here + * we take that into account in the previous iterations + */ + break; + } + + } else { + + data_offset = sorted_idx->second; + data_length = ( ( sorted_idx + 1 )->second - data_offset ); + + + /* read request data */ + + // is there anything to read? + if ( data_length > 0 ) { + + // update payload + if ( sorted_idx->first == "req-hdr" ) { + payload.req_header = read_data( socket, data_length ); + } else if ( sorted_idx->first == "req-body" ) { + payload.req_body = read_data( socket, data_length ); + } else if ( sorted_idx->first == "res-hdr" ) { + payload.res_header = read_data( socket, data_length ); + } else if ( sorted_idx->first == "res-body" ) { + payload.res_body = read_data( socket, data_length ); + } else { + // TODO: error? + } + + } + + } + + } + + // update request + request->payload( payload ); + + return true; + + } + + + bool read_req_continue_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw() { + + std::vector sorted_encaps_header; + icap::Header::encapsulated_header_data_t header_idx; + + // copy the payload from request so we can append to it + icap::payload_t payload; + payload.req_header = request->payload().req_header; + payload.req_body = request->payload().req_body; + payload.res_header = request->payload().res_header; + payload.res_body = request->payload().res_body; + payload.ieof = request->payload().ieof; + + // header + icap::Header * header = request->header(); + sorted_encaps_header = header->sort_encapsulated_header(); + + // sanity check + if ( sorted_encaps_header.size() > 0 ) { + + // we are only interested in the last header entity + header_idx = sorted_encaps_header.back(); + + // read payload data + if ( header_idx.first == "req-body" ) { + payload.ieof = read_chunked_payload( socket, payload.req_body ); + } else if ( header_idx.first == "res-body" ) { + payload.ieof = read_chunked_payload( socket, payload.res_body ); + } + + } else { + + // something isn't quite right + return false; + + } + + // update request + request->payload( payload ); + + return true; + + } + + + bool send_headers( icap::Header * header, socketlibrary::TCPSocket * socket ) throw() { + + std::string line; + icap::Header::headers_index_t i; + icap::ResponseHeader::headers_t headers; + + // headers + headers = header->headers(); + + for ( i = headers.begin(); i != headers.end(); i++ ) { + + line = i->first; + line.append( ": " ); + line.append( i->second ); + + if (! send_line( line, socket ) ) { + return false; + } + + } + + // send encapsulated header + line = "Encapsulated: "; + line.append( header->encapsulated_header_str() ); + if (! send_line( line, socket ) ) { + return false; + } + + // end of header + if (! send_data( "\r\n", socket ) ) { + return false; + } + + return true; + + } + + + bool send_response( icap::Response * response, socketlibrary::TCPSocket * socket ) throw() { + + bool r_success = true; + + icap::ResponseHeader * header; + + // grab the response header + header = response->header(); + + // response status + std::string line = header->protocol(); + line.append( " " ); + line.append( itoa( header->status() ) ); + line.append( " " ); + line.append( response_status( header->status() ) ); + + r_success = send_line( line, socket ); + + // response headers + if ( r_success ) { + r_success = send_headers( header, socket ); + } + + // response content (if there are any) + if ( r_success ) { + + // req-hdr + if ( response->payload().req_header.size() > 0 ) { + send_data( response->payload().req_header, socket ); + } + + // red-body + if ( response->payload().req_body.size() > 0 ) { + send_chunked( response->payload().req_body, socket ); + } + + // res-hdr + if ( response->payload().res_header.size() > 0 ) { + send_data( response->payload().res_header, socket ); + } + + // res-body + if ( response->payload().res_body.size() > 0 ) { + send_chunked( response->payload().res_body, socket ); + } + + } + + return r_success; + + } + + + const std::string response_status( const ResponseHeader::status_t &status ) throw() { + + // FIXME: probably there's a better way of mapping this + std::map status_text; + + status_text[ResponseHeader::CONTINUE] = "Continue"; + status_text[ResponseHeader::OK] = "OK"; + status_text[ResponseHeader::NO_CONTENT] = "No modifications needed"; + status_text[ResponseHeader::BAD_REQUEST] = "Bad request"; + status_text[ResponseHeader::NOT_FOUND] = "ICAP Service not found"; + status_text[ResponseHeader::NOT_ALLOWED] = "Method not allowed for service"; + status_text[ResponseHeader::REQ_TIMEOUT] = "Request timeout"; + status_text[ResponseHeader::SERVER_ERROR] = "Server error"; + status_text[ResponseHeader::NOT_IMPLEMENTED] = "Method not implemented"; + status_text[ResponseHeader::BAD_GATEWAY] = "Bad gateway"; + status_text[ResponseHeader::SERVICE_OVERLOADED] = "Service overloaded"; + status_text[ResponseHeader::NOT_SUPPORTED] = "ICAP version not supported by server"; + + return status_text[status]; + + } + + } /* end of namespace util */ + +} /* end of namespace icap */ + diff --git a/lib/icap/util.h b/lib/icap/util.h new file mode 100644 index 0000000..366bb9c --- /dev/null +++ b/lib/icap/util.h @@ -0,0 +1,265 @@ +/* + * C++ ICAP library + * Copyright (C) 2012 Uditha Atukorala + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef ICAP_UTIL_H +#define ICAP_UTIL_H + +#include + +#include +#include "request.h" +#include "response.h" + +#ifndef ICAP_BUFFER_SIZE +#define ICAP_BUFFER_SIZE 1024 +#endif + + +namespace icap { + + namespace util { + + struct chunk_t { + unsigned int size; + std::string extention; + std::string data; + }; + + /** + * Convert a number into a string + * + * @param number number to be converted + * @return converted string + */ + template std::string itoa( T number ) { + std::ostringstream ss; + ss << number; + + return ss.str(); + } + + /** + * Convert a hexadecimal number to a decimal number. + * + * @param hex hex to convert to + * @return converted decimal value + */ + unsigned int hextodec( const std::string &hex ) throw(); + + /** + * Convert a decimal number to its hexadecimal value + * + * @param dec decimal number + * @return converted hex value + */ + const std::string dectohex( const unsigned int &dec ) throw(); + + /** + * Read a line (ending with \r\n) from the socket + * + * @param socket socket to read from + * @param buf buffer to read the data into + * @param buf_length length / size of the buffer data is read into + * @param incl_endl (optional) switch to control whether to include \r\n in the read line, + * default is false. + * @return number of bytes read + */ + int read_line( socketlibrary::TCPSocket * socket, char * buf, int buf_length, bool incl_endl = false ) throw(); + + /** + * Read a line (ending with \r\n) from the socket + * + * @param socket socket instance to read data from + * @param incl_endl (optional) switch to control whether to include \r\n in the read line, + * default is false. + * @return read data + */ + std::string read_line( socketlibrary::TCPSocket * socket, bool incl_endl = false ) throw(); + + /** + * Read data from the socket + * + * @param socket socket instance to read data from + * @param size size / length of data to be read + * @return read data + */ + std::string read_data( socketlibrary::TCPSocket * socket, int size ) throw(); + + /** + * Read chunk size. This is a helper method used by read_chunked(). + * + * @param socket socket instance to read from + * @return chunk size + */ + unsigned int read_chunk_size( socketlibrary::TCPSocket * socket ) throw(); + + /** + * Read chunk header from the given socket. + * + * @param socket socket instance to read data from + * @param chunk chunk data structure to store header data + */ + void read_chunk_header( socketlibrary::TCPSocket * socket, chunk_t &chunk ) throw(); + + /** + * Read a data chunk from a HTTP chunked transfer encoded data stream. + * + * @param socket socket instance to read data from + * @return chunk data structure + */ + chunk_t read_chunk( socketlibrary::TCPSocket * socket ) throw(); + + /** + * Read chunked data from the given socket + * + * @param socket socket instance to read data from + * @return read data (without the control characters) + */ + std::string read_chunked( socketlibrary::TCPSocket * socket ) throw(); + + /** + * Read chunked payload data from the given socket + * + * @param socket socket instance to read data from + * @param payload payload to read data into + * @return boolean flag to denote the presence of "ieof" + */ + bool read_chunked_payload( socketlibrary::TCPSocket * socket, std::string &payload ) throw(); + + /** + * Send / write a line (ending with \r\n) to the socket + * + * @param line line to send through the socket without the line-ending chars + * @param socket socket object to write the data to + * @return boolean to denote success or failure + */ + bool send_line( const std::string &line, socketlibrary::TCPSocket * socket ) throw(); + + /** + * Send / write data to the socket. + * If chunked is set to true then data will be transferred using + * "chunked" transfer-encoding. + * + * @param data data to be sent + * @param socket socket instance to write to + * @return boolean to denote success or failure + */ + bool send_data( const std::string &data, socketlibrary::TCPSocket * socket ) throw(); + + /** + * Send / write data to the socket using chunked transfer encoding + * + * @param data data to be sent + * @param socket socket instance to write to + * @return boolean to denote success or failure + */ + bool send_chunked( const std::string &data, socketlibrary::TCPSocket * socket ) throw(); + + /** + * split a string into a vector by the given delimiter + * + * @param str input string + * @param delimiter (optional) delimiter, defaults to " " + */ + std::vector split( const std::string &str, const std::string &delimiter = " " ) throw(); + + /** + * Left trim (trim from start) a passed in string + * + * @param str string to trim + * @return trimmed string + */ + std::string <rim( std::string &str ) throw(); + + /** + * Right trim (trim from end) a passed in string + * + * @param str string to trim + * @return trimmed string + */ + std::string &rtrim( std::string &str ) throw(); + + /** + * Trim (trim from both ends) a passed in string + * + * @param str string to trim + * @return trimmed string + */ + std::string &trim( std::string &str ) throw(); + + /** + * Read icap request header from the socket passes in + * + * @param socket socket object to read data from + * @return icap request header object + */ + icap::RequestHeader * read_req_header( socketlibrary::TCPSocket * socket ) throw(); + + /** + * Read icap request into the icap::Request instance + * using the socket passed in + * + * @param request request object to read data into + * @param socket socket object to read data from + * @return boolean to denote success or failure + */ + bool read_req_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw(); + + /** + * Read icap request data after a '100 Continue' response. This will not look for any + * additional headers and will treat any data coming through the socket as payload data. + * + * @param request request object to read data into + * @param socket socket object to read data from + * @return boolean to denote success or failure + */ + bool read_req_continue_data( icap::Request * request, socketlibrary::TCPSocket * socket ) throw(); + + /** + * Send / write header data to a socket + * + * @param headers headers to be sent + * @param socket socket object to write the data to + * @return boolean to denote success or failure + */ + bool send_headers( icap::Header::headers_t headers, socketlibrary::TCPSocket * socket ) throw(); + + /** + * Output a response using the passed in icap::Response class to the + * passed in socket + * + * @param response response object to get the response data from + * @param socket socket object to send the data to + * @return boolean to denote success or failure + */ + bool send_response( icap::Response * response, socketlibrary::TCPSocket * socket ) throw(); + + /** + * Returns the response status text for the given status + * + * @param status status to get the text for + */ + const std::string response_status( const ResponseHeader::status_t &status ) throw(); + + } /* end of namespace util */ + +} /* end of namespace icap */ + +#endif /* !ICAP_UTIL_H */ + -- cgit v1.2.3