Show / Hide Table of Contents

MSDN.WhiteKnight - Stack Overflow answers

Ответ на "Какой POST/GET запрос выполняется при нажатии кнопки на сайте?"

Answer 1171116

Link

В WebBrowser, конечно, нет функционала для получения HTTP-запросов. Обычно для этих целей используют специальные программы, веб-отладчики. Но кое-какое решение можно состряпать и самостоятельно. Ключ к решению здесь - управляющий код SIO_RCVALL в WinSock, который позволяет прослушивать через сокет все IP-пакеты на сетевом интерфейсе. Основа решения описана здесь: https://ru.stackoverflow.com/a/1019378/240512, в данном ответе мы добавим, помимо заголовков запросов, прослушивание их содержимого:

using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Net.NetworkInformation;

namespace WpfTest
{
    public partial class MainWindow : Window
    {
        string navigated_host = ""; //последний сайт, на который перешел WebBrowser
        IPAddress target_ip=null; //IP адрес последнего сервера, к которому обратился WebBrowser
        object sync = new object();

        public MainWindow()
        {
            InitializeComponent();
            webbrowser.Navigating += webbrowser_Navigating;

            var ips = GetIpAddresses();

            foreach (IPAddress ip in ips)
            {
                Thread th = new Thread(ThreadProc);
                th.IsBackground = true;
                th.Start((object)ip);
            }

        }

        void TextBoxWriteLine(string s)
        {
            this.Dispatcher.Invoke(() =>
            {
                textbox.Text += s + Environment.NewLine;
            });
        }

        void webbrowser_Navigating(object sender, System.Windows.Navigation.NavigatingCancelEventArgs e)
        {
            lock (sync)
            {
                navigated_host = e.Uri.Host;
            }
        }

        //Получает все локальные IP-адреса
        public static List<IPAddress> GetIpAddresses()
        {
            List<IPAddress> res = new List<IPAddress>(10);

            var ifs = NetworkInterface.GetAllNetworkInterfaces();

            foreach (var interf in ifs)
            {
                var ipprop = interf.GetIPProperties();
                if (ipprop == null) continue;
                var unicast = ipprop.UnicastAddresses;
                if (unicast == null) continue;

                //находим первый Unicast-адрес
                foreach (var addr in unicast)
                {
                    if (addr.Address.AddressFamily != AddressFamily.InterNetwork) continue;
                    res.Add(addr.Address);
                    break;
                }
            }

            return res;
        }

        const byte PROTO_TCP = 6;

