1. Christian Fischer
  2. wiesel

Commits

Christian Fischer  committed cf838fe

added HttpConnection and ConnectionDataSource classes

  • Participants
  • Parent commits bbfd1b0
  • Branches default

Comments (0)

Files changed (6)

File src/net/wiesel/io/net/connection_datasource.cpp

View file
  • Ignore whitespace
+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * 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; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * 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
+ */
+#include "connection_datasource.h"
+#include "connection.h"
+
+#include <sstream>
+
+using namespace wiesel;
+
+
+ConnectionDataSource::ConnectionDataSource() {
+	return;
+}
+
+ConnectionDataSource::ConnectionDataSource(const URI& uri) : uri(uri) {
+	return;
+}
+
+ConnectionDataSource::~ConnectionDataSource() {
+	return;
+}
+
+
+DataBuffer *ConnectionDataSource::getDataBuffer() {
+	if (content == NULL) {
+		ref<Connection> connection = Connection::createConnection(uri);
+		if (connection) {
+			std::stringstream ss;
+			char c;
+
+			while(connection->read((Connection::data_t*)&c, 1) > 0) {
+				ss.put(c);
+			}
+
+			content = ExclusiveDataBuffer::createCopyOf(ss.str());
+		}
+	}
+
+	return content;
+}
+
+void ConnectionDataSource::releaseDataBuffer() {
+	content = NULL;
+}

File src/net/wiesel/io/net/connection_datasource.h

View file
  • Ignore whitespace
+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * 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; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * 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
+ */
+#ifndef __WIESEL_IO_NET_CONNECTION_DATASOURCE_H__
+#define __WIESEL_IO_NET_CONNECTION_DATASOURCE_H__
+
+#include <wiesel/io/datasource.h>
+#include <wiesel/io/uri.h>
+#include <wiesel/wiesel-net.def>
+
+namespace wiesel {
+
+	/**
+	 * @brief A datasource from any connection.
+	 */
+	class WIESEL_NET_EXPORT ConnectionDataSource : public DataSource
+	{
+	private:
+		ConnectionDataSource();
+
+	public:
+		ConnectionDataSource(const URI& uri);
+		virtual ~ConnectionDataSource();
+
+	public:
+		virtual DataBuffer *getDataBuffer();
+		virtual void releaseDataBuffer();
+
+		/**
+		 * @brief Get the URI where the content will be loaded from.
+		 */
+		inline const URI& getURI() const {
+			return uri;
+		}
+
+	private:
+		URI					uri;
+		ref<DataBuffer>		content;
+	};
+
+}
+
+#endif // __WIESEL_IO_NET_CONNECTION_DATASOURCE_H__
+

File src/net/wiesel/io/net/http_connection.cpp

View file
  • Ignore whitespace
