proxygen/lib/utils/ParseURL.h (154 lines of code) (raw):

/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. */ #pragma once #include <glog/logging.h> #include <folly/Conv.h> #include <folly/Optional.h> #include <folly/Portability.h> #include <folly/Range.h> #include <folly/String.h> #include <proxygen/lib/utils/Export.h> #include <string> namespace proxygen { // ParseURL can handle non-fully-formed URLs. This class must not persist beyond // the lifetime of the buffer underlying the input StringPiece class ParseURL { public: /* Parse a URL. If parsing succeeds, return a fully formed ParseURL with * valid() == true. If parsing fails, returns nothing. If you need the * partial parse results, use parseURLMaybeInvalid below. */ static folly::Expected<ParseURL, folly::Unit> parseURL( folly::StringPiece urlVal, bool strict = false) noexcept { ParseURL parseUrl(urlVal, strict); if (parseUrl.valid()) { return parseUrl; } else { return folly::makeUnexpected(folly::Unit()); } } /* Parse a URL. Returns a ParseURL object that may or may not be valid. * Caller should check valid() */ static ParseURL parseURLMaybeInvalid(folly::StringPiece urlVal, bool strict = false) noexcept { return ParseURL(urlVal, strict); } // Deprecated. Will be removed soon explicit ParseURL(folly::StringPiece urlVal, bool strict = true) noexcept { init(urlVal, strict); } ParseURL(ParseURL&& goner) : url_(goner.url_), scheme_(goner.scheme_), path_(goner.path_), query_(goner.query_), fragment_(goner.fragment_), port_(goner.port_), valid_(goner.valid_), initialized_(goner.initialized_) { moveHostAndAuthority(std::move(goner)); } ParseURL& operator=(ParseURL&& goner) { url_ = goner.url_; scheme_ = goner.scheme_; path_ = goner.path_; query_ = goner.query_; fragment_ = goner.fragment_; port_ = goner.port_; valid_ = goner.valid_; initialized_ = goner.initialized_; moveHostAndAuthority(std::move(goner)); return *this; } ParseURL& operator=(const ParseURL&) = delete; ParseURL(const ParseURL&) = delete; ParseURL() = default; void init(folly::StringPiece urlVal, bool strict = false) { CHECK(!initialized_); url_ = urlVal; parse(strict); initialized_ = true; } operator bool() const { return valid(); } folly::StringPiece url() const { return url_; } folly::StringPiece scheme() const { return scheme_; } std::string authority() const { return authority_; } bool hasHost() const { return valid() && !host_.empty(); } folly::StringPiece host() const { return host_; } uint16_t port() const { return port_; } std::string hostAndPort() const { std::string rc = host_.str(); if (port_ != 0) { folly::toAppend(":", port_, &rc); } return rc; } folly::StringPiece path() const { return path_; } folly::StringPiece query() const { return query_; } folly::StringPiece fragment() const { return fragment_; } bool valid() const { return valid_; } folly::StringPiece hostNoBrackets() { stripBrackets(); return hostNoBrackets_; } bool hostIsIPAddress(); FB_EXPORT void stripBrackets() noexcept; FOLLY_NODISCARD folly::Optional<folly::StringPiece> getQueryParam( folly::StringPiece name) const noexcept; private: void moveHostAndAuthority(ParseURL&& goner) { if (!valid_) { return; } int64_t hostOff = -1; int64_t hostNoBracketsOff = -1; if (goner.host_.empty() || (goner.host_.data() >= goner.url_.data() && goner.host_.data() < goner.url_.end())) { // relative url_ host_ = goner.host_; } else { // relative authority_ hostOff = goner.host_.data() - goner.authority_.data(); } if (goner.hostNoBrackets_.empty() || (goner.hostNoBrackets_.data() >= goner.url_.data() && goner.hostNoBrackets_.data() < goner.url_.end())) { // relative url_ hostNoBrackets_ = goner.hostNoBrackets_; } else { // relative authority_ hostNoBracketsOff = goner.hostNoBrackets_.data() - goner.authority_.data(); } authority_ = std::move(goner.authority_); if (hostOff >= 0) { host_.reset(authority_.data() + hostOff, goner.host_.size()); } if (hostNoBracketsOff >= 0) { hostNoBrackets_.reset(authority_.data() + hostNoBracketsOff, goner.hostNoBrackets_.size()); } } FB_EXPORT void parse(bool strict) noexcept; void parseNonFully(bool strict) noexcept; bool parseAuthority() noexcept; folly::StringPiece url_; folly::StringPiece scheme_; std::string authority_; folly::StringPiece host_; folly::StringPiece hostNoBrackets_; folly::StringPiece path_; folly::StringPiece query_; folly::StringPiece fragment_; uint16_t port_{0}; bool valid_{false}; bool initialized_{false}; }; } // namespace proxygen