W3C home > Mailing lists > Public > www-lib@w3.org > January to March 1999

Re: Sending headers

From: <Jim_Ravan@avid.com>
Date: Tue, 16 Mar 1999 11:19:27 -0500
To: www-lib@w3.org
Message-ID: <85256736.0059AC3C.00@amm02.avid.com>


Gert,

>With libwww, how can I send my own headers along with a request? Or can
only
>standard headers be sent? I would like to send a cookie with my request,
as
>if it was coming from a browser. I know cookies are not supported by
libwww
>(yet).

I *just* finished code to send and receive cookies. Look at the bottom of
the HTTPGenMake routine in HTTPGen.c. There is a comment that states "Put
out extra information, if any". There you'll find two loops, one to walk
the HTRequest_generator list in the request, and one to walk the global
HTHeader_generator list. These lists are expected to contain individual
elements that contain the addresses of HTPostCallback functions. So a
function needs to be constructed to write the cookies to the stream. A
function that I wrote to put out cookies looks like this:

// LIBWWW stream struct
struct _HTStream
{
     const HTStreamClass*     isa;
     HTStream*                target;
};

static int SendCookies(HTRequest* request, HTStream* stream)
/*
 *   ARGUMENTS
 *        request        (IN) - current LIBWWW request object.
 *        stream         (IN) - current LIBWWW stream object.
 *
 *   RETURN VALUE
 *        HT_OK          continue processing other request generators.
 *
 *   DESCRIPTION
 *        This LIBWWW Request Generator adds all generated cookie headers
 *        to the current request.
 */
{
     char*     cookie;        // cookie header.
     HTList*   local;         // copy of cookieList to use for walking.

     local = cookieList;

     // Send all the cookies.
     while (cookie = (char*)HTList_nextObject(local))
          (*stream->target->isa->put_block)(stream->target, cookie,
strlen(cookie));

     HTList_delete(cookieList);    // Release the list.
     cookieList = NULL;

     return HT_OK;  // Indicate that request generator processing should
continue.
}


But, all in all, it's pretty uninteresting, huh? The generator just walks a
list and writes the list elements to a stream. But where's the list
"cookieList", and why is it necessary?

Well, *that's* a little more interesting. Obviously, the cookieList
contains the fully formatted cookie strings to be sent. Some other code
puts the cookie strings on the list. What code? ... Before filters. I have
a set of before filters that generate the actual cookie text. I attach
whichever cookie header before filters I need to the request to generate
the proper cookies. In my application, I have to send various cookies at
various times depending on what is being done at the moment. The code to
attach the cookie before filters to the request is:

request = HTRequest_new();
// Send session ID cookie.
HTRequest_addBefore(request, SetSessionContext, NULL, sess->ssID,
HT_FILTER_LAST, FALSE);

(sess->ssID contains a character string, for example, "3748596741")

Note that the before filters have a context parameter, in this example,
sess->ssID. That's the necessary magic. I use the before filter context
pointer to pass information about the cookie value to the cookie filter.
Note that the generator callback does *not* have a context pointer. That is
why there has to be a cookieList. cookieList is a static list where the
before cookie filters attach their cookie strings. I had to do it that way
because I could not pass a context pointer directly to the generator and
have the generator format the cookie strings directly. This means this
solution won't thread very well, but that was not currently an issue for my
application. And who adds the SendCookies generator to the request? I chose
to do that in the cookie filters. You could just as easily do that in the
request setup code. And you could decide to add all this stuff to the
global lists. I chose to add all this at the request level. Here's a cookie
filter:

#define   kCRLF     "\x0D\x0A"

static int SetSessionContext(HTRequest* request, void* param, int mode)
/*
 *   ARGUMENTS
 *        request        (IN) - current LIBWWW request object.
 *        param          (IN) - context that contains a session ID.
 *        mode      (IN) - unused.
 *
 *   RETURN VALUE
 *        HT_OK          continue processing LIBWWW BEFORE filters.
 *
 *   DESCRIPTION
 *        This LIBWWW Before Filter adds a cookie header to the current
request
 *        that identifies the current session.
 */
{
     HTList*   list;                               // Request Generators
list.
     char*     sessionID = (char*)param;      // SessionID.
     char*     linebuf;                       // Build cookie header here.
     int       override;                      // Read, but not used.

     if (sessionID) // If there is a sessionID...
     {
          // Format a sessionID cookie header and put it on the cookieList.
          linebuf = (char*)malloc(257);
          sprintf(linebuf, "Cookie: SessionID=%s;%s", sessionID, kCRLF);

          if (!cookieList)
               cookieList = HTList_new();

          HTList_addObject(cookieList, linebuf);

          // If necessary, create the request generator list.
          list = HTRequest_generator(request, &override);
          if (!list)
          {
               list = HTList_new();
               HTList_addObject(list, SendCookies);
               HTRequest_setGenerator(request, list, FALSE);
          }
     }

     return HT_OK;  // Indicate that Before Filter processing should
continue.
}

In summary, here's how it all works. Write an HTPostCallback that writes
cookies from a static list to the stream. Write one or more before filters
that format cookie strings and place them on that static list. Each cookie
filter also adds the HTPostCallback to the request if it's not already
there. When setting up a request, add the before filters that generate the
cookies you need.

Of course, if you only have one cookie to generate, you don't need the
before filters. Just stick the value in a static and do it all in the
HTPostCallback. But I expect most applications need to generate more than
one type of cookie. All this would be much simpler, and threadable, if the
generator had a context parameter. Ah well.

Hope this helps.

regards,
-jim
Received on Tuesday, 16 March 1999 11:24:12 GMT

This archive was generated by hypermail 2.2.0+W3C-0.50 : Monday, 23 April 2007 18:18:29 GMT