Rectangle 27 18

TIdMultipartFormDataStream
procedure TForm1.SendPostData;
var
  Stream: TStringStream;
  Params: TIdMultipartFormDataStream;
begin
  Stream := TStringStream.Create('');
  try
   Params := TIdMultipartFormDataStream.Create;
   try
    Params.AddFile('File1', 'C:\test.txt','application/octet-stream');
    try
     HTTP.Post('http://posttestserver.com/post.php', Params, Stream);
    except
     on E: Exception do
       ShowMessage('Error encountered during POST: ' + E.Message);
    end;
    ShowMessage(Stream.DataString);
   finally
    Params.Free;
   end;
  finally
   Stream.Free;
  end;
end;

It works but i wish to know what i was doing wrong in my code...

Use wireshark and compare the header produced by your code and Indy??

Its so obvious of course TIdMultipartFormDataStream is the upload a file component I've been looking for how did I miss it ? :)

@TobyAllen: Learning something new every day is part of a developer's career :)

fyi, for anyone not familiar with php or indy: File1 in this example is the name of variable for your $_FILES[""] in php. Took me a while to figure that out! Thanks for the good answer.

delphi - Http Post with indy - Stack Overflow

delphi http post indy
Rectangle 27 1

TIdSSLIOHandlerSocketOpenSSL sets a hard-coded 30 second read/write timeout on an SSL socket on Windows Vista+ when the ReadTimeout property is <= 0, so chances are the connection is slow enough to take longer than 30 seconds to transmit data. Try setting the ReadTimeout property to a higher value to see if it delays the error. If so, then there really is a transmission issue.

You can use a packet sniffer, such as Wireshark, to make sure data is actually being transmitted back and forth in a timely manner. Also look at the call stack when the exception is raised to see if the timeout is occurring during the SSL handshake, while sending the HTTP request, or while receiving the HTTP response. That will help determine whether it is an issue with OpenSSL, Indy, or the server.

Hi Remy, thanks for the advice. The request and response seemed to be arriving in a reasonable time, but I was able to step through the code and found that it was throwing a exception because the connection was closed gracefully by the server after sending a 200 header while the client was waiting to read a non-existent response body. Using the Post method without passing a response stream fixes the issue.

TIdHTTP reads a response body if a response body is actually expected. For a POST request, no body is present if there is a Content-Length: 0 response header and no Transfer-Encoding: chunked response header, or if the Content-Length header is missing and the server closes the connection after the headers. Any other combination requires a response body to be present. TIdHTTP recognizes and handles those conditions.

As for discarding data, if you pass a nil response stream, TIdHTTP will still read the response body, if there is one, but it will discard whatever body reads. On the other hand, if you do not pass a response stream at all (nil or otherwise), then you will be calling the overloaded version of Post() that returns a String, so TIdHTTP will still read a response body, if there is one, and you will be the one discarding data, not TIdHTTP.

http - Delphi - Indy 10 #10600 Connection Timeout with POST over 32767...

delphi http post indy
Rectangle 27 2

Calling a PHP from Indy can fail because of the User-Agent, then you get 403 error.

var Answer: string;
begin
  GetHTML:= TIdHTTP.create(Nil);
  try
    GetHTML.Request.UserAgent:= 'Mozilla/3.0';
    Answer:= GetHTML.Get('http://www.testserver.com/test.php?id=1');
  finally
    GetHTML.Free;
  end;
end;

delphi - Http Post with indy - Stack Overflow

delphi http post indy
Rectangle 27 2

Just found the problem. I added the wrong separator between the "Authorization" and "Bearer" words.

After replacing the '=' by ':', I received the expected response, like the one received by POSTMAN.

CustomHeaders.Values[]
FIdHTTP.Request.CustomHeaders.Valus['Authorization'] := 'Bearer ' + txtToken.Text;

It worked that way too. Thanks for the alternative Remy, and thanks for all your support on Stackoverflow. I've learned a lot on other questions already answered by you. =)

http - How to add a "Authorization=Bearer" header with Indy in Delphi?...

http delphi access-token indy bearer-token
Rectangle 27 0

Indy HTTP Server (TIdHTTPServer) supports HTTP Basic Authentication with the properties AuthExists, AuthUser and AuthPass of the Request object and the Response.AuthRealm property. (I have not checked if NTLM or Digest auth are supported also).

