Hello, If you call HTTP_HttpSendRequestA, and pass in lpszHeaders that are not terminate with '\r\n', AND you are attempting to send POST data, it won't work, because there will not be an empty line between the HTTP headers and the POST data. (The remote server will simply wait a few minutes thinking you have not sent the POST data yet, eventually timing out). I believe it is a mistake for wine to assume the lpszHeaders will be terminated with '\r\n'. The Xten sipphone client does not terminate lpszHeaders with '\r\n', and it works fine under numerous versions of Microsoft Windows. MSDN also makes no mention of any need to terminate the lpszHeaders with '\r\n'. Below is a rather simple (and safe) patch that adds a '\r\n' to lpszHeaders if it is not already terminated by '\r\n'. Note, the variable name 'lpszHeaders_r_n' is kind of lame, please feel free to pick a better name if you have an idea. Jeremy Shaw. --- orig/dlls/wininet/http.c +++ mod/dlls/wininet/http.c @@ -1160,6 +1160,7 @@ INT i; BOOL bSuccess = FALSE; LPSTR requestString = NULL; + LPSTR lpszHeaders_r_n = NULL; /* lpszHeaders with atleast one pair of \r\n at the end */ INT requestStringLen; INT responseLen; INT headerLength = 0; @@ -1236,10 +1237,34 @@ strlen(HTTPHEADER) + 5; /* " \r\n\r\n" */ + /* add "\r\n" to end of lpszHeaders if needed */ + if (lpszHeaders) + { + int len = strlen(lpszHeaders); + + /* Check if the string is terminated with \r\n, but not if + * the string is less that 2 characters long, because then + * we would be looking at memory before the beginning of + * the string. Besides, if it is less than 2 characters + * long, then clearly, its not terminated with \r\n. + */ + if ((len > 2) && (memcmp(lpszHeaders + (len - 2), "\r\n", 2) == 0)) + { + lpszHeaders_r_n = HTTP_strdup(lpszHeaders); + } + else + { + TRACE("Adding \r\n to lpszHeaders.\n"); + lpszHeaders_r_n = HeapAlloc( GetProcessHeap(), 0, strlen(lpszHeaders) + 3 ); + strcpy( lpszHeaders_r_n, lpszHeaders ); + strcpy( lpszHeaders_r_n + strlen(lpszHeaders), "\r\n" ); + } + } + /* Add length of passed headers */ if (lpszHeaders) { - headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders) : dwHeaderLength; + headerLength = -1 == dwHeaderLength ? strlen(lpszHeaders_r_n) : dwHeaderLength; requestStringLen += headerLength + 2; /* \r\n */ } @@ -1319,12 +1344,18 @@ cnt += sprintf(requestString + cnt, "%s%s", HTTPHOSTHEADER, lpwhr->lpszHostName); /* Append passed request headers */ - if (lpszHeaders) + if (lpszHeaders_r_n) { strcpy(requestString + cnt, "\r\n"); cnt += 2; - strcpy(requestString + cnt, lpszHeaders); + strcpy(requestString + cnt, lpszHeaders_r_n); cnt += headerLength; + /* only add \r\n if not already present */ + if (memcmp((requestString + cnt) - 2, "\r\n", 2) != 0) + { + strcpy(requestString + cnt, "\r\n"); + cnt += 2; + } } /* Set (header) termination string for request */ @@ -1345,7 +1376,7 @@ cnt += dwOptionalLength; /* we also have to decrease the expected string length by two, * since we won't be adding on those following \r\n's */ - requestStringLen -= 2; + requestStringLen -= 2; } else { /* if there is no optional data, add on another \r\n just to be safe */ @@ -1463,6 +1494,9 @@ if (requestString) HeapFree(GetProcessHeap(), 0, requestString); + + if (lpszHeaders) + HeapFree(GetProcessHeap(), 0, lpszHeaders_r_n); /* TODO: send notification for P3P header */