+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * 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; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * 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
+ */
+#include "http_connection.h"
+
+#include <cstdlib>
+#include <sstream>
+#include <map>
+
+#include "wiesel/util/log.h"
+
+using namespace wiesel;
+
+
+HttpConnector::HttpConnector() {
+	return;
+}
+
+HttpConnector::~HttpConnector() {
+	return;
+}
+
+
+Connection* HttpConnector::createConnection(const URI& uri) {
+	if (
+			(uri.getScheme() == "http")
+		||	(uri.getScheme() == "https")
+		||	(uri.getScheme() == "" && uri.getHost().substr(4) == "www.")
+	) {
+		HttpConnection *connection = HttpConnection::createRequest(uri);
+		if (connection) {
+			connection->finishRequest();
+
+			HttpStatusCode response = connection->waitForResponse();
+			if (response >= 200 && response <= 299) {
+				return connection;
+			}
+			else {
+				delete connection;
+			}
+		}
+	}
+
+	return NULL;
+}
+
+
+
+HttpConnection::HttpConnection() {
+}
+
+HttpConnection::~HttpConnection() {
+}
+
+
+HttpConnection* HttpConnection::createRequest(const URI& uri, Method method) {
+	HttpConnection *connection = new HttpConnection();
+	connection->setCurrentURI(uri);
+
+	URI socket_uri;
+	socket_uri.setHost(uri.getHost());
+	socket_uri.setPort(uri.hasPort() ? uri.getPort() : 80);
+
+	connection->internal_connection = Connection::createConnection(socket_uri);
+	if (connection->isConnected() == false) {
+		delete connection;
+		return NULL;
+	}
+
+	const std::string HTTP_ENDL("\r\n");
+	std::stringstream ss;
+
+	switch(method) {
+		case Method_GET: {
+			ss << "GET";
+			break;
+		}
+
+		case Method_POST: {
+			ss << "POST";
+			break;
+		}
+	}
+
+	ss << ' ';
+	ss << (uri.getPath().empty() ? "/" : uri.getPath());
+
+	const std::string query = uri.getQueryString();
+	if (query.empty() == false) {
+		ss << '?';
+		ss << query;
+	}
+
+	ss << " HTTP/1.1" << HTTP_ENDL;
+
+	std::string header_request = ss.str();
+	connection->send((const data_t*)(header_request.c_str()), header_request.length());
+
+	connection->sendHeader("Host", connection->getURI().getAuthority());
+
+	return connection;
+}
+
+
+bool HttpConnection::sendHeader(const std::string& name, const std::string& value) {
+	std::stringstream ss;
+	ss << name;
+	ss << ": ";
+	ss << value;
+	ss << "\r\n";
+
+	std::string line = ss.str();
+
+	return send((const data_t*)(line.c_str()), line.length());
+}
+
+
+bool HttpConnection::finishRequest() {
+	return send((const data_t*)("\r\n"), 2);
+}
+
+
+HttpStatusCode HttpConnection::waitForResponse() {
+	// clear last response
+	last_response = NULL;
+
+	HttpResponse *response = new HttpResponse();
+	bool success = response->readFrom(this);
+
+	if (success) {
+		last_response = response;
+		return response->getStatusCode();
+	}
+
+	if (!success) {
+		delete response;
+	}
+
+	return HTTP_NotFound;
+}
+
+
+const HttpResponse* HttpConnection::getLastResponse() const {
+	return last_response;
+}
+
+
+
+
+bool HttpConnection::isConnected() const {
+	return (internal_connection!=NULL) && (internal_connection->isConnected());
+}
+
+
+void HttpConnection::disconnect() {
+	if (internal_connection) {
+		internal_connection->disconnect();
+	}
+}
+
+
+bool HttpConnection::send(const data_t* data, size_t size) {
+	if (internal_connection) {
+		bool result = internal_connection->send(data, size);
+
+		if (result == false) {
+			disconnect();
+		}
+
+		return result;
+	}
+
+	return false;
+}
+
+
+int HttpConnection::read(data_t *ptr, size_t size) {
+	if (internal_connection) {
+		int result = internal_connection->read(ptr, size);
+
+		if (result <= 0) {
+			disconnect();
+		}
+
+		return result;
+	}
+
+	return 0;
+}
+
+
+
+
+
+HttpResponse::HttpResponse() {
+	this->status_code = HTTP_NotFound;
+}
+
+HttpResponse::~HttpResponse() {
+	return;
+}
+
+
+bool HttpResponse::readFrom(Connection* connection) {
+	std::stringstream ss;
+
+	do {
+		char c;
+
+		do {
+			int result = connection->read((Connection::data_t*)&c, 1);
+
+			// connection interrupted
+			if (result <= 0 || !connection->isConnected()) {
+				status_code = HTTP_ServiceUnavailable;
+				return false;
+			}
+
+			if (c == '\r') {
+				continue;
+			}
+
+			if (c == '\n') {
+				break;
+			}
+
+			ss.put(c);
+		}
+		while(true);
+
+		std::string line = ss.str();
+		ss.str("");
+
+		// done
+		if (line.empty()) {
+			break;
+		}
+
+		if (line.substr(0, 5) == "HTTP/") {
+			if (
+					line.substr(5, 3) == "1.0"
+				||	line.substr(5, 3) == "1.1"
+			) {
+				int num = std::atoi(line.substr(9, 3).c_str());
+				if (num) {
+					status_code = static_cast<HttpStatusCode>(num);
+				}
+			}
+
+			continue;
+		}
+
+		std::string::size_type seperator = line.find(": ");
+		if (seperator != std::string::npos) {
+			parameters.insert(std::pair<std::string,std::string>(
+							line.substr(0, seperator),
+							line.substr(seperator + 2)
+			));
+		}
+	}
+	while(true);
+
+	return true;
+}
+
+
+std::string HttpResponse::get(const std::string& attrib) const {
+	ParameterMap::const_iterator it = parameters.find(attrib);
+	if (it != parameters.end()) {
+		return it->second;
+	}
+
+	return std::string();
+}
+

