]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
HTTP "auth done right". See lib/README.httpauth
authorDaniel Stenberg <daniel@haxx.se>
Wed, 24 Nov 2004 16:11:35 +0000 (16:11 +0000)
committerDaniel Stenberg <daniel@haxx.se>
Wed, 24 Nov 2004 16:11:35 +0000 (16:11 +0000)
33 files changed:
CHANGES
RELEASE-NOTES
TODO-RELEASE
docs/TODO
docs/curl.1
docs/examples/Makefile.am
docs/examples/README
docs/examples/anyauthput.c [new file with mode: 0644]
docs/examples/https.c
docs/examples/multi-post.c
docs/examples/persistant.c
docs/examples/simplepost.c
docs/libcurl/curl_easy_setopt.3
include/curl/curl.h
lib/README.httpauth
lib/http.c
lib/http.h
lib/transfer.c
lib/transfer.h
lib/url.c
lib/urldata.h
packages/vms/config-vms.h_with_ssl
packages/vms/config-vms.h_without_ssl
src/main.c
tests/data/test154
tests/data/test155
tests/data/test156
tests/data/test170
tests/data/test174
tests/data/test175
tests/data/test176
tests/data/test177
tests/data/test88

diff --git a/CHANGES b/CHANGES
index 514d0cc09593e7bc5eff19e15b2104581d7c25c8..7900474c359214fb906f0e4334fc07b0353d8d4f 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -11,6 +11,16 @@ Daniel (24 November 2004)
   with Msys/Mingw on Windows.
 
 Daniel (22 November 2004)
+- Made HTTP PUT and POST requests no longer use HEAD when doing multi-pass
+  auth negotiation (NTLM, Digest and Negotiate), but instead use the request
+  keyword "properly". Details in lib/README.httpauth. This also introduces
+  CURLOPT_IOCTLFUNCTION and CURLOPT_IOCTLDATA, to be used by apps that use the
+  "any" auth alternative as then libcurl may need to send the PUT/POST data
+  more than once and thus may need to ask the app to "rewind" the read data
+  stream to start.
+
+  See also the new example using this: docs/examples/anyauthput.c
+
 - David Phillips enhanced test 518. I made it depend on a "feature" so that
   systems without getrlimit() won't attempt to test 518. configure now checks
   for getrlimit() and setrlimit() for this test case.
index a2c108075955b10b852a11bfc0115f9aeec96f89..4a06b3681308b08613572607f7165081bd72504c 100644 (file)
@@ -3,13 +3,16 @@ Curl and libcurl 7.12.3
  Public curl release number:               84
  Releases counted from the very beginning: 111
  Available command line options:           100
- Available curl_easy_setopt() options:     121
+ Available curl_easy_setopt() options:     123
  Number of public functions in libcurl:    46
  Amount of public web site mirrors:        13
  Number of known libcurl bindings:         29
 
 This release includes the following changes:
 
+ o CURLOPT_IOCTLFUNCTION and CURLOPT_IOCTLDATA added. If your app uses HTTP
+   Digest, NTLM or Negotiate authentication, you will most likely want to use
+   these
  o -w time_redirect and num_redirects
  o no longer uses libcurl.def for building on Windows, OS/2 and Netware
  o builds on Windows CE
@@ -19,6 +22,7 @@ This release includes the following changes:
 
 This release includes the following bugfixes:
 
+ o HTTP PUT/POST with Digest, NTLM or Negotiate no longer uses HEAD
  o now gracefully bails out when exceeding FD_SETSIZE file descriptors
  o CURLINFO_REDIRECT_TIME works
  o building with gssapi libs and hdeaders in the default dirs
index 147df3e253e02a8b2dd67bbb9076c2c1266bf9d0..24719c76c824096e3631f5adfb603ce707d7edef 100644 (file)
@@ -6,7 +6,3 @@ To get fixed in 7.12.3 (planned release: December 2004)
 47 - Peter Sylvester's patch for SRP on the TLS layer
      Awaits OpenSSL support for this, no need to support this in libcurl before
      there's an OpenSSL release that does it.
-
-51 - PUT/POST with multipass authenticaion
-     Daniel works on this.
-
index 94507ea982bcc169b20c78a6a2d52d7ba9a124fa..888b9d371100bfd74f2bbb19efc36cddcb340b65 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
@@ -38,6 +38,11 @@ TODO
 
  LIBCURL - multi interface
 
+ * Add a curl_multi_fdset() alternative that returns only two arrays with file
+   desrciptors for reading and writing to allow the app to use whatever
+   function it prefers. Plus, this allows apps to avoid the FD_SETSIZE problem
+   with select().
+
  * Add curl_multi_timeout() to make libcurl's ares-functionality better.
 
  * Make sure we don't ever loop because of non-blocking sockets return
index dd022534a00e9614e4007df597b91cfeb59f3870..e2fdc8bd99c9b186b84b91e1e7997a67aa493f10 100644 (file)
@@ -91,6 +91,11 @@ network round-trip. This is used instead of setting a specific authentication
 method, which you can do with \fI--basic\fP, \fI--digest\fP, \fI--ntlm\fP, and
 \fI--negotiate\fP. (Added in 7.10.6)
 
+Note that using --anyauth is not recommended if you do uploads from stdin,
+since it may require data to be sent twice and then the client must be able to
+rewind. If the need should arise when uploading from stdin, the upload
+operation will fail.
+
 If this option is used several times, the following occurrences make no
 difference.
 .IP "-b/--cookie <name=data>"
index 6425707d84e07be47691b4a752ff49fd8e040aee..34ac520a723a405b85eab141740829cef2903264 100644 (file)
@@ -9,7 +9,8 @@ EXTRA_DIST = README curlgtk.c sepheaders.c simple.c postit2.c           \
  ftpupload.c httpput.c simplessl.c ftpgetresp.c http-post.c            \
  post-callback.c multi-app.c multi-double.c multi-single.c             \
  multi-post.c fopen.c simplepost.c makefile.dj curlx.c https.c         \
- multi-debugcallback.c fileupload.c getinfo.c ftp3rdparty.c debug.c
+ multi-debugcallback.c fileupload.c getinfo.c ftp3rdparty.c debug.c    \
+ anyauthput.c
 
 all:
        @echo "done"
