Re: Problem with fast posts
[email protected] (Hanspeter Halle)
| Newsgroups | gmane.comp.lib.libwww |
|---|---|
| Message-ID | <[email protected]> |
As nobody could help me I had to do it by myself. You find a patch attached to fix the problem. I admitt that the solution is not very elegant but the main modification is kept in the HTTP.c, so the chance of implications on other functions is quite low. I hope it will find it's way into the CVS. Regards Hanspeter Am Freitag, 29. November 2002 13:26 schrieb Hanspeter Halle: > We are using libwww in a WAP Gateway to perform the HTTP requests. Gets are > working fine but the posts are broken if the www server supports > pipelining and 2 posts are to be made in a short intervall. What happens is > the following: > > - TCP link to server is established through any request and the server > signals to support pipelining. > > - 1st post request comes in and the post header is sent out. This starts a > 2s timer which should trigger the data output > > - Before the timer expires the 2nd post is to be executed and the header > of this is sent out at once. Again a timer is started. > > - Timer expires and data of post 1 is sent .OR. > Server complains about missing data > > I tracked this down by studying the libwww logs and the code but I would > request some help in how to fix this bug. Hope somebody is able to do this. > > Thanks, > Hanspeter
post-bugfix.patch
(text/x-diff, 5.8 KB)
Index: Library/src/HTHost.c
===================================================================
RCS file: /sources/public/libwww/Library/src/HTHost.c,v
retrieving revision 2.72
diff -c -r2.72 HTHost.c
*** HTHost.c 2000/07/28 13:56:08 2.72
--- HTHost.c 2002/12/05 13:05:59
***************
*** 1163,1168 ****
--- 1163,1209 ----
return NO;
}
+
+ /*
+ ** [email protected]: Return the successor resp. predecessor of the given request in
+ ** the pipeline if any
+ */
+ extern HTNet * HTHost_predecessor (HTHost * host, HTNet * net)
+ {
+ HTList * lp;
+ HTNet * net2;
+
+ if (!host || !net)
+ return NULL;
+
+ for (lp=host->pipeline;(net2=HTList_nextObject (lp)); )
+ if ( net2 == net ) break;
+
+ if ( !net2 )
+ return NULL;
+
+ return HTList_nextObject (lp);
+ }
+
+ extern HTNet * HTHost_successor (HTHost * host, HTNet * net)
+ {
+ HTList * lp;
+ HTNet * net2;
+ HTNet * res = NULL;
+
+ if (!host || !net)
+ return NULL;
+
+ for (lp=host->pipeline;(net2=HTList_nextObject (lp)); ) {
+ if ( net2 == net )
+ return res;
+ else
+ res = net2;
+ }
+
+ return NULL;
+ }
+
/*
** Handle pending host objects.
** There are two ways we can end up with pending reqyests:
Index: Library/src/HTHost.html
===================================================================
RCS file: /sources/public/libwww/Library/src/HTHost.html,v
retrieving revision 2.29
diff -c -r2.29 HTHost.html
*** HTHost.html 1999/07/07 15:43:28 2.29
--- HTHost.html 2002/12/05 13:06:00
***************
*** 201,206 ****
--- 201,209 ----
extern BOOL HTHost_deleteNet (HTHost * host, HTNet * net, int status);
extern HTList * HTHost_net (HTHost * host);
+
+ extern HTNet * HTHost_predecessor (HTHost * host, HTNet * net);
+ extern HTNet * HTHost_successor (HTHost * host, HTNet * net);
</PRE>
<H2>
Channels
Index: Library/src/HTNet.c
===================================================================
RCS file: /sources/public/libwww/Library/src/HTNet.c,v
retrieving revision 2.106
diff -c -r2.106 HTNet.c
*** HTNet.c 2000/07/04 15:26:25 2.106
--- HTNet.c 2002/12/05 13:06:02
***************
*** 1299,1301 ****
--- 1299,1324 ----
{
return (net && net->countRawBytes);
}
+
+
+ /* ------------------------------------------------------------------------- */
+ /* Delay pipeline successors */
+ /* ------------------------------------------------------------------------- */
+
+
+ extern void HTNet_enableSuccessor (HTNet * net)
+ {
+ if ( net )
+ net->successorEnabled = YES;
+ }
+
+
+ /*
+ ** Check if this request has finished sending.
+ ** If net==NULL we suppose the asking request has no
+ ** predecessor, so sending is allowed
+ */
+ extern BOOL HTNet_isSuccessorEnabled (HTNet * net)
+ {
+ return net ? net->successorEnabled : YES;
+ }
Index: Library/src/HTNet.html
===================================================================
RCS file: /sources/public/libwww/Library/src/HTNet.html,v
retrieving revision 2.57
diff -c -r2.57 HTNet.html
*** HTNet.html 2000/07/04 15:18:51 2.57
--- HTNet.html 2002/12/05 13:06:03
***************
*** 665,670 ****
--- 665,679 ----
<PRE>extern BOOL HTNet_setRawBytesCount (HTNet * net, BOOL mode);
extern BOOL HTNet_rawBytesCount (HTNet * net);
</PRE>
+ <H3>
+ Delay pipeline successors
+ </H3>
+ <P>
+ [email protected]: With pipelining the next request after a post could easily be sent before
+ the post data where completely out. So we provide a flag here telling that this request is completely sent.
+ <PRE>extern void HTNet_enableSuccessor (HTNet * net);
+ extern BOOL HTNet_isSuccessorEnabled (HTNet * net);
+ </PRE>
<PRE>
#endif /* HTNET_H */
</PRE>
Index: Library/src/HTNetMan.html
===================================================================
RCS file: /sources/public/libwww/Library/src/HTNetMan.html,v
retrieving revision 2.25
diff -c -r2.25 HTNetMan.html
*** HTNetMan.html 1998/09/24 19:48:52 2.25
--- HTNetMan.html 2002/12/05 13:06:03
***************
*** 65,70 ****
--- 65,73 ----
/* Eric's sleezoid cheat - should go to extra pipeline object */
HTEventType registeredFor;
+
+ /* Hanspeter's post bug workaround */
+ BOOL successorEnabled;
};
extern SOCKET HTNet_socket(HTNet * me);
Index: Library/src/HTTP.c
===================================================================
RCS file: /sources/public/libwww/Library/src/HTTP.c,v
retrieving revision 1.192
diff -c -r1.192 HTTP.c
*** HTTP.c 2002/05/28 18:36:25 1.192
--- HTTP.c 2002/12/05 13:06:06
***************
*** 1063,1070 ****
--- 1063,1079 ----
** time so that we can write some more data to the net.
*/
if (status != HT_OK) {
+ HTHost * host = HTNet_host(http->net);
+ HTNet * successor;
+
HTTimer_delete(http->timer);
http->timer = NULL;
+ HTNet_enableSuccessor ( http->net );
+ successor = HTHost_successor ( host, http->net );
+ if ( ! successor )
+ HTHost_launchPending ( host );
+ else
+ HTNet_execute( successor, HTEvent_WRITE);
} else if (!http->repetitive_writing) {
http->timer = HTTimer_new(NULL, FlushPutEvent, http, HTRepeatWrite, YES, YES);
http->repetitive_writing = YES;
***************
*** 1255,1260 ****
--- 1264,1274 ----
if (type == HTEvent_WRITE) {
HTStream * input = HTRequest_inputStream(request);
HTPostCallback * pcbf = HTRequest_postCallback(request);
+
+ /* hphalle: Check if predecessor has finished writing */
+ if (!HTNet_isSuccessorEnabled(HTHost_predecessor(host, net)))
+ return HT_OK;
+
status = HTRequest_flush(request) ?
HTHost_forceFlush(host) : (*input->isa->flush)(input);
***************
*** 1289,1294 ****
--- 1303,1309 ----
** Check to see if we can start a new request
** pending in the host object.
*/
+ HTNet_enableSuccessor ( net );
HTHost_launchPending(host);
type = HTEvent_READ;
}