Написать Indy 10 кодов Delphi для C ++ Builder's Indy 10

Я новичок в изучении C ++ Builder. Три дня назад я установил Embarcadero®. C++Builder® 2010. Мне очень интересно изучать этот язык.

В Delphi я обычно пишу простой прокси-сервер с использованием TIdMappedPortTCP из Indy 9 и 10. Обычно я использую его события OnExecute и OnOutboundData для изменения данных, когда они проходят через прокси.

Так как я новичок в C ++ Builder, я не знаю, как преобразовать мой Delphi-код в абсолютно правильный код C ++ Builder.

Я пробовал и пробовал много способов, включая чтение нескольких книг, одной из которых является Borland C ++ Builder - The Complete Reference от Герберта Шильдта, а также для увеличения знаний. К сожалению, в книге вообще не обсуждались очень важные вещи, связанные с моим состоянием. Кроме того, я нахожу ссылки на Google, но я не нашел.

Итак, я рискнул попросить вашей помощи. Мне это действительно нужно. Пожалуйста помоги! Большое спасибо.

Ниже приведен код Delphi моей Indy 10, который я хочу написать в C ++ Builder.

......

procedure TForm.IdMappedPortTCP1Execute(AContext: TIdContext);
var
Mydata, NetData: string;
begin
  if (Pos('HTTP',netstring(AContext)) <> 0) or (Pos('GET',netstring(AContext)) <> 0) then begin
   NetData := netstring(AContext);
   TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(AddHeader(netstring(AContext),'Connection: Keep-Alive'));
     Sleep(1000);
     Mydata  := 'GET http://website.com/ HTTP/1.1'+#13#10+'Host: website.com'#13#10;
     NetData := Mydata + Netdata;
   TIdMappedPortContext(AContext).NetData := netbyte(Netdata);
   TIdMappedPortContext(AContext).OutboundClient.IOHandler.Write(netbyte(Mydata + NetData));
  end;
end;

......

1 ответ

Решение

Дословный перевод на C++Builder будет выглядеть так:

......

String __fastcall AddHeader(String S, String Header)
{
    S = StringReplace(S, "\r\n\r\n", "\r\n" + Header + "\r\n\r\n", TReplaceFlags() << rfReplaceAll);
    return S;
}

void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
    String Mydata, NetData;

    if ((netstring(AContext).Pos("HTTP") != 0) || (netstring(AContext).Pos("GET") != 0))
    {
        NetData = netstring(AContext);
        TIdMappedPortContext(AContext)->OutboundClient->IOHandler->Write(AddHeader(netstring(AContext), "Connection: Keep-Alive"));
        Sleep(1000);
        Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n";
        NetData = Mydata + Netdata;
        static_cast<TIdMappedPortContext*>(AContext)->NetData = netbyte(Netdata);
        static_cast<TIdMappedPortContext*>(AContext)->OutboundClient->IOHandler->Write(netbyte(Mydata + NetData));
    }
}

......

Вот слегка сжатая версия:

......

String __fastcall AddHeader(String S, String Header)
{
    return StringReplace(S, "\r\n\r\n", "\r\n" + Header + "\r\n\r\n", TReplaceFlags() << rfReplaceAll);
}

void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
    String NetData = netstring(AContext);
    if ((NetData.Pos("HTTP") != 0) || (NetData.Pos("GET") != 0))
    {
        Sleep(1000);
        String Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n" + AddHeader(NetData, "Connection: Keep-Alive");
        static_cast<TIdMappedPortContext*>(AContext)->NetData = netbyte(Mydata);
    }
}

......

Но в любом случае, это определенно НЕ надежный способ реализации жизнеспособного HTTP-прокси в Indy. На самом деле, Indy 10 представила конкретный TIdHTTPProxyServer компонент для этой цели. Вы должны серьезно рассмотреть возможность использования этого вместо TIdMappedPortTCP, Например, вышесказанное можно сделать в TIdHTTPProxyServer как это:

class TIdHTTPProxyServerContextAccess : public TIdHTTPProxyServerContext
{
public:
    void SetCommand(String Value) { FCommand = Value; }
    void SetDocument(String Value) { FDocument = Value; }
    void SetTarget(String Value) { FTarget = Value; }
};

void __fastcall TForm1.IdHTTPProxyServer1HTTPBeforeCommand(TIdHTTPProxyServerContext *AContext)
{
    static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetCommand("GET");
    static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetTarget ("http://website.com/");
    static_cast<TIdHTTPProxyServerContextAccess*>(AContext)->SetDocument("/");

    AContext->Headers->Values["Host"] = "website.com";
    AContext->Headers->Values["Connection"] = "Keep-Alive";

    /*
    the original code was not changing the Host/Port where the
    HTTP request was being sent to.  But if you needed to,
    you can do it like this... 

    static_cast<TIdTCPClient*>(AContext->OutboundClient)->Host = "website.com";
    static_cast<TIdTCPClient*>(AContext->OutboundClient)->Port = 80;
    */
}

Обновление: netstring() а также netbyte() функции, с которыми вы связаны, имеют синтаксические ошибки и лишние накладные расходы (нет необходимости задействовать MIME просто для преобразования строки в байтовый массив и наоборот, в Indy есть функции специально для этой цели). Вот исправленные версии:

String __fastcall netstring(TIdMappedPortContext* AContext)
{
    return BytesToStringRaw(AContext->NetData);
}

TIdBytes __fastcall netbyte(String S)
{
    return ToBytes(S, IndyTextEncoding_8Bit());
}

Таким образом, вы могли бы просто полностью исключить функции:

void __fastcall TForm::IdMappedPortTCP1Execute(TIdContext *AContext)
{
    TIdMappedPortContext *ctx = static_cast<TIdMappedPortContext*>(AContext)
    String NetData = BytesToStringRaw(ctx->NetData);
    if ((NetData.Pos("HTTP") != 0) || (NetData.Pos("GET") != 0))
    {
        Sleep(1000);
        String Mydata = "GET http://website.com/ HTTP/1.1\r\nHost: website.com\r\n" + AddHeader(NetData, "Connection: Keep-Alive");
        ctx->NetData = ToBytes(Mydata);
    }
}
Другие вопросы по тегам