index dd053d8f0ed30483dff6a7d166f42cd5a7a8658b..9951241c5095e524924e19fcd3db0da7902a321d 100644 (file)
@@ -1,4 +1,8 @@
-EXAMPLES
+                                  _   _ ____  _
+                              ___| | | |  _ \| |
+                             / __| | | | |_) | |
+                            | (__| |_| |  _ <| |___
+                             \___|\___/|_| \_\_____|
 
 This directory is for libcurl programming examples. They are meant to show
 some simple steps on how you can build your own application to take full
@@ -7,6 +11,8 @@ advantage of libcurl.
 If you end up with other small but still useful example sources, please mail
 them for submission in future packages and on the web site.
 
+BUILDING
+
 The Makefile.example is an example makefile that could be used to build these
 examples. Just edit the file according to your system and requirements first.
 
@@ -23,3 +29,34 @@ want you do reorganize them like:
 applications/experiments. Even if the examples in this directory use that site
 as an example URL at some places, it doesn't mean that the URLs work or that
 we expect you to actually torture our web site with your tests! Thanks.
+
+EXAMPLES
+
+anyauthput.c   - HTTP PUT using "any" authentication method
+curlgtk.c      - download using a GTK progress bar
+curlx.c        - getting file info from the remote cert data
+debug.c        - showing how to use the debug callback
+fileupload.c   - uploading to a file:// URL
+fopen.c        - fopen() layer that supports opening URLs and files
+ftp3rdparty.c  - FTP 3rd party transfer
+ftpget.c       - simple getting a file from FTP
+ftpgetresp.c   - get the response strings from the FTP server
+ftpupload.c    - upload a file to a FTP server
+getinfo.c      - get the Content-Type from the recent transfer
+getinmemory.c  - download a file to memory only
+http-post.c    - HTTP POST
+httpput.c      - HTTP PUT a local file
+https.c        - simple HTTPS transfer
+multi-app.c    - a multi-interface app
+multi-debugcallback.c - a multi-interface app using the debug callback
+multi-double.c - a multi-interface app doing two simultaneous transfers
+multi-post.c   - a multi-interface app doing a multipart formpost
+multi-single.c - a multi-interface app getting a single file
+multithread.c  - an example using multi-treading transfering multiple files
+persistant.c   - request two URLs with a persistant connection
+post-callback.c - send a HTTP POST using a callback
+postit2.c      - send a HTTP multipart formpost
+sepheaders.c   - download headers to a separate file
+simple.c       - the most simple download a URL source
+simplepost.c   - HTTP POST
+simplessl.c    - HTTPS example with certificates many options set
diff --git a/docs/examples/anyauthput.c b/docs/examples/anyauthput.c
new file mode 100644 (file)
index 0000000..c548633
--- /dev/null
@@ -0,0 +1,135 @@
+/*****************************************************************************
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
+ *                             \___|\___/|_| \_\_____|
+ *
+ * $Id$
+ */
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+#include <curl/curl.h>
+
+#if LIBCURL_VERSION_NUM < 0x070c03
+#error "upgrade your libcurl to no less than 7.12.3"
+#endif
+
+/*
+ * This example shows a HTTP PUT operation with authentiction using "any"
+ * type. It PUTs a file given as a command line argument to the URL also given
+ * on the command line.
+ *
+ * Since libcurl 7.12.3, using "any" auth and POST/PUT requires a set ioctl
+ * function.
+ *
+ * This example also uses its own read callback.
+ */
+
+/* ioctl callback function */
+static curlioerr my_ioctl(CURL *handle, curliocmd cmd, void *userp)
+{
+  int fd = (int)userp;
+
+  (void)handle; /* not used in here */
+
+  switch(cmd) {
+  case CURLIOCMD_RESTARTREAD:
+    /* mr libcurl kindly asks as to rewind the read data stream to start */
+    if(-1 == lseek(fd, 0, SEEK_SET))
+      /* couldn't rewind */
+      return CURLIOE_FAILRESTART;
+
+    break;
+
+  default: /* ignore unknown commands */
+    return CURLIOE_UNKNOWNCMD;
+  }
+  return CURLIOE_OK; /* success! */
+}
+
+/* read callback function, fread() look alike */
+size_t read_callback(void *ptr, size_t size, size_t nmemb, void *stream)
+{
+  size_t retcode;
+
+  int fd = (int)stream;
+
+  retcode = read(fd, ptr, size * nmemb);
+
+  fprintf(stderr, "*** We read %d bytes from file\n", retcode);
+
+  return retcode;
+}
+
+int main(int argc, char **argv)
+{
+  CURL *curl;
+  CURLcode res;
+  int hd ;
+  struct stat file_info;
+
+  char *file;
+  char *url;
+
+  if(argc < 3)
+    return 1;
+
+  file= argv[1];
+  url = argv[2];
+
+  /* get the file size of the local file */
+  hd = open(file, O_RDONLY) ;
+  fstat(hd, &file_info);
+
+  /* In windows, this will init the winsock stuff */
+  curl_global_init(CURL_GLOBAL_ALL);
+
+  /* get a curl handle */
+  curl = curl_easy_init();
+  if(curl) {
+    /* we want to use our own read function */
+    curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);
+
+    /* which file to upload */
+    curl_easy_setopt(curl, CURLOPT_READDATA, hd);
+
+    /* set the ioctl function */
+    curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, my_ioctl);
+
+    /* pass the file descriptor to the ioctl callback as well */
+    curl_easy_setopt(curl, CURLOPT_IOCTLDATA, hd);
+
+    /* enable "uploading" (which means PUT when doing HTTP) */
+    curl_easy_setopt(curl, CURLOPT_UPLOAD, TRUE) ;
+
+    /* specify target URL, and note that this URL should also include a file
+       name, not only a directory (as you can do with GTP uploads) */
+    curl_easy_setopt(curl,CURLOPT_URL, url);
+
+    /* and give the size of the upload, this supports large file sizes
+       on systems that have general support for it */
+    curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, file_info.st_size);
+
+    /* tell libcurl we can use "any" auth, which lets the lib pick one, but it
+       also costs one extra round-trip and possibly sending of all the PUT
+       data twice!!! */
+    curl_easy_setopt(curl, CURLOPT_HTTPAUTH, CURLAUTH_ANY);
+
+    /* set user name and password for the authentication */
+    curl_easy_setopt(curl, CURLOPT_USERPWD, "user:password");
+
+    /* Now run off and do what you've been told! */
+    res = curl_easy_perform(curl);
+
+    /* always cleanup */
+    curl_easy_cleanup(curl);
+  }
+  close(hd); /* close the local file */
+
+  curl_global_cleanup();
+  return 0;
+}
index 9ce5a308beef418e4d9d2d83ee3bf31d0a2784d9..8ce7c0b3ab0e32936bbb5a86e92a9dc9f028aa95 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * $Id$
index b5a436449f9e889237f73c022f28fdf6adeb3a27..0f9a599ac1cdbd467128d2defb35a6c2f62869cf 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * $Id$
index 0a17031b8032a13a672a922cd49e0c2ce609c45b..673889914d217a11913fc563a6dc5cbfbfebff84 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * $Id$
index 57c1f61d78e2840b5873c8864323ce62a83f82a3..1d156c5837023fa290468eb3ca6d8faf39e31992 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- *                                  _   _ ____  _     
- *  Project                     ___| | | |  _ \| |    
- *                             / __| | | | |_) | |    
- *                            | (__| |_| |  _ <| |___ 
+ *                                  _   _ ____  _
+ *  Project                     ___| | | |  _ \| |
+ *                             / __| | | | |_) | |
+ *                            | (__| |_| |  _ <| |___
  *                             \___|\___/|_| \_\_____|
  *
  * $Id$
index 42385801770d7b871209d7f8288bb5554c324a86..e75ae4a2c04a31168d6c695fffe44b35b6782a48 100644 (file)
@@ -21,7 +21,7 @@
 .\" * $Id$
 .\" **************************************************************************
 .\"
-.TH curl_easy_setopt 3 "12 Mar 2004" "libcurl 7.11.1" "libcurl Manual"
+.TH curl_easy_setopt 3 "21 Nov 2004" "libcurl 7.12.3" "libcurl Manual"
 .SH NAME
 curl_easy_setopt - set options for a curl easy handle
 .SH SYNOPSIS
@@ -142,6 +142,18 @@ don't specify a read callback, this must be a valid FILE *.
 
 This option is also known with the older name \fICURLOPT_INFILE\fP, the name
 \fICURLOPT_READDATA\fP was introduced in 7.9.7.
+.IP CURLOPT_IOCTLFUNCTION
+Function pointer that should match the \fIcurl_ioctl_callback\fP prototype
+found in \fI<curl/curl.h>\fP. This function gets called by libcurl when
+something special I/O-related needs to be done that the library can't do by
+itself. For now, rewinding the read data stream is the only action it can
+request. The rewinding of the read data stream may be necessary when doing a
+HTTP PUT or POST with a multi-pass authentication method.  (Opion added in
+7.12.3)
+.IP CURLOPT_IOCTLDATA
+Pass a pointer that will be untouched by libcurl and passed as the 3rd
+argument in the ioctl callback set with \fICURLOPT_IOCTLFUNCTION\fP.  (Option
+added in 7.12.3)
 .IP CURLOPT_PROGRESSFUNCTION
 Function pointer that should match the \fIcurl_progress_callback\fP prototype
 found in \fI<curl/curl.h>\fP. This function gets called by libcurl instead of
index 393916020320c05eaaaba187e30e7ec57a7f337c..820d2a7a0277f6d4eb3ccfab0ab690b4fa30cde4 100644 (file)
@@ -163,19 +163,39 @@ typedef size_t (*curl_write_callback)(char *buffer,
                                       size_t nitems,
                                       void *outstream);
 
-/* This is a brand new return code for the read callback that will signal
-   the caller to immediately abort the current transfer. */
+/* This is a return code for the read callback that, when returned, will
+   signal libcurl to immediately abort the current transfer. */
 #define CURL_READFUNC_ABORT 0x10000000
 typedef size_t (*curl_read_callback)(char *buffer,
-                                     size_t size,
-                                     size_t nitems,
-                                     void *instream);
+                                      size_t size,
+                                      size_t nitems,
+                                      void *instream);
 
