cURL / Mailing Lists / curl-library / Single Mail

curl-library

Libcurl: Auth Digest + POST : why it does not work

From: Bernard Fouché <bernard.fouche_at_kuantic.com>
Date: Mon, 9 Feb 2004 20:03:20 +0100

Hi there.

I few weeks ago, I reported that the combination :

CURLOPT_POSTFIELDS + CURLOPT+CURLAUTH_DIGEST

was not working. I think that I found why.

In lib/http.c, line 1458, there is:

if(!authdone)
    /* Until the auth is done, pretend we only do get */
    httpreq = HTTPREQ_GET;
  else
    httpreq = data->set.httpreq;

So from the beginning of the function Curl_http (line 1044) until this
point, all the processing
is done for the original type of request (a POST in my case), then till the
end of the function,
the function assumes a GET if auth is not yet done (always true when the
application calls
the server the first time)

With such a design, libcurl will send a header like:

POST /Url.....

with no Content-Length since the Content-Length is not used by GET!

So I made a patch and tried to have things clean: before patching I
downloaded and ran
curl-7.11.0 tests and got failure for tests 300, 301, 304, 306 and 509.

I then patched http.c and ran the tests again (from a 'make clean; make;
make test' each time)
and got the same test failures PLUS TEST88 (since that test is using a PUT
with Digest auth
and expect a header sent with PUT!), so maybe my patch is clea ;-). I run
Fedora (FC_1).

The patch is simple: perform the test much earlier, change also the
'request' char pointer and
then changes all further references from 'data->set.httpreq' to 'httpreq'
till the end of the function.

I think that such a change should be done otherwise the curl lib interface
will seem messy to a
programmer if, when having to use Digest Auth + POST, it is required that
first a 'no-use' GET
has to be done explicitely with curl_easy_perform. Or the documentation must
be changed to
tell it clearly. Or, like it is now done, a 'silent GET' is done
automatically and correctly, whatever
the type of the initial request. (anyway a few lines of documentation would
help to explain why
a tcpdump will show an unexpected GET before the required POST!)

  Bernard

Here is a diff -c:

*** lib/http.old.c 2004-01-11 23:17:58.000000000 +0100
--- lib/http.c 2004-02-09 19:50:23.000000000 +0100
***************
*** 1097,1102 ****
--- 1097,1110 ----
    if(result)
      return result;

+ /// until the auth is done, pretend we only do GET
+ if(!authdone){
+ httpreq = HTTPREQ_GET;
+ request=(char *)"GET";
+ }
+ else
+ httpreq = data->set.httpreq;
+
    Curl_safefree(conn->allocptr.ref);
    if(data->change.referer && !checkheaders(data, "Referer:"))
      conn->allocptr.ref = aprintf("Referer: %s\015\012",
data->change.referer);
***************
*** 1109,1115 ****
    else
      conn->allocptr.cookie = NULL;

! if(!conn->bits.upload_chunky && (data->set.httpreq != HTTPREQ_GET)) {
      /* not a chunky transfer but data is to be sent */
      ptr = checkheaders(data, "Transfer-Encoding:");
      if(ptr) {
--- 1117,1123 ----
    else
      conn->allocptr.cookie = NULL;

! if(!conn->bits.upload_chunky && (httpreq != HTTPREQ_GET)) {
      /* not a chunky transfer but data is to be sent */
      ptr = checkheaders(data, "Transfer-Encoding:");
      if(ptr) {
***************
*** 1204,1210 ****
      /* The path sent to the proxy is in fact the entire URL */
      ppath = data->change.url;
    }
! if(HTTPREQ_POST_FORM == data->set.httpreq) {
      /* we must build the whole darned post sequence first, so that we have
         a size of the whole shebang before we start to send it */
       result = Curl_getFormData(&http->sendit, data->set.httppost,
--- 1212,1218 ----
      /* The path sent to the proxy is in fact the entire URL */
      ppath = data->change.url;
    }
! if(HTTPREQ_POST_FORM == httpreq) {
      /* we must build the whole darned post sequence first, so that we have
         a size of the whole shebang before we start to send it */
       result = Curl_getFormData(&http->sendit, data->set.httppost,
***************
*** 1223,1231 ****
    if(!checkheaders(data, "Accept:"))
      http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg,
image/pjpeg, */*\r\n";

! if(( (HTTPREQ_POST == data->set.httpreq) ||
! (HTTPREQ_POST_FORM == data->set.httpreq) ||
! (HTTPREQ_PUT == data->set.httpreq) ) &&
       conn->resume_from) {

/**********************************************************************
       * Resuming upload in HTTP means that we PUT or POST and that we have
--- 1231,1239 ----
    if(!checkheaders(data, "Accept:"))
      http->p_accept = "Accept: image/gif, image/x-xbitmap, image/jpeg,
image/pjpeg, */*\r\n";

! if(( (HTTPREQ_POST == httpreq) ||
! (HTTPREQ_POST_FORM == httpreq) ||
! (HTTPREQ_PUT == httpreq) ) &&
       conn->resume_from) {

/**********************************************************************
       * Resuming upload in HTTP means that we PUT or POST and that we have
***************
*** 1287,1300 ****
       * or uploading and we always let customized headers override our
internal
       * ones if any such are specified.
       */
! if((data->set.httpreq == HTTPREQ_GET) &&
         !checkheaders(data, "Range:")) {
        /* if a line like this was already allocated, free the previous one
*/
        if(conn->allocptr.rangeline)
          free(conn->allocptr.rangeline);
        conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
conn->range);
      }
! else if((data->set.httpreq != HTTPREQ_GET) &&
              !checkheaders(data, "Content-Range:")) {

        if(conn->resume_from) {
--- 1295,1308 ----
       * or uploading and we always let customized headers override our
internal
       * ones if any such are specified.
       */
! if((httpreq == HTTPREQ_GET) &&
         !checkheaders(data, "Range:")) {
        /* if a line like this was already allocated, free the previous one
*/
        if(conn->allocptr.rangeline)
          free(conn->allocptr.rangeline);
        conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
conn->range);
      }
! else if((httpreq != HTTPREQ_GET) &&
              !checkheaders(data, "Content-Range:")) {

        if(conn->resume_from) {
***************
*** 1455,1466 ****
      http->postdata = NULL; /* nothing to post at this point */
      Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */

- if(!authdone)
- /* until the auth is done, pretend we only do GET */
- httpreq = HTTPREQ_GET;
- else
- httpreq = data->set.httpreq;
-
      switch(httpreq) {

      case HTTPREQ_POST_FORM:
--- 1463,1468 ----
Received on 2004-02-10