view plugins/links/uri.cpp @ 824:06cc2f95f479

misc: happy new year!
author David Demelier <markand@malikania.fr>
date Tue, 08 Jan 2019 20:41:20 +0100
parents 7145a3df4cb7
children 5e25439fe98d
line wrap: on
line source

/*
 * uri.cpp -- simple uriparser based parser
 *
 * Copyright (c) 2013-2019 David Demelier <markand@malikania.fr>
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#include <regex>

#include <uriparser/Uri.h>

#include "scope_exit.hpp"
#include "uri.hpp"

using std::nullopt;
using std::optional;
using std::regex;
using std::regex_match;
using std::smatch;
using std::string;

namespace irccd {

auto uri::parse(const string& link) noexcept -> optional<uri>
{
	/*
	 * The message may contain additional text, example:
	 *
	 * markand: http://example.org check this site
	 */
	regex regex("^(https?:\\/\\/[^\\s]+).*$");
	smatch match;

	if (!regex_match(link, match, regex))
		return nullopt;

	UriParserStateA state;
	UriUriA hnd;
	uri ret;
	string copy = match[1].str();
	scope_exit exit([&hnd] { uriFreeUriMembersA(&hnd); });

	state.uri = &hnd;

	if (uriParseUriA(&state, copy.c_str()) != URI_SUCCESS)
		return nullopt;

	if (hnd.scheme.first)
		ret.scheme = string(hnd.scheme.first, hnd.scheme.afterLast - hnd.scheme.first);

	// We're only interested in http and https.
	if (ret.scheme != "http" && ret.scheme != "https")
		return nullopt;

	// Correct port if not specified.
	if (ret.port.empty())
		ret.port = ret.scheme == "http" ? "80" : "443";

	if (hnd.hostText.first)
		ret.hostname = string(hnd.hostText.first, hnd.hostText.afterLast - hnd.hostText.first);
	if (hnd.portText.first)
		ret.port = string(hnd.portText.first, hnd.portText.afterLast - hnd.portText.first);

	for (auto p = hnd.pathHead; p != nullptr; p = p->next) {
		ret.path += "/";
		ret.path += string(p->text.first, p->text.afterLast - p->text.first);
	}

	// Correct path if empty.
	if (ret.path.empty())
		ret.path = "/";

	// Add query if needed.
	if (hnd.query.first) {
		ret.path += "?";
		ret.path += string(hnd.query.first, hnd.query.afterLast - hnd.query.first);
	}

	return ret;
}

} // !irccd