+
+#ifndef CURL_NO_OLDIES
   /* not used since 7.10.8, will be removed in a future release */
 typedef int (*curl_passwd_callback)(void *clientp,
                                     const char *prompt,
                                     char *buffer,
                                     int buflen);
+#endif
+
+typedef enum {
+  CURLIOE_OK,            /* I/O operation successful */
+  CURLIOE_UNKNOWNCMD,    /* command was unknown to callback */
+  CURLIOE_FAILRESTART,   /* failed to restart the read */
+  CURLIOE_LAST           /* never use */
+} curlioerr;
+
+typedef enum  {
+  CURLIOCMD_NOP,         /* no operation */
+  CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
+  CURLIOCMD_LAST         /* never use */
+} curliocmd;
+
+typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
+                                         int cmd,
+                                         void *clientp);
 
 /*
  * The following typedef's are signatures of malloc, free, realloc, strdup and
@@ -282,7 +302,8 @@ typedef enum {
   CURLE_LDAP_INVALID_URL,        /* 62 - Invalid LDAP URL */
   CURLE_FILESIZE_EXCEEDED,       /* 63 - Maximum file size exceeded */
   CURLE_FTP_SSL_FAILED,          /* 64 - Requested FTP SSL level failed */
-
+  CURLE_SEND_FAIL_REWIND,        /* 65 - Sending the data requires a rewind
+                                    that failed */
   CURL_LAST /* never use! */
 } CURLcode;
 
@@ -854,6 +875,9 @@ typedef enum {
   */
   CINIT(FTPSSLAUTH, LONG, 129),
 
+  CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
+  CINIT(IOCTLDATA, OBJECTPOINT, 131),
+
   CURLOPT_LASTENTRY /* the last unused */
 } CURLoption;
 
index baa279a7fdce4ff2744a1b246b681bd62e27c993..9605045107df90aed52b0e8f15699a92c5b821a6 100644 (file)
    determined. Possibly the current transfer speed should be taken into
    account as well.
 
+   NOTE: if the size of the POST data is less than MAX_INITIAL_POST_SIZE (when
+   CURLOPT_POSTFIELDS is used), libcurl will send everything in one single
+   write() (all request-headers and request-body) and thus it will
+   unconditionally send the full post data here.
+
 2. PUT/POST with multi-pass auth but not yet completely negotiated:
 
    Send a PUT/POST request, we know that it will be rejected and thus we claim
index 50638f5bf9829a16a22289dc4d389646974281dc..1277fa21d3a101f8eaafa8519a392ebb3fb731b5 100644 (file)
@@ -192,6 +192,80 @@ static bool pickoneauth(struct auth *pick)
   return picked;
 }
 
