Jump to content
coenenp

TW3HttpRequest issue

Recommended Posts

Hello,

 

What I'm working on is the following.

 

- Delphi application with Indy http server

- the index.html file created by SMS is streamed through the indy http server so that a user can access this index.html file using his browser (http://127.0.0.1:8080/index.html)

- The created index.html file by SMS is form with a button and a memo (simple test application).

- A click on the button will try to that will do a TW3HttpRequest to the same delphi application with the same indy http server

 

Strange here is that it works when I run the index.html from the internal SMS browser but not when the index.html is streamed to a browser. I did a test with Chrome and Firefox.

 

So when running from the internal SMS browser I can do a http request to the indy http server (http://127.0.0.1:8080/1) and I get a reply. Also when I open the index.html file directly using chrome it also works. But not when it's streamed from the same http server as the one where I want to get the http request from. Screenshot attached.

 

Best Regards,

Pascal

post-952-0-57685800-1408473742_thumb.jpg

Share this post


Link to post
Share on other sites

you need to set the AResponse.ContentType to html or something like that, otherwise the browser will only download the file as text

 

Somethink like this:

Info.ContentType := 'text/html';
Info.CharSet := 'UTF-8';

Share this post


Link to post
Share on other sites

Hello Andre,

 

Still not working. I found some information here about how to stream the html file. I also tried your advice.

 

http://delphi-kb.blogspot.be/2011/05/creating-simple-http-server.html

 

When I compare the html code (using Chrome) then the one from the indy http server (streamed) is exactly the same as the one where i directly loaded the index.html file in chrome. I don't understand why the TW3HttpRequest fails if the index.html is coming from the indy http server.

 

I debugged the indy http server and noticed the following:

 

- The OnCommandGet event gets triggered on the chrome request for the index.hmtl file

- The OnCommandGet event isn't triggered on the TW3HttpRequest from the 'streamed' index.html file => error: GET http://127.0.0.1:8080/1 net::ERR_FAILED

- The OnCommandGet event gets triggered on the TW3HttpRequest from the in chrome locally loaded index.html file

 

Any idea?

 

Best Regards,

Pascal

Share this post


Link to post
Share on other sites

Some extra information. The Indy http server has no fixed IP bindings and is using the local host IP 127.0.0.1 and the newtwork IP 192.168.2.109

 

So I decided to open the index.html file using http://192.168.2.109:8080/index.html(instead of http://127.0.0.1:8080/index.html)

 

The result is that it works now and I've add an extra button on my form so now I can do a TW3HttpRequest from http://127.0.0.1:8080/1and from http://192.168.2.109:8080/1. Both work (when I get the index.html file from  http://192.168.2.109:8080/index.html). 

 

Now I don't understand why it doesn't work when the index.html file is streamed from 127.0.0.1. It can't be the Indy http server part because it works with 192.168.2.109.

Share this post


Link to post
Share on other sites

I've added some debug screenshots (network - headers) from the Chrome browser. It seems that there is something wrong with the http request when the index.html is coming from the localhost 127.0.0.1. This information is generated after the onclick event of the button asking a httprequest from http://127.0.0.1:8080/1

 

It's is completely different with the one from http://192.168.2.109:8080/index.html

post-952-0-10016700-1408560257_thumb.jpg

post-952-0-70672600-1408560262_thumb.jpg

Share this post


Link to post
Share on other sites

I would suggest that this is CORS related?

 

 

I.e: The server will only allow requests from websites that are located on the same domain/url/ip.

 

 

 

I recently updated our TW3HttpRequest tutorial (http://smartmobilestudio.com/documentation/networking/tw3httprequest/),

and I discovered that several domains had moved to same-origin policy. We used google.com as an example before, but this doesn't work anymore.

Share this post


Link to post
Share on other sites

I've added:  'Access-Control-Allow-Origin: *' to the indy http server respons (you can see this in the screenshot - Respons info). Without this line even none of the above works (like you also discovered).

 

 

It seems that when using the index.html from http://127.0.0.1:8080/index.htmlthen TW3HttpRequest isn't fired. I certainly don't get a trigger in the OnCommandGet from the indy httpserver and there seems to be something wrong with the headers when the request is triggered.

Share this post


Link to post
Share on other sites

Ok did some more test work and have found something. It seems that Chrome, due to the app.manifest file?, caches the index.html and res/app.css. When it does this then the whole TW3HttpRequest doesn't work (not when streamed from 127.0.0.1:8080 and also not when streamed from 192.168.2.109:8080). It had to clear the cache and prevent it from caching again to get it to work (chrome://appcache-internals/).

 

In the next reply I'll add the screenhots where I prevent Chrome from caching these files. In this case everything works as normal. I can do a TW3HttpRequest to 127.0.0.1, 192.168.2.109 and also to date.jsontest.com without any problem. When I stop my delphi application then the index.hml from 127.0.0.1:8080 is no longer available (it isn't cached).

 

Now can somebody explain why a TW3HttpRequest from a cached index.html file doestn't work?

 

Best Regards,

Pascal

post-952-0-18896200-1408647530_thumb.jpg

post-952-0-04476000-1408647536_thumb.jpg

Share this post


Link to post
Share on other sites

>>Now can somebody explain why a TW3HttpRequest from a cached index.html file doestn't work?

 

If the cache'd call is a failed-call then that is what is cached.

Also, use bindings with indy. So you should bind the localhost to the IP (thats what bindings are for).

 

With CORS in place there should not be a problem. We are using Indy inside the application ourselves, with no special modifications. Worst case scenario i can export the settings we use, but there no "magic" in it.

 

Also: Turn off the manifest while developing. Then flush the browser-content-cache completely.

Also try to bind the indy server.

Share this post


Link to post
Share on other sites

This is from our server class..

 

Hope that clears up the problem:



procedure TIDEServer.HandleHTTPGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
  FileName: TFileName;

  procedure Failed;
  begin
    AResponseInfo.ResponseNo := 220;
    AResponseInfo.ResponseText := Format(RStrFileNotFoundError, [FileName]);
  end;

begin
  // basically format filename
  FileName := StringReplace(ARequestInfo.Document, '/', '\', [rfReplaceAll]);
  if (FileName = '') or (FileName = '\') then
    FileName := 'index.html';

  if FileName[1] = '\' then
    Delete(FileName, 1, 1);
  FileName := IncludeTrailingPathDelimiter(FRootPath) + FileName;

  // ensure the file exists
  if not FileExists(FileName) then
  begin
    Failed;
    Exit;
  end;

  // should manifests be served?
  if (ExtractFileExt(FileName) = '.manifest') and not FServerManifest then
  begin
    Failed;
    Exit;
  end;

  // ensure a MIME map exists to check the MIME type for a given file
  Assert(Assigned(FMIMEMap));

  AResponseInfo.CustomHeaders.AddValue('Access-Control-Allow-Origin', '*');
  AResponseInfo.CharSet := 'utf-8';
  AResponseInfo.ResponseNo := 200;
  AResponseInfo.ContentType := FMIMEMap.GetFileMIMEType(FileName);
  if Pos('text', AResponseInfo.ContentType) > 0 then
    AResponseInfo.ContentText := LoadTextFromFile(FileName)
  else
    AResponseInfo.ContentStream := TFileStream.Create(FileName,
      fmOpenRead or fmShareDenyNone);

  (* Apple has a special "manifest" file, check if this is such
    a case. It needs to have the datatype set to cache-manifest *)
  if ExtractFileExt(LowerCase(FileName)) = '.manifest' then
    AResponseInfo.ContentType := 'text/cache-manifest'
  else
  if Assigned(FOnFileServed) then
    FOnFileServed(Self, FileName);
end;

And here is the mime-table setup:

procedure TIDEServer.StartServer(ARootFolder: string);
begin
  if not GetActive then
  begin
    FRootPath := Trim(ARootFolder);
    if DirectoryExists(FRootPath) then
    begin

      try
        FServer.Active := True;

        // eventually create MIME map if not exist already
        if not Assigned(FMIMEMap) then
          FMIMEMap := TIdMimeTable.Create(True);

      except
        on e: Exception do
        begin
          raise EIDEServer.CreateFmt(RStrFailedToStartServerException,
            [e.ClassName, e.Message]);
        end;
      end;

      try
        if Assigned(FOnStart) then
          FOnStart(Self);
      except
        on Exception do;
      end;

    end
    else
      raise EIDEServer.CreateFmt(RStrFailedToStartServerRootPath, [FRootPath]);
  end
  else
    raise ESmartIdeException.Create(RStrServerAlreadyActive);
end;

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×