By setting the AuthRealm property in the Response, the client will be notified that a Basic Authentification is required. If the client sends the username and password in the request, the server can check it in the command handler.

So actually Indy provides built-in support for securing resources - this works both with a normal browser and with a REST client, both will only be able to access server resources if the request includes the auth header.

I have implemented it also in my Indy based (commercial) web framework. The example code secures all content on the server and has a hard coded user name / password combination.

procedure TBasicAuthHandlerWrapper.Handle(Target: string; Context:
  TdjServerContext;
  Request: TIdHTTPRequestInfo; Response: TIdHTTPResponseInfo);
const
  AUTH_USER = 'sherlock';
  AUTH_PASS = 'holmes';
begin
  if Request.AuthExists and ((Request.AuthUsername = AUTH_USER) and
    (Request.AuthPassword = AUTH_PASS)) then
  begin
    // pass
    inherited;
  end
  else
  begin
    // show login dialog
    Response.AuthRealm := 'Welcome to Web Components Server!';
  end;
end;

Note: this example protects all resources independent of extension and path. But this is easy to add in the method body, by checking conditions of the path which is available in Request.Document.

delphi - Does an Indy HTTP server have a built-in way to assign securi...

security delphi delphi-xe2 indy indy10
Rectangle 27 0

Actually I jumped to conclusion. That didn't throw and error, and it did return HTML, but it return the login page back instead of the accounts page. I am re-opening a new question

http - Login to craigslist to retrieve account page using Delphi and I...

delphi http delphi-2010 indy
Rectangle 27 0

Answering my own: I think I figured it out - I did a PropFile with allprop and a depth of 1. That seems to give me everything in a current "directory" and I can drill down with that. Unless there is a nicer way (or if I am not using PropFind correctly), I will consider this closed. References that were helpful:

http - Getting WebDAV content via Delphi and Indy 10 TIdHTTP - Stack O...

delphi http webdav indy indy10
Rectangle 27 0

FIdHTTPClient.Request.Connection := 'keep-alive'
FIdHTTPClient.Request.CustomHeaders.Add('Connection: keep-alive')
FIdHTTPClient.ProtocolVersion := pv1_1

Regardless of which version you use, the robot has to support keep-alives in the first place, or else TIdHTTP has no choice but to make a new socket connection for each request. If the robot sends an HTTP 1.0 response that does not include a Connection: keep-alive header, or an HTTP 1.1 response that includes a Connection: close header, then keep-alives are not supported.

Hello Remy. The robot does support keep-alive. I checked the response headers and here's what it returns: HTTP/1.0 200 OK Date: Thu, 01 Jan 1970 00:25:03 GMT Server: WYM/1.0 Connection: Keep-Alive Keep-Alive: timeout=3600, max=108000 Content-Type: text/plain Content-Length: 395 Last-Modified: Thu, 01 Jan 1970 00:25:03 GMT Pragma: no-cache Cache-Control: no-cache Expires: 01 Jan 1970 00:00:00 GMT

Is TIdHTTP honoring the keep-alive, reusing a single connection for multiple requests? Or is it dropping the connection and establishing a new one each time? Use a packet sniffer such as Wireshark to see the network activity in real time to see what is actually happening.

Can I rely on the stream number to tell me if the connection is being re-used? That is, if the stream number changes each request, then keep-alive is not being honored? Or should I be looking for some other specific Wireshark log item?(s)

Improving Indy HTTP client performance on older systems, especially la...

delphi http sockets indy robot
Rectangle 27 0

VCL means Visual Component Library. There's nothing about Indy that is "visual" (meaning "seen at runtime"), meaning that "VCL components are useless in a FireMonkey application" has no relevance to Indy.

You can create a new FireMonkey HD application in Delphi XE2, target OS X, and the Indy component pages are still available in the IDE, meaning that they are compatible with supported FireMonkey cross-platform targets. They're also available for FireMonkey HD Windows targets (32 and 64 bit).

As I mentioned, they're available for supported operating systems (I specifically mentioned OS X). I don't know about iOS, but I'd suspect so, as AFAIK Indy supports FreePascal. As far as "VCL", it's common for it to be used for non-visual as well as visual components; the incompatibility between FireMonkey and the VCL is primarily (not strictly) related to visual components, as they rely on the underlying API. Indy doesn't always use Windows Sockets; there was a version of Indy for Kylix, which ran on Linux and therefore didn't have WinSock available either.

