summaryrefslogtreecommitdiffstats
path: root/ext/yahttp/yahttp/url.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'ext/yahttp/yahttp/url.hpp')
-rw-r--r--ext/yahttp/yahttp/url.hpp200
1 files changed, 200 insertions, 0 deletions
diff --git a/ext/yahttp/yahttp/url.hpp b/ext/yahttp/yahttp/url.hpp
new file mode 100644
index 0000000..fbdd48d
--- /dev/null
+++ b/ext/yahttp/yahttp/url.hpp
@@ -0,0 +1,200 @@
+#pragma once
+#include <sstream>
+#include <string>
+
+#include "utility.hpp"
+
+#ifndef YAHTTP_MAX_URL_LENGTH
+#define YAHTTP_MAX_URL_LENGTH 2048
+#endif
+
+namespace YaHTTP {
+ /*! URL parser and container */
+ class URL {
+ private:
+ bool parseSchema(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return false; // no data
+ if ( (pos1 = url.find_first_of(":",pos)) == std::string::npos ) return false; // schema is mandatory
+ protocol = url.substr(pos, pos1-pos);
+ if (protocol == "http") port = 80;
+ if (protocol == "https") port = 443;
+ pos = pos1+1; // after :
+ if (url.compare(pos, 2, "//") == 0) {
+ pathless = false; // if this is true we put rest into parameters
+ pos += 2;
+ }
+ return true;
+ }; //<! parse schema/protocol part
+
+ bool parseHost(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return true; // no data
+ if ( (pos1 = url.find_first_of("/", pos)) == std::string::npos ) {
+ host = url.substr(pos);
+ path = "/";
+ pos = url.size();
+ } else {
+ host = url.substr(pos, pos1-pos);
+ pos = pos1;
+ }
+ if (host.at(0) == '[') { // IPv6
+ if ((pos1 = host.find_first_of("]")) == std::string::npos) {
+ // incomplete address
+ return false;
+ }
+ size_t pos2;
+ if ((pos2 = host.find_first_of(":", pos1)) != std::string::npos) {
+ std::istringstream tmp(host.substr(pos2 + 1));
+ tmp >> port;
+ }
+ host = host.substr(1, pos1 - 1);
+ } else if ( (pos1 = host.find_first_of(":")) != std::string::npos ) {
+ std::istringstream tmp(host.substr(pos1+1));
+ tmp >> port;
+ host = host.substr(0, pos1);
+ }
+ return true;
+ }; //<! parse host and port
+
+ bool parseUserPass(const std::string& url, size_t &pos) {
+ size_t pos1,pos2;
+ if (pos >= url.size()) return true; // no data
+
+ if ( (pos1 = url.find_first_of("@",pos)) == std::string::npos ) return true; // no userinfo
+ pos2 = url.find_first_of(":",pos);
+
+ if (pos2 != std::string::npos) { // comes with password
+ username = url.substr(pos, pos2 - pos);
+ password = url.substr(pos2+1, pos1 - pos2 - 1);
+ password = Utility::decodeURL(password);
+ } else {
+ username = url.substr(pos, pos1 - pos);
+ }
+ pos = pos1+1;
+ username = Utility::decodeURL(username);
+ return true;
+ }; //<! parse possible username and password
+
+ bool parsePath(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return true; // no data
+ if (url[pos] != '/') return false; // not an url
+ if ( (pos1 = url.find_first_of("?", pos)) == std::string::npos ) {
+ path = url.substr(pos);
+ pos = url.size();
+ } else {
+ path = url.substr(pos, pos1-pos);
+ pos = pos1;
+ }
+ return true;
+ }; //<! parse path component
+
+ bool parseParameters(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return true; // no data
+ if (url[pos] == '#') return true; // anchor starts here
+ if (url[pos] != '?') return false; // not a parameter
+ if ( (pos1 = url.find_first_of("#", pos)) == std::string::npos ) {
+ parameters = url.substr(pos+1);;
+ pos = url.size();
+ } else {
+ parameters = url.substr(pos+1, pos1-pos-1);
+ pos = pos1;
+ }
+ if (parameters.size()>0 && *(parameters.end()-1) == '&') parameters.resize(parameters.size()-1);
+ return true;
+ }; //<! parse url parameters
+
+ bool parseAnchor(const std::string& url, size_t &pos) {
+ if (pos >= url.size()) return true; // no data
+ if (url[pos] != '#') return false; // not anchor
+ anchor = url.substr(pos+1);
+ return true;
+ }; //<! parse anchor
+
+ void initialize() {
+ protocol = ""; host = ""; port = 0; username = ""; password = ""; path = ""; parameters = ""; anchor =""; pathless = true;
+ }; //<! initialize to empty URL
+
+ public:
+ std::string to_string() const {
+ std::string tmp;
+ std::ostringstream oss;
+
+ if (protocol.empty() == false) {
+ oss << protocol << ":";
+ if (host.empty() == false) {
+ oss << "//";
+ }
+ }
+
+ if (username.empty() == false) {
+ if (password.empty() == false)
+ oss << Utility::encodeURL(username) << ":" << Utility::encodeURL(password) << "@";
+ else
+ oss << Utility::encodeURL(username) << "@";
+ }
+ if (host.empty() == false)
+ oss << host;
+ if (!(protocol == "http" && port == 80) &&
+ !(protocol == "https" && port == 443) &&
+ port > 0)
+ oss << ":" << port;
+
+ oss << path;
+ if (parameters.empty() == false) {
+ if (!pathless)
+ oss << "?";
+ oss << parameters;
+ }
+ if (anchor.empty() == false)
+ oss << "#" << anchor;
+ return oss.str();
+ }; //<! convert this URL to string
+
+ std::string protocol; //<! schema/protocol
+ std::string host; //<! host
+ int port; //<! port
+ std::string username; //<! username
+ std::string password; //<! password
+ std::string path; //<! path
+ std::string parameters; //<! url parameters
+ std::string anchor; //<! anchor
+ bool pathless; //<! whether this url has no path
+
+ URL() { initialize(); }; //<! construct empty url
+ URL(const std::string& url) {
+ parse(url);
+ }; //<! calls parse with url
+
+ URL(const char *url) {
+ parse(std::string(url));
+ }; //<! calls parse with url
+
+ bool parse(const std::string& url) {
+ // setup
+ initialize();
+
+ if (url.size() > YAHTTP_MAX_URL_LENGTH) return false;
+ size_t pos = 0;
+ if (*(url.begin()) != '/') { // full url?
+ if (parseSchema(url, pos) == false) return false;
+ if (pathless) {
+ parameters = url.substr(pos);
+ return true;
+ }
+ if (parseUserPass(url, pos) == false) return false;
+ if (parseHost(url, pos) == false) return false;
+ }
+ if (parsePath(url, pos) == false) return false;
+ if (parseParameters(url, pos) == false) return false;
+ return parseAnchor(url, pos);
+ }; //<! parse various formats of urls ranging from http://example.com/foo?bar=baz into data:base64:d089swt64wt...
+
+ friend std::ostream & operator<<(std::ostream& os, const URL& url) {
+ os<<url.to_string();
+ return os;
+ };
+ };
+};