+/*
+ * perhapsrewind()
+ *
+ * If we are doing POST or PUT {
+ *   If we have more data to send {
+ *     If we are doing NTLM {
+ *       Keep sending since we must not disconnect
+ *     }
+ *     else {
+ *       If there is more than just a little data left to send, close
+ *       the current connection by force.
+ *     }
+ *   }
+ *   If we have sent any data {
+ *     If we don't have track of all the data {
+ *       call app to tell it to rewind
+ *     }
+ *     else {
+ *       rewind internally so that the operation can restart fine
+ *     }
+ *   }
+ * }
+ */
+static CURLcode perhapsrewind(struct connectdata *conn)
+{
+  struct HTTP *http = conn->proto.http;
+  struct SessionHandle *data = conn->data;
+  curl_off_t bytessent = http->writebytecount;
+  curl_off_t expectsend = -1; /* default is unknown */
+
+  /* figure out how much data we are expected to send */
+  switch(data->set.httpreq) {
+  case HTTPREQ_POST:
+    if(data->set.postfieldsize != -1)
+      expectsend = data->set.postfieldsize;
+    break;
+  case HTTPREQ_PUT:
+    if(data->set.infilesize != -1)
+      expectsend = data->set.infilesize;
+    break;
+  case HTTPREQ_POST_FORM:
+    expectsend = http->postsize;
+    break;
+  default:
+    break;
+  }
+
+  conn->bits.rewindaftersend = FALSE; /* default */
+
+  if((expectsend == -1) || (expectsend > bytessent)) {
+    /* There is still data left to send */
+    if((data->state.authproxy.picked == CURLAUTH_NTLM) ||/* using NTLM */
+       (data->state.authhost.picked == CURLAUTH_NTLM) ) {
+      conn->bits.close = FALSE; /* don't close, keep on sending */
+
+      /* rewind data when completely done sending! */
+      conn->bits.rewindaftersend = TRUE;
+      return CURLE_OK;
+    }
+    else {
+      /* If there is more than just a little data left to send, close the
+       * current connection by force.
+       */
+      conn->bits.close = TRUE;
+      conn->size = 0; /* don't download any more than 0 bytes */
+    }
+  }
+
+  if(bytessent)
+    return Curl_readrewind(conn);
+
+  return CURLE_OK;
+}
+
 /*
  * Curl_http_auth_act() gets called when a all HTTP headers have been received
  * and it checks what authentication methods that are available and decides
@@ -211,25 +285,33 @@ CURLcode Curl_http_auth_act(struct connectdata *conn)
 
   if(conn->bits.user_passwd &&
      ((conn->keep.httpcode == 401) ||
-      (conn->bits.authprobe && conn->keep.httpcode < 300))) {
+      (conn->bits.authneg && conn->keep.httpcode < 300))) {
     pickhost = pickoneauth(&data->state.authhost);
     if(!pickhost)
       data->state.authproblem = TRUE;
   }
   if(conn->bits.proxy_user_passwd &&
      ((conn->keep.httpcode == 407) ||
-      (conn->bits.authprobe && conn->keep.httpcode < 300))) {
+      (conn->bits.authneg && conn->keep.httpcode < 300))) {
     pickproxy = pickoneauth(&data->state.authproxy);
     if(!pickproxy)
       data->state.authproblem = TRUE;
   }
 
-  if(pickhost || pickproxy)
+  if(pickhost || pickproxy) {
     conn->newurl = strdup(data->change.url); /* clone URL */
 