Awesome, that means I can start looking for a Delphi XE2 Copy! :)

I can confirm that iOS is NOT supported by Indy. There is currently no internet option in iOS FireMonkey as standard. There is at least one third party option though.

http - Does Delphi XE2 FireMonkey support Indy for cross-platform apps...

delphi http indy delphi-xe2 firemonkey
Rectangle 27 0

There are four problems with your code:

POSTData := TIdMultipartFormDataStream.Create;
try
  for i := Low(arquivos) to High(arquivos) do
  begin
    if FileExists(arquivos[i]) then 
    begin
      //AddFile() will choose the content type for you based on the file extension
      POSTData.AddFile('files[]', arquivos[i]);
    end;
  end;
  HTTP.Post('http://localhost/ENVIO/MultUp.php', POSTData);
finally
  POSTData.Free;
end;

+1 I've deleted my answer, as you caught a couple additional errors I didn't. (And thanks for the edit on my answer as well.)

indy - Trouble when try send HTTP multiple files in same field (Delphi...

delphi indy idhttp
Rectangle 27 0

Sounds to me like a WebSocket task, since your connection is not plain HTTP question/answer oriented any more, but a stream of content.

AFAIK there are two kind of stream in websockets: binary and text. I suspect your JSON stream is some text content, from the websocket point of view.

Another option is to use long-pooling or some older protocols, which are more rooter-friendly - when the connection switch to websockets mode, it is no standard HTTP any more, so some "sensible" packet-inspection tools (on a corporate network) may identify it as a security attack (e.g. DoS), so may stop the connection.

If I get it right, both solutions require rewriting the service? Because I don't have access to it.

@himself If your request is to have the connection open and not use Content-Length headers, this is not HTTP any more, therefore I suppose you will have to change the service side!

Mhm, guess what the service side will say? "Nowhere in HTTP standard it says that HTTP middleware can buffer data for extended periods of time. Therefore our service is fine, I suppose you'll have to fix your HTTP client code". Back to square one.

@ArnaudBouchez it is still HTTP - content-length header can be ommitted, and the server simply closes the connection at the end (see RFC 2616), and connections are persistent in HTTP 1.1 by default

@mjn My point was that even if it "may" be compliant with HTTP standard, websockets layout does not smell good for some OSI level 7 security inspectors. Server or router may stop the connection with some kind of timeout, if it did not recognize the stream as a "classic" HTTP stateless process. It may be the open door to DoS - see bugs.webkit.org/show_bug.cgi?id=32246 and media.blackhat.com/bh-us-12/Briefings/Shekyan/

delphi - HTTP continuous packeted stream with Indy - Stack Overflow

delphi indy indy10 idhttp
Rectangle 27 0

While using TCP stream was an option, in the end I went with original solution of writing custom TIdIOHandlerStack descendant.

The motivation was that with TIdHTTP I know what doesn't work and only need to fix that, while switching to lower level TCP means new problems can arise.

Here's the code that I'm using, and I'm going to discuss the key points here.

TIdStreamIoHandler
TIdIOHandlerStack
ReadBytes
ReadStream
function TryReadBytes(var VBuffer: TIdBytes; AByteCount: Integer;
  AAppend: Boolean = True): integer; virtual;
procedure ReadStream(AStream: TStream; AByteCount: TIdStreamSize = -1;
  AReadUntilDisconnect: Boolean = False); override;

Both are modified Indy functions which can be found in IdIOHandler.TIdIOHandler. In ReadBytes the while clause has to be replaced with a singe ReadFromSource() request, so that TryReadBytes returns after reading up to AByteCount bytes in one go.

Based on this, ReadStream has to handle all combinations of AByteCount (>0, <0) and ReadUntilDisconnect (true, false) to cyclically read and then write to stream chunks of data arriving from the socket.

Note that ReadStream need not terminate prematurely even in this stream version if only part of the requested data is available in the socket. It just has to write that part to the stream instantly instead of caching it in FInputBuffer, then block and wait for the next part of data.

as Indy is open source, modified sources may (and, if helpful for others, should) be made public

@mjn: Didn't know that, thank you. Added the code.

delphi - HTTP continuous packeted stream with Indy - Stack Overflow

delphi indy indy10 idhttp
Rectangle 27 0

Unfortunately, there is no option to specify a custom Host header that specifies a different hostname than the one specified in the URL. The URL has priority. Any hostname you specify in the Request.Host or even the Request.CustomHeaders is overwritten by the hostname in the URL.

If the hostname in the URL is not registered with DNS, you will not be able to reach it with any web browser, or most HTTP libraries including TIdHTTP. While the HTTP protocol itself defines how the Host header works, current web browser technology uses the hostname from the URL, and so does TIdHTTP. So it does not make sense to have a website that uses a hostname that is not registered with DNS in the first place, as most modern client systems would not be able to retrieve it. DNS is required to convert the URL's hostname into an IP address, and then the same hostname is put into the Host header.

delphi - Indy HTTP: Cannot change Host header - Stack Overflow

delphi http indy indy10 delphi-xe7
Rectangle 27 0

When TIdHTTP encounters a server error, it raises an EIdHTTPProtocolException exception, where its ErrorCode property contains the HTTP status code (500, etc), its Message property contains the HTTP status text ("Internal Error", etc), and its ErrorMessage property contains the body text of the response, if any. So, for example:

try
  IdHTTP1.Get(...);
except
  on E: EIdHTTPProtocolException do begin
    // use E.ErrorCode, E.Message, and E.ErrorMessage as needed...
  end;
end;

http - Delphi: Indy - how to get the response body on error? - Stack O...

delphi http httpresponse indy
Rectangle 27 0

Do you mean that D2007 string is different than D2010 string?

Yes. D2009+ is unicode, IIRC I had to copy stringtostream too, and adapt it to ansistring, there was no ansistring stringtostream in D2009+. And I wanted my filetype remain the same and compatible.

Karelian, the change in string types is the major difference between Delphi 2010 and Delphi 2007. If you missed that, you probably missed a lot of other things. It would be a good idea for you to go read the release notes.

OK. But this new unicode string causes so hidden effect to IdHttp Post. I fear what other surprises there will be. Compability of my old codes must be carefully checked with Delphi and Indy release notes .

http - Problem with Indy IdHttp Post in Delphi 2010 - Stack Overflow

delphi http unicode delphi-2010 indy
Rectangle 27 0

Include the hoKeepOrigProtocol option into the HTTPOptions property set (set it to True). Except that keep the ProtocolVersion property set to pv1_1 (which is the default value).

In the TIdCustomHTTP.Post method code there's a comment explaining the current behavior:

Currently when issuing a POST, IdHTTP will automatically set the protocol to version 1.0 independently of the value it had initially. This is because there are some servers that don't respect the RFC to the full extent. In particular, they don't respect sending/not sending the Expect: 100-Continue header. Until we find an optimum solution that does NOT break the RFC, we will restrict POSTS to version 1.0.

A few lines below is the change to the version 1.0 with the following comment:

// If hoKeepOrigProtocol is SET, it is possible to assume that the developer
// is sure in operations of the server
if not (hoKeepOrigProtocol in FOptions) then begin
  if Connected then begin
    Disconnect;
  end;
  FProtocolVersion := pv1_0;
end;

And the above code is skipped (the version is not changed) if you have the hoKeepOrigProtocol option included in the HTTPOptions.

Delphi w Indy 10: idHTTPRequest POST always is HTTP 1.0, how to make i...

delphi indy
Rectangle 27 0

  • Start a new VCL Forms project
  • Drop a TidHTTPServer component onto the Form

Double-click the form to create an OnCreate() event and activate the server

Back on the form, select the HTTP Server component, and create an OnCommandGet event

In this OnCommandGet event (which is called within a child thread whenever a GET/POST occurs), handle the request, by populating the response..

AResponseInfo.ContentText := '<html><head><title>My First Response</title></head>' + 
  '<body>Command: ' + ARequestInfo.Command +
  '<br />Host: ' + ARequestInfo.Host +
  '<br />URI: ' + ARequestInfo.URI +
  '<br />UserAgent: ' + ARequestInfo.UserAgent +
  '</body></html>';

Run your demo app and then launch a browser to http://localhost and you should get a response. (Unless you have something else listening on Port 80 in which case your demo app will generate an exception)

delphi - Indy 10 Http Server sample - Stack Overflow

delphi http delphi-7 indy
Rectangle 27 0

To use TIdThreadMgrPool, at a minimum all you have to do is create an instance of it, assign that to the TIdHTTPServer.ThreadMgr property, and set its PoolSize property. All of that can be done at design-time.

Keep in mind that the PoolSize does not limit the number of connections on the server. The server has its own MaxConnections property for that purpose. For example, you could have a PoolSize of 10 and have 15 clients connected simultaneously, and thus 15 threads running. When they disconnect, 10 threads will be put back in the pool and 5 threads will be terminated.

To customize the pool threads, you can derive a new class from TIdPeerThread, optionally override its virtual BeforeExecute() and AfterExecute() methods to perform per-thread initializations the cleanups, and then assign that class to the server's (not the ThreadMgr's) ThreadClass property at runtime before activating the server. Inside your server event handlers, you can then typecast the provided TIdPeerThread object to your custom class and use it as needed.

