Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Implementierungsfrage zu Uri, HttpUrl und HttpServer
BlackMatrix
myCSharp.de - Member



Dabei seit:
Beiträge: 218

Themenstarter:

Implementierungsfrage zu Uri, HttpUrl und HttpServer

beantworten | zitieren | melden

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
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von BlackMatrix am .
private Nachricht | Beiträge des Benutzers
Abt
myCSharp.de - Team

Avatar #avatar-4119.png


Dabei seit:
Beiträge: 15.928

beantworten | zitieren | melden

Zitat von BlackMatrix
Genug erzählt, nun gibts Code:
Gibts auch ne Frage?
[Hinweis] Wie poste ich richtig? Punkt 5
Zitat von BlackMatrix
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.
private Nachricht | Beiträge des Benutzers
MarsStein
myCSharp.de - Experte

Avatar #avatar-3191.gif


Dabei seit:
Beiträge: 3.170
Herkunft: Trier -> München

beantworten | zitieren | melden

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
private Nachricht | Beiträge des Benutzers
BlackMatrix
myCSharp.de - Member



Dabei seit:
Beiträge: 218

Themenstarter:

beantworten | zitieren | melden

Zitat von Abt
Zitat von BlackMatrix
Beispielsweise soll "http://www.example.net" == "http://example.net/" sein.
Das ist technisch gesehen falsch.

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.
Zitat von Abt
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.
Zitat von Abt
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.
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von BlackMatrix am .
private Nachricht | Beiträge des Benutzers
zommi
myCSharp.de - Member

Avatar #avatar-2617.png


Dabei seit:
Beiträge: 1.361
Herkunft: Berlin

beantworten | zitieren | melden

Hi BlackMatrix,
Zitat von 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
private Nachricht | Beiträge des Benutzers