Конференция "Сети" » Дайте пример HTTP прокси на WinSock!! Без VCL/
 
  • ratatui (21.10.09 22:49) [0]
    Подскажите где можно скачать или дайте листинг!
    Спасибо!
  • Сергей М. © (22.10.09 08:59) [1]
    Чем же VCL не угодила ?
  • koha! (22.10.09 22:18) [2]
    Тем и не у годила, чтословно слон в посудной лавке, грамоздкая однако...
  • Anatoly Podgoretsky © (23.10.09 11:52) [3]
    А на написание прокси с нуля могут уйти годы, нормального конечно прокси.
  • Сергей М. © (23.10.09 12:03) [4]

    > на написание прокси с нуля могут уйти годы, нормального
    > конечно прокси


    Желающим "фраернуться перед кентами" годы не проблема)
  • CrytoGen (23.10.09 14:26) [5]
    а им не нужен нормальный прокси, им нужен не громоздкий :)
  • Palladin © (24.10.09 14:10) [6]
    Интересно, а что такое громоздкий прокси...
  • clickmaker © (26.10.09 11:09) [7]
    > что такое громоздкий прокси

    ну как... тот, который на VCL
  • SergP © (27.10.09 12:30) [8]

    > Подскажите где можно скачать или дайте листинг!


    У меня где-то валяется диск от одной книги Фленова. Там есть исходники простейшего http-прокси...
  • SergP © (27.10.09 12:36) [9]
    Щас Скопипащу это все сюда:
    main.pas

    unit MainUnit;

    interface

    uses
     Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
     Dialogs, StdCtrls, winsock;

    type
     THTTPProxyForm = class(TForm)
       bnStart: TButton;
       Label1: TLabel;
       edPort: TEdit;
       Label2: TLabel;
       edExtProxyAddr: TEdit;
       Label3: TLabel;
       edExtProxyPort: TEdit;
       procedure bnStartClick(Sender: TObject);
       procedure FormCreate(Sender: TObject);
     private
       { Private declarations }
     public
       { Public declarations }
     end;

    var
     HTTPProxyForm: THTTPProxyForm;

    implementation

    uses ServerThreadUnit;

    {$R *.dfm}

    procedure THTTPProxyForm.bnStartClick(Sender: TObject);
    var
    st:TServerThread;
    begin
    st:=TServerThread.Create(true);
    st.iLocalPort:=StrToIntDef(edPort.Text, 8088);
    st.iExtProxyPort:=StrToIntDef(edExtProxyPort.Text, 8080);
    st.sExtProxyAddr:=edExtProxyAddr.Text;
    st.Resume;
    end;

    procedure THTTPProxyForm.FormCreate(Sender: TObject);
    var
    wData : WSADATA;
    begin
    // Загрузка WinSock
    if WSAStartup(MAKEWORD(1,1), wData) <> 0 then
    begin
      MessageBox(0, 'Не могу загрузить WinSock', 'Ошибка', 0);
      exit;
    end;
    end;

    end.

  • SergP © (27.10.09 12:36) [10]
    ServerThreadUnit.pas

    unit ServerThreadUnit;

    interface

    uses
     Classes, winsock, windows;

    type
     TServerThread = class(TThread)
     private
       { Private declarations }
     protected
       procedure Execute; override;
     public
      iLocalPort, iExtProxyPort:Integer;
      sExtProxyAddr:String;
     end;

    implementation

    uses ClientThreadUnit;

    procedure TestWinSockError(S:String);
    var
    iErr:Integer;
    sFullErr:String;
    begin
    sFullErr:='Неизвестная ошибка';
    iErr:=WSAGetLastError();

    case iErr of
     WSANOTINITIALISED: sFullErr:='Нужно сначала вызвать функцию WSASturtup, а потом создавать сокет';
    WSAENETDOWN: sFullErr:='Cвязь нарушена, возможные причины - отошёл кабель или отключились от Интернета';
    WSAEADDRINUSE: sFullErr:='Указанный адрес уже используется';
    WSAEFAULT: sFullErr:='Параметры name и namelen не соответствуют выбранной адресации. Параметр namelen может быть меньше необходимого значения, а name содержать некорректные данные';
    WSAEINPROGRESS: sFullErr:='Выполняется операция в блокирующем режиме. Вы уже запустили на выполнение какую-то функцию и нужно дождаться завершения её работы';
    WSAEINVAL: sFullErr:='Сокет уже связан с адресом';
    WSAENOBUFS: sFullErr:='Недостаточно буферов, слишком много соединений';
    WSAENOTSOCK: sFullErr:='Неверный дескриптор сокета';
     WSAEISCONN: sFullErr:='Сокет уже подключён';
     WSAEMFILE: sFullErr:='Нет больше доступных дескрипторов';
    end;

    MessageBox(0, PChar('Ошибка в функции '+S+' - '+sFullErr), 'Ошибка', 0);
    end;

    function TestFuncError(iErr:Integer; FuncName:String):Boolean;
    begin
    Result:=false;
    if iErr = SOCKET_ERROR then
     begin
      TestWinSockError(FuncName);
      Result:=true;
     end;
    end;

    procedure TServerThread.Execute;
    var
    sServerListen, stClientSocket : TSOCKET;
    localaddr : sockaddr_in;
    ct : TClientThread;
    begin
    // Создание сокета
    sServerListen := socket(AF_INET, SOCK_STREAM, 0);
    if sServerListen = INVALID_SOCKET then
     begin
      MessageBox(0, 'Ошибка создания сокета', 'Ошибка', 0);
      exit;
     end;

    // Запонение структуры адреса
    localaddr.sin_addr.s_addr := htonl(INADDR_ANY);
    localaddr.sin_family := AF_INET;
    localaddr.sin_port := htons(iLocalPort);

    // Связывание сокета с локальным адресом
    if TestFuncError(bind(sServerListen, localaddr, sizeof(localaddr)), 'bind') then
     exit;

    if TestFuncError(listen(sServerListen, 4), 'Listen') then
     exit;

    while true do
     begin
      stClientSocket := accept(sServerListen, nil, nil);
      if stClientSocket=INVALID_SOCKET then
       continue;

      ct:=TClientThread.Create(true);
      ct.stClient := stClientSocket;
      ct.iExtProxyPort := iExtProxyPort;
      ct.sExtProxyAddr := sExtProxyAddr;
      ct.Resume;
     end;
    end;

    end.

  • SergP © (27.10.09 12:37) [11]
    ClientThreadUnit.pas

    unit ClientThreadUnit;

    interface

    uses
     Classes, winsock, sysutils, windows;

    type
     TClientThread = class(TThread)
     private
       { Private declarations }
     protected
       procedure Execute; override;
     public
       iExtProxyPort:Integer;
       sExtProxyAddr:String;
       stClient:TSocket;
     end;

    implementation

    { TClientThread }

    function LookupName(name:String): TInAddr;
    var
    HostEnt: PHostEnt;
    InAddr: TInAddr;
    begin
    if name[4]='.' then
     InAddr.s_addr := inet_addr(PChar(name))
    else
     begin
     HostEnt := gethostbyname(PChar(name));
     FillChar(InAddr, SizeOf(InAddr), 0);
     if HostEnt <> nil then
      begin
       with InAddr, HostEnt^ do
        begin
         S_un_b.s_b1 := h_addr^[0];
         S_un_b.s_b2 := h_addr^[1];
         S_un_b.s_b3 := h_addr^[2];
         S_un_b.s_b4 := h_addr^[3];
        end;
      end
     end;
     Result := InAddr;
    end;

    procedure SendStr(s:TSocket; str:String);
    var
    sRecvBuff : array [0..255] of char;
    TempStr : AnsiString;
    begin
    TempStr:=str+#13+#10;
    CopyMemory(@sRecvBuff, PChar(TempStr), Length(TempStr));
    send(s, sRecvBuff, Length(TempStr), 0);
    end;

    procedure TClientThread.Execute;
    var
    Buff: array [0..1024] of char;
    iPort: Integer;
    sRequest, sHost:String;
    server_addr : sockaddr_in;
    sock_server : TSocket;
    iMode, iSize : Integer;
    rfds : TFDSET;
    begin
    ////////////////////////////
    //Считывание заголовка
    Recv(stClient, Buff, 1024, 0);

    sRequest:=String(Buff);

    // Нет заголовка
    if sRequest='' then
     begin
      CloseSocket(stClient);
      exit;
     end;

    ////////////////////////////
    // Выдераем адрес сервера и порт
    sHost:=Copy(sRequest, Pos('Host: ', sRequest), 255);
    Delete(sHost, Pos(#13, sHost), 255);
    Delete(sHost, 1, 6);
    iPort:=StrToIntDef(Copy(sHost, Pos(':', sHost)+1, 255), 80);
    Delete(sHost, Pos(':', sHost), 255);

    // Если не найден host то ошибка
    if sHost='' then
     begin
      SendStr(stClient, 'HTTP/1.0 400 Invalid header received from browser');
      CloseSocket(stClient);
      exit;
     end;

    // Если есть внешний проксик, то перенаправляем на него
    if sExtProxyAddr<>'' then
     begin
       iPort := iExtProxyPort;
       sHost := sExtProxyAddr;
     end;

    sock_server := socket(AF_INET, SOCK_STREAM, 0);

    // Ищем сервер/проксик
    server_addr.sin_addr.s_addr := htonl(INADDR_ANY);
    server_addr.sin_family := AF_INET;
    server_addr.sin_port := htons(iPort);
    server_addr.sin_addr := LookupName(sHost);

    //Соединение с сервером
    if connect(sock_server, server_addr, sizeof(server_addr))=SOCKET_ERROR then
     begin
      SendStr(stClient, '404 Host Not Found');
      exit;
     end;

    iMode:=1;
    setsockopt(sock_server, IPPROTO_TCP, TCP_NODELAY, @iMode, sizeof (integer));

    // Перенаправляем запрос серверу или другому проксику
    send(sock_server, buff, strlen(buff),0);

    // Теперь работаем посредником между клиентом и сервером
    // передавая запрошенные данные
    while true do
     begin
      // Добавляем сокеты в набор для ожидания
      FD_ZERO(rfds);
      FD_SET(stClient, rfds);
      FD_SET(sock_server, rfds);

      if (select(0, @rfds, nil, nil, nil) < 0) then
       exit;

      // Если пришел запрос от клиента
      // то перенаправляем серверу
      if(FD_ISSET(stClient, rfds)) then
     begin
      iSize := recv(stClient, buff, sizeof(buff), 0);

         if iSize=-1 then break;

      Send(sock_server, buff, iSize, 0);
      continue;
     end;

      // Если пришли данные от сервера
      // то перенаправляем клиенту
      if(FD_ISSET(sock_server, rfds)) then
     begin
      iSize := recv(sock_server, buff, sizeof(buff), 0);

         // Сервер уже всё выслал
         if iSize=0 then
          exit;

      Send(stClient, buff, iSize, 0);
      continue;
     end;
     end;
    CloseSocket(stClient);
    CloseSocket(sock_server);
    end;

    end.


  • SergP © (27.10.09 12:40) [12]

    > main.pas


    MainUnit.pas

    Ну и если понадобиться, то:

    MainUnit.dfm
    object HTTPProxyForm: THTTPProxyForm
     Left = 260
     Top = 107
     BorderStyle = bsSingle
     Caption = 'Proxy'
     ClientHeight = 145
     ClientWidth = 314
     Color = clBtnFace
     Font.Charset = DEFAULT_CHARSET
     Font.Color = clWindowText
     Font.Height = -11
     Font.Name = 'MS Sans Serif'
     Font.Style = []
     OldCreateOrder = False
     OnCreate = FormCreate
     PixelsPerInch = 96
     TextHeight = 13
     object Label1: TLabel
       Left = 8
       Top = 16
       Width = 25
       Height = 13
       Caption = #1055#1086#1088#1090
     end
     object Label2: TLabel
       Left = 8
       Top = 80
       Width = 105
       Height = 13
       Caption = #1040#1076#1088'. '#1074#1085#1077#1096'. '#1087#1088#1086#1082#1089#1080#1082#1072
     end
     object Label3: TLabel
       Left = 8
       Top = 48
       Width = 108
       Height = 13
       Caption = #1055#1086#1088#1090' '#1074#1085#1077#1096'. '#1087#1088#1086#1082#1089#1080#1082#1072
     end
     object bnStart: TButton
       Left = 120
       Top = 112
       Width = 75
       Height = 25
       Caption = #1047#1072#1087#1091#1089#1082
       TabOrder = 0
       OnClick = bnStartClick
     end
     object edPort: TEdit
       Left = 128
       Top = 16
       Width = 177
       Height = 21
       TabOrder = 1
       Text = '8080'
     end
     object edExtProxyAddr: TEdit
       Left = 128
       Top = 80
       Width = 177
       Height = 21
       TabOrder = 3
       Text = '192.168.8.88'
     end
     object edExtProxyPort: TEdit
       Left = 128
       Top = 48
       Width = 177
       Height = 21
       TabOrder = 2
       Text = '8080'
     end
    end

  • Сергей М. © (27.10.09 14:38) [13]

    > //Считывание заголовка
    > Recv(stClient, Buff, 1024, 0);
    >
    > sRequest:=String(Buff);


    Не надо учить людей плохому.
  • SergP © (27.10.09 15:20) [14]

    > Не надо учить людей плохому.


    ну я человеку только скопипастил Фленова.... Без отсебятины...

    А вообще ИМХО иногда лучше научить плохому, чем вообще не научить ничему...
  • Сергей М. © (27.10.09 15:50) [15]

    > я только скопипастил

    .. и оказал тем самым медвежью услугу
  • Anatoly Podgoretsky © (27.10.09 16:08) [16]

    > ну я человеку только скопипастил Фленова

    Нала дура чем хвастаться
    (с) известный анекдот
  • Dennis I. Komarov © (27.10.09 17:51) [17]

    > иногда лучше научить плохому, чем вообще не научить ничему.
    > ..

    Глупость несусветная...
  • Anatoly Podgoretsky © (28.10.09 10:32) [18]
    > Dennis I. Komarov  (27.10.2009 17:51:17)  [17]

    Да он в соучастники и в сокамерники напрашивается.
  • SergP © (28.10.09 19:58) [19]

    > Нала дура чем хвастаться
    > (с) известный анекдот


    > Глупость несусветная...


    > Да он в соучастники и в сокамерники напрашивается.


    О. Какие содержательные ответы.


    > Сергей М. ©   (27.10.09 15:50) [15]
    >
    >
    > > я только скопипастил
    >
    > .. и оказал тем самым медвежью услугу


    А почему сразу медвежью услугу?
    Человек просил листинг, и я ему его дал...
    По крайней мере для начала это уже кое что...
    А то, что у г-на Фленова имеются некоторые ошибки, так это даже хорошо...
    Человеку будет над чем подумать: как это исправить чтобы работало.
    А что касается этого:

    > > //Считывание заголовка
    > > Recv(stClient, Buff, 1024, 0);
    > >
    > > sRequest:=String(Buff);
    >


    то думаю что вопрошающий сам увидит что:
    1. Не факт, что 1 кбайта хватит для хранения заголовка, ибо заголовок может быть длинее (особенно когда куки большие), и тогда значение поля "Host" может и не попасть в sRequest.
    2.  Не факт, что весь запрос будет >= 1 кбайту. (в таком случае в конце sRequest будет всякий мусор, который мы отправим на сервер).
    3. Не факт что при вызове Recv мы успели получить необходимую часть заголовка. Т.е. нужно ждать пока гарантированно не получим нужную часть заголовка.
    Не знаю конечно почему Фленов опубликовал свой код в таком виде... Может у него при тестировании браузер выдавал корректные с точки зрения его прокси-сервера запросы, или еще что-нить.
    Но тем не менее у топикстартера уже будет хоть что-то для начала и далее он будет пытаться уже сам исправить это, или задавать уже конкретные вопросы.
    Заодно обнаружит и исправит и прочие ошибки, которые там имеются...

    ну а если уважаемый АП считает, что такой метод помощи в корне неверен, у него имеется полное право удалить мои сообщения.
 
Конференция "Сети" » Дайте пример HTTP прокси на WinSock!! Без VCL/
Есть новые Нет новых   [134427   +35][b:0.001][p:0.013]