You can add methods to your custom thread class and have them internally access the DLL, throttling as needed. The simplest throttle would be to use a single shared semaphore to control the number of threads that can enter the semaphore at a time. In that regard, you can then limit to, say, 2 threads at a time even if 15 threads are running.

Since you say you want to "run the DLL in a thread", a semaphore will likely not be enough. In that case, I would recommend using an I/O Completion Port instead. You can have your custom thread class post a request to the IOCP using PostQueuedCompletionStatus() and wait for the response to come back. Throttling is accomplished by the number of threads you create to service the IOCP, such as one thread per CPU core. Each IOCP thread would use GetQueuedCompletionStatus() in a loop to receive posted requests.

Indy is not asynchronous, so you would not be able to post a request to the IOCP and let it send a response back to the client directly when ready. The server sends a response back to the client using the same thread that manages the client connection. So the client thread will have to post a request to the IOCP and wait for its response, then send that response to the client. You can define a record that contains a TEvent, input values needed for calling the DLL, and output values for the DLL's response. Then create an instance of that record, post a pointer to it to the IOCP, and wait for the TEvent to be signalled. When an IOCP thread receives the record pointer, it can call the DLL as needed, fill the record with the response, and then signal the record's TEvent. The waiting client thread will then be unblocked and can send the record's response data to the client as needed.

