Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2021-01

fcl-web: Trequest.RemoteAddr is empty (sometimes)

10 messages · 3 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

Luca Olivetti

Hello,

I need to tailor the content based on the remote ip address. I use the property RemoteAddr of a TRequest, but sometimes it is empty. I see that it is a header, what I didn't see (yet, I'll trace through the code later) is if it is sent from the remote host or is it filled based on the ip address of the connection.
If the former, is there a more reliable way to obtain the connected ip address?
If the latter is it a bug?

Bye

Luca

Reply by email

Luca Olivetti
to Luca Olivetti

El 7/1/21 a les 16:15, Luca Olivetti via fpc-pascal ha escrit:

Show quoted text 10 lines
Hello, I need to tailor the content based on the remote ip address. I use the property RemoteAddr of a TRequest, but sometimes it is empty. I see that it is a header, what I didn't see (yet, I'll trace through the code later) is if it is sent from the remote host or is it filled based on the ip address of the connection. If the former, is there a more reliable way to obtain the connected ip address? If the latter is it a bug?

I now see that it set in TFPHTTPConnection.ReadRequestHeaders:

    Result.RemoteAddress := SocketAddrToString(FSocket.RemoteAddress)

In turn SocketAddrToString returns an empty string if the address is ipv6, but in my case it shouldn't be (the clients, firefox under windows 10 uses the ipv4 address of the server and most of the time I get the correct remote address, even from the same client). Another option is that TSocketStream.GetRemoteAddress cannot get the address (if fpGetPeerName fails).

Bye

Luca

Reply by email

Luca Olivetti
to Luca Olivetti

El 7/1/21 a les 16:59, Luca Olivetti via fpc-pascal ha escrit:

Show quoted text 20 lines
El 7/1/21 a les 16:15, Luca Olivetti via fpc-pascal ha escrit: > Hello, > > I need to tailor the content based on the remote ip address. > I use the property RemoteAddr of a TRequest, but sometimes it is empty. > I see that it is a header, what I didn't see (yet, I'll trace through > the code later) is if it is sent from the remote host or is it filled > based on the ip address of the connection. > If the former, is there a more reliable way to obtain the connected ip > address? > If the latter is it a bug? I now see that it set in TFPHTTPConnection.ReadRequestHeaders:    Result.RemoteAddress := SocketAddrToString(FSocket.RemoteAddress) In turn SocketAddrToString returns an empty string if the address is ipv6, but in my case it shouldn't be (the clients, firefox under windows 10 uses the ipv4 address of the server and most of the time I get the correct remote address, even from the same client).

Besides, it seems that the server only listens on ipv4. I'm puzzled, I really can't see where this empty RemoteAddress could come from.

Bye

Luca

Reply by email

Michael Van Canneyt
to Luca Olivetti
Luca Olivetti wrote 25 lines
El 7/1/21 a les 16:59, Luca Olivetti via fpc-pascal ha escrit: > El 7/1/21 a les 16:15, Luca Olivetti via fpc-pascal ha escrit: >> Hello, >> >> I need to tailor the content based on the remote ip address. >> I use the property RemoteAddr of a TRequest, but sometimes it is empty. >> I see that it is a header, what I didn't see (yet, I'll trace through >> the code later) is if it is sent from the remote host or is it filled >> based on the ip address of the connection. >> If the former, is there a more reliable way to obtain the connected ip >> address? >> If the latter is it a bug? > > I now see that it set in TFPHTTPConnection.ReadRequestHeaders: > >    Result.RemoteAddress := SocketAddrToString(FSocket.RemoteAddress) > > In turn SocketAddrToString returns an empty string if the address is > ipv6, but in my case it shouldn't be (the clients, firefox under windows > 10 uses the ipv4 address of the server and most of the time I get the > correct remote address, even from the same client). Besides, it seems that the server only listens on ipv4. I'm puzzled, I really can't see where this empty RemoteAddress could come from.

Are you using https ?

Michael.

Reply by email

Luca Olivetti
to Michael Van Canneyt

El 8/1/21 a les 11:06, Michael Van Canneyt via fpc-pascal ha escrit:

Are you using https ?

No, plain text http.
An even weirder fact is that I seem to get the wrong ip address (i.e. the address of a different client).

Bye

Luca

Reply by email

Luca Olivetti
to Luca Olivetti

El 8/1/21 a les 11:14, Luca Olivetti via fpc-pascal ha escrit:

Show quoted text 8 lines
El 8/1/21 a les 11:06, Michael Van Canneyt via fpc-pascal ha escrit: > > Are you using https ? No, plain text http. An even weirder fact is that I seem to get the wrong ip address (i.e. the address of a different client).

I think I found the possible cause:

