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;
  		      }
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.