        public string ParseIpPacket(byte[] data, IPAddress src_ip)
        {
            ushort dummy;
            byte b;

            MemoryStream ms = new MemoryStream(data);
            BinaryReader br = new BinaryReader(ms);
            uint header_len;
            uint total_len;
            IPAddress src, dst;
            string host = "";

            //parse IP packet header
            using (ms)
            using (br)
            {
                b = br.ReadByte();
                byte ver = (byte)((b & (byte)0xF0) >> 4); //IP version
                if (ver != 4)
                {
                    TextBoxWriteLine("Unsupported IP version: " + ver.ToString());
                    return null;
                }

                byte ihl = (byte)(b & (byte)0x0F);//header length
                header_len = ihl * 4u;

                b = br.ReadByte();

                //packet length
                byte[] temp = new byte[2];
                temp[1] = br.ReadByte();
                temp[0] = br.ReadByte();
                total_len = BitConverter.ToUInt16(temp, 0);

                dummy = br.ReadUInt16();
                dummy = br.ReadUInt16();

                byte ttl = br.ReadByte();
                byte proto = br.ReadByte();

                dummy = br.ReadUInt16();

                //source IP
                temp = new byte[4];
                temp[0] = br.ReadByte();
                temp[1] = br.ReadByte();
                temp[2] = br.ReadByte();
                temp[3] = br.ReadByte();
                src = new IPAddress(temp);

                //destination IP
                temp[0] = br.ReadByte();
                temp[1] = br.ReadByte();
                temp[2] = br.ReadByte();
                temp[3] = br.ReadByte();
                dst = new IPAddress(temp);

                if (proto != PROTO_TCP) return null;
            }

            //Parse TCP packet
            uint tcp_size = total_len - header_len;
            byte[] tcp_data = new byte[tcp_size];
            Array.Copy(data, header_len, tcp_data, 0, tcp_size);

            ms = new MemoryStream(tcp_data);
            br = new BinaryReader(ms);
            byte tcp_header_size;
            uint http_size;

            using (ms)
            using (br)
            {
                var src_port = br.ReadUInt16();
                var dst_port = br.ReadUInt16();
                br.ReadUInt32();
                br.ReadUInt32();
                tcp_header_size = (byte)(br.ReadByte() >> 4);
                tcp_header_size *= 4;
                http_size = tcp_size - tcp_header_size;
            }

            byte[] http_data = new byte[http_size];
            Array.Copy(tcp_data, tcp_header_size, http_data, 0, http_size);

            //Parse HTTP data
            string res = Encoding.UTF8.GetString(http_data);

            lock (this.sync)
            {
                //если IP-адрес соответствует сохраненному адресу сервера, возвращаем содержимое запроса
                if (dst.Equals(this.target_ip))
                {
                    return res;
                }
            }

            string[] arr = res.Split("\n\r".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
                        
            if (arr.Length > 2 && arr[0].Contains("HTTP/"))
            {
                //найдем поле Host
                for (int i = 1; i < arr.Length; i++)
                {
                    if (arr[i].StartsWith("Host: "))
                    {
                        host = arr[i].Replace("Host: ", "");
                        break;
                    }
                }

                if (host == "")
                {
                    //пытаемся получить имя узла из обратного DNS
                    try
                    {
                        host = Dns.GetHostEntry(dst).HostName;
                    }
                    catch (SocketException)
                    {
                        host = "";
                    }
                }

                lock (sync)
                {
                    if (host == navigated_host)
                    {
                        //если поле host соответствует сайту, на который перешел веб-браузер, сохраняем IP сервера
                        this.target_ip = dst;

                        //возвращаем содержимое запроса
                        return res;
                    }
                }
            }

            return null;
        }

        public void ThreadProc(object args)
        {
            var mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw,
                       ProtocolType.IP);

            IPAddress ipaddr = (IPAddress)args;

            //начинаем прослушивание пакетов на интерфейсе...
            mainSocket.Bind(new IPEndPoint(ipaddr, 0));

            mainSocket.SetSocketOption(SocketOptionLevel.IP,  //Applies only to IP packets
                           SocketOptionName.HeaderIncluded, //Set the include header
                           true);                           //option to true

            byte[] byTrue = new byte[4] { 1, 0, 0, 0 };
            byte[] byOut = new byte[4];

            //Socket.IOControl is analogous to the WSAIoctl method of Winsock 2
            mainSocket.IOControl(IOControlCode.ReceiveAll,  //SIO_RCVALL of Winsock
                     byTrue, byOut);

            byte[] buffer = new byte[1024 * 20];
            int res;

            while (true)
            {
                try
                {
                    res = mainSocket.Receive(buffer);

                    var result = ParseIpPacket(buffer, ipaddr);

                    if (result != null)
                    {
                        TextBoxWriteLine(result);
                    }
                }
                catch (Exception ex)
                {
                    if (ex.GetType() != typeof(System.Threading.Tasks.TaskCanceledException))
                    {
                        TextBoxWriteLine(ex.ToString());
                    }
                }
            }
        }

        private void Button1_Click(object sender, RoutedEventArgs e)
        {
            webbrowser.Navigate("http://example.com/");
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            this.Close();
        }
    }
}

Ограничения решения:

  • Работает только с IPv4-интерфейсами
  • Работает только протоколом HTTP (не HTTPS)
  • Для запуска требуются права администратора

Content is retrieved from StackExchange API.

Auto-generated by ruso-archive tools.

Back to top Stack Overflow answers (published from sources in GitHub repository). Copyright (c) 2020, MSDN.WhiteKnight. Content licensed under BSD 3-Clause License.
Generated by DocFX