I have an own thread that spawns a TEmbeddedHttpServer (actually a derived class to manage server-sent-events,
https://lists.lazarus-ide.org/pipermail/lazarus/2020-June/238072.html) with threaded:=true.

My thread has a method to manage the requests and it does this

     FRequest:=ARequest;
     Synchronize(@SyncNewConnection);
     if FCommandQueuenil then .....

I think that, since the method is called from a different thread for each request, if two requests come at the same time, the FRequest and/or the FCommandQueue (which is set in the synchronized method) could get mixed up.

I now did 2 things:

1) protected that part of the code with a critical section
2) use TThread.Synchronize(nil,..) (since it's not my thread but another one

    FCrit.Acquire;
    FRequest:=ARequest;
    TThread.Synchronize(nil,@SyncNewConnection);
    LocCommandQueue:=FCommandQueue;
    FCrit.Release;
    if LocCommandQueuenil then...

WDYT?

Am I right thinking that, even if several copies of the above method are running, each will get it's own local variables, so the LocCommandQueue variable (as well as the other locals) won't be clobbered by another copy? Or should I declare them as threadvar?

Bye

Luca

Reply by email

Santiago A.
to Luca Olivetti: El 7/1/21 a les 16:59, Luca Olivetti via fpc-pascal ha escrit: Besides, it seems that the…
Luca Olivetti wrote 27 lines
El 7/1/21 a les 16:59, Luca Olivetti via fpc-pascal ha escrit: > El 7/1/21 a les 16:15, Luca Olivetti via fpc-pascal ha escrit: >> Hello, >> >> I need to tailor the content based on the remote ip address. >> I use the property RemoteAddr of a TRequest, but sometimes it is empty. >> I see that it is a header, what I didn't see (yet, I'll trace >> through the code later) is if it is sent from the remote host or is >> it filled based on the ip address of the connection. >> If the former, is there a more reliable way to obtain the connected >> ip address? >> If the latter is it a bug? > > I now see that it set in TFPHTTPConnection.ReadRequestHeaders: > >     Result.RemoteAddress := SocketAddrToString(FSocket.RemoteAddress) > > In turn SocketAddrToString returns an empty string if the address is > ipv6, but in my case it shouldn't be (the clients, firefox under > windows 10 uses the ipv4 address of the server and most of the time I > get the correct remote address, even from the same client). Besides, it seems that the server only listens on ipv4. I'm puzzled, I really can't see where this empty RemoteAddress could come from. Bye

In windows 10 when you connect to localhost, it may connect with IPV6 and route to ipv4 with weird results.
Try to connect using IP 127.0.0.1 http://127.0.0.1 You may also add in C:\Windows\System32\drivers\etc\hosts a line like localhost4 127.0.0.1
and then http://localhost4
You may also disable IPV6 service if you don't use it. I have, because it is seldom used, it looks like every device/system still works only with IPV4

Saludos Santiago A.

Reply by email

Michael Van Canneyt
to Luca Olivetti: El 8/1/21 a les 11:14, Luca Olivetti via fpc-pascal ha escrit: I think I found the…
Luca Olivetti wrote 28 lines
El 8/1/21 a les 11:14, Luca Olivetti via fpc-pascal ha escrit: > El 8/1/21 a les 11:06, Michael Van Canneyt via fpc-pascal ha escrit: > >> >> Are you using https ? > > No, plain text http. > An even weirder fact is that I seem to get the wrong ip address (i.e. > the address of a different client). I think I found the possible cause: I have an own thread that spawns a TEmbeddedHttpServer (actually a derived class to manage server-sent-events, https://lists.lazarus-ide.org/pipermail/lazarus/2020-June/238072.html) with threaded:=true. My thread has a method to manage the requests and it does this FRequest:=ARequest; Synchronize(@SyncNewConnection); if FCommandQueuenil then ..... I think that, since the method is called from a different thread for each request, if two requests come at the same time, the FRequest and/or the FCommandQueue (which is set in the synchronized method) could get mixed up.

If there is only 1 FRequest instance/location in your thread, then this is definitely so...

Show quoted text 18 lines
I now did 2 things: 1) protected that part of the code with a critical section 2) use TThread.Synchronize(nil,..) (since it's not my thread but another one FCrit.Acquire; FRequest:=ARequest; TThread.Synchronize(nil,@SyncNewConnection); LocCommandQueue:=FCommandQueue; FCrit.Release; if LocCommandQueuenil then... WDYT? From the info you gave me, I think this could work, yes.

Care should be taken that the critical lock does not cause a deadlock, I don't know what happens in SyncNewConnection.

Show quoted text 5 lines
Am I right thinking that, even if several copies of the above method are running, each will get it's own local variables, so the LocCommandQueue variable (as well as the other locals) won't be clobbered by another copy? Or should I declare them as threadvar?

If FCommandQueue is the only thing that is set during SyncNewConnection based on TRequest, then yes. For safety, I would Nil the FCommandQueue after assigning it to locCommandQueue.

Michael.

Reply by email

Luca Olivetti
to Michael Van Canneyt

El 12/1/21 a les 10:24, Michael Van Canneyt via fpc-pascal ha escrit:

Show quoted text 9 lines
> > Am I right thinking that, even if several copies of the above method > are running, each will get it's own local variables, so the > LocCommandQueue variable (as well as the other locals) won't be > clobbered by another copy? > Or should I declare them as threadvar? If FCommandQueue is the only thing that is set during SyncNewConnection based on TRequest, then yes.

yes to "each will get its [*] own local" or yes to "should I declare them as threadvar"?

For safety, I would Nil the FCommandQueue after assigning it to locCommandQueue.

No need, it's only used as a return value from the synchronized method.

[*] sorry for the "it's" in the original sentence

Bye

Luca

Reply by email

Michael Van Canneyt
to Luca Olivetti
Luca Olivetti wrote 14 lines
El 12/1/21 a les 10:24, Michael Van Canneyt via fpc-pascal ha escrit: >> >> Am I right thinking that, even if several copies of the above method >> are running, each will get it's own local variables, so the >> LocCommandQueue variable (as well as the other locals) won't be >> clobbered by another copy? >> Or should I declare them as threadvar? > > If FCommandQueue is the only thing that is set during SyncNewConnection > based on TRequest, then yes. yes to "each will get its [*] own local" or yes to "should I declare them as threadvar"?

Yes to "each will get its own local copy".
I don't think threadvars are needed here.

Michael.

Reply by email