o missing ssh.obj in VS makefiles
o FTP ;type=i URLs now work with CURLOPT_PROXY_TRANSFER_MODE in Turkish locale
+ o realms with quoted quotation marks in HTTP Digest headers
This release includes the following known bugs:
This release would not have looked like this without help, code, reports and
advice from friends like these:
- Lisa Xu, Daniel Fandrich, Craig A West
+ Lisa Xu, Daniel Fandrich, Craig A West, Alexey Borzov
Thanks! (and sorry if I forgot to mention someone)
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
- * Copyright (C) 1998 - 2008, Daniel Stenberg, <daniel@haxx.se>, et al.
+ * Copyright (C) 1998 - 2009, Daniel Stenberg, <daniel@haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
/* The last #include file should be: */
#include "memdebug.h"
+#define MAX_VALUE_LENGTH 256
+#define MAX_CONTENT_LENGTH 1024
+
+/*
+ * Return 0 on success and then the buffers are filled in fine.
+ *
+ * Non-zero means failure to parse.
+ */
+static int get_pair(const char *str, char *value, char *content,
+ const char **endptr)
+{
+ int c;
+ bool starts_with_quote = FALSE;
+ bool escape = FALSE;
+
+ for(c=MAX_VALUE_LENGTH-1; (*str && (*str != '=') && c--); )
+ *value++ = *str++;
+ *value=0;
+
+ if('=' != *str++)
+ /* eek, no match */
+ return 1;
+
+ if('\"' == *str) {
+ /* this starts with a quote so it must end with one as well! */
+ str++;
+ starts_with_quote = TRUE;
+ }
+
+ for(c=MAX_CONTENT_LENGTH-1; *str && c--; str++) {
+ switch(*str) {
+ case '\\':
+ if(!escape) {
+ /* possibly the start of an escaped quote */
+ escape = TRUE;
+ *content++ = '\\'; /* even though this is an escape character, we still
+ store it as-is in the target buffer */
+ continue;
+ }
+ break;
+ case ',':
+ if(!starts_with_quote) {
+ /* this signals the end of the content if we didn't get a starting quote
+ and then we do "sloppy" parsing */
+ c=0; /* the end */
+ continue;
+ }
+ break;
+ case '\r':
+ case '\n':
+ /* end of string */
+ c=0;
+ continue;
+ case '\"':
+ if(!escape && starts_with_quote) {
+ /* end of string */
+ c=0;
+ continue;
+ }
+ break;
+ }
+ escape = FALSE;
+ *content++ = *str;
+ }
+ *content=0;
+
+ *endptr = str;
+
+ return 0; /* all is fine! */
+}
+
/* Test example headers:
WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
Curl_digest_cleanup_one(d);
while(more) {
- char value[256];
- char content[1024];
+ char value[MAX_VALUE_LENGTH];
+ char content[MAX_CONTENT_LENGTH];
size_t totlen=0;
while(*header && ISSPACE(*header))
header++;
- /* how big can these strings be? */
- if((2 == sscanf(header, "%255[^=]=\"%1023[^\"]\"",
- value, content)) ||
- /* try the same scan but without quotes around the content but don't
- include the possibly trailing comma, newline or carriage return */
- (2 == sscanf(header, "%255[^=]=%1023[^\r\n,]",
- value, content)) ) {
- if(!strcmp("\"\"", content)) {
- /* for the name="" case where we get only the "" in the content
- * variable, simply clear the content then
- */
- content[0]=0;
- }
+ /* extract a value=content pair */
+ if(!get_pair(header, value, content, &header)) {
+
if(Curl_raw_equal(value, "nonce")) {
d->nonce = strdup(content);
if(!d->nonce)
else
break; /* we're done here */
- header += totlen;
/* pass all additional spaces here */
while(*header && ISSPACE(*header))
header++;
#ifdef CURL_DOES_CONVERSIONS
CURLcode rc;
/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
- It converts digest text to ASCII so the MD5 will be correct for
+ It converts digest text to ASCII so the MD5 will be correct for
what ultimately goes over the network.
*/
#define CURL_OUTPUT_DIGEST_CONV(a, b) \
--- /dev/null
+<testcase>
+<info>
+<keywords>
+HTTP
+HTTP GET
+HTTP Digest auth
+</keywords>
+</info>
+# Server-side
+<reply>
+<data>
+HTTP/1.1 401 Authorization Required swsclose\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+WWW-Authenticate: Digest realm="test \"this\" realm!!", nonce="1053604145"\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 26\r
+\r
+This is not the real page
+</data>
+
+# This is supposed to be returned when the server gets a
+# Authorization: Digest line passed-in from the client
+<data1000>
+HTTP/1.1 200 OK swsclose\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 23\r
+\r
+This IS the real page!
+</data1000>
+
+<datacheck>
+HTTP/1.1 401 Authorization Required swsclose\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+WWW-Authenticate: Digest realm="test \"this\" realm!!", nonce="1053604145"\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 26\r
+\r
+HTTP/1.1 200 OK swsclose\r
+Server: Apache/1.3.27 (Darwin) PHP/4.1.2\r
+Content-Type: text/html; charset=iso-8859-1\r
+Content-Length: 23\r
+\r
+This IS the real page!
+</datacheck>
+
+</reply>
+
+# Client-side
+<client>
+<server>
+http
+</server>
+<features>
+crypto
+</features>
+ <name>
+HTTP with Digest and realm with quoted quotes
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/1095 -u testuser:testpass --digest
+</command>
+</client>
+
+# Verify data after the test has been "shot"
+<verify>
+<strip>
+^User-Agent:.*
+</strip>
+<protocol>
+GET /1095 HTTP/1.1\r
+Host: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+GET /1095 HTTP/1.1\r
+Authorization: Digest username="testuser", realm="test \"this\" realm!!", nonce="1053604145", uri="/1095", response="a1c7931ece9e8617bae2715045e4f49f"\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: %HOSTIP:%HTTPPORT\r
+Accept: */*\r
+\r
+</protocol>
+</verify>
+</testcase>