Thanks @Remy. You don't happen to have a link to an example. Always easiest to see working code.

web services - Delphi 7 Indy 9 multithreaded HTTP Server - Stack Overf...

web-services delphi webserver indy httpserver
Rectangle 27 0

Xxm actually provides an interface you can code against so the result is portable over IIS, Apache or the plain HTTP server with multi-threading. There's also a http.sys version and a connector to run locally right into Internet Explorer (great for debugging). Each of these also have an 'auto-update' version, that will hot-swap the projects DLL and use it for any new requests (great for live servers).

web services - Delphi 7 Indy 9 multithreaded HTTP Server - Stack Overf...

web-services delphi webserver indy httpserver
Rectangle 27 0

IdCustomHTTPServer
TIdHTTPRangeStream

If the client requests a ranged download, create an instance of TIdHTTPRangeStream and pass it your intended TStream and the client's requested range, then assign it as the ContentStream to be sent. TIdHTTPRangeStream also has a ResponseCode property that you need to assign to the response's ResponseNo property.

void __fastcall TfrmMain::httpServerCommandGet(TIdContext *AContext, TIdHTTPRequestInfo *ARequestInfo, TIdHTTPResponseInfo *AResponseInfo)
{
    // create file stream ...

    // THTTPServer parses the ranges for you
    if (ARequestInfo->Ranges->Count > 0)
    {
        if (ARequestInfo->Ranges->Count > 1)
        {
            AResponseInfo->ResponseNo = 416;
            return;
        }

        TIdEntityRange *range = ARequestInfo->Ranges->Range[0];

        TIdHTTPRangeStream *rstream = new TIdHTTPRangeStream(stream, range->StartPos, range->EndPos, true);

        AResponseInfo->ResponseNo = rstream->ResponseCode;
        AResponseInfo->ContentRangeStart = rstream->RangeStart;
        AResponseInfo->ContentRangeEnd = rstream->RangeEnd;
        AResponseInfo->ContentStream = rstream;
        AResponseInfo->AcceptRanges = "bytes";
    }
    else
    {
        AResponseInfo->ContentStream = stream;
    }

    // no need to seek the target stream manually
    // no need to set the ContentLength manually
    // no need to call WriteHeader() and WriteContent() manually
    //
    // TIdHTTPServer handles all that for you internally!
}

delphi - Indy Http Server with resume support - Stack Overflow

delphi tcp c++builder indy httpserver