I recently updated a client's VFP app that uses WWC ver 5.72 to make calls to a web-based documents database (through a REST api supplied with that). My code mostly uses httpGet() and very few other WWC calls.
The app has continued to have regular/intermittent errors. The web guy has stomped out most of the errors on his side except for about a dozen per day. He says that the remaining errors are because the VFP app is restting the connection (or not closing it properly). Here is the error snippet he sent me from the web side.
As part of my general error trapping, I also am logging anything that comes back as an incomplete response so that I have a record of when the error occurred on the VFP side to match up with. The call to the above was sent as:
Hi Albert The Error in the log is (see below) is a socket reset error from the calling program (the peer) — is there any chance your program is not properly closing the socket after API calls? Or at least if there is an issue? Please review and let me know. 2017-02-28 15:08:37,533 WARN [http-bio-0.0.0.0-8080-exec-72] [com.concena.clientfolders.api.rest.AddDocument] *** REST API: AddDocument: detected mime type = application/pdf 2017-02-28 15:08:51,355 WARN [http-bio-0.0.0.0-8080-exec-50] [com.concena.clientfolders.api.rest.AddDocument] *** REST API: AddDocument: detected mime type = application/pdf 2017-02-28 15:08:54,085 WARN [http-bio-0.0.0.0-8080-exec-3] [com.concena.clientfolders.api.rest.UpdateDocument] *** REST API: UpdateDocument: detected mime type = application/vnd.ms-excel 2017-02-28 15:09:16,284 WARN [http-bio-0.0.0.0-8080-exec-57] [com.concena.clientfolders.api.rest.UpdateDocument] *** REST API: UpdateDocument: detected mime type = application/vnd.ms-excel 2017-02-28 15:09:17,298 ERROR [http-bio-0.0.0.0-8080-exec-3] [org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/nuxeo]] Exception intercepted org.apache.catalina.connector.ClientAbortException: java.net.SocketException: Connection reset by peer: socket write error at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:367) at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:331) at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:101) at sun.nio.cs.StreamEncoder.implFlush(Unknown Source) at sun.nio.cs.StreamEncoder.flush(Unknown Source) at java.io.OutputStreamWriter.flush(Unknown Source)
- and my error trap says that the string came back either empty or not character type.
- the above call was made using a single line of code that would have waited for a response:
.icResultString = .ioHTTP.HttpGet(lcURL,.icUserName,.icUserPassword) && where .ioHTTP is an instance of your wwHttp class
So he says the connection is being reset but if my code is just sitting and waiting, under what conditions would it get reset? I am going to guess that it is not a timeout waiting as the timeout value is set to 15 secs (is there any way to test if a timeout occurrred, any property of wwhttp that gets set on a timeout?).
Can you give any tips on how I can test whether it is being reset from the VFP side or what I could do to track this down? Any place I should insert some test code or ??
Not sure. We're using the standard Windows HTTP client (WinInet) and it works with just about anything so for a single location where there are problems blaming the HTTP client is kind of rich, especially if hte behavior is intermittent.
I can't connect to the server so I can't try this out myself, but you can try playing with the
Keep-Alive header in the HTTP request you're making. WinInet by default tries to keep connections to the server open but you can force them to close after each request.
+++ Rick ---
This seems to be "going away" as the other developer is finally taking his side of it seriously and he was rewriting some sections over the weekend in the Rest api - and things have improved.
If this does not stay solved, would property nError in the http class give me the last error that occurred regardless of which function was just called?
cErrorMsg is what you want to look at.
nError will be the WinHttp error which may or may not be useful. You just want to check for non-zero values which is an error. You also want to check the status code to check for http errors (400+ status codes) errors depending on what you are doing.
Connection reset errors are almost always related to network issues at the router/proxy level or a connection that can't be made at all. The most common thing is proxy or router dropping keep alive connections. Server applications can cause problems if they send data and then abort mid-way through were essentially the server cuts off the connection.
If you're using Windows XP, there were lots of connection level problems with the HTTP stack so if that's the case it's possible it's the client. However these things were addressed in Vista forward. You can also try the nHttpConnectMode property to see if using direct connection or Windows Configuration settings work better for you. Again it depends on your network setup. Finally you might want to try excluding your app from AV software which can get in the way especially with binary files like PDFs and executables that end up running on your machine.
+++ Rick ---
Thanks for the suggestions. I did not see them until now as the problems seemed to be going away as the web guy tweaked his code (which sortof suggests to me that there are issues on his end). I will most likely end up adding some code into your source to check the cErrorMsg and if that shows me anything, check into disabling AV on this app.
On another note, when looking at this again today, I was looking for where the connection handle is setup and then stored within the class (found .hHTTPSESSION and .hIPSession in your code). I traced through the code and I can see where you open, use and close each session. This made me wonder if I am doing anything wrong in using the class (I don't think so but best to check). Here is how I use it:
I have a wrapper class that contains all the methods to fetch XML strings from the server
I first instantiate an instance of that for use throughout the app; let's call it oWrapper
when oWrapper instantiates, it also hooks in an instance of wwHttp since that is always needed
this comes oWrapper.ioHTTP
every method then uses .ioHTTP as needed; all calls pretty well use .httpGet()
so every call calls .httpGet() and that opens a connection to the server, uses it and closes it
since every call waits for a response, there should be no overwriting of oWrapper.ioHTTP.hIPSession or .ioHTTP.hHttpSession
there are no timers running that can spawn some other http request so it should just sit and wait for a response
Can you see any problem with this? There is no need to instantiate a new copy of .ioHTTP with each call correct? I can just re-use the same http object for each call since only one call at a time is made?
I prefer creating a new instance in each request because it clears out all the buffers. HTTP is a transitory protocol which connects and disconnects for each request anyway so it makes sense to treat hte connection the same way.
But that said as long as you call loHttp.Close() to reset all the handles and clear the old POST buffer things should work fine.
+++ Rick ---