2008-12-11 10 views
12

muszę utworzyć żądanie strony internetowej dostarczanej do naszych stron internetowych, ale muszę być w stanie ustawić informacje nagłówka hosta też. Próbowałem to za pomocą HttpWebRequest, ale informacje nagłówka jest tylko do odczytu (lub przynajmniej część Host jest). Muszę to zrobić, ponieważ chcemy wykonać wstępne żądanie strony, zanim użytkownik będzie mógł to zrobić. Mamy 10 serwerów WWW, które są zrównoważone pod względem obciążenia, więc musimy poprosić o plik z każdego z serwerów WWW.Zapytanie Strona internetowa w języku C# fałszowanie Hostię

Próbowałem następujące:

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm"); 
request.Headers.Set("Host", "www.mywebsite.com"); 
WebResponse response = request.GetResponse(); 

Oczywiście to nie działa, ponieważ nie mogę zaktualizować nagłówek, a ja nie wiem, czy to jest rzeczywiście dobry sposób, żeby to zrobić.

+0

To pytanie jest bardzo blisko związane z http://stackoverflow.com/ pytania/323264/http-request-bypass-dns-net Może ktoś powinien zamknąć to jako duplikat? –

Odpowiedz

9

udało mi się dowiedzieć, bardziej długi dmuchania trasę za pomocą gniazd. Znalazłem odpowiedź na stronie MSDN dla IPEndPoint:

string getString = "GET /path/mypage.htm HTTP/1.1\r\nHost: www.mysite.mobi\r\nConnection: Close\r\n\r\n"; 
Encoding ASCII = Encoding.ASCII; 
Byte[] byteGetString = ASCII.GetBytes(getString); 
Byte[] receiveByte = new Byte[256]; 
Socket socket = null; 
String strPage = null; 
try 
{ 
    IPEndPoint ip = new IPEndPoint(IPAddress.Parse("10.23.1.93"), 80); 
    socket = new Socket(ip.AddressFamily, SocketType.Stream, ProtocolType.Tcp); 
    socket.Connect(ip); 
} 
catch (SocketException ex) 
{ 
    Console.WriteLine("Source:" + ex.Source); 
    Console.WriteLine("Message:" + ex.Message); 
} 
socket.Send(byteGetString, byteGetString.Length, 0); 
Int32 bytes = socket.Receive(receiveByte, receiveByte.Length, 0); 
strPage = strPage + ASCII.GetString(receiveByte, 0, bytes); 

while (bytes > 0) 
{ 
    bytes = socket.Receive(receiveByte, receiveByte.Length, 0); 
    strPage = strPage + ASCII.GetString(receiveByte, 0, bytes); 
} 
socket.Close(); 
0

porządku, trochę badań okazuje się następująco:

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=384456

Wydaje MS może coś z tym zrobić w pewnym momencie.

+0

Otrzymuję wyjątek "ArgumentException: nagłówek" Host "nie może być bezpośrednio modyfikowany Nazwa parametru: name". Zakładam, że jest on odczytywany tylko w HttpWebRequest klasy – Xetius

+0

W dół głosowania, ponieważ ta odpowiedź nie działa. –

+0

Czy nie byłoby lepiej stworzyć nową odpowiedź niż cofnąć i całkowicie przepisać swoją starą? –

0

„host” header są chronione i nie mogą być zmieniane programowo. Przypuszczam, aby obejść ten problem, można spróbować związać poprzez odbicie do prywatnej „InnerCollection” własność WebRequest obiektu i wywołanie „Set” ar „Dodaj” metodę na nim modyfikacji nagłówka Host. Nie próbowałem tego, ale z szybkiego spojrzenia na kod źródłowy w Reflectorze, myślę, że jest to łatwe do wykonania. Ale tak, wiązanie z prywatnymi właściwościami obiektów szkieletowych nie jest najlepszym sposobem na osiągnięcie celów. :) Używaj tylko, jeśli MUSISZ.

edit: Albo jak inny facet wspomina w połączonego pytanie, wystarczy otworzyć gniazdo i zrobić szybkie „GET” ręcznie. Powinien to być nie myślenia, jeśli nie musisz majstrować przy innych rzeczach, takich jak ciasteczka czy cokolwiek innego, co zapewnia HttpWebRequest.

2

wiem, że to jest stary, ale natknąłem się na ten sam dokładnym problemu i znalazłem lepsze rozwiązanie tego Następnie za pomocą gniazd lub refleksji ...

Co zrobiłem było utworzyć nową klasę, która durives z WebHeaderCollection i omija sprawdzanie tego, co trzymasz w środku:

public class MyHeaderCollection:WebHeaderCollection 
{ 
    public new void Set(string name, string value) 
    { 
     AddWithoutValidate(name, value); 
    } 
    //or 
    public new string this[string name] 
    { 
     get { return base[name]; } 
     set { AddWithoutValidate(name, value); } 
    } 
} 

i oto jak go używać:

var http = WebRequest.Create("http://example.com/"); 
    var headers = new MyHeaderCollection(); 
    http.Headers = headers; 

    //Now you can add/override anything you like without validation: 
    headers.Set("Host", http.RequestUri.Host); 
    //or 
    headers["Host"] = http.RequestUri.Host; 

Nadzieja to pomaga ktoś patrząc na to!

+2

To nie działa w 3.5SP1 - kolekcja przekazana do nagłówków nie jest zachowywana, zostaje skopiowana do nowej kolekcji WebHeaderCollection, więc wszystkie nagłówki zostają ponownie zatwierdzone. – nitzmahone