File src/net/wiesel/io/net/http_connection.h

View file
  • Ignore whitespace
+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * 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; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * 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
+ */
+#ifndef __WIESEL_IO_NET_HTTP_CONNECTION_H__
+#define __WIESEL_IO_NET_HTTP_CONNECTION_H__
+
+#include "socket_connection.h"
+#include "http_status_codes.h"
+
+#include <map>
+
+namespace wiesel {
+
+
+	class HttpConnection;
+	class HttpResponse;
+
+
+	class WIESEL_NET_EXPORT HttpConnector : public IConnector
+	{
+	public:
+		HttpConnector();
+		virtual ~HttpConnector();
+
+		virtual Connection* createConnection(const URI& uri);
+	};
+
+
+
+	/**
+	 * @brief A connection class for sending requests to a HTTP server
+	 * and receive data from it.
+	 */
+	class WIESEL_NET_EXPORT HttpConnection : public Connection
+	{
+	public:
+		/**
+		 * @brief The HTTP-Request method.
+		 */
+		enum Method {
+			Method_GET,
+			Method_POST,
+		};
+
+	public:
+		HttpConnection();
+		virtual ~HttpConnection();
+
+		/**
+		 * @brief Starts a new HTTP request.
+		 * The client can send more data or call \ref finishRequest and
+		 * wait for the server's response.
+		 * @param uri		The URI to connect to.
+		 * @param method	The request-method.
+		 * @return A valid HttpConnection on success, or \c NULL on fail.
+		 */
+		static HttpConnection *createRequest(const URI& uri, Method method=Method_GET);
+
+	// sending data
+	public:
+		/**
+		 * @brief Send a single line as HTTP header for the current request.
+		 */
+		bool sendHeader(const std::string& name, const std::string& value);
+
+		/**
+		 * @brief Finish the request and tell the server to send the requested data.
+		 * It's neccessary to call this function in order to receive data.
+		 */
+		bool finishRequest();
+
+	// response
+	public:
+		/**
+		 * @brief Blocks until a full response was received.
+		 * When the request was successful, the client can start reading
+		 * the requested data from the connection.
+		 * @return A HTTP response code.
+		 */
+		HttpStatusCode waitForResponse();
+
+		/**
+		 * @brief Get the last response, if any.
+		 */
+		const HttpResponse* getLastResponse() const;
+
+	// Connection
+	public:
+		virtual bool isConnected() const;
+		virtual void disconnect();
+		virtual bool send(const data_t* data, size_t size);
+		virtual int  read(data_t *ptr, size_t size);
+
+	private:
+		ref<Connection>		internal_connection;
+		ref<HttpResponse>	last_response;
+	};
+
+
+
+	/**
+	 * @brief A class storing the result of a HTTP request.
+	 */
+	class WIESEL_NET_EXPORT HttpResponse : public virtual SharedObject
+	{
+	public:
+		HttpResponse();
+		virtual ~HttpResponse();
+
+	public:
+		/**
+		 * @brief Read the response from a connection.
+		 * @param connection	A connection to read from.
+		 * @return	\c true on success. Even on success,
+		 *			there's no guarantee to get valid date,
+		 *			see the response status code for details.
+		 */
+		bool readFrom(Connection *connection);
+
+	public:
+		/**
+		 * @brief Get the HTTP Status Code returned to this response.
+		 */
+		inline HttpStatusCode getStatusCode() const {
+			return status_code;
+		}
+
+		/**
+		 * @brief Get a specific attribute from the HTTP response.
+		 */
+		std::string get(const std::string& attrib) const;
+
+	private:
+		typedef std::map<std::string, std::string>	ParameterMap;
+
+		HttpStatusCode		status_code;
+		ParameterMap		parameters;
+	};
+
+}
+
+#endif // __WIESEL_IO_NET_HTTP_CONNECTION_H__
+

