Laden...

Implementierungsfrage zu Uri, HttpUrl und HttpServer

Erstellt von BlackMatrix vor 10 Jahren Letzter Beitrag vor 10 Jahren 1.286 Views
B
BlackMatrix Themenstarter:in
218 Beiträge seit 2012
vor 10 Jahren
Implementierungsfrage zu Uri, HttpUrl und HttpServer

Guten Abend,

ich habe recht lange für eine eigentlich einfache Implementierung gebraucht und bin mir immer noch nicht wirklich im Klaren, ob das so richtig designt und gecodet ist.

Und zwar habe ich 3 Klassen. Die Uri-Klasse des .NET-Frameworks, eine HttpUrl-Klasse, die nur Http- und Https-Uris erlauben soll (und dementsprechend von Uri ableiten sollten) und die HttpServer-Klasse, die neben Eigenschaften wie Erreichbarkeit und eben der Http(s)-Uri auch noch die Möglichkeit des Vergleiches bieten soll. Beispielsweise soll "http://www.example.net" == "http://example.net/" sein. Ein weiterer Punkt soll sein, dass beim Erstellen eines HttpServers mit dem String "http://www.example.net/path" der HttpServer "http://www.example.net/" erstellt werden soll.

Gibt da wohl genug Wege, die nach Rom führen...

Genug erzählt, nun gibts Code:

public class HttpUrl : Uri
    {
        public static readonly Regex DomainRegex = new Regex(@"https?://(www\.)?(?<basedomain>[A-Za-z\d_.-]+\.[A-Za-z]{2,4})", RegexOptions.ExplicitCapture);// ~ ?

        public string BaseDomain { get; private set; }// z.B.: "example.net"
        public string Domain { get; private set; }// z.B.: http://www.example.net/

        private HttpUrl(string httpUrlString)
            :base(httpUrlString)
        {
        }

        public static HttpUrl Create(string httpUrlString, bool removePathAndQueries = false)
        {
            Match match = VerifyDomainMatch(httpUrlString);

            HttpUrl httpUrl;
            string domain = AppendSlash(match.Value);

            if (removePathAndQueries)
                httpUrl = new HttpUrl(domain);
            else
                httpUrl = new HttpUrl(httpUrlString);

            httpUrl.Domain = domain;
            httpUrl.BaseDomain = match.Groups["basedomain"].Value;

            return httpUrl;
        }

        private static string AppendSlash(string httpDomain)
        {
            return string.Concat(httpDomain, "/");// http://www.example.net --> http://www.example.net/
        }

        private static Match VerifyDomainMatch(string url)
        {
            Match match = DomainRegex.Match(url);
            if (!match.Success)
                throw new FormatException("Die angegebene URL ist nicht im korrekten Http-Url-Format.");

            return match;
        }
public class HttpServer : IEquatable<HttpServer>
    {
        public HttpUrl Url { get; private set; }

        public HttpServer(string httpDomain)
        {
            Url = HttpUrl.Create(httpDomain, true);
        }

        #region Overrides

        public override bool Equals(object obj)
        {
            if (!(obj is HttpServer))
                return false;
            return Equals((HttpServer)obj);
        }

        public bool Equals(HttpServer other)
        {
            if (ReferenceEquals(null, other))
                return false;
            if (ReferenceEquals(this, other))
                return true;
            return Equals(Url.BaseDomain, other.Url.BaseDomain);
        }

        public override int GetHashCode()
        {
            return Url.BaseDomain.GetHashCode();
        }

        public static bool operator ==(HttpServer left, HttpServer right)
        {
            if (Object.ReferenceEquals(left, right))
                return true;
            return left.Equals(right);
        }

        public static bool operator !=(HttpServer left, HttpServer right)
        {
            return !(left == right);
        }

        public override string ToString()
        {
            return Url.AbsoluteUri;
        }

        #endregion

    }

Viele Grüße

BlackMatrix

16.806 Beiträge seit 2008
vor 10 Jahren

Genug erzählt, nun gibts Code:

Gibts auch ne Frage?
[Hinweis] Wie poste ich richtig? Punkt 5

Beispielsweise soll "http://www.example.net" == "http://example.net/" sein.

Das ist technisch gesehen falsch.
"domain.net" und "www.domain.net" sind zwei völlig verschiedene Dinge.
Aufgrund der Gewohnheit ist es nur ein inoffizieller Standard, dass die Top-Level Domain auf die www-Subdomain umleitet.
Dies wird nicht vom Browser gemacht, sondern vom Webserver. Die gängigen Konfigurationstools wie Plex und Confixx richten dieses Verhalten sogar standardmäßig ein.

In Deinem Code gehst Du aber eher auf den Backslash ein. Laut RFC ist dieser Optional.
Diesen hart immer anzufügen ist erlaubt; persönlich finde ich es aber unschön.

Dein Regex ist dahingehend falsch, dass ein Webserver auch durchaus auf einer anderen Subdomain als auf www liegen darf. Paypal führt zB die Subdomain "secure." an, um den Benutzer eine gewisse Sicherheit "vorzugaukeln" / zu suggerieren.
Ebenso werden Domains zB England (co.uk) und Australien (com.au) nicht richtig erkannt. Dann wäre da noch IPs und und und...
siehe auch In search of the perfect URL validation regex - "etwas" komplizierter als Dein Vorhaben.

Für HttpUrl an für sich _wahrscheinlich _die Komposition eher eignen als die Vererbung.

3.170 Beiträge seit 2006
vor 10 Jahren

Hallo zusammen,

        public bool Equals(HttpServer other)
        {
            if (ReferenceEquals(null, other))
                return false;
            if (ReferenceEquals(this, other))
                return true;
            return Equals(Url.BaseDomain, other.Url.BaseDomain);
        }

es werden mit diesem Code ja nicht nur die www-Subdomains, sondern wenn ich es richtig blicke alle Subdomains "abgeschnitten" beim Vergleich. Das kann richtig oder auch nicht richtig sein, je nachdem was man will.

@BlackMatrix
Da musst Du Dir darüber im klaren sein, ob das für Deinen Anwendungsfall so stimmt. Tatsache ist, dass unter der gleichen "BaseDomain" etliche verschieden(s)te Websites liegen können, die jeweils für sich existieren und mit den anderen nicht das geringste zu tun haben müssen.

Gruß, MarsStein

Non quia difficilia sunt, non audemus, sed quia non audemus, difficilia sunt! - Seneca

B
BlackMatrix Themenstarter:in
218 Beiträge seit 2012
vor 10 Jahren

Beispielsweise soll "http://www.example.net" == "http://example.net/" sein.
Das ist technisch gesehen :::

In meinem Programm soll letztendlich jeder Server, einschließlich jeder Subdomain, nur einmal vorhanden sein. HttpUrl soll also jede mögliche Http-Uri entgegennehmen können und nur der HttpServer soll miteinander vergleichen werden. Es sollte also im Endeffekt der HttpServer http://secure.paypal.com == HttpServer http://www.paypal.com und http://paypal.com sein. Wenn ich es richtig verstehe, dann können die 3 ja über unterschiedliche IPs erreichbar sein und damit auch unterschiedliche Erreichbarkeiten haben. Mein Hauptanliegen liegt aber eben auf der Gleichheit, aber die ist für jemanden der die Klasse HttpServer liest jedoch aber nicht logisch.

In Deinem Code gehst Du aber eher auf den Backslash ein. Laut RFC ist dieser Optional.
Diesen hart immer anzufügen ist erlaubt; persönlich finde ich es aber unschön.

Ich brauche eine Standardisierung um die Urls weiterzuverarbeiten, um z.B. Paths anzuhängen.

Dein Regex ist dahingehend falsch, dass ein Webserver auch durchaus auf einer anderen Subdomain als auf www liegen darf. [...] Ebenso werden Domains zB England (co.uk) und Australien (com.au) nicht richtig erkannt. Dann wäre da noch IPs und und und...

Stimmt bei meinem alten Regex hatte ich das noch richtiger. Wobei ich dazu sagen muss, dass mit komplexeren Regexes es teilweise schwierig ist eine 100%ige Sicherheit hinzubekommen.

1.361 Beiträge seit 2007
vor 10 Jahren

Hi BlackMatrix,

Stimmt bei meinem alten Regex hatte ich das noch richtiger. Wobei ich dazu sagen muss, dass mit komplexeren Regexes es teilweise schwierig ist eine 100%ige Sicherheit hinzubekommen.

Yup, die "Base"-Domain aus einer komplexen Domain zu extrahieren ist nicht leicht.

Es gibt keine "allgemeine" Regel für Dinge wie:


[URL]www.shop.com[/URL] -> shop.com
shop.com -> shop.com
shop.co.uk -> shop.co.uk
shop.bl.uk -> bl.uk

Eine ähnliche Diskussion gibt es auf Stackoverflow: regex - how to get domain name from URL.

Du kommst für eine zufriedenstellende Lösung nicht umhin dir eine Liste aller gültigen Top-Level-Domains zu besorgen. Zum Glück hilft dir das Internet, insbesondere Mozilla mit seiner Mozilla: Public Suffix List.

Zusätzlich dann noch alles lowercasen, Punycode umwandeln, IPv4 Adressen korrekt erkennen, IPv6 Adressen (inkl Kurzformen) korrekt erkennen, ...
Das müsste es dann schon gewesen sein.

beste Grüße
zommi