4

miałem problem gdzie dns URL Kiedyś miałem kilka różnych adresów IP, chciałem zadzwonić każdy adres oddzielnie przy użyciu tej samej nazwy DNS hosta - rozwiązaniem jest użycie serwera proxy:

string retVal = ""; 
      // Can't change the 'Host' header property because .NET protects it 
      // HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 
      // request.Headers.Set(HttpRequestHeader.Host, DEPLOYER_HOST); 
      // so we must use a workaround 
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 
      request.Proxy = new WebProxy(ip); 
      using (WebResponse response = request.GetResponse()) 
      { 
       using (TextReader reader = new StreamReader(response.GetResponseStream())) 
       { 
        string line; 
        while ((line = reader.ReadLine()) != null) 
         retVal += line; 
       } 
      } 
      return retVal; 

Nagłówek hosta jest automatycznie ustawiany z "adresu URL".NET, a „ip” zawiera rzeczywisty adres serwera WWW, którą chcesz się skontaktować (można użyć nazwy DNS tutaj zbyt)

+2

Oczywiście to nie zadziała, gdy będziemy musieli używać proxy :) –

10

Chociaż jest to bardzo późno odpowiedź, może ktoś może uzyskać korzyści z niego

HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri("http://192.168.1.1")); 
request.Headers.GetType().InvokeMember("ChangeInternal", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod, null, request.Headers, new object[] {"Host","www.mysite.com"}); 

Odbicie jest twoim przyjacielem :)

+0

LB - to jest fajne, jestem nowy w C# i nie wiem, co jest refleksją i jak twoja odpowiedź zadziałała dla mnie – xameeramir

+0

Uwaga: To się zmieni hosta, ale zostanie nadpisany wartością w adresie URL, do którego wysłałeś żądanie. – User1

1

Wiem, że to stare pytanie, ale w dzisiejszych czasach możesz to zrobić.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://192.168.1.5/filename.htm"); 
request.Host = "www.mywebstite.com"; 
WebResponse response = request.GetResponse(); 
1

Nekromowanie.
Dla tych, którzy wciąż na .NET 2.0
Jest to w rzeczywistości dość łatwe, jeśli wiesz jak.

Problem polega na tym, że nie można ustawić nagłówka hosta, ponieważ struktura nie pozwala na zmianę wartości w czasie wykonywania. (.net framework 4.0+ pozwoli ci przesłonić hosta w httpwebrequest).

Następną próbą będzie ustawienie nagłówka z odbiciem - tak jak zademonstrowano w górnym przegłosowanym odpowiedzi tutaj - w celu obejścia go, co pozwoli ci zmienić wartość nagłówka. Ale przy starcie, to będzie nadpisać ta wartość z części hosta z url, co oznacza odbicie przyniesie ci nic, dlatego ja nie rozumiem, dlaczego ludzie zachować się głosowanie to.

Jeśli nazwa dns nie istnieje, co jest szczerym jedynym przypadkiem, w którym chcesz to zrobić w pierwszej kolejności, nie możesz jej ustawić, ponieważ .NET nie może go rozwiązać, i nie można przesłonić resolwera .NET DNS.

Ale możesz ustawić webproxy z tym samym adresem IP co serwer docelowy.

Dlatego, jeśli IP serwera jest 28.14.88.71:

public class myweb : System.Net.WebClient 
{ 
    protected override System.Net.WebRequest GetWebRequest(System.Uri address) 
    { 
     System.Net.WebRequest request = (System.Net.WebRequest)base.GetWebRequest(address); 
     //string host = "redmine.nonexistantdomain.com"; 

     //request.Headers.GetType().InvokeMember("ChangeInternal", 
     // System.Reflection.BindingFlags.NonPublic | 
     // System.Reflection.BindingFlags.Instance | 
     // System.Reflection.BindingFlags.InvokeMethod, null, 
     // request.Headers, new object[] { "Host", host } 
     //); 

     //server IP and port 
     request.Proxy = new System.Net.WebProxy("http://28.14.88.71:80"); 

     // .NET 4.0 only 
     System.Net.HttpWebRequest foo = (System.Net.HttpWebRequest)request; 
     //foo.Host = host; 

     // The below reflection-based operation is not necessary, 
     // if the server speaks HTTP 1.1 correctly 
     // and the firewall doesn't interfere 
     // https://yoursunny.com/t/2009/HttpWebRequest-IP/ 
     System.Reflection.FieldInfo horribleProxyServicePoint = (typeof(System.Net.ServicePoint)) 
      .GetField("m_ProxyServicePoint", System.Reflection.BindingFlags.NonPublic | 
      System.Reflection.BindingFlags.Instance); 

     horribleProxyServicePoint.SetValue(foo.ServicePoint, false); 
     return foo; // or return request; if you don't neet this 
    } 


    } 

i voila, teraz

myweb wc = new myweb(); 
string str = wc.DownloadString("http://redmine.netexistantdomain.com"); 

i masz odpowiednią stronę z powrotem, jeśli 28.14.88.71 jest serwer WWW z wirtualnym hosting oparty na nazwach (oparty na nagłówku hosta http).

Teraz masz poprawną odpowiedź na oryginalne pytanie, zarówno dla WebRequest, jak i WebClient. Myślę, że używanie niestandardowych gniazd do tego byłoby niewłaściwym podejściem, szczególnie gdy powinno się używać SSL, a gdy rzeczywiste rozwiązanie jest tak proste ...

Powiązane problemy