File src/net/wiesel/io/net/http_connection.loadable_module

View file
  • Ignore whitespace
+
+#include <wiesel/module_registry.h>
+#include "http_connection.h"
+#include "connector.h"
+
+
+// add the module to the module registry
+namespace wiesel {
+	REGISTER_MODULE_SINGLETON(
+			IConnector,
+			HttpConnector,
+			&generic_create<HttpConnector>,
+			"HTTP",
+			0x01010000u,
+			IModuleLoader::PriorityHigh
+	)
+}

File src/net/wiesel/io/net/http_status_codes.h

View file
  • Ignore whitespace
+/**
+ * Copyright (C) 2012
+ * Christian Fischer
+ *
+ * https://bitbucket.org/baldur/wiesel/
+ *
+ * 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; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * 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
+ */
+#ifndef __WIESEL_IO_NET_HTTP_STATUS_CODES_H__
+#define __WIESEL_IO_NET_HTTP_STATUS_CODES_H__
+
+namespace wiesel {
+
+	/**
+	 * @brief A list of possible HTTP-Status codes
+	 */
+	enum HttpStatusCode {
+		HTTP_Continue						= 100,
+		HTTP_SwitchingProtocols				= 101,
+		HTTP_Processing						= 102,
+
+		HTTP_OK								= 200,
+		HTTP_Created						= 201,
+		HTTP_Accepted						= 202,
+		HTTP_NonAuthorativeInformation		= 203,
+		HTTP_NoContent						= 204,
+		HTTP_ResetContent					= 205,
+		HTTP_PartialContent					= 206,
+		HTTP_MultiStatus					= 207,
+
+		HTTP_MultipleChoices				= 300,
+		HTTP_MovedPermanently				= 301,
+		HTTP_Found							= 302,
+		HTTP_SeeOther						= 303,
+		HTTP_NotModified					= 304,
+		HTTP_UseProxy						= 305,
+		HTTP_TemporaryRedirect				= 307,
+
+		HTTP_BadRequest						= 400,
+		HTTP_Unauthorized					= 401,
+		HTTP_PaymentRequired				= 402,
+		HTTP_Forbidden						= 403,
+		HTTP_NotFound						= 404,
+		HTTP_MethodNotAllowed				= 405,
+		HTTP_NotAcceptable					= 406,
+		HTTP_ProxyAuthenticationRequired	= 407,
+		HTTP_RequestTimeout					= 408,
+		HTTP_Conflict						= 409,
+		HTTP_Gone							= 410,
+		HTTP_LengthRequired					= 411,
+		HTTP_PreconditionFailed				= 412,
+		HTTP_RequestEntitiyTooLarge			= 413,
+		HTTP_RequestUrlTooLong				= 414,
+		HTTP_UnsupportedMediaType			= 415,
+		HTTP_RequestedRangeNotSatisfiable	= 416,
+		HTTP_ExpectationFailed				= 417,
+		HTTP_ImATeapot						= 418,
+		HTTP_PolicyNotFulfilled				= 420,
+		HTTP_TooManyConnections				= 421,
+		HTTP_UnprocessableEntity			= 422,
+		HTTP_Locked							= 423,
+		HTTP_FailedDependency				= 424,
+		HTTP_UnorderedCollection			= 425,
+		HTTP_UpgradeRequired				= 426,
+		HTTP_TooManyRequests				= 429,
+
+		HTTP_InternalServerError			= 500,
+		HTTP_NotImplemented					= 501,
+		HTTP_BadGateway						= 502,
+		HTTP_ServiceUnavailable				= 503,
+		HTTP_GatewayTimeout					= 504,
+		HTTP_HttpVersionNotSupported		= 505,
+		HTTP_VariantAlsoNegotiates			= 506,
+		HTTP_InsufficientStorage			= 507,
+		HTTP_BandwidthLimitExceeded			= 509,
+		HTTP_NotExtended					= 510,
+	};
+
+}
+
+#endif // __WIESEL_IO_NET_HTTP_STATUS_CODES_H__
+