+    if((data->set.httpreq != HTTPREQ_GET) &&
+       (data->set.httpreq != HTTPREQ_HEAD)) {
+      code = perhapsrewind(conn);
+      if(code)
+        return code;
+    }
+  }
+
   else if((conn->keep.httpcode < 300) &&
           (!data->state.authhost.done) &&
-          conn->bits.authprobe) {
+          conn->bits.authneg) {
     /* no (known) authentication available,
        authentication is not "done" yet and
        no authentication seems to be required and
@@ -273,29 +355,34 @@ Curl_http_output_auth(struct connectdata *conn,
   CURLcode result = CURLE_OK;
   struct SessionHandle *data = conn->data;
   char *auth=NULL;
+  struct auth *authhost;
+  struct auth *authproxy;
 
   curlassert(data);
 
+  authhost = &data->state.authhost;
+  authproxy = &data->state.authproxy;
+
   if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
      conn->bits.user_passwd)
     /* continue please */ ;
   else {
-    data->state.authhost.done = TRUE;
-    data->state.authproxy.done = TRUE;
+    authhost->done = TRUE;
+    authproxy->done = TRUE;
     return CURLE_OK; /* no authentication with no user or password */
   }
 
-  if(data->state.authhost.want && !data->state.authhost.picked)
+  if(authhost->want && !authhost->picked)
     /* The app has selected one or more methods, but none has been picked
        so far by a server round-trip. Then we set the picked one to the
        want one, and if this is one single bit it'll be used instantly. */
-    data->state.authhost.picked = data->state.authhost.want;
+    authhost->picked = authhost->want;
 
-  if(data->state.authproxy.want && !data->state.authproxy.picked)
+  if(authproxy->want && !authproxy->picked)
     /* The app has selected one or more methods, but none has been picked so
        far by a proxy round-trip. Then we set the picked one to the want one,
        and if this is one single bit it'll be used instantly. */
-    data->state.authproxy.picked = data->state.authproxy.want;
+    authproxy->picked = authproxy->want;
 
   /* To prevent the user+password to get sent to other than the original
      host due to a location-follow, we do some weirdo checks here */
@@ -308,7 +395,7 @@ Curl_http_output_auth(struct connectdata *conn,
     if (conn->bits.httpproxy &&
         (conn->bits.tunnel_proxy == proxytunnel)) {
 #ifdef USE_SSLEAY
-      if(data->state.authproxy.want == CURLAUTH_NTLM) {
+      if(authproxy->want == CURLAUTH_NTLM) {
         auth=(char *)"NTLM";
         result = Curl_output_ntlm(conn, TRUE);
         if(result)
@@ -316,7 +403,7 @@ Curl_http_output_auth(struct connectdata *conn,
       }
       else
 #endif
-      if(data->state.authproxy.want == CURLAUTH_BASIC) {
+      if(authproxy->want == CURLAUTH_BASIC) {
         /* Basic */
         if(conn->bits.proxy_user_passwd &&
            !checkheaders(data, "Proxy-authorization:")) {
@@ -325,10 +412,12 @@ Curl_http_output_auth(struct connectdata *conn,
           if(result)
             return result;
         }
-        data->state.authproxy.done = TRUE;
+        /* NOTE: Curl_output_basic() should set 'done' TRUE, as the other auth
+           functions work that way */
+        authproxy->done = TRUE;
       }
 #ifndef CURL_DISABLE_CRYPTO_AUTH
-      else if(data->state.authproxy.want == CURLAUTH_DIGEST) {
+      else if(authproxy->want == CURLAUTH_DIGEST) {
         auth=(char *)"Digest";
         result = Curl_output_digest(conn,
                                     TRUE, /* proxy */
@@ -338,31 +427,36 @@ Curl_http_output_auth(struct connectdata *conn,
           return result;
       }
 #endif
-      infof(data, "Proxy auth using %s with user '%s'\n",
-            auth, conn->proxyuser?conn->proxyuser:"");
+      if(auth) {
+        infof(data, "Proxy auth using %s with user '%s'\n",
+              auth, conn->proxyuser?conn->proxyuser:"");
+        authproxy->multi = !authproxy->done;
+      }
+      else
+        authproxy->multi = FALSE;
     }
     else
       /* we have no proxy so let's pretend we're done authenticating
          with it */
-      data->state.authproxy.done = TRUE;
+      authproxy->done = TRUE;
 
     /* Send web authentication header if needed */
     {
       auth = NULL;
 #ifdef HAVE_GSSAPI
-      if((data->state.authhost.want == CURLAUTH_GSSNEGOTIATE) &&
+      if((authhost->want == CURLAUTH_GSSNEGOTIATE) &&
          data->state.negotiate.context &&
          !GSS_ERROR(data->state.negotiate.status)) {
         auth=(char *)"GSS-Negotiate";
         result = Curl_output_negotiate(conn);
         if (result)
           return result;
-        data->state.authhost.done = TRUE;
+        authhost->done = TRUE;
       }
       else
 #endif
 #ifdef USE_SSLEAY
-      if(data->state.authhost.picked == CURLAUTH_NTLM) {
+      if(authhost->picked == CURLAUTH_NTLM) {
         auth=(char *)"NTLM";
         result = Curl_output_ntlm(conn, FALSE);
         if(result)
@@ -372,7 +466,7 @@ Curl_http_output_auth(struct connectdata *conn,
 #endif
       {
 #ifndef CURL_DISABLE_CRYPTO_AUTH
-        if(data->state.authhost.picked == CURLAUTH_DIGEST) {
+        if(authhost->picked == CURLAUTH_DIGEST) {
           auth=(char *)"Digest";
           result = Curl_output_digest(conn,
                                       FALSE, /* not a proxy */
@@ -382,7 +476,7 @@ Curl_http_output_auth(struct connectdata *conn,
             return result;
         } else
 #endif
-        if(data->state.authhost.picked == CURLAUTH_BASIC) {
+        if(authhost->picked == CURLAUTH_BASIC) {
           if(conn->bits.user_passwd &&
              !checkheaders(data, "Authorization:")) {
             auth=(char *)"Basic";
@@ -391,16 +485,21 @@ Curl_http_output_auth(struct connectdata *conn,
               return result;
           }
           /* basic is always ready */
-          data->state.authhost.done = TRUE;
+          authhost->done = TRUE;
         }
       }
-      if(auth)
+      if(auth) {
         infof(data, "Server auth using %s with user '%s'\n",
               auth, conn->user);
+
+        authhost->multi = !authhost->done;
+      }
+      else
+        authhost->multi = FALSE;
     }
   }
   else
-    data->state.authhost.done = TRUE;
+    authhost->done = TRUE;
 
   return result;
 }
@@ -1304,20 +1403,15 @@ CURLcode Curl_http(struct connectdata *conn)
   if(result)
     return result;
 
-  if((!data->state.authhost.done || !data->state.authproxy.done ) &&
-     (httpreq != HTTPREQ_GET)) {
-    /* Until we are authenticated, we switch over to HEAD. Unless its a GET
-       we want to do. The explanation for this is rather long and boring, but
-       the point is that it can't be done otherwise without risking having to
-       send the POST or PUT data multiple times. */
-    httpreq = HTTPREQ_HEAD;
-    request = (char *)"HEAD";
-    conn->bits.no_body = TRUE;
-    conn->bits.authprobe = TRUE; /* this is a request done to probe for
-                                    authentication methods */
+  if((data->state.authhost.multi || data->state.authproxy.multi) &&
+     (httpreq != HTTPREQ_GET) &&
+     (httpreq != HTTPREQ_HEAD)) {
+    /* Auth is required and we are not authenticated yet. Make a PUT or POST
+       with content-length zero as a "probe". */
+    conn->bits.authneg = TRUE;
   }
   else
-    conn->bits.authprobe = FALSE;
+    conn->bits.authneg = FALSE;
 
   Curl_safefree(conn->allocptr.ref);
   if(data->change.referer && !checkheaders(data, "Referer:"))
@@ -1759,7 +1853,7 @@ CURLcode Curl_http(struct connectdata *conn)
     switch(httpreq) {
 
     case HTTPREQ_POST_FORM:
-      if(!http->sendit) {
+      if(!http->sendit || conn->bits.authneg) {
         /* nothing to post! */
         result = add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
         if(result)
@@ -1857,11 +1951,16 @@ CURLcode Curl_http(struct connectdata *conn)
 
     case HTTPREQ_PUT: /* Let's PUT the data to the server! */
 
-      if((data->set.infilesize>0) && !conn->bits.upload_chunky) {
+      if(conn->bits.authneg)
+        postsize = 0;
+      else
+        postsize = data->set.infilesize;
+
+      if((postsize != -1) && !conn->bits.upload_chunky) {
         /* only add Content-Length if not uploading chunked */
         result = add_bufferf(req_buffer,
-                             "Content-Length: %" FORMAT_OFF_T "\r\n", /* size */
-                             data->set.infilesize );
+                             "Content-Length: %" FORMAT_OFF_T "\r\n",
+                             postsize );
         if(result)
           return result;
       }
@@ -1884,19 +1983,19 @@ CURLcode Curl_http(struct connectdata *conn)
         return result;
 
       /* set the upload size to the progress meter */
-      Curl_pgrsSetUploadSize(data, data->set.infilesize);
+      Curl_pgrsSetUploadSize(data, postsize);
 
       /* this sends the buffer and frees all the buffer resources */
       result = add_buffer_send(req_buffer, conn,
                                &data->info.request_size);
       if(result)
-        failf(data, "Failed sending POST request");
+        failf(data, "Failed sending PUT request");
       else
         /* prepare for transfer */
         result = Curl_Transfer(conn, FIRSTSOCKET, -1, TRUE,
                                &http->readbytecount,
-                               FIRSTSOCKET,
-                               &http->writebytecount);
+                               postsize?FIRSTSOCKET:-1,
+                               postsize?&http->writebytecount:NULL);
       if(result)
         return result;
       break;
@@ -1904,10 +2003,13 @@ CURLcode Curl_http(struct connectdata *conn)
     case HTTPREQ_POST:
       /* this is the simple POST, using x-www-form-urlencoded style */
 
-      /* store the size of the postfields */
-      postsize = (data->set.postfieldsize != -1)?
-        data->set.postfieldsize:
-        (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
+      if(conn->bits.authneg)
+        postsize = 0;
+      else
+        /* figure out the size of the postfields */
+        postsize = (data->set.postfieldsize != -1)?
+          data->set.postfieldsize:
+          (data->set.postfields?(curl_off_t)strlen(data->set.postfields):0);
 
       if(!conn->bits.upload_chunky) {
         /* We only set Content-Length and allow a custom Content-Length if
index d321333fe2e904d65b44980ce6ed9299ad54af55..57f1d115e1b0eebafcbfd3e9801d6ba6b15120df 100644 (file)
@@ -57,13 +57,20 @@ int Curl_http_should_fail(struct connectdata *conn);
    public curl/curl.h header. */
 #define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
 
-/* MAX_INITIAL_POST_SIZE indicates the number of kilobytes that will be sent
-   in the initial part of a multi-part POST message. This is primarily for
-   OpenVMS where the maximum number of bytes allowed per I/O is 64K.  For
-   other systems that do not define this, the default is (as it was
-   previously) 100K. */
+/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
+   data get included in the initial data chunk sent to the server. If the
+   data is larger than this, it will automatically get split up in multiple
+   system calls.
+
+   This value used to be fairly big (100K), but we must take into account that
+   if the server rejects the POST due for authentication reasons, this data
+   will always be uncondtionally sent and thus it may not be larger than can
+   always be afforded to send twice.
+
+   It must not be greater than 64K to work on VMS.
+*/
 #ifndef MAX_INITIAL_POST_SIZE
-#define MAX_INITIAL_POST_SIZE (100*1024)
+#define MAX_INITIAL_POST_SIZE 1024
 #endif
 
 #endif
index b52e40ef1e8b4487b2a65800493cb02ca816d3b4..5e833353850bc0400a409b19b0536b4aa92ec8b7 100644 (file)
@@ -193,6 +193,55 @@ checkhttpprefix(struct SessionHandle *data,
   return FALSE;
 }
 
+/*
+ * Curl_readrewind() rewinds the read stream. This typically (so far) only
+ * used for HTTP POST/PUT with multi-pass authentication when a sending was
+ * denied and a resend is necessary.
+ */
+CURLcode Curl_readrewind(struct connectdata *conn)
+{
+  struct SessionHandle *data = conn->data;
+
+  conn->bits.rewindaftersend = FALSE; /* we rewind now */
+
+  /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+     CURLOPT_HTTPPOST, call app to rewind
+  */
+  if(data->set.postfields ||
+     (data->set.httpreq == HTTPREQ_POST_FORM))
+    ; /* do nothing */
+  else {
+    if(data->set.ioctl) {
+      curlioerr err;
+
+      err = data->set.ioctl(data, CURLIOCMD_RESTARTREAD,
+                            data->set.ioctl_client);
+      infof(data, "the ioctl callback returned %d\n", (int)err);
+
+      if(err) {
+        /* FIXME: convert to a human readable error message */
+        failf(data, "ioctl callback returned error %d\n", (int)err);
+        return CURLE_SEND_FAIL_REWIND;
+      }
+    }
+    else {
+      /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+         given FILE * stream and we can actually attempt to rewind that
+         ourself with fseek() */
+      if(data->set.fread == (curl_read_callback)fread) {
+        if(-1 != fseek(data->set.in, 0, SEEK_SET))
+          /* successful rewind */
+          return CURLE_OK;
+      }
+
+      /* no callback set or failure aboe, makes us fail at once */
+      failf(data, "necessary data rewind wasn't possible\n");
+      return CURLE_SEND_FAIL_REWIND;
+    }
+  }
+  return CURLE_OK;
+}
+
 
 /*
  * Curl_readwrite() is the low-level function to be called when data is to
@@ -1163,6 +1212,12 @@ CURLcode Curl_readwrite(struct connectdata *conn,
             /* done */
             k->keepon &= ~KEEP_WRITE; /* we're done writing */
             writedone = TRUE;
+
+            if(conn->bits.rewindaftersend) {
+              result = Curl_readrewind(conn);
+              if(result)
+                return result;
+            }
             break;
           }
 
index 1b7eb828fcde9eb15a2c45e806ef671fc5f06fc3..78a3e046b66c250491c39da24a7630c35c6e8c74 100644 (file)
@@ -34,7 +34,7 @@ void Curl_single_fdset(struct connectdata *conn,
                        fd_set *exc_fd_set,
                        int *max_fd);
 CURLcode Curl_readwrite_init(struct connectdata *conn);
-
+CURLcode Curl_readrewind(struct connectdata *conn);
 CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
 
 /* This sets up a forthcoming transfer */
index c1ff239935f653b6cec9ccfb90b947a3fe5806d2..1b15d69578ab825c5656c19144f55272c2deaa13 100644 (file)
--- a/lib/url.c
+++ b/lib/url.c
@@ -1099,6 +1099,18 @@ CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option, ...)
       /* When set to NULL, reset to our internal default function */
       data->set.fread = (curl_read_callback)fread;
     break;
+  case CURLOPT_IOCTLFUNCTION:
+    /*
+     * I/O control callback. Might be NULL.
+     */
+    data->set.ioctl = va_arg(param, curl_ioctl_callback);
+    break;
+  case CURLOPT_IOCTLDATA:
+    /*
+     * I/O control data pointer. Might be NULL.
+     */
+    data->set.ioctl_client = va_arg(param, void *);
+    break;
   case CURLOPT_SSLCERT:
     /*
      * String that holds file name of the SSL certificate to use
index 764ca3c515d055e7787f80e19e5d0edff9063fec..e161e8083e42c5a7c1cfd61acb28d71a23fe9004 100644 (file)
@@ -319,9 +319,14 @@ struct ConnectBits {
                          This is implicit when SSL-protocols are used through
                          proxies, but can also be enabled explicitly by
                          apps */
-  bool authprobe;     /* set TRUE when this transfer is done to probe for auth
-                         types, as when asking for "any" type when speaking
-                         HTTP */
+  bool authneg;       /* TRUE when the auth phase has started, which means
+                         that we are creating a request with an auth header,
+                         but it is not the final request in the auth
+                         negotiation. */
+  bool rewindaftersend;/* TRUE when the sending couldn't be stopped even
+                          though it will be discarded. When the whole send
+                          operation is done, we must call the data rewind
+                          callback. */
 };
 
 struct hostname {
@@ -696,6 +701,9 @@ struct auth {
                  resource */
   bool done;  /* TRUE when the auth phase is done and ready to do the *actual*
                  request */
+  bool multi; /* TRUE if this is not yet authenticated but within the auth
+                 multipass negotiation */
+
 };
 
 struct UrlState {
@@ -827,7 +835,9 @@ struct UserDefined {
   curl_read_callback fread;          /* function that reads the input */
   curl_progress_callback fprogress;  /* function for progress information */
   curl_debug_callback fdebug;      /* function that write informational data */
+  curl_ioctl_callback ioctl;       /* function for I/O control */
   void *progress_client; /* pointer to pass to the progress callback */
+  void *ioctl_client;   /* pointer to pass to the ioctl callback */
   long timeout;         /* in seconds, 0 means no timeout */
   long connecttimeout;  /* in seconds, 0 means no timeout */
   long ftp_response_timeout; /* in seconds, 0 means no timeout */
index 9d8e522b7d682cae926f1d1851b993e95806ef51..e47acbe614fbcb5043f44a3251994100ef15d586 100755 (executable)
 #endif
 #endif
 
-/* Define to set number of kilobytes in initial POST message. On VMS systems
-   this is important as the default is 100 and the maximum amount of data
-   transferable in a VMS $QIO is 64K. All VMS versions prior to Alpha/I64
-   V8.2 and TCP/IP V5.5 are affected by this. */
-#define MAX_INITIAL_POST_SIZE (60*1024)
-
 /* Define if you have the ANSI C header files.  */
 #define STDC_HEADERS 1
 
index 0d7eee7c80ddca71bf8f1434fdcc9e23bb342bce..5b87c1dd255be6e33d4fd43610650f911b5684bf 100755 (executable)
 #endif
 #endif
 
-/* Define to set the number of kilobytes per POST message. On VMS systems
-   this is important as the default is 100 and the maximum amount of data
-   transferable in a VMS QIO is 64K. All VMS versions prior to Alpha/I64 V8.2
-   and TCP/IP V5.5 are affected by this. */
-#define MAX_INITIAL_POST_SIZE (60*1024)
-
 /* Define if you have the ANSI C header files.  */
 #define STDC_HEADERS 1
 
index 653deb1a5b4283d3e0367956dc0b86493392db15..f7431b4d1ee49b2f3043e19b1212fbaeb63b819a 100644 (file)
@@ -2420,8 +2420,30 @@ struct InStruct {
   struct Configurable *config;
 };
 
+static curlioerr my_ioctl(CURL *handle, curliocmd cmd, void *userp)
+{
+  struct InStruct *in=(struct InStruct *)userp;
+  (void)handle; /* not used in here */
+
+  switch(cmd) {
+  case CURLIOCMD_RESTARTREAD:
+    /* mr libcurl kindly asks as to rewind the read data stream to start */
+    if(-1 == fseek(in->stream, 0, SEEK_SET))
+      /* couldn't rewind, the reason is in errno but errno is just not
+         portable enough and we don't actually care that much why we failed. */
+      return CURLIOE_FAILRESTART;
+
+    break;
+
+  default: /* ignore unknown commands */
+    return CURLIOE_UNKNOWNCMD;
+  }
+  return CURLIOE_OK;
+}
+
 static int my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
 {
+  int rc;
   struct InStruct *in=(struct InStruct *)userp;
   struct Configurable *config = in->config;
   curl_off_t size = (curl_off_t)(sz * nmemb);  /* typecast to prevent warnings
@@ -2480,7 +2502,11 @@ static int my_fread(void *buffer, size_t sz, size_t nmemb, void *userp)
     config->lastsendsize = sz*nmemb;
   }
 
-  return fread(buffer, sz, nmemb, in->stream);
+  rc = fread(buffer, sz, nmemb, in->stream);
+#if 0
+  fprintf(stderr, "CALLBACK returning %d bytes data\n", (int)rc);
+#endif
+  return rc;
 }
 
 struct ProgressData {
@@ -3333,6 +3359,10 @@ operate(struct Configurable *config, int argc, char *argv[])
         /* what call to read */
         curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_fread);
 
+        /* libcurl 7.12.3 business: */
+        curl_easy_setopt(curl, CURLOPT_IOCTLDATA, &input);
+        curl_easy_setopt(curl, CURLOPT_IOCTLFUNCTION, my_ioctl);
+
         if(config->recvpersecond) {
           /* tell libcurl to use a smaller sized buffer as it allows us to
              make better sleeps! 7.9.9 stuff! */
index 07be0c6b43f94775a86a545431ab3ebaa446dff0..010137ecefa7dc37acfc8eebef00eb2c6d35b6ce 100644 (file)
@@ -72,10 +72,12 @@ four is the number of lines
 ^User-Agent:.*
 </strip>
 <protocol>
-HEAD /154 HTTP/1.1\r
+PUT /154 HTTP/1.1\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 85\r
+Expect: 100-continue\r
 \r
 PUT /154 HTTP/1.1\r
 Authorization: Digest username="testuser", realm="gimme all yer s3cr3ts", nonce="11223344", uri="/154", response="b71551e12d1c456e47d8388ecb2edeca"\r
index 56322ebe2d71293f72096a754f0795a29b7d0596..55a965e49f36f42ecda04a2bee3f7c80efcd5b2d 100644 (file)
@@ -90,16 +90,20 @@ four is the number of lines
 ^User-Agent:.*
 </strip>
 <protocol>
-HEAD /155 HTTP/1.1\r
+PUT /155 HTTP/1.1\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 85\r
+Expect: 100-continue\r
 \r
-HEAD /155 HTTP/1.1\r
+PUT /155 HTTP/1.1\r
 Authorization: NTLM TlRMTVNTUAABAAAAAgIAAAAAAAAgAAAAAAAAACAAAAA=\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 0\r
+Expect: 100-continue\r
 \r
 PUT /155 HTTP/1.1\r
 Authorization: NTLM TlRMTVNTUAADAAAAGAAYAEgAAAAYABgAYAAAAAAAAABAAAAACAAIAEAAAAAAAAAASAAAAAAAAAB4AAAAAYIAAHRlc3R1c2VyWmRDApEJkUyGOPS3DjvASModEeW/N/FBqYVyF4y6/y/7F6qmEQ7lXjXFF3tH1145\r
index f2f4aaabc599e86a06310cf82ff0412dfd0c783f..9a9aae9aa7a7da1feb41b8501bc046816584dbba 100644 (file)
@@ -58,11 +58,6 @@ four is the number of lines
 ^User-Agent:.*
 </strip>
 <protocol>
-HEAD /156 HTTP/1.1\r
-Host: 127.0.0.1:%HTTPPORT\r
-Pragma: no-cache\r
-Accept: */*\r
-\r
 PUT /156 HTTP/1.1\r
 User-Agent: curl/7.10.5 (i686-pc-linux-gnu) libcurl/7.10.5 OpenSSL/0.9.7a ipv6 zlib/1.1.3\r
 Host: 127.0.0.1:%HTTPPORT\r
index 659f693db3263dbf30a6735d992da97caa78d700..46012ad4ebc249805bece840c990d586cad697fe 100644 (file)
@@ -24,12 +24,13 @@ http://a.galaxy.far.far.away/170 --proxy http://%HOSTIP:%HTTPPORT --proxy-user f
 ^User-Agent: curl/.*
 </strip>
 <protocol>
-HEAD http://a.galaxy.far.far.away/170 HTTP/1.1\r
+POST http://a.galaxy.far.far.away/170 HTTP/1.1\r
 Proxy-Authorization: NTLM TlRMTVNTUAABAAAAAgIAAAAAAAAgAAAAAAAAACAAAAA=\r
 User-Agent: curl/7.12.0-CVS (i686-pc-linux-gnu) libcurl/7.12.0-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 libidn/0.4.3\r
 Host: a.galaxy.far.far.away\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 0\r
 \r
 </protocol>
 # 52 is CURLE_GOT_NOTHING
index 363a4899e97afcb3c0628320067eda5819964b39..6f19a76130a36837ad1585989aae771abcfc1163 100644 (file)
@@ -1,35 +1,13 @@
 # Server-side
 <reply>
 <data>
-HTTP/1.1 200 beng swsclose swsbounce\r
+HTTP/1.1 200 beng swsclose\r
 Server: Microsoft-IIS/6.0\r
 Authentication-Info: Passport1.4 tname=MSPAuth,tname=MSPProf,tname=MSPConsent,tname=MSPSecAuth\r
 Content-Type: text/html; charset=iso-8859-1\r
 \r
 This is not the real page
 </data>
-
-<data1>
-HTTP/1.1 200 moo swsclose\r
-Server: Microsoft-IIS/6.0\r
-Content-Type: text/html; charset=iso-8859-1\r
-\r
-content for you
-</data1>
-
-<datacheck>
-HTTP/1.1 200 beng swsclose swsbounce\r
-Server: Microsoft-IIS/6.0\r
-Authentication-Info: Passport1.4 tname=MSPAuth,tname=MSPProf,tname=MSPConsent,tname=MSPSecAuth\r
-Content-Type: text/html; charset=iso-8859-1\r
-\r
-HTTP/1.1 200 moo swsclose\r
-Server: Microsoft-IIS/6.0\r
-Content-Type: text/html; charset=iso-8859-1\r
-\r
-content for you
-</datacheck>
-
 </reply>
 
 # Client-side
@@ -52,12 +30,6 @@ http://%HOSTIP:%HTTPPORT/174 -u testuser:testpass --anyauth -d "junkelijunk"
 ^User-Agent:.*
 </strip>
 <protocol nonewline=yes>
-HEAD /174 HTTP/1.1\r
-User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
-Host: 127.0.0.1:%HTTPPORT\r
-Pragma: no-cache\r
-Accept: */*\r
-\r
 POST /174 HTTP/1.1\r
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
 Host: 127.0.0.1:%HTTPPORT\r
index 57496cd8332312f3f946e4aea2f5dddad640cfbe..1cf9ac48162165dad1b2603daed7bdc8e5562fe6 100644 (file)
@@ -52,11 +52,13 @@ http://%HOSTIP:%HTTPPORT/175 -u auser:apasswd --digest -d "junkelijunk"
 ^User-Agent:.*
 </strip>
 <protocol nonewline=yes>
-HEAD /175 HTTP/1.1\r
+POST /175 HTTP/1.1\r
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 0\r
+Content-Type: application/x-www-form-urlencoded\r
 \r
 POST /175 HTTP/1.1\r
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
index 387a6895957858db76a787a5174211f6871f7666..5d9cbff44ce7b3536d3e052e1f517ca0f0fa8f35 100644 (file)
@@ -56,12 +56,14 @@ http://%HOSTIP:%HTTPPORT/176 -u auser:apasswd --ntlm -d "junkelijunk"
 ^User-Agent:.*
 </strip>
 <protocol nonewline=yes>
-HEAD /176 HTTP/1.1\r
+POST /176 HTTP/1.1\r
 Authorization: NTLM TlRMTVNTUAABAAAAAgIAAAAAAAAgAAAAAAAAACAAAAA=\r
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 0\r
+Content-Type: application/x-www-form-urlencoded\r
 \r
 POST /176 HTTP/1.1\r
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
index 8543ab694dfa848e410aa564ba0e12337d114188..9188de0450cdc45bfeaffbcf58440e4399c98d09 100644 (file)
@@ -29,11 +29,13 @@ http://%HOSTIP:%HTTPPORT/177 -u auser:apasswd --digest -d "junkelijunk"
 ^User-Agent:.*
 </strip>
 <protocol>
-HEAD /177 HTTP/1.1\r
+POST /177 HTTP/1.1\r
 User-Agent: curl/7.12.1-CVS (i686-pc-linux-gnu) libcurl/7.12.1-CVS OpenSSL/0.9.6b ipv6 zlib/1.1.4 GSS libidn/0.4.6\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 0\r
+Content-Type: application/x-www-form-urlencoded\r
 \r
 </protocol>
 </verify>
index a07b3a3e1df7b797f3e19b80ae5b591c7cdce14d..e6e2e4779ff05cf41ba506b1f2e064b5f849bf2c 100644 (file)
@@ -66,10 +66,12 @@ four is the number of lines
 ^User-Agent:.*
 </strip>
 <protocol>
-HEAD /88 HTTP/1.1\r
+PUT /88 HTTP/1.1\r
 Host: 127.0.0.1:%HTTPPORT\r
 Pragma: no-cache\r
 Accept: */*\r
+Content-Length: 0\r
+Expect: 100-continue\r
 \r
 PUT /88 HTTP/1.1\r
 Authorization: Digest username="testuser", realm="testrealm", nonce="1053604145", uri="/88", response="78a49fa53d0c228778297687d4168e71"\r