Wine-devel
Threads by month
- ----- 2026 -----
- March
- February
- January
- ----- 2025 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2003 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2002 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2001 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
August 2019
- 66 participants
- 557 discussions
20 Aug '19
TestAgent was fixed a couple of years ago so the TestBot should not have
to deal with such lines anymore.
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
testbot/lib/WineTestBot/LogUtils.pm | 15 ++++++---------
1 file changed, 6 insertions(+), 9 deletions(-)
diff --git a/testbot/lib/WineTestBot/LogUtils.pm b/testbot/lib/WineTestBot/LogUtils.pm
index b75607af..3dca2e44 100644
--- a/testbot/lib/WineTestBot/LogUtils.pm
+++ b/testbot/lib/WineTestBot/LogUtils.pm
@@ -351,16 +351,14 @@ sub ParseWineTestReport($$$)
_CheckUnit($Parser, $Cur, $1, "todo");
$Cur->{LineTodos}++;
}
- # TestLauncher's skip message is quite broken
- elsif ($Line =~ /^([_a-z0-9]+)(?:\.c)?:\d+:? Tests? skipped: / or
+ elsif ($Line =~ /^([_a-z0-9]+)\.c:\d+: Tests skipped: / or
($Cur->{Unit} ne "" and
- $Line =~ /($Cur->{Unit})(?:\.c)?:\d+:? Tests? skipped: /))
+ $Line =~ /($Cur->{Unit})\.c:\d+: Tests skipped: /))
{
my $Unit = $1;
# Don't complain and don't count misplaced skips. Only complain if they
- # are misreported (see _CloseTestUnit). Also TestLauncher uses the wrong
- # name in its skip message when skipping tests.
- if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "" or $Unit eq $Cur->{Dll})
+ # are misreported (see _CloseTestUnit).
+ if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "")
{
$Cur->{LineSkips}++;
}
@@ -396,9 +394,8 @@ sub ParseWineTestReport($$$)
my ($Pid, $Unit, $Todos, $Failures, $Skips) = ($1, $2, $3, $4, $5);
# Dlls that have only one test unit will run it even if there is
- # no argument. Also TestLauncher uses the wrong name in its test
- # summary line when skipping tests.
- if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "" or $Unit eq $Cur->{Dll})
+ # no argument.
+ if ($Unit eq $Cur->{Unit} or $Cur->{Unit} eq "")
{
# There may be more than one summary line due to child processes
$Cur->{Pids}->{$Pid || 0} = 1;
--
2.20.1
1
0
[PATCH] winetest: Add test instructions in the dissect and gather scripts.
by Francois Gouget 20 Aug '19
by Francois Gouget 20 Aug '19
20 Aug '19
Signed-off-by: Francois Gouget <fgouget(a)codeweavers.com>
---
winetest/dissect | 6 ++++++
winetest/gather | 5 +++++
2 files changed, 11 insertions(+)
diff --git a/winetest/dissect b/winetest/dissect
index c95d628f..e5b2815f 100755
--- a/winetest/dissect
+++ b/winetest/dissect
@@ -26,6 +26,12 @@
# where DIGIT is for resolving name clashes and data/BUILD/outdated is
# created to signal the change in the given build.
#
+# To test this script:
+# - Make sure $workdir is not set in winetest.conf
+# - Put a test report in queue/rep1/report
+# - Run ./dissect
+# - Examine the result in data/
+#
# Exit: 0 - successfully processed a report, call again
# 1 - failed to process a report, call again
# 2 - there was nothing to do
diff --git a/winetest/gather b/winetest/gather
index a894377e..31ba8fa0 100755
--- a/winetest/gather
+++ b/winetest/gather
@@ -25,6 +25,11 @@
# script. Races and concurrency problems must be dealt with on that higher
# level.
#
+# To test this script:
+# - Make sure $workdir is not set in winetest.conf
+# - After running dissect, run ./gather
+# - Examine the result in data/
+#
# Exit: 0 - successfully processed a build, call again
# 1 - should not happen
# 2 - there was nothing to do
--
2.20.1
1
0
20 Aug '19
A recent change to the game Everquest adds a call to EnumSystemFirmwareTables.
This of course causes the game to crash. Adding this stub call restores full
functionality to the game.
Signed-off-by: Steven Bell <bell.steven(a)gmail.com>
---
.../api-ms-win-core-sysinfo-l1-2-0.spec | 2 +-
.../api-ms-win-core-sysinfo-l1-2-1.spec | 2 +-
dlls/kernel32/cpu.c | 10 ++++++++++
dlls/kernel32/kernel32.spec | 2 +-
dlls/kernelbase/kernelbase.spec | 2 +-
5 files changed, 14 insertions(+), 4 deletions(-)
diff --git a/dlls/api-ms-win-core-sysinfo-l1-2-0/api-ms-win-core-sysinfo-l1-2-0.spec b/dlls/api-ms-win-core-sysinfo-l1-2-0/api-ms-win-core-sysinfo-l1-2-0.spec
index 9b0567412d..1103427d4d 100644
--- a/dlls/api-ms-win-core-sysinfo-l1-2-0/api-ms-win-core-sysinfo-l1-2-0.spec
+++ b/dlls/api-ms-win-core-sysinfo-l1-2-0/api-ms-win-core-sysinfo-l1-2-0.spec
@@ -1,4 +1,4 @@
-@ stub EnumSystemFirmwareTables
+@ stdcall EnumSystemFirmwareTables(long ptr long) kernel32.EnumSystemFirmwareTables
@ stdcall GetComputerNameExA(long ptr ptr) kernel32.GetComputerNameExA
@ stdcall GetComputerNameExW(long ptr ptr) kernel32.GetComputerNameExW
@ stdcall GetLocalTime(ptr) kernel32.GetLocalTime
diff --git a/dlls/api-ms-win-core-sysinfo-l1-2-1/api-ms-win-core-sysinfo-l1-2-1.spec b/dlls/api-ms-win-core-sysinfo-l1-2-1/api-ms-win-core-sysinfo-l1-2-1.spec
index 6da2f25fa1..9a89b4b57a 100644
--- a/dlls/api-ms-win-core-sysinfo-l1-2-1/api-ms-win-core-sysinfo-l1-2-1.spec
+++ b/dlls/api-ms-win-core-sysinfo-l1-2-1/api-ms-win-core-sysinfo-l1-2-1.spec
@@ -1,5 +1,5 @@
@ stub DnsHostnameToComputerNameExW
-@ stub EnumSystemFirmwareTables
+@ stdcall EnumSystemFirmwareTables(long ptr long) kernel32.EnumSystemFirmwareTables
@ stdcall GetComputerNameExA(long ptr ptr) kernel32.GetComputerNameExA
@ stdcall GetComputerNameExW(long ptr ptr) kernel32.GetComputerNameExW
@ stdcall GetLocalTime(ptr) kernel32.GetLocalTime
diff --git a/dlls/kernel32/cpu.c b/dlls/kernel32/cpu.c
index 7668a10ea4..3f4f6c6bad 100644
--- a/dlls/kernel32/cpu.c
+++ b/dlls/kernel32/cpu.c
@@ -365,3 +365,13 @@ UINT WINAPI GetSystemFirmwareTable(DWORD provider, DWORD id, void *buffer, DWORD
HeapFree(GetProcessHeap(), 0, sfti);
return buffer_size;
}
+
+
+/***********************************************************************
+ * EnumSystemFirmwareTables (KERNEL32.@)
+ */
+UINT WINAPI EnumSystemFirmwareTables(DWORD provider, void *buffer, DWORD size)
+{
+ FIXME("(0x%08x, %p, %d)\n", provider, buffer, size);
+ return 0;
+}
diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 016c3022dc..fb8e4c9642 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -418,7 +418,7 @@
@ stdcall EnumResourceTypesW(long ptr long)
@ stdcall EnumSystemCodePagesA(ptr long)
@ stdcall EnumSystemCodePagesW(ptr long)
-# @ stub EnumSystemFirmwareTables
+@ stdcall EnumSystemFirmwareTables(long ptr long)
@ stdcall EnumSystemGeoID(long long ptr)
@ stdcall EnumSystemLanguageGroupsA(ptr long ptr)
@ stdcall EnumSystemLanguageGroupsW(ptr long ptr)
diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec
index 4bb2b55cde..91e78889e6 100644
--- a/dlls/kernelbase/kernelbase.spec
+++ b/dlls/kernelbase/kernelbase.spec
@@ -312,7 +312,7 @@
@ stdcall EnumResourceTypesExA(long ptr long long long)
@ stdcall EnumResourceTypesExW(long ptr long long long)
@ stdcall EnumSystemCodePagesW(ptr long) kernel32.EnumSystemCodePagesW
-# @ stub EnumSystemFirmwareTables
+@ stdcall EnumSystemFirmwareTables(long ptr long) kernel32.EnumSystemFirmwareTables
@ stdcall EnumSystemGeoID(long long ptr) kernel32.EnumSystemGeoID
@ stdcall EnumSystemLanguageGroupsW(ptr long ptr) kernel32.EnumSystemLanguageGroupsW
@ stdcall EnumSystemLocalesA(ptr long) kernel32.EnumSystemLocalesA
--
2.20.1
2
1
19 Aug '19
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
v2: attempt to fix or work around some test failures
dlls/httpapi/tests/Makefile.in | 2 +-
dlls/httpapi/tests/httpapi.c | 847 ++++++++++++++++++++++++++++++++-
2 files changed, 829 insertions(+), 20 deletions(-)
diff --git a/dlls/httpapi/tests/Makefile.in b/dlls/httpapi/tests/Makefile.in
index 1c253a789b..20210a3451 100644
--- a/dlls/httpapi/tests/Makefile.in
+++ b/dlls/httpapi/tests/Makefile.in
@@ -1,5 +1,5 @@
TESTDLL = httpapi.dll
-IMPORTS = httpapi
+IMPORTS = httpapi ws2_32
C_SRCS = \
httpapi.c
diff --git a/dlls/httpapi/tests/httpapi.c b/dlls/httpapi/tests/httpapi.c
index e1437552a8..01a517b3db 100644
--- a/dlls/httpapi/tests/httpapi.c
+++ b/dlls/httpapi/tests/httpapi.c
@@ -1,7 +1,8 @@
/*
- * HttpApi tests
+ * HTTP server API tests
*
* Copyright 2017 Nikolay Sivov for CodeWeavers
+ * Copyright 2019 Zebediah Figura
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,6 +31,9 @@
#include "wine/test.h"
+static const WCHAR localhost_urlW[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
+static const WCHAR localhost_url2W[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','1','/',0};
+
static ULONG (WINAPI *pHttpCreateServerSession)(HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *session_id,
ULONG reserved);
static ULONG (WINAPI *pHttpCloseServerSession)(HTTP_SERVER_SESSION_ID session_id);
@@ -49,32 +53,827 @@ static void init(void)
#undef X
}
-static void test_HttpCreateHttpHandle(void)
+static const char simple_req[] =
+ "GET /foobar HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: WINE\r\n"
+ "\r\n";
+
+static int create_client_socket(void)
+{
+ struct sockaddr_in sockaddr =
+ {
+ .sin_family = AF_INET,
+ .sin_port = htons(50000),
+ .sin_addr.S_un.S_addr = inet_addr("127.0.0.1"),
+ };
+ int s = socket(AF_INET, SOCK_STREAM, 0), ret;
+ ret = connect(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
+ ok(!ret, "Failed to connect socket, error %u.\n", GetLastError());
+ return s;
+}
+
+/* Helper function for when we don't care about the response received. */
+static void send_response_v1(HANDLE queue, HTTP_REQUEST_ID id, int s)
+{
+ HTTP_RESPONSE_V1 response = {};
+ char response_buffer[2048];
+ int ret;
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, id, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, NULL, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+}
+
+static void test_v1_server(void)
{
- HANDLE handle, handle2;
+ static const WCHAR invalid_url1[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
+ static const WCHAR invalid_url2[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
+ static const WCHAR invalid_url3[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
+ static const WCHAR invalid_url4[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t','/',0};
+ static const WCHAR invalid_url5[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','/',0};
+ static const WCHAR invalid_url6[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','0','/',0};
+ static const WCHAR cooked_urlW[] = {'h','t','t','p',':','/','/',
+ 'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/','f','o','o','b','a','r',0};
+
+ char DECLSPEC_ALIGN(8) req_buffer[2048], response_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ struct sockaddr_in sockaddr, *sin;
+ HTTP_RESPONSE_V1 response = {};
+ HANDLE queue, queue2;
+ unsigned int i;
+ OVERLAPPED ovl;
+ DWORD ret_size;
ULONG ret;
- BOOL b;
+ SOCKET s;
+ int len;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
ret = HttpCreateHttpHandle(NULL, 0);
-todo_wine
- ok(ret == ERROR_INVALID_PARAMETER, "Unexpected ret value %u.\n", ret);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Unexpected error %u.\n", ret);
/* Non-zero reserved parameter is accepted on XP/2k3. */
- handle = NULL;
- ret = HttpCreateHttpHandle(&handle, 0);
-todo_wine {
+ queue = NULL;
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Unexpected ret value %u.\n", ret);
+ if (ret) return;
+ ok(!!queue, "Unexpected handle value %p.\n", queue);
+
+ queue2 = NULL;
+ ret = HttpCreateHttpHandle(&queue2, 0);
ok(!ret, "Unexpected ret value %u.\n", ret);
- ok(handle != NULL, "Unexpected handle value %p.\n", handle);
+ ok(queue2 && queue2 != queue, "Unexpected handle %p.\n", queue2);
+ ret = CloseHandle(queue2);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+
+ ret = HttpReceiveHttpRequest(NULL, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_INVALID_HANDLE, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, 0xdeadbeef, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ ret = HttpAddUrl(NULL, localhost_urlW, NULL);
+ ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_INVALID_PARAMETER /* < Vista */, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url1, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url2, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url3, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url4, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url5, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url6, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(ret == ERROR_ALREADY_EXISTS, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, localhost_url2W, NULL);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ len = sizeof(sockaddr);
+ ret = getsockname(s, (struct sockaddr *)&sockaddr, &len);
+ ok(ret == 0, "getsockname() failed, error %u.\n", WSAGetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, TRUE);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+
+ ok(!req->Flags, "Got flags %#x.\n", req->Flags);
+ ok(req->ConnectionId, "Expected nonzero connection ID.\n");
+ ok(req->RequestId, "Expected nonzero connection ID.\n");
+ ok(!req->UrlContext, "Got URL context %s.\n", wine_dbgstr_longlong(req->UrlContext));
+ ok(req->Version.MajorVersion == 1, "Got major version %u.\n", req->Version.MajorVersion);
+ ok(req->Version.MinorVersion == 1, "Got major version %u.\n", req->Version.MinorVersion);
+ ok(req->Verb == HttpVerbGET, "Got verb %u.\n", req->Verb);
+ ok(!req->UnknownVerbLength, "Got unknown verb length %u.\n", req->UnknownVerbLength);
+ ok(req->RawUrlLength == 7, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!req->pUnknownVerb, "Got unknown verb %s.\n", req->pUnknownVerb);
+ ok(!strcmp(req->pRawUrl, "/foobar"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 58, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 14, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(!req->CookedUrl.QueryStringLength, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, cooked_urlW), "Got full URL '%ls'.\n", req->CookedUrl.pFullUrl);
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host '%ls'.\n", req->CookedUrl.pHost);
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path '%ls'.\n", req->CookedUrl.pAbsPath);
+ ok(!req->CookedUrl.pQueryString, "Got query string '%ls'.\n", req->CookedUrl.pQueryString);
+ ok(!memcmp(req->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ sin = (SOCKADDR_IN *)req->Address.pLocalAddress;
+ ok(sin->sin_family == AF_INET, "Got family %u.\n", sin->sin_family);
+ ok(ntohs(sin->sin_port) == 50000, "Got wrong port %u.\n", ntohs(sin->sin_port));
+ ok(sin->sin_addr.S_un.S_addr == inet_addr("127.0.0.1"), "Got address %08x.\n", sin->sin_addr.S_un.S_addr);
+ ok(!req->Headers.UnknownHeaderCount, "Got %u unknown headers.\n", req->Headers.UnknownHeaderCount);
+ ok(!req->Headers.pUnknownHeaders, "Got unknown headers %p.\n", req->Headers.pUnknownHeaders);
+ for (i = 0; i < ARRAY_SIZE(req->Headers.KnownHeaders); ++i)
+ {
+ if (i == HttpHeaderConnection)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 10, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "keep-alive"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else if (i == HttpHeaderHost)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 15, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "localhost:50000"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else if (i == HttpHeaderUserAgent)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 4, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "WINE"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else
+ {
+ ok(!req->Headers.KnownHeaders[i].RawValueLength, "Header %#x: got length %u.\n",
+ i, req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!req->Headers.KnownHeaders[i].pRawValue, "Header %#x: got value '%s'.\n",
+ i, req->Headers.KnownHeaders[i].pRawValue);
+ }
+ }
+ ok(req->BytesReceived == strlen(simple_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(!req->EntityChunkCount, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(!req->pEntityChunks, "Got entity chunks %p.\n", req->pEntityChunks);
+ ok(!req->RawConnectionId, "Got SSL connection ID %s.\n", wine_dbgstr_longlong(req->RawConnectionId));
+ ok(!req->pSslInfo, "Got SSL info %p.\n", req->pSslInfo);
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ response.Headers.KnownHeaders[HttpHeaderRetryAfter].pRawValue = "120";
+ response.Headers.KnownHeaders[HttpHeaderRetryAfter].RawValueLength = 3;
+ ret = HttpSendHttpResponse(queue, 0xdeadbeef, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(ret, "Got error %u.\n", GetLastError());
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret == ret_size, "Expected size %u, got %u.\n", ret_size, ret);
+
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nRetry-After: 120\r\n"), "Missing or malformed Retry-After header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+
+ ret = HttpReceiveHttpRequest(queue, req->RequestId, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+
+ /* HttpReceiveHttpRequest() may return synchronously, but this cannot be
+ * reliably tested. Introducing a delay after send() and before
+ * HttpReceiveHttpRequest() confirms this. */
+
+ ret = HttpRemoveUrl(NULL, localhost_urlW);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(ret == ERROR_FILE_NOT_FOUND, "Got error %u.\n", ret);
+ ret = HttpRemoveUrl(queue, localhost_url2W);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+
+ closesocket(s);
+ CloseHandle(ovl.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(ret == ERROR_INVALID_HANDLE, "Got error %u.\n", ret);
}
- handle2 = NULL;
- ret = HttpCreateHttpHandle(&handle2, 0);
-todo_wine {
- ok(!ret, "Unexpected ret value %u.\n", ret);
- ok(handle2 != NULL && handle != handle2, "Unexpected handle %p.\n", handle2);
+
+static void test_v1_completion_port(void)
+{
+ char DECLSPEC_ALIGN(8) req_buffer[2048], response_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ HTTP_RESPONSE_V1 response = {};
+ OVERLAPPED ovl, *povl;
+ HANDLE queue, port;
+ DWORD ret_size;
+ ULONG_PTR key;
+ ULONG ret;
+ SOCKET s;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+
+ port = CreateIoCompletionPort(queue, NULL, 123, 0);
+ ok(!!port, "Failed to create completion port, error %u.\n", GetLastError());
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret_size = key = 0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 1000);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(povl == &ovl, "OVERLAPPED pointers didn't match.\n");
+ ok(key == 123, "Got unexpected key %lu.\n", key);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret_size = key = 0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 1000);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(povl == &ovl, "OVERLAPPED pointers didn't match.\n");
+ ok(key == 123, "Got unexpected key %lu.\n", key);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret == ret_size, "Expected size %u, got %u.\n", ret_size, ret);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ CloseHandle(port);
+ CloseHandle(ovl.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
}
- b = CloseHandle(handle);
-todo_wine
- ok(b, "Failed to close queue handle.\n");
+
+static void test_v1_multiple_requests(void)
+{
+ char DECLSPEC_ALIGN(8) req_buffer1[2048], DECLSPEC_ALIGN(8) req_buffer2[2048];
+ HTTP_REQUEST_V1 *req1 = (HTTP_REQUEST_V1 *)req_buffer1, *req2 = (HTTP_REQUEST_V1 *)req_buffer2;
+ HTTP_RESPONSE_V1 response = {};
+ struct sockaddr_in sockaddr;
+ OVERLAPPED ovl1, ovl2;
+ DWORD ret_size;
+ SOCKET s1, s2;
+ HANDLE queue;
+ ULONG ret;
+ int len;
+
+ ovl1.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ ovl2.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req1, sizeof(req_buffer1), NULL, &ovl1);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req2, sizeof(req_buffer2), NULL, &ovl2);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl1, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ s1 = create_client_socket();
+ ret = send(s1, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = WaitForSingleObject(ovl1.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(ret == WAIT_TIMEOUT, "Got %u.\n", ret);
+
+ s2 = create_client_socket();
+ ret = send(s2, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = WaitForSingleObject(ovl1.hEvent, 0);
+ ok(!ret, "Got %u.\n", ret);
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+
+ len = sizeof(sockaddr);
+ getsockname(s1, (struct sockaddr *)&sockaddr, &len);
+ ok(!memcmp(req1->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ len = sizeof(sockaddr);
+ getsockname(s2, (struct sockaddr *)&sockaddr, &len);
+ ok(!memcmp(req2->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ ok(req1->ConnectionId != req2->ConnectionId,
+ "Expected different connection IDs, but got %s.\n", wine_dbgstr_longlong(req1->ConnectionId));
+ ok(req1->RequestId != req2->RequestId,
+ "Expected different request IDs, but got %s.\n", wine_dbgstr_longlong(req1->RequestId));
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, req1->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl1, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = HttpSendHttpResponse(queue, req2->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl2, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ /* Test sending multiple requests from the same socket. */
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req1, sizeof(req_buffer1), NULL, &ovl1);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req2, sizeof(req_buffer2), NULL, &ovl2);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ ret = send(s1, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+ ret = send(s1, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = WaitForSingleObject(ovl1.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(ret == WAIT_TIMEOUT, "Got %u.\n", ret);
+
+ ret = HttpSendHttpResponse(queue, req1->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl1, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+ ok(req1->ConnectionId == req2->ConnectionId, "Expected same connection IDs.\n");
+ ok(req1->RequestId != req2->RequestId,
+ "Expected different request IDs, but got %s.\n", wine_dbgstr_longlong(req1->RequestId));
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s1);
+ closesocket(s2);
+ CloseHandle(ovl1.hEvent);
+ CloseHandle(ovl2.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_short_buffer(void)
+{
+ char DECLSPEC_ALIGN(8) req_buffer[2048], DECLSPEC_ALIGN(8) req_buffer2[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer, *req2 = (HTTP_REQUEST_V1 *)req_buffer2;
+ HTTP_REQUEST_ID req_id;
+ OVERLAPPED ovl;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(HTTP_REQUEST_V1) - 1, &ret_size, NULL);
+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(HTTP_REQUEST_V1), &ret_size, NULL);
+ ok(ret == ERROR_MORE_DATA, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(!!req->ConnectionId, "Got connection ID %s.\n", wine_dbgstr_longlong(req->ConnectionId));
+ ok(!!req->RequestId, "Got request ID %s.\n", wine_dbgstr_longlong(req->RequestId));
+ ok(!req->Version.MajorVersion || req->Version.MajorVersion == 0xcccc /* < Vista */,
+ "Got major version %u.\n", req->Version.MajorVersion);
+ ok(!req->BytesReceived || req->BytesReceived == ((ULONGLONG)0xcccccccc << 32 | 0xcccccccc) /* < Vista */,
+ "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+
+ /* At this point the request has been assigned a specific ID, and one cannot
+ * receive it by calling with HTTP_NULL_ID. */
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req2, sizeof(req_buffer2), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ req_id = req->RequestId;
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, req_id, 0, (HTTP_REQUEST *)req, ret_size - 1, &ret_size, NULL);
+ ok(ret == ERROR_MORE_DATA, "Got error %u.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, req_id, 0, (HTTP_REQUEST *)req, ret_size, &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(req->RequestId == req_id, "Got request ID %s.\n", wine_dbgstr_longlong(req->RequestId));
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ CloseHandle(ovl.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_entity_body(void)
+{
+ char DECLSPEC_ALIGN(8) req_buffer[4096], response_buffer[2048], req_body[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ HTTP_RESPONSE_V1 response = {};
+ HTTP_DATA_CHUNK chunks[2] = {};
+ ULONG ret, chunk_size;
+ unsigned int i;
+ DWORD ret_size;
+ HANDLE queue;
+ SOCKET s;
+
+ static const char post_req[] =
+ "POST /xyzzy HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Length: 5\r\n"
+ "\r\n"
+ "ping";
+
+ static const char post_req2[] =
+ "POST /xyzzy HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Length: 2048\r\n"
+ "\r\n";
+
+ for (i = 0; i < sizeof(req_body); ++i)
+ req_body[i] = i / 111;
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, post_req, sizeof(post_req), 0);
+ ok(ret == sizeof(post_req), "send() returned %d.\n", ret);
+ /* Windows versions before 8 will return success, and report that an entity
+ * body exists in the Flags member, but fail to account for it in the
+ * BytesReceived member or actually copy it to the buffer, if
+ * HttpReceiveHttpRequest() is called before the kernel has finished
+ * receiving the entity body. Add a small delay to work around this. */
+ Sleep(100);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(req->Flags == HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS, "Got flags %#x.\n", req->Flags);
+ ok(req->BytesReceived == sizeof(post_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength == 1,
+ "Got header length %u.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue, "5"),
+ "Got header value %s.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue);
+ ok(!req->EntityChunkCount, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(!req->pEntityChunks, "Got entity chunks %p.\n", req->pEntityChunks);
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ response.EntityChunkCount = ARRAY_SIZE(chunks);
+ response.pEntityChunks = chunks;
+ chunks[0].DataChunkType = HttpDataChunkFromMemory;
+ chunks[0].FromMemory.pBuffer = (void *)"pong";
+ chunks[0].FromMemory.BufferLength = 4;
+ chunks[1].DataChunkType = HttpDataChunkFromMemory;
+ chunks[1].FromMemory.pBuffer = (void *)"pang";
+ chunks[1].FromMemory.BufferLength = 4;
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, NULL, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nContent-Length: 8\r\n"), "Missing or malformed Content-Length header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+ ok(!memcmp(response_buffer + ret - 12, "\r\n\r\npongpang", 12), "Response did not end with entity data.\n");
+
+ ret = HttpReceiveHttpRequest(queue, req->RequestId, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+
+ /* http won't overwrite a Content-Length header if we manually supply one,
+ * but it also won't truncate the entity body to match. It will however
+ * always write its own Date header. */
+
+ ret = send(s, post_req, sizeof(post_req), 0);
+ ok(ret == sizeof(post_req), "send() returned %d.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ response.Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength = 1;
+ response.Headers.KnownHeaders[HttpHeaderContentLength].pRawValue = "6";
+ response.Headers.KnownHeaders[HttpHeaderDate].RawValueLength = 10;
+ response.Headers.KnownHeaders[HttpHeaderDate].pRawValue = "yesteryear";
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, NULL, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nContent-Length: 6\r\n"), "Missing or malformed Content-Length header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+ ok(!strstr(response_buffer, "yesteryear"), "Unexpected Date value.\n");
+ ok(!memcmp(response_buffer + ret - 12, "\r\n\r\npongpang", 12), "Response did not end with entity data.\n");
+
+ /* Test the COPY_BODY flag. */
+
+ ret = send(s, post_req, sizeof(post_req), 0);
+ ok(ret == sizeof(post_req), "send() returned %d.\n", ret);
+ Sleep(100);
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+ (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(!req->Flags, "Got flags %#x.\n", req->Flags);
+ ok(req->BytesReceived == sizeof(post_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength == 1,
+ "Got header length %u.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue, "5"),
+ "Got header value %s.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue);
+ ok(req->EntityChunkCount == 1, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(req->pEntityChunks[0].DataChunkType == HttpDataChunkFromMemory,
+ "Got chunk type %u.\n", req->pEntityChunks[0].DataChunkType);
+ ok(req->pEntityChunks[0].FromMemory.BufferLength == 5,
+ "Got chunk length %u.\n", req->pEntityChunks[0].FromMemory.BufferLength);
+ ok(!memcmp(req->pEntityChunks[0].FromMemory.pBuffer, "ping", 5),
+ "Got chunk data '%s'.\n", (char *)req->pEntityChunks[0].FromMemory.pBuffer);
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = send(s, post_req2, strlen(post_req2), 0);
+ ok(ret == strlen(post_req2), "send() returned %d.\n", ret);
+ ret = send(s, req_body, sizeof(req_body), 0);
+ ok(ret == sizeof(req_body), "send() returned %d.\n", ret);
+
+ Sleep(100);
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+ (HTTP_REQUEST *)req, 2000, &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size == 2000, "Got size %u.\n", ret_size);
+ ok(req->Flags == HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS, "Got flags %#x.\n", req->Flags);
+ ok(req->BytesReceived == strlen(post_req2) + 2048, "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength == 4,
+ "Got header length %u.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue, "2048"),
+ "Got header value %s.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue);
+ ok(req->EntityChunkCount == 1, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(req->pEntityChunks[0].DataChunkType == HttpDataChunkFromMemory,
+ "Got chunk type %u.\n", req->pEntityChunks[0].DataChunkType);
+ chunk_size = req->pEntityChunks[0].FromMemory.BufferLength;
+ ok(chunk_size > 0 && chunk_size < 2000, "Got chunk size %u.\n", chunk_size);
+ ok(!memcmp(req->pEntityChunks[0].FromMemory.pBuffer, req_body, chunk_size), "Chunk data didn't match.\n");
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_bad_request(void)
+{
+ char response_buffer[2048];
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, "foo\r\n", strlen("foo\r\n"), 0);
+ ok(ret == strlen("foo\r\n"), "send() returned %d.\n", ret);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+
+ ok(!strncmp(response_buffer, "HTTP/1.1 400 Bad Request\r\n", 26), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nConnection: close\r\n"), "Missing or malformed Connection header.\n");
+
+ ret = send(s, "foo\r\n", strlen("foo\r\n"), 0);
+ ok(ret == strlen("foo\r\n"), "send() returned %d.\n", ret);
+
+ WSASetLastError(0xdeadbeef);
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(!ret, "Connection should be shut down.\n");
+ ok(!WSAGetLastError(), "Got error %u.\n", WSAGetLastError());
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_cooked_url(void)
+{
+ static const WCHAR cooked_urlW[] = {'h','t','t','p',':','/','/',
+ 'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/','f','o','o','b','a','r','?','a','=','b',0};
+
+ char DECLSPEC_ALIGN(8) req_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ static const char req1[] =
+ "GET /foobar?a=b HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "\r\n";
+
+ static const char req2[] =
+ "GET http://localhost:50000/ HTTP/1.1\r\n"
+ "Host: ignored\r\n"
+ "Connection: keep-alive\r\n"
+ "\r\n";
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, req1, strlen(req1), 0);
+ ok(ret == strlen(req1), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(req->RawUrlLength == 11, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!strcmp(req->pRawUrl, "/foobar?a=b"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 66, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 14, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(req->CookedUrl.QueryStringLength == 8, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, cooked_urlW),
+ "Got full URL '%ls'.\n", req->CookedUrl.pFullUrl);
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host '%ls'.\n", req->CookedUrl.pHost);
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path '%ls'.\n", req->CookedUrl.pAbsPath);
+ ok(req->CookedUrl.pQueryString == req->CookedUrl.pFullUrl + 29,
+ "Got query string '%ls'.\n", req->CookedUrl.pQueryString);
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = send(s, req2, strlen(req2), 0);
+ ok(ret == strlen(req2), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(req->RawUrlLength == 23, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!strcmp(req->pRawUrl, "http://localhost:50000/"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 46, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 2, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(!req->CookedUrl.QueryStringLength, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, localhost_urlW),
+ "Got full URL '%ls'.\n", req->CookedUrl.pFullUrl);
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host '%ls'.\n", req->CookedUrl.pHost);
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path '%ls'.\n", req->CookedUrl.pAbsPath);
+ ok(!req->CookedUrl.pQueryString, "Got query string '%ls'.\n", req->CookedUrl.pQueryString);
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_unknown_tokens(void)
+{
+ char DECLSPEC_ALIGN(8) req_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ static const char req1[] =
+ "xyzzy / HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "Qux: foo baz \r\n"
+ "\r\n";
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, req1, strlen(req1), 0);
+ ok(ret == strlen(req1), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(req->Verb == HttpVerbUnknown, "Got verb %u.\n", req->Verb);
+ ok(req->UnknownVerbLength == 5, "Got unknown verb length %u.\n", req->UnknownVerbLength);
+ ok(!strcmp(req->pUnknownVerb, "xyzzy"), "Got unknown verb %s.\n", req->pUnknownVerb);
+ ok(req->Headers.UnknownHeaderCount == 1, "Got %u unknown headers.\n", req->Headers.UnknownHeaderCount);
+ ok(req->Headers.pUnknownHeaders[0].NameLength == 3, "Got name length %u.\n",
+ req->Headers.pUnknownHeaders[0].NameLength);
+ ok(!strcmp(req->Headers.pUnknownHeaders[0].pName, "Qux"), "Got name %s.\n",
+ req->Headers.pUnknownHeaders[0].pName);
+ ok(req->Headers.pUnknownHeaders[0].RawValueLength == 7, "Got value length %u.\n",
+ req->Headers.pUnknownHeaders[0].RawValueLength);
+ ok(!strcmp(req->Headers.pUnknownHeaders[0].pRawValue, "foo baz"), "Got value %s.\n",
+ req->Headers.pUnknownHeaders[0].pRawValue);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
}
static void test_HttpCreateServerSession(void)
@@ -184,14 +983,24 @@ static void test_HttpCreateUrlGroup(void)
START_TEST(httpapi)
{
HTTPAPI_VERSION version = { 1, 0 };
+ WSADATA wsadata;
ULONG ret;
init();
+ WSAStartup(MAKEWORD(1,1), &wsadata);
+
ret = HttpInitialize(version, HTTP_INITIALIZE_SERVER, NULL);
ok(!ret, "Failed to initialize library, ret %u.\n", ret);
- test_HttpCreateHttpHandle();
+ test_v1_server();
+ test_v1_completion_port();
+ test_v1_multiple_requests();
+ test_v1_short_buffer();
+ test_v1_entity_body();
+ test_v1_bad_request();
+ test_v1_cooked_url();
+ test_v1_unknown_tokens();
test_HttpCreateServerSession();
test_HttpCreateUrlGroup();
--
2.22.0
2
1
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=44958
Signed-off-by: Alistair Leslie-Hughes <leslie_alistair(a)hotmail.com>
---
dlls/dbgeng/dbgeng.c | 478 ++++++++++++++++++++++++++++++++++++++-----
1 file changed, 426 insertions(+), 52 deletions(-)
diff --git a/dlls/dbgeng/dbgeng.c b/dlls/dbgeng/dbgeng.c
index 9fcce32607..35796dd8a7 100644
--- a/dlls/dbgeng/dbgeng.c
+++ b/dlls/dbgeng/dbgeng.c
@@ -63,7 +63,7 @@ struct target_process
struct debug_client
{
- IDebugClient IDebugClient_iface;
+ IDebugClient7 IDebugClient_iface;
IDebugDataSpaces IDebugDataSpaces_iface;
IDebugSymbols3 IDebugSymbols3_iface;
IDebugControl2 IDebugControl2_iface;
@@ -241,7 +241,7 @@ static void debug_client_detach_target(struct target_process *target)
target->handle = NULL;
}
-static struct debug_client *impl_from_IDebugClient(IDebugClient *iface)
+static struct debug_client *impl_from_IDebugClient(IDebugClient7 *iface)
{
return CONTAINING_RECORD(iface, struct debug_client, IDebugClient_iface);
}
@@ -271,14 +271,20 @@ static struct debug_client *impl_from_IDebugSystemObjects(IDebugSystemObjects *i
return CONTAINING_RECORD(iface, struct debug_client, IDebugSystemObjects_iface);
}
-static HRESULT STDMETHODCALLTYPE debugclient_QueryInterface(IDebugClient *iface, REFIID riid, void **obj)
+static HRESULT STDMETHODCALLTYPE debugclient_QueryInterface(IDebugClient7 *iface, REFIID riid, void **obj)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
TRACE("%p, %s, %p.\n", iface, debugstr_guid(riid), obj);
if (IsEqualIID(riid, &IID_IDebugClient) ||
- IsEqualIID(riid, &IID_IUnknown))
+ IsEqualIID(riid, &IID_IDebugClient2) ||
+ IsEqualIID(riid, &IID_IDebugClient3) ||
+ IsEqualIID(riid, &IID_IDebugClient4) ||
+ IsEqualIID(riid, &IID_IDebugClient5) ||
+ IsEqualIID(riid, &IID_IDebugClient6) ||
+ IsEqualIID(riid, &IID_IDebugClient7) ||
+ IsEqualIID(riid, &IID_IUnknown))
{
*obj = iface;
}
@@ -316,7 +322,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_QueryInterface(IDebugClient *iface,
return S_OK;
}
-static ULONG STDMETHODCALLTYPE debugclient_AddRef(IDebugClient *iface)
+static ULONG STDMETHODCALLTYPE debugclient_AddRef(IDebugClient7 *iface)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
ULONG refcount = InterlockedIncrement(&debug_client->refcount);
@@ -332,7 +338,7 @@ static void debug_target_free(struct target_process *target)
heap_free(target);
}
-static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient *iface)
+static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient7 *iface)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
ULONG refcount = InterlockedDecrement(&debug_client->refcount);
@@ -356,14 +362,14 @@ static ULONG STDMETHODCALLTYPE debugclient_Release(IDebugClient *iface)
return refcount;
}
-static HRESULT STDMETHODCALLTYPE debugclient_AttachKernel(IDebugClient *iface, ULONG flags, const char *options)
+static HRESULT STDMETHODCALLTYPE debugclient_AttachKernel(IDebugClient7 *iface, ULONG flags, const char *options)
{
FIXME("%p, %#x, %s stub.\n", iface, flags, debugstr_a(options));
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetKernelConnectionOptions(IDebugClient *iface, char *buffer,
+static HRESULT STDMETHODCALLTYPE debugclient_GetKernelConnectionOptions(IDebugClient7 *iface, char *buffer,
ULONG buffer_size, ULONG *options_size)
{
FIXME("%p, %p, %u, %p stub.\n", iface, buffer, buffer_size, options_size);
@@ -371,14 +377,14 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetKernelConnectionOptions(IDebugCl
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetKernelConnectionOptions(IDebugClient *iface, const char *options)
+static HRESULT STDMETHODCALLTYPE debugclient_SetKernelConnectionOptions(IDebugClient7 *iface, const char *options)
{
FIXME("%p, %s stub.\n", iface, debugstr_a(options));
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_StartProcessServer(IDebugClient *iface, ULONG flags, const char *options,
+static HRESULT STDMETHODCALLTYPE debugclient_StartProcessServer(IDebugClient7 *iface, ULONG flags, const char *options,
void *reserved)
{
FIXME("%p, %#x, %s, %p stub.\n", iface, flags, debugstr_a(options), reserved);
@@ -386,7 +392,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_StartProcessServer(IDebugClient *if
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_ConnectProcessServer(IDebugClient *iface, const char *remote_options,
+static HRESULT STDMETHODCALLTYPE debugclient_ConnectProcessServer(IDebugClient7 *iface, const char *remote_options,
ULONG64 *server)
{
FIXME("%p, %s, %p stub.\n", iface, debugstr_a(remote_options), server);
@@ -394,14 +400,14 @@ static HRESULT STDMETHODCALLTYPE debugclient_ConnectProcessServer(IDebugClient *
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_DisconnectProcessServer(IDebugClient *iface, ULONG64 server)
+static HRESULT STDMETHODCALLTYPE debugclient_DisconnectProcessServer(IDebugClient7 *iface, ULONG64 server)
{
FIXME("%p, %s stub.\n", iface, wine_dbgstr_longlong(server));
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIds(IDebugClient *iface, ULONG64 server,
+static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIds(IDebugClient7 *iface, ULONG64 server,
ULONG *ids, ULONG count, ULONG *actual_count)
{
FIXME("%p, %s, %p, %u, %p stub.\n", iface, wine_dbgstr_longlong(server), ids, count, actual_count);
@@ -409,7 +415,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIds(IDebugCl
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIdByExecutableName(IDebugClient *iface,
+static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIdByExecutableName(IDebugClient7 *iface,
ULONG64 server, const char *exe_name, ULONG flags, ULONG *id)
{
FIXME("%p, %s, %s, %#x, %p stub.\n", iface, wine_dbgstr_longlong(server), debugstr_a(exe_name), flags, id);
@@ -417,7 +423,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIdByExecutab
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessDescription(IDebugClient *iface, ULONG64 server,
+static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessDescription(IDebugClient7 *iface, ULONG64 server,
ULONG systemid, ULONG flags, char *exe_name, ULONG exe_name_size, ULONG *actual_exe_name_size,
char *description, ULONG description_size, ULONG *actual_description_size)
{
@@ -427,7 +433,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessDescription(IDebug
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_AttachProcess(IDebugClient *iface, ULONG64 server, ULONG pid, ULONG flags)
+static HRESULT STDMETHODCALLTYPE debugclient_AttachProcess(IDebugClient7 *iface, ULONG64 server, ULONG pid, ULONG flags)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
struct target_process *process;
@@ -451,7 +457,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_AttachProcess(IDebugClient *iface,
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE debugclient_CreateProcess(IDebugClient *iface, ULONG64 server, char *cmdline,
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcess(IDebugClient7 *iface, ULONG64 server, char *cmdline,
ULONG flags)
{
FIXME("%p, %s, %s, %#x stub.\n", iface, wine_dbgstr_longlong(server), debugstr_a(cmdline), flags);
@@ -459,7 +465,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_CreateProcess(IDebugClient *iface,
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessAndAttach(IDebugClient *iface, ULONG64 server, char *cmdline,
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessAndAttach(IDebugClient7 *iface, ULONG64 server, char *cmdline,
ULONG create_flags, ULONG pid, ULONG attach_flags)
{
FIXME("%p, %s, %s, %#x, %u, %#x stub.\n", iface, wine_dbgstr_longlong(server), debugstr_a(cmdline), create_flags,
@@ -468,63 +474,63 @@ static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessAndAttach(IDebugClient
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetProcessOptions(IDebugClient *iface, ULONG *options)
+static HRESULT STDMETHODCALLTYPE debugclient_GetProcessOptions(IDebugClient7 *iface, ULONG *options)
{
FIXME("%p, %p stub.\n", iface, options);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_AddProcessOptions(IDebugClient *iface, ULONG options)
+static HRESULT STDMETHODCALLTYPE debugclient_AddProcessOptions(IDebugClient7 *iface, ULONG options)
{
FIXME("%p, %#x stub.\n", iface, options);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_RemoveProcessOptions(IDebugClient *iface, ULONG options)
+static HRESULT STDMETHODCALLTYPE debugclient_RemoveProcessOptions(IDebugClient7 *iface, ULONG options)
{
FIXME("%p, %#x stub.\n", iface, options);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetProcessOptions(IDebugClient *iface, ULONG options)
+static HRESULT STDMETHODCALLTYPE debugclient_SetProcessOptions(IDebugClient7 *iface, ULONG options)
{
FIXME("%p, %#x stub.\n", iface, options);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_OpenDumpFile(IDebugClient *iface, const char *filename)
+static HRESULT STDMETHODCALLTYPE debugclient_OpenDumpFile(IDebugClient7 *iface, const char *filename)
{
FIXME("%p, %s stub.\n", iface, debugstr_a(filename));
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_WriteDumpFile(IDebugClient *iface, const char *filename, ULONG qualifier)
+static HRESULT STDMETHODCALLTYPE debugclient_WriteDumpFile(IDebugClient7 *iface, const char *filename, ULONG qualifier)
{
FIXME("%p, %s, %u stub.\n", iface, debugstr_a(filename), qualifier);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_ConnectSession(IDebugClient *iface, ULONG flags, ULONG history_limit)
+static HRESULT STDMETHODCALLTYPE debugclient_ConnectSession(IDebugClient7 *iface, ULONG flags, ULONG history_limit)
{
FIXME("%p, %#x, %u stub.\n", iface, flags, history_limit);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_StartServer(IDebugClient *iface, const char *options)
+static HRESULT STDMETHODCALLTYPE debugclient_StartServer(IDebugClient7 *iface, const char *options)
{
FIXME("%p, %s stub.\n", iface, debugstr_a(options));
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_OutputServers(IDebugClient *iface, ULONG output_control,
+static HRESULT STDMETHODCALLTYPE debugclient_OutputServers(IDebugClient7 *iface, ULONG output_control,
const char *machine, ULONG flags)
{
FIXME("%p, %u, %s, %#x stub.\n", iface, output_control, debugstr_a(machine), flags);
@@ -532,14 +538,14 @@ static HRESULT STDMETHODCALLTYPE debugclient_OutputServers(IDebugClient *iface,
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_TerminateProcesses(IDebugClient *iface)
+static HRESULT STDMETHODCALLTYPE debugclient_TerminateProcesses(IDebugClient7 *iface)
{
FIXME("%p stub.\n", iface);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_DetachProcesses(IDebugClient *iface)
+static HRESULT STDMETHODCALLTYPE debugclient_DetachProcesses(IDebugClient7 *iface)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
struct target_process *target;
@@ -554,112 +560,112 @@ static HRESULT STDMETHODCALLTYPE debugclient_DetachProcesses(IDebugClient *iface
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE debugclient_EndSession(IDebugClient *iface, ULONG flags)
+static HRESULT STDMETHODCALLTYPE debugclient_EndSession(IDebugClient7 *iface, ULONG flags)
{
FIXME("%p, %#x stub.\n", iface, flags);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetExitCode(IDebugClient *iface, ULONG *code)
+static HRESULT STDMETHODCALLTYPE debugclient_GetExitCode(IDebugClient7 *iface, ULONG *code)
{
FIXME("%p, %p stub.\n", iface, code);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_DispatchCallbacks(IDebugClient *iface, ULONG timeout)
+static HRESULT STDMETHODCALLTYPE debugclient_DispatchCallbacks(IDebugClient7 *iface, ULONG timeout)
{
FIXME("%p, %u stub.\n", iface, timeout);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_ExitDispatch(IDebugClient *iface, IDebugClient *client)
+static HRESULT STDMETHODCALLTYPE debugclient_ExitDispatch(IDebugClient7 *iface, IDebugClient *client)
{
FIXME("%p, %p stub.\n", iface, client);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_CreateClient(IDebugClient *iface, IDebugClient **client)
+static HRESULT STDMETHODCALLTYPE debugclient_CreateClient(IDebugClient7 *iface, IDebugClient **client)
{
FIXME("%p, %p stub.\n", iface, client);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetInputCallbacks(IDebugClient *iface, IDebugInputCallbacks **callbacks)
+static HRESULT STDMETHODCALLTYPE debugclient_GetInputCallbacks(IDebugClient7 *iface, IDebugInputCallbacks **callbacks)
{
FIXME("%p, %p stub.\n", iface, callbacks);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetInputCallbacks(IDebugClient *iface, IDebugInputCallbacks *callbacks)
+static HRESULT STDMETHODCALLTYPE debugclient_SetInputCallbacks(IDebugClient7 *iface, IDebugInputCallbacks *callbacks)
{
FIXME("%p, %p stub.\n", iface, callbacks);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetOutputCallbacks(IDebugClient *iface, IDebugOutputCallbacks **callbacks)
+static HRESULT STDMETHODCALLTYPE debugclient_GetOutputCallbacks(IDebugClient7 *iface, IDebugOutputCallbacks **callbacks)
{
FIXME("%p, %p stub.\n", iface, callbacks);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetOutputCallbacks(IDebugClient *iface, IDebugOutputCallbacks *callbacks)
+static HRESULT STDMETHODCALLTYPE debugclient_SetOutputCallbacks(IDebugClient7 *iface, IDebugOutputCallbacks *callbacks)
{
FIXME("%p, %p stub.\n", iface, callbacks);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetOutputMask(IDebugClient *iface, ULONG *mask)
+static HRESULT STDMETHODCALLTYPE debugclient_GetOutputMask(IDebugClient7 *iface, ULONG *mask)
{
FIXME("%p, %p stub.\n", iface, mask);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetOutputMask(IDebugClient *iface, ULONG mask)
+static HRESULT STDMETHODCALLTYPE debugclient_SetOutputMask(IDebugClient7 *iface, ULONG mask)
{
FIXME("%p, %#x stub.\n", iface, mask);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetOtherOutputMask(IDebugClient *iface, IDebugClient *client, ULONG *mask)
+static HRESULT STDMETHODCALLTYPE debugclient_GetOtherOutputMask(IDebugClient7 *iface, IDebugClient *client, ULONG *mask)
{
FIXME("%p, %p, %p stub.\n", iface, client, mask);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetOtherOutputMask(IDebugClient *iface, IDebugClient *client, ULONG mask)
+static HRESULT STDMETHODCALLTYPE debugclient_SetOtherOutputMask(IDebugClient7 *iface, IDebugClient *client, ULONG mask)
{
FIXME("%p, %p, %#x stub.\n", iface, client, mask);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetOutputWidth(IDebugClient *iface, ULONG *columns)
+static HRESULT STDMETHODCALLTYPE debugclient_GetOutputWidth(IDebugClient7 *iface, ULONG *columns)
{
FIXME("%p, %p stub.\n", iface, columns);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetOutputWidth(IDebugClient *iface, ULONG columns)
+static HRESULT STDMETHODCALLTYPE debugclient_SetOutputWidth(IDebugClient7 *iface, ULONG columns)
{
FIXME("%p, %u stub.\n", iface, columns);
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetOutputLinePrefix(IDebugClient *iface, char *buffer, ULONG buffer_size,
+static HRESULT STDMETHODCALLTYPE debugclient_GetOutputLinePrefix(IDebugClient7 *iface, char *buffer, ULONG buffer_size,
ULONG *prefix_size)
{
FIXME("%p, %p, %u, %p stub.\n", iface, buffer, buffer_size, prefix_size);
@@ -667,14 +673,14 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetOutputLinePrefix(IDebugClient *i
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetOutputLinePrefix(IDebugClient *iface, const char *prefix)
+static HRESULT STDMETHODCALLTYPE debugclient_SetOutputLinePrefix(IDebugClient7 *iface, const char *prefix)
{
FIXME("%p, %s stub.\n", iface, debugstr_a(prefix));
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetIdentity(IDebugClient *iface, char *buffer, ULONG buffer_size,
+static HRESULT STDMETHODCALLTYPE debugclient_GetIdentity(IDebugClient7 *iface, char *buffer, ULONG buffer_size,
ULONG *identity_size)
{
FIXME("%p, %p, %u, %p stub.\n", iface, buffer, buffer_size, identity_size);
@@ -682,7 +688,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetIdentity(IDebugClient *iface, ch
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_OutputIdentity(IDebugClient *iface, ULONG output_control, ULONG flags,
+static HRESULT STDMETHODCALLTYPE debugclient_OutputIdentity(IDebugClient7 *iface, ULONG output_control, ULONG flags,
const char *format)
{
FIXME("%p, %u, %#x, %s stub.\n", iface, output_control, flags, debugstr_a(format));
@@ -690,7 +696,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_OutputIdentity(IDebugClient *iface,
return E_NOTIMPL;
}
-static HRESULT STDMETHODCALLTYPE debugclient_GetEventCallbacks(IDebugClient *iface, IDebugEventCallbacks **callbacks)
+static HRESULT STDMETHODCALLTYPE debugclient_GetEventCallbacks(IDebugClient7 *iface, IDebugEventCallbacks **callbacks)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
@@ -705,7 +711,7 @@ static HRESULT STDMETHODCALLTYPE debugclient_GetEventCallbacks(IDebugClient *ifa
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE debugclient_SetEventCallbacks(IDebugClient *iface, IDebugEventCallbacks *callbacks)
+static HRESULT STDMETHODCALLTYPE debugclient_SetEventCallbacks(IDebugClient7 *iface, IDebugEventCallbacks *callbacks)
{
struct debug_client *debug_client = impl_from_IDebugClient(iface);
@@ -719,14 +725,327 @@ static HRESULT STDMETHODCALLTYPE debugclient_SetEventCallbacks(IDebugClient *ifa
return S_OK;
}
-static HRESULT STDMETHODCALLTYPE debugclient_FlushCallbacks(IDebugClient *iface)
+static HRESULT STDMETHODCALLTYPE debugclient_FlushCallbacks(IDebugClient7 *iface)
{
FIXME("%p stub.\n", iface);
return E_NOTIMPL;
}
-static const IDebugClientVtbl debugclientvtbl =
+static HRESULT STDMETHODCALLTYPE debugclient_WriteDumpFile2(IDebugClient7 *iface, const char *dumpfile, ULONG qualifier,
+ ULONG flags, const char *comment)
+{
+ FIXME("%p, %s, %d, 0x%08x, %s.\n", iface, debugstr_a(dumpfile), qualifier, flags, debugstr_a(comment));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_AddDumpInformationFile(IDebugClient7 *iface, const char *infofile, ULONG type)
+{
+ FIXME("%p, %s, %d.\n", iface, debugstr_a(infofile), type);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_EndProcessServer(IDebugClient7 *iface, ULONG64 server)
+{
+ FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(server));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_WaitForProcessServerEnd(IDebugClient7 *iface, ULONG timeout)
+{
+ FIXME("%p, %d.\n", iface, timeout);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_IsKernelDebuggerEnabled(IDebugClient7 *iface)
+{
+ FIXME("%p.\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_TerminateCurrentProcess(IDebugClient7 *iface)
+{
+ FIXME("%p.\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_DetachCurrentProcess(IDebugClient7 *iface)
+{
+ FIXME("%p.\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_AbandonCurrentProcess(IDebugClient7 *iface)
+{
+ FIXME("%p.\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessSystemIdByExecutableNameWide(IDebugClient7 *iface, ULONG64 server,
+ const WCHAR *exename, ULONG flags, ULONG *id)
+{
+ FIXME("%p, %s, %s, 0x%08x, %p.\n", iface, wine_dbgstr_longlong(server), debugstr_w(exename), flags, id);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetRunningProcessDescriptionWide(IDebugClient7 *iface, ULONG64 server, ULONG id,
+ ULONG flags, WCHAR *exename, ULONG size, ULONG *actualsize, WCHAR *description, ULONG desc_size, ULONG *actual_desc_size)
+{
+ FIXME("%p, %s, %d, 0x%08x, %s, %d, %p, %s, %d, %p.\n", iface, wine_dbgstr_longlong(server), id, flags, debugstr_w(exename), size,
+ actualsize, debugstr_w(description), desc_size, actual_desc_size );
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessWide(IDebugClient7 *iface, ULONG64 server, WCHAR *commandline, ULONG flags)
+{
+ FIXME("%p, %s, %s, 0x%08x.\n", iface, wine_dbgstr_longlong(server), debugstr_w(commandline), flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessAndAttachWide(IDebugClient7 *iface, ULONG64 server, WCHAR *commandline,
+ ULONG flags, ULONG processid, ULONG attachflags)
+{
+ FIXME("%p, %s, %s, 0x%08x, %d, 0x%08x.\n", iface, wine_dbgstr_longlong(server), debugstr_w(commandline), flags, processid, attachflags);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_OpenDumpFileWide(IDebugClient7 *iface, const WCHAR *filename, ULONG64 handle)
+{
+ FIXME("%p, %s, %s.\n", iface, debugstr_w(filename), wine_dbgstr_longlong(handle));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_WriteDumpFileWide(IDebugClient7 *iface, const WCHAR *filename, ULONG64 handle,
+ ULONG qualifier, ULONG flags, const WCHAR *comment)
+{
+ FIXME("%p, %s, %s, %d, 0x%08x, %s.\n", iface, debugstr_w(filename), wine_dbgstr_longlong(handle),
+ qualifier, flags, debugstr_w(comment));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_AddDumpInformationFileWide(IDebugClient7 *iface, const WCHAR *filename,
+ ULONG64 handle, ULONG type)
+{
+ FIXME("%p, %s, %s, %d.\n", iface, debugstr_w(filename), wine_dbgstr_longlong(handle), type);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetNumberDumpFiles(IDebugClient7 *iface, ULONG *count)
+{
+ FIXME("%p, %p.\n", iface, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetDumpFile(IDebugClient7 *iface, ULONG index, char *buffer, ULONG buf_size,
+ ULONG *name_size, ULONG64 *handle, ULONG *type)
+{
+ FIXME("%p, %d, %p, %d, %p, %p, %p.\n", iface, index, buffer, buf_size, name_size, handle, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetDumpFileWide(IDebugClient7 *iface, ULONG index, WCHAR *buffer, ULONG buf_size,
+ ULONG *name_size, ULONG64 *handle, ULONG *type)
+{
+ FIXME("%p, %d, %p, %d, %p, %p, %p.\n", iface, index, buffer, buf_size, name_size, handle, type);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_AttachKernelWide(IDebugClient7 *iface, ULONG flags, const WCHAR *options)
+{
+ FIXME("%p, 0x%08x, %s.\n", iface, flags, debugstr_w(options));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetKernelConnectionOptionsWide(IDebugClient7 *iface, WCHAR *buffer,
+ ULONG buf_size, ULONG *size)
+{
+ FIXME("%p, %p, %d, %p.\n", iface, buffer, buf_size, size);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetKernelConnectionOptionsWide(IDebugClient7 *iface, const WCHAR *options)
+{
+ FIXME("%p, %p.\n", iface, options);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_StartProcessServerWide(IDebugClient7 *iface, ULONG flags, const WCHAR *options, void *reserved)
+{
+ FIXME("%p, 0x%08x, %s, %p.\n", iface, flags, debugstr_w(options), reserved);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_ConnectProcessServerWide(IDebugClient7 *iface, const WCHAR *options, ULONG64 *server)
+{
+ FIXME("%p, %s, %p.\n", iface, debugstr_w(options), server);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_StartServerWide(IDebugClient7 *iface, const WCHAR *options)
+{
+ FIXME("%p, %s.\n", iface, debugstr_w(options));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_OutputServersWide(IDebugClient7 *iface, ULONG control, const WCHAR *machine, ULONG flags)
+{
+ FIXME("%p, %d, %s, 0x%08x.\n", iface, control, debugstr_w(machine), flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetOutputCallbacksWide(IDebugClient7 *iface, IDebugOutputCallbacksWide **callbacks)
+{
+ FIXME("%p, %p.\n", iface, callbacks);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetOutputCallbacksWide(IDebugClient7 *iface, IDebugOutputCallbacksWide *callbacks)
+{
+ FIXME("%p, %p.\n", iface, callbacks);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetOutputLinePrefixWide(IDebugClient7 *iface, WCHAR *buffer, ULONG buf_size, ULONG *size)
+{
+ FIXME("%p, %p, %d, %p.\n", iface, buffer, buf_size, size);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetOutputLinePrefixWide(IDebugClient7 *iface, const WCHAR *prefix)
+{
+ FIXME("%p, %s.\n", iface, debugstr_w(prefix));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetIdentityWide(IDebugClient7 *iface, WCHAR *buffer, ULONG buf_size, ULONG *identity)
+{
+ FIXME("%p, %p, %d, %p.\n", iface, buffer, buf_size, identity);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_OutputIdentityWide(IDebugClient7 *iface, ULONG control, ULONG flags, const WCHAR *format)
+{
+ FIXME("%p, %d, 0x%08x, %s.\n", iface, control, flags, debugstr_w(format));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetEventCallbacksWide(IDebugClient7 *iface, IDebugEventCallbacksWide **callbacks)
+{
+ FIXME("%p, %p .\n", iface, callbacks);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetEventCallbacksWide(IDebugClient7 *iface, IDebugEventCallbacksWide *callbacks)
+{
+ FIXME("%p .\n", iface);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcess2(IDebugClient7 *iface, ULONG64 server, char *command, void *options,
+ ULONG buf_size, const char *initial, const char *environment)
+{
+ FIXME("%p %s, %s, %p, %d, %s, %s.\n", iface, wine_dbgstr_longlong(server), debugstr_a(command), options,
+ buf_size, debugstr_a(initial), debugstr_a(environment));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcess2Wide(IDebugClient7 *iface, ULONG64 server, WCHAR *command, void *options,
+ ULONG size, const WCHAR *initial, const WCHAR *environment)
+{
+ FIXME("%p %s, %s, %p, %d, %s, %s.\n", iface, wine_dbgstr_longlong(server), debugstr_w(command), options,
+ size, debugstr_w(initial), debugstr_w(environment));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessAndAttach2(IDebugClient7 *iface, ULONG64 server, char *command,
+ void *options, ULONG buf_size, const char *initial, const char *environment, ULONG processid, ULONG flags)
+{
+ FIXME("%p %s, %s, %p, %d, %s, %s, %d, 0x%08x.\n", iface, wine_dbgstr_longlong(server), debugstr_a(command), options,
+ buf_size, debugstr_a(initial), debugstr_a(environment), processid, flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_CreateProcessAndAttach2Wide(IDebugClient7 *iface, ULONG64 server, WCHAR *command,
+ void *buffer, ULONG buf_size, const WCHAR *initial, const WCHAR *environment, ULONG processid, ULONG flags)
+{
+ FIXME("%p %s, %s, %p, %d, %s, %s, %d, 0x%08x.\n", iface, wine_dbgstr_longlong(server), debugstr_w(command), buffer,
+ buf_size, debugstr_w(initial), debugstr_w(environment), processid, flags);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_PushOutputLinePrefix(IDebugClient7 *iface, const char *prefix, ULONG64 *handle)
+{
+ FIXME("%p, %p.\n", iface, handle);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_PushOutputLinePrefixWide(IDebugClient7 *iface, const WCHAR *prefix, ULONG64 *handle)
+{
+ FIXME("%p, %p.\n", iface, handle);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_PopOutputLinePrefix(IDebugClient7 *iface, ULONG64 handle)
+{
+ FIXME("%p, %s.\n", iface, wine_dbgstr_longlong(handle));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetNumberInputCallbacks(IDebugClient7 *iface, ULONG *count)
+{
+ FIXME("%p, %p.\n", iface, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetNumberOutputCallbacks(IDebugClient7 *iface, ULONG *count)
+{
+ FIXME("%p, %p.\n", iface, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetNumberEventCallbacks(IDebugClient7 *iface, ULONG flags, ULONG *count)
+{
+ FIXME("%p, 0x%08x, %p.\n", iface, flags, count);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetQuitLockString(IDebugClient7 *iface, char *buffer, ULONG buf_size, ULONG *size)
+{
+ FIXME("%p, %s, %d, %p.\n", iface, debugstr_a(buffer), buf_size, size);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetQuitLockString(IDebugClient7 *iface, char *string)
+{
+ FIXME("%p, %s.\n", iface, debugstr_a(string));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_GetQuitLockStringWide(IDebugClient7 *iface, WCHAR *buffer, ULONG buf_size, ULONG *size)
+{
+ FIXME("%p, %s, %d, %p.\n", iface, debugstr_w(buffer), buf_size, size);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetQuitLockStringWide(IDebugClient7 *iface, const WCHAR *string)
+{
+ FIXME("%p, %s.\n", iface, debugstr_w(string));
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetEventContextCallbacks(IDebugClient7 *iface, IDebugEventContextCallbacks *callbacks)
+{
+ FIXME("%p, %p.\n", iface, callbacks);
+ return E_NOTIMPL;
+}
+
+static HRESULT STDMETHODCALLTYPE debugclient_SetClientContext(IDebugClient7 *iface, void *context, ULONG size)
+{
+ FIXME("%p, %p, %d.\n", iface, context, size);
+ return E_NOTIMPL;
+}
+
+static const IDebugClient7Vtbl debugclientvtbl =
{
debugclient_QueryInterface,
debugclient_AddRef,
@@ -776,6 +1095,61 @@ static const IDebugClientVtbl debugclientvtbl =
debugclient_GetEventCallbacks,
debugclient_SetEventCallbacks,
debugclient_FlushCallbacks,
+ /* IDebugClient2 */
+ debugclient_WriteDumpFile2,
+ debugclient_AddDumpInformationFile,
+ debugclient_EndProcessServer,
+ debugclient_WaitForProcessServerEnd,
+ debugclient_IsKernelDebuggerEnabled,
+ debugclient_TerminateCurrentProcess,
+ debugclient_DetachCurrentProcess,
+ debugclient_AbandonCurrentProcess,
+ /* IDebugClient3 */
+ debugclient_GetRunningProcessSystemIdByExecutableNameWide,
+ debugclient_GetRunningProcessDescriptionWide,
+ debugclient_CreateProcessWide,
+ debugclient_CreateProcessAndAttachWide,
+ /* IDebugClient4 */
+ debugclient_OpenDumpFileWide,
+ debugclient_WriteDumpFileWide,
+ debugclient_AddDumpInformationFileWide,
+ debugclient_GetNumberDumpFiles,
+ debugclient_GetDumpFile,
+ debugclient_GetDumpFileWide,
+ /* IDebugClient5 */
+ debugclient_AttachKernelWide,
+ debugclient_GetKernelConnectionOptionsWide,
+ debugclient_SetKernelConnectionOptionsWide,
+ debugclient_StartProcessServerWide,
+ debugclient_ConnectProcessServerWide,
+ debugclient_StartServerWide,
+ debugclient_OutputServersWide,
+ debugclient_GetOutputCallbacksWide,
+ debugclient_SetOutputCallbacksWide,
+ debugclient_GetOutputLinePrefixWide,
+ debugclient_SetOutputLinePrefixWide,
+ debugclient_GetIdentityWide,
+ debugclient_OutputIdentityWide,
+ debugclient_GetEventCallbacksWide,
+ debugclient_SetEventCallbacksWide,
+ debugclient_CreateProcess2,
+ debugclient_CreateProcess2Wide,
+ debugclient_CreateProcessAndAttach2,
+ debugclient_CreateProcessAndAttach2Wide,
+ debugclient_PushOutputLinePrefix,
+ debugclient_PushOutputLinePrefixWide,
+ debugclient_PopOutputLinePrefix,
+ debugclient_GetNumberInputCallbacks,
+ debugclient_GetNumberOutputCallbacks,
+ debugclient_GetNumberEventCallbacks,
+ debugclient_GetQuitLockString,
+ debugclient_SetQuitLockString,
+ debugclient_GetQuitLockStringWide,
+ debugclient_SetQuitLockStringWide,
+ /* IDebugClient6 */
+ debugclient_SetEventContextCallbacks,
+ /* IDebugClient7 */
+ debugclient_SetClientContext,
};
static HRESULT STDMETHODCALLTYPE debugdataspaces_QueryInterface(IDebugDataSpaces *iface, REFIID riid, void **obj)
--
2.17.1
1
0
19 Aug '19
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47623
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/ntoskrnl.exe/ntoskrnl.c | 11 -----------
dlls/ntoskrnl.exe/sync.c | 14 ++++++++++++++
2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 210f42b6b9..09fb6605bc 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -3178,17 +3178,6 @@ BOOLEAN WINAPI IoSetThreadHardErrorMode(BOOLEAN EnableHardErrors)
return FALSE;
}
-
-/*****************************************************
- * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
- */
-VOID WINAPI IoInitializeRemoveLockEx(PIO_REMOVE_LOCK lock, ULONG tag,
- ULONG maxmin, ULONG high, ULONG size)
-{
- FIXME("(%p %u %u %u %u) stub\n", lock, tag, maxmin, high, size);
-}
-
-
/*****************************************************
* IoAcquireRemoveLockEx (NTOSKRNL.EXE.@)
*/
diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
index ea4165cda6..0b2ca6f6b7 100644
--- a/dlls/ntoskrnl.exe/sync.c
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -1195,3 +1195,17 @@ ULONG WINAPI ExIsResourceAcquiredSharedLite( ERESOURCE *resource )
return ret;
}
+
+/***********************************************************************
+ * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoInitializeRemoveLockEx( IO_REMOVE_LOCK *lock, ULONG tag,
+ ULONG max_minutes, ULONG max_count, ULONG size )
+{
+ TRACE("lock %p, tag %#x, max_minutes %u, max_count %u, size %u.\n",
+ lock, tag, max_minutes, max_count, size);
+
+ KeInitializeEvent( &lock->Common.RemoveEvent, SynchronizationEvent, FALSE );
+ lock->Common.Removed = FALSE;
+ lock->Common.IoCount = 0;
+}
--
2.22.0
2
9
19 Aug '19
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/httpapi/tests/Makefile.in | 2 +-
dlls/httpapi/tests/httpapi.c | 858 ++++++++++++++++++++++++++++++++-
2 files changed, 840 insertions(+), 20 deletions(-)
diff --git a/dlls/httpapi/tests/Makefile.in b/dlls/httpapi/tests/Makefile.in
index 1c253a789b..20210a3451 100644
--- a/dlls/httpapi/tests/Makefile.in
+++ b/dlls/httpapi/tests/Makefile.in
@@ -1,5 +1,5 @@
TESTDLL = httpapi.dll
-IMPORTS = httpapi
+IMPORTS = httpapi ws2_32
C_SRCS = \
httpapi.c
diff --git a/dlls/httpapi/tests/httpapi.c b/dlls/httpapi/tests/httpapi.c
index e1437552a8..a7bf6c2e28 100644
--- a/dlls/httpapi/tests/httpapi.c
+++ b/dlls/httpapi/tests/httpapi.c
@@ -1,7 +1,8 @@
/*
- * HttpApi tests
+ * HTTP server API tests
*
* Copyright 2017 Nikolay Sivov for CodeWeavers
+ * Copyright 2019 Zebediah Figura
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -30,6 +31,9 @@
#include "wine/test.h"
+static const WCHAR localhost_urlW[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
+static const WCHAR localhost_url2W[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','1','/',0};
+
static ULONG (WINAPI *pHttpCreateServerSession)(HTTPAPI_VERSION version, HTTP_SERVER_SESSION_ID *session_id,
ULONG reserved);
static ULONG (WINAPI *pHttpCloseServerSession)(HTTP_SERVER_SESSION_ID session_id);
@@ -49,32 +53,838 @@ static void init(void)
#undef X
}
-static void test_HttpCreateHttpHandle(void)
+static const char simple_req[] =
+ "GET /foobar HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "User-Agent: WINE\r\n"
+ "\r\n";
+
+static int create_client_socket(void)
+{
+ struct sockaddr_in sockaddr =
+ {
+ .sin_family = AF_INET,
+ .sin_port = htons(50000),
+ .sin_addr.S_un.S_addr = inet_addr("127.0.0.1"),
+ };
+ int s = socket(AF_INET, SOCK_STREAM, 0), ret;
+ ret = connect(s, (struct sockaddr *)&sockaddr, sizeof(sockaddr));
+ ok(!ret, "Failed to connect socket, error %u.\n", GetLastError());
+ return s;
+}
+
+/* Helper function for when we don't care about the response received. */
+static void send_response_v1(HANDLE queue, HTTP_REQUEST_ID id, int s)
+{
+ HTTP_RESPONSE_V1 response = {};
+ char response_buffer[2048];
+ int ret;
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, id, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, NULL, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+}
+
+static void test_v1_server(void)
{
- HANDLE handle, handle2;
+ static const WCHAR invalid_url1[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
+ static const WCHAR invalid_url2[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0',0};
+ static const WCHAR invalid_url3[] = {'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/',0};
+ static const WCHAR invalid_url4[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t','/',0};
+ static const WCHAR invalid_url5[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','/',0};
+ static const WCHAR invalid_url6[] = {'h','t','t','p',':','/','/','l','o','c','a','l','h','o','s','t',':','0','/',0};
+ static const WCHAR cooked_urlW[] = {'h','t','t','p',':','/','/',
+ 'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/','f','o','o','b','a','r',0};
+
+ char req_buffer[2048], response_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ struct sockaddr_in sockaddr, *sin;
+ HTTP_RESPONSE_V1 response = {};
+ HANDLE queue, queue2;
+ unsigned int i;
+ OVERLAPPED ovl;
+ DWORD ret_size;
ULONG ret;
- BOOL b;
+ SOCKET s;
+ int len;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
ret = HttpCreateHttpHandle(NULL, 0);
-todo_wine
- ok(ret == ERROR_INVALID_PARAMETER, "Unexpected ret value %u.\n", ret);
+ todo_wine ok(ret == ERROR_INVALID_PARAMETER, "Unexpected error %u.\n", ret);
/* Non-zero reserved parameter is accepted on XP/2k3. */
- handle = NULL;
- ret = HttpCreateHttpHandle(&handle, 0);
-todo_wine {
+ queue = NULL;
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Unexpected ret value %u.\n", ret);
+ if (ret) return;
+ ok(!!queue, "Unexpected handle value %p.\n", queue);
+
+ queue2 = NULL;
+ ret = HttpCreateHttpHandle(&queue2, 0);
ok(!ret, "Unexpected ret value %u.\n", ret);
- ok(handle != NULL, "Unexpected handle value %p.\n", handle);
+ ok(queue2 && queue2 != queue, "Unexpected handle %p.\n", queue2);
+ ret = CloseHandle(queue2);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+
+ ret = HttpReceiveHttpRequest(NULL, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_INVALID_HANDLE, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, 0xdeadbeef, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ ret = HttpAddUrl(NULL, localhost_urlW, NULL);
+ ok(ret == ERROR_INVALID_HANDLE || ret == ERROR_INVALID_PARAMETER /* < Vista */, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url1, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url2, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url3, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url4, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url5, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, invalid_url6, NULL);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(ret == ERROR_ALREADY_EXISTS, "Got error %u.\n", ret);
+ ret = HttpAddUrl(queue, localhost_url2W, NULL);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ len = sizeof(sockaddr);
+ ret = getsockname(s, (struct sockaddr *)&sockaddr, &len);
+ ok(ret == 0, "getsockname() failed, error %u.\n", WSAGetLastError());
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, TRUE);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+
+ ok(!req->Flags, "Got flags %#x.\n", req->Flags);
+ ok(req->ConnectionId, "Expected nonzero connection ID.\n");
+ ok(req->RequestId, "Expected nonzero connection ID.\n");
+ ok(!req->UrlContext, "Got URL context %s.\n", wine_dbgstr_longlong(req->UrlContext));
+ ok(req->Version.MajorVersion == 1, "Got major version %u.\n", req->Version.MajorVersion);
+ ok(req->Version.MinorVersion == 1, "Got major version %u.\n", req->Version.MinorVersion);
+ ok(req->Verb == HttpVerbGET, "Got verb %u.\n", req->Verb);
+ ok(!req->UnknownVerbLength, "Got unknown verb length %u.\n", req->UnknownVerbLength);
+ ok(req->RawUrlLength == 7, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!req->pUnknownVerb, "Got unknown verb %s.\n", req->pUnknownVerb);
+ ok(!strcmp(req->pRawUrl, "/foobar"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 58, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 14, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(!req->CookedUrl.QueryStringLength, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, cooked_urlW), "Got full URL '%ls'.\n", req->CookedUrl.pFullUrl);
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host '%ls'.\n", req->CookedUrl.pHost);
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path '%ls'.\n", req->CookedUrl.pAbsPath);
+ ok(!req->CookedUrl.pQueryString, "Got query string '%ls'.\n", req->CookedUrl.pQueryString);
+ ok(!memcmp(req->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ sin = (SOCKADDR_IN *)req->Address.pLocalAddress;
+ ok(sin->sin_family == AF_INET, "Got family %u.\n", sin->sin_family);
+ ok(ntohs(sin->sin_port) == 50000, "Got wrong port %u.\n", ntohs(sin->sin_port));
+ ok(sin->sin_addr.S_un.S_addr == inet_addr("127.0.0.1"), "Got address %08x.\n", sin->sin_addr.S_un.S_addr);
+ ok(!req->Headers.UnknownHeaderCount, "Got %u unknown headers.\n", req->Headers.UnknownHeaderCount);
+ ok(!req->Headers.pUnknownHeaders, "Got unknown headers %p.\n", req->Headers.pUnknownHeaders);
+ for (i = 0; i < ARRAY_SIZE(req->Headers.KnownHeaders); ++i)
+ {
+ if (i == HttpHeaderConnection)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 10, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "keep-alive"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else if (i == HttpHeaderHost)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 15, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "localhost:50000"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else if (i == HttpHeaderUserAgent)
+ {
+ ok(req->Headers.KnownHeaders[i].RawValueLength == 4, "Got length %u.\n",
+ req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[i].pRawValue, "WINE"),
+ "Got connection '%s'.\n", req->Headers.KnownHeaders[i].pRawValue);
+ }
+ else
+ {
+ ok(!req->Headers.KnownHeaders[i].RawValueLength, "Header %#x: got length %u.\n",
+ i, req->Headers.KnownHeaders[i].RawValueLength);
+ ok(!req->Headers.KnownHeaders[i].pRawValue, "Header %#x: got value '%s'.\n",
+ i, req->Headers.KnownHeaders[i].pRawValue);
+ }
+ }
+ ok(req->BytesReceived == strlen(simple_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(!req->EntityChunkCount, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(!req->pEntityChunks, "Got entity chunks %p.\n", req->pEntityChunks);
+ ok(!req->RawConnectionId, "Got SSL connection ID %s.\n", wine_dbgstr_longlong(req->RawConnectionId));
+ ok(!req->pSslInfo, "Got SSL info %p.\n", req->pSslInfo);
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ response.Headers.KnownHeaders[HttpHeaderRetryAfter].pRawValue = "120";
+ response.Headers.KnownHeaders[HttpHeaderRetryAfter].RawValueLength = 3;
+ ret = HttpSendHttpResponse(queue, 0xdeadbeef, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, FALSE);
+ ok(ret, "Got error %u.\n", GetLastError());
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret == ret_size, "Expected size %u, got %u.\n", ret_size, ret);
+
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nRetry-After: 120\r\n"), "Missing or malformed Retry-After header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+
+ ret = HttpReceiveHttpRequest(queue, req->RequestId, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+
+ /* HttpReceiveHttpRequest() may return synchronously, but this cannot be
+ * reliably tested. Introducing a delay after send() and before
+ * HttpReceiveHttpRequest() confirms this. */
+
+ ret = HttpRemoveUrl(NULL, localhost_urlW);
+ ok(ret == ERROR_INVALID_PARAMETER, "Got error %u.\n", ret);
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(ret == ERROR_FILE_NOT_FOUND, "Got error %u.\n", ret);
+ ret = HttpRemoveUrl(queue, localhost_url2W);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+
+ closesocket(s);
+ CloseHandle(ovl.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(ret == ERROR_INVALID_HANDLE, "Got error %u.\n", ret);
}
- handle2 = NULL;
- ret = HttpCreateHttpHandle(&handle2, 0);
-todo_wine {
- ok(!ret, "Unexpected ret value %u.\n", ret);
- ok(handle2 != NULL && handle != handle2, "Unexpected handle %p.\n", handle2);
+
+static void test_v1_completion_port(void)
+{
+ char req_buffer[2048], response_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ HTTP_RESPONSE_V1 response = {};
+ OVERLAPPED ovl, *povl;
+ HANDLE queue, port;
+ DWORD ret_size;
+ ULONG_PTR key;
+ ULONG ret;
+ SOCKET s;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+
+ port = CreateIoCompletionPort(queue, NULL, 123, 0);
+ ok(!!port, "Failed to create completion port, error %u.\n", GetLastError());
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret_size = key = 0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 1000);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(povl == &ovl, "OVERLAPPED pointers didn't match.\n");
+ ok(key == 123, "Got unexpected key %lu.\n", key);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 0);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == WAIT_TIMEOUT, "Got error %u.\n", GetLastError());
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret_size = key = 0xdeadbeef;
+ ret = GetQueuedCompletionStatus(port, &ret_size, &key, &povl, 1000);
+ ok(ret, "Got error %u.\n", GetLastError());
+ ok(povl == &ovl, "OVERLAPPED pointers didn't match.\n");
+ ok(key == 123, "Got unexpected key %lu.\n", key);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret == ret_size, "Expected size %u, got %u.\n", ret_size, ret);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ CloseHandle(port);
+ CloseHandle(ovl.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
}
- b = CloseHandle(handle);
-todo_wine
- ok(b, "Failed to close queue handle.\n");
+
+static void test_v1_multiple_requests(void)
+{
+ char req_buffer1[2048], req_buffer2[2048];
+ HTTP_REQUEST_V1 *req1 = (HTTP_REQUEST_V1 *)req_buffer1, *req2 = (HTTP_REQUEST_V1 *)req_buffer2;
+ HTTP_RESPONSE_V1 response = {};
+ struct sockaddr_in sockaddr;
+ OVERLAPPED ovl1, ovl2;
+ DWORD ret_size;
+ SOCKET s1, s2;
+ HANDLE queue;
+ ULONG ret;
+ int len;
+
+ ovl1.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ ovl2.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req1, sizeof(req_buffer1), NULL, &ovl1);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req2, sizeof(req_buffer2), NULL, &ovl2);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl1, &ret_size, FALSE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_IO_INCOMPLETE, "Got error %u.\n", GetLastError());
+
+ s1 = create_client_socket();
+ ret = send(s1, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = WaitForSingleObject(ovl1.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(ret == WAIT_TIMEOUT, "Got %u.\n", ret);
+
+ s2 = create_client_socket();
+ ret = send(s2, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = WaitForSingleObject(ovl1.hEvent, 0);
+ ok(!ret, "Got %u.\n", ret);
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+
+ len = sizeof(sockaddr);
+ getsockname(s1, (struct sockaddr *)&sockaddr, &len);
+ ok(!memcmp(req1->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ len = sizeof(sockaddr);
+ getsockname(s2, (struct sockaddr *)&sockaddr, &len);
+ ok(!memcmp(req2->Address.pRemoteAddress, &sockaddr, len), "Client addresses didn't match.\n");
+ ok(req1->ConnectionId != req2->ConnectionId,
+ "Expected different connection IDs, but got %s.\n", wine_dbgstr_longlong(req1->ConnectionId));
+ ok(req1->RequestId != req2->RequestId,
+ "Expected different request IDs, but got %s.\n", wine_dbgstr_longlong(req1->RequestId));
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ ret = HttpSendHttpResponse(queue, req1->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl1, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ret = HttpSendHttpResponse(queue, req2->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl2, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ /* Test sending multiple requests from the same socket. */
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req1, sizeof(req_buffer1), NULL, &ovl1);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req2, sizeof(req_buffer2), NULL, &ovl2);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ ret = send(s1, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+ ret = send(s1, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ ret = WaitForSingleObject(ovl1.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(ret == WAIT_TIMEOUT, "Got %u.\n", ret);
+
+ ret = HttpSendHttpResponse(queue, req1->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, &ovl1, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = WaitForSingleObject(ovl2.hEvent, 100);
+ ok(!ret, "Got %u.\n", ret);
+ ok(req1->ConnectionId == req2->ConnectionId, "Expected same connection IDs.\n");
+ ok(req1->RequestId != req2->RequestId,
+ "Expected different request IDs, but got %s.\n", wine_dbgstr_longlong(req1->RequestId));
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s1);
+ closesocket(s2);
+ CloseHandle(ovl1.hEvent);
+ CloseHandle(ovl2.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_short_buffer(void)
+{
+ char req_buffer[2048], req_buffer2[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer, *req2 = (HTTP_REQUEST_V1 *)req_buffer2;
+ HTTP_REQUEST_ID req_id;
+ OVERLAPPED ovl, ovl2;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ ovl.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+ ovl2.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL);
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(HTTP_REQUEST_V1) - 1, NULL, &ovl);
+ ok(ret == ERROR_INSUFFICIENT_BUFFER, "Got error %u.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(HTTP_REQUEST_V1), NULL, &ovl);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, simple_req, strlen(simple_req), 0);
+ ok(ret == strlen(simple_req), "send() returned %d.\n", ret);
+
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, TRUE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_MORE_DATA, "Got error %u.\n", GetLastError());
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(!!req->ConnectionId, "Got connection ID %s.\n", wine_dbgstr_longlong(req->ConnectionId));
+ ok(!!req->RequestId, "Got request ID %s.\n", wine_dbgstr_longlong(req->RequestId));
+ ok(!req->Version.MajorVersion || req->Version.MajorVersion == 0xcccc /* < Vista */,
+ "Got major version %u.\n", req->Version.MajorVersion);
+ ok(!req->BytesReceived || req->BytesReceived == ((ULONGLONG)0xcccccccc << 32 | 0xcccccccc) /* < Vista */,
+ "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+
+ /* At this point the request has been assigned a specific ID, and one cannot
+ * receive it by calling with HTTP_NULL_ID. */
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req2, sizeof(req_buffer2), NULL, &ovl2);
+ ok(ret == ERROR_IO_PENDING, "Got error %u.\n", ret);
+
+ req_id = req->RequestId;
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, req_id, 0, (HTTP_REQUEST *)req, ret_size - 1, NULL, &ovl);
+ ok(ret == ERROR_MORE_DATA || ret == ERROR_IO_PENDING /* < 8 */, "Got error %u.\n", ret);
+ SetLastError(0xdeadbeef);
+ ret = GetOverlappedResult(queue, &ovl, &ret_size, TRUE);
+ ok(!ret, "Expected failure.\n");
+ ok(GetLastError() == ERROR_MORE_DATA, "Got error %u.\n", GetLastError());
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, req_id, 0, (HTTP_REQUEST *)req, ret_size, NULL, &ovl);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(req->RequestId == req_id, "Got request ID %s.\n", wine_dbgstr_longlong(req->RequestId));
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ CloseHandle(ovl2.hEvent);
+ CloseHandle(ovl.hEvent);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_entity_body(void)
+{
+ char req_buffer[4096], response_buffer[2048], req_body[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ HTTP_RESPONSE_V1 response = {};
+ HTTP_DATA_CHUNK chunks[2] = {};
+ ULONG ret, chunk_size;
+ unsigned int i;
+ DWORD ret_size;
+ HANDLE queue;
+ SOCKET s;
+
+ static const char post_req[] =
+ "POST /xyzzy HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Length: 5\r\n"
+ "\r\n"
+ "ping";
+
+ static const char post_req2[] =
+ "POST /xyzzy HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "Content-Length: 2048\r\n"
+ "\r\n";
+
+ for (i = 0; i < sizeof(req_body); ++i)
+ req_body[i] = i / 111;
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, post_req, sizeof(post_req), 0);
+ ok(ret == sizeof(post_req), "send() returned %d.\n", ret);
+ /* Windows versions before 8 will return success, and report that an entity
+ * body exists in the Flags member, but fail to account for it in the
+ * BytesReceived member or actually copy it to the buffer, if
+ * HttpReceiveHttpRequest() is called before the kernel has finished
+ * receiving the entity body. Add a small delay to work around this. */
+ Sleep(100);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(req->Flags == HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS, "Got flags %#x.\n", req->Flags);
+ ok(req->BytesReceived == sizeof(post_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength == 1,
+ "Got header length %u.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue, "5"),
+ "Got header value %s.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue);
+ ok(!req->EntityChunkCount, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(!req->pEntityChunks, "Got entity chunks %p.\n", req->pEntityChunks);
+
+ response.StatusCode = 418;
+ response.pReason = "I'm a teapot";
+ response.ReasonLength = 12;
+ response.EntityChunkCount = ARRAY_SIZE(chunks);
+ response.pEntityChunks = chunks;
+ chunks[0].DataChunkType = HttpDataChunkFromMemory;
+ chunks[0].FromMemory.pBuffer = (void *)"pong";
+ chunks[0].FromMemory.BufferLength = 4;
+ chunks[1].DataChunkType = HttpDataChunkFromMemory;
+ chunks[1].FromMemory.pBuffer = (void *)"pang";
+ chunks[1].FromMemory.BufferLength = 4;
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, NULL, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nContent-Length: 8\r\n"), "Missing or malformed Content-Length header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+ ok(!memcmp(response_buffer + ret - 12, "\r\n\r\npongpang", 12), "Response did not end with entity data.\n");
+
+ ret = HttpReceiveHttpRequest(queue, req->RequestId, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(ret == ERROR_CONNECTION_INVALID, "Got error %u.\n", ret);
+
+ /* http won't overwrite a Content-Length header if we manually supply one,
+ * but it also won't truncate the entity body to match. It will however
+ * always write its own Date header. */
+
+ ret = send(s, post_req, sizeof(post_req), 0);
+ ok(ret == sizeof(post_req), "send() returned %d.\n", ret);
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ response.Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength = 1;
+ response.Headers.KnownHeaders[HttpHeaderContentLength].pRawValue = "6";
+ response.Headers.KnownHeaders[HttpHeaderDate].RawValueLength = 10;
+ response.Headers.KnownHeaders[HttpHeaderDate].pRawValue = "yesteryear";
+ ret = HttpSendHttpResponse(queue, req->RequestId, 0, (HTTP_RESPONSE *)&response, NULL, NULL, NULL, 0, NULL, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+ ok(!strncmp(response_buffer, "HTTP/1.1 418 I'm a teapot\r\n", 27), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nContent-Length: 6\r\n"), "Missing or malformed Content-Length header.\n");
+ ok(!!strstr(response_buffer, "\r\nDate:"), "Missing Date header.\n");
+ ok(!strstr(response_buffer, "yesteryear"), "Unexpected Date value.\n");
+ ok(!memcmp(response_buffer + ret - 12, "\r\n\r\npongpang", 12), "Response did not end with entity data.\n");
+
+ /* Test the COPY_BODY flag. */
+
+ ret = send(s, post_req, sizeof(post_req), 0);
+ ok(ret == sizeof(post_req), "send() returned %d.\n", ret);
+ Sleep(100);
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+ (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(!req->Flags, "Got flags %#x.\n", req->Flags);
+ ok(req->BytesReceived == sizeof(post_req), "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength == 1,
+ "Got header length %u.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue, "5"),
+ "Got header value %s.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue);
+ ok(req->EntityChunkCount == 1, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(req->pEntityChunks[0].DataChunkType == HttpDataChunkFromMemory,
+ "Got chunk type %u.\n", req->pEntityChunks[0].DataChunkType);
+ ok(req->pEntityChunks[0].FromMemory.BufferLength == 5,
+ "Got chunk length %u.\n", req->pEntityChunks[0].FromMemory.BufferLength);
+ ok(!memcmp(req->pEntityChunks[0].FromMemory.pBuffer, "ping", 5),
+ "Got chunk data '%s'.\n", (char *)req->pEntityChunks[0].FromMemory.pBuffer);
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = send(s, post_req2, strlen(post_req2), 0);
+ ok(ret == strlen(post_req2), "send() returned %d.\n", ret);
+ ret = send(s, req_body, sizeof(req_body), 0);
+ ok(ret == sizeof(req_body), "send() returned %d.\n", ret);
+
+ Sleep(100);
+
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, HTTP_RECEIVE_REQUEST_FLAG_COPY_BODY,
+ (HTTP_REQUEST *)req, 2000, &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size == 2000, "Got size %u.\n", ret_size);
+ ok(req->Flags == HTTP_REQUEST_FLAG_MORE_ENTITY_BODY_EXISTS, "Got flags %#x.\n", req->Flags);
+ ok(req->BytesReceived == strlen(post_req2) + 2048, "Got %s bytes.\n", wine_dbgstr_longlong(req->BytesReceived));
+ ok(req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength == 4,
+ "Got header length %u.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].RawValueLength);
+ ok(!strcmp(req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue, "2048"),
+ "Got header value %s.\n", req->Headers.KnownHeaders[HttpHeaderContentLength].pRawValue);
+ ok(req->EntityChunkCount == 1, "Got %u entity chunks.\n", req->EntityChunkCount);
+ ok(req->pEntityChunks[0].DataChunkType == HttpDataChunkFromMemory,
+ "Got chunk type %u.\n", req->pEntityChunks[0].DataChunkType);
+ chunk_size = req->pEntityChunks[0].FromMemory.BufferLength;
+ ok(chunk_size > 0 && chunk_size < 2000, "Got chunk size %u.\n", chunk_size);
+ ok(!memcmp(req->pEntityChunks[0].FromMemory.pBuffer, req_body, chunk_size), "Chunk data didn't match.\n");
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_bad_request(void)
+{
+ char response_buffer[2048];
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, "foo\r\n", strlen("foo\r\n"), 0);
+ ok(ret == strlen("foo\r\n"), "send() returned %d.\n", ret);
+
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(ret > 0, "recv() failed.\n");
+
+ if (winetest_debug > 1)
+ trace("%.*s\n", ret, response_buffer);
+
+ ok(!strncmp(response_buffer, "HTTP/1.1 400 Bad Request\r\n", 26), "Got incorrect status line.\n");
+ ok(!!strstr(response_buffer, "\r\nConnection: close\r\n"), "Missing or malformed Connection header.\n");
+
+ ret = send(s, "foo\r\n", strlen("foo\r\n"), 0);
+ ok(ret == strlen("foo\r\n"), "send() returned %d.\n", ret);
+
+ WSASetLastError(0xdeadbeef);
+ ret = recv(s, response_buffer, sizeof(response_buffer), 0);
+ ok(!ret, "Connection should be shut down.\n");
+ ok(!WSAGetLastError(), "Got error %u.\n", WSAGetLastError());
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_cooked_url(void)
+{
+ static const WCHAR cooked_urlW[] = {'h','t','t','p',':','/','/',
+ 'l','o','c','a','l','h','o','s','t',':','5','0','0','0','0','/','f','o','o','b','a','r','?','a','=','b',0};
+
+ char req_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ static const char req1[] =
+ "GET /foobar?a=b HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "\r\n";
+
+ static const char req2[] =
+ "GET http://localhost:50000/ HTTP/1.1\r\n"
+ "Host: ignored\r\n"
+ "Connection: keep-alive\r\n"
+ "\r\n";
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, req1, strlen(req1), 0);
+ ok(ret == strlen(req1), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(req->RawUrlLength == 11, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!strcmp(req->pRawUrl, "/foobar?a=b"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 66, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 14, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(req->CookedUrl.QueryStringLength == 8, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, cooked_urlW),
+ "Got full URL '%ls'.\n", req->CookedUrl.pFullUrl);
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host '%ls'.\n", req->CookedUrl.pHost);
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path '%ls'.\n", req->CookedUrl.pAbsPath);
+ ok(req->CookedUrl.pQueryString == req->CookedUrl.pFullUrl + 29,
+ "Got query string '%ls'.\n", req->CookedUrl.pQueryString);
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = send(s, req2, strlen(req2), 0);
+ ok(ret == strlen(req2), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(ret_size > sizeof(*req), "Got size %u.\n", ret_size);
+ ok(req->RawUrlLength == 23, "Got raw URL length %u.\n", req->RawUrlLength);
+ ok(!strcmp(req->pRawUrl, "http://localhost:50000/"), "Got raw URL %s.\n", req->pRawUrl);
+ ok(req->CookedUrl.FullUrlLength == 46, "Got full URL length %u.\n", req->CookedUrl.FullUrlLength);
+ ok(req->CookedUrl.HostLength == 30, "Got host length %u.\n", req->CookedUrl.HostLength);
+ ok(req->CookedUrl.AbsPathLength == 2, "Got absolute path length %u.\n", req->CookedUrl.AbsPathLength);
+ ok(!req->CookedUrl.QueryStringLength, "Got query string length %u.\n", req->CookedUrl.QueryStringLength);
+ ok(!wcscmp(req->CookedUrl.pFullUrl, localhost_urlW),
+ "Got full URL '%ls'.\n", req->CookedUrl.pFullUrl);
+ ok(req->CookedUrl.pHost == req->CookedUrl.pFullUrl + 7, "Got host '%ls'.\n", req->CookedUrl.pHost);
+ ok(req->CookedUrl.pAbsPath == req->CookedUrl.pFullUrl + 22,
+ "Got absolute path '%ls'.\n", req->CookedUrl.pAbsPath);
+ ok(!req->CookedUrl.pQueryString, "Got query string '%ls'.\n", req->CookedUrl.pQueryString);
+
+ send_response_v1(queue, req->RequestId, s);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
+}
+
+static void test_v1_unknown_tokens(void)
+{
+ char req_buffer[2048];
+ HTTP_REQUEST_V1 *req = (HTTP_REQUEST_V1 *)req_buffer;
+ DWORD ret_size;
+ HANDLE queue;
+ ULONG ret;
+ SOCKET s;
+
+ static const char req1[] =
+ "xyzzy / HTTP/1.1\r\n"
+ "Host: localhost:50000\r\n"
+ "Connection: keep-alive\r\n"
+ "Qux: foo baz \r\n"
+ "\r\n";
+
+ ret = HttpCreateHttpHandle(&queue, 0);
+ todo_wine ok(!ret, "Got error %u.\n", ret);
+ if (ret) return;
+ ret = HttpAddUrl(queue, localhost_urlW, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+
+ s = create_client_socket();
+ ret = send(s, req1, strlen(req1), 0);
+ ok(ret == strlen(req1), "send() returned %d.\n", ret);
+
+ memset(req_buffer, 0xcc, sizeof(req_buffer));
+ ret = HttpReceiveHttpRequest(queue, HTTP_NULL_ID, 0, (HTTP_REQUEST *)req, sizeof(req_buffer), &ret_size, NULL);
+ ok(!ret, "Got error %u.\n", ret);
+ ok(req->Verb == HttpVerbUnknown, "Got verb %u.\n", req->Verb);
+ ok(req->UnknownVerbLength == 5, "Got unknown verb length %u.\n", req->UnknownVerbLength);
+ ok(!strcmp(req->pUnknownVerb, "xyzzy"), "Got unknown verb %s.\n", req->pUnknownVerb);
+ ok(req->Headers.UnknownHeaderCount == 1, "Got %u unknown headers.\n", req->Headers.UnknownHeaderCount);
+ ok(req->Headers.pUnknownHeaders[0].NameLength == 3, "Got name length %u.\n",
+ req->Headers.pUnknownHeaders[0].NameLength);
+ ok(!strcmp(req->Headers.pUnknownHeaders[0].pName, "Qux"), "Got name %s.\n",
+ req->Headers.pUnknownHeaders[0].pName);
+ ok(req->Headers.pUnknownHeaders[0].RawValueLength == 7, "Got value length %u.\n",
+ req->Headers.pUnknownHeaders[0].RawValueLength);
+ ok(!strcmp(req->Headers.pUnknownHeaders[0].pRawValue, "foo baz"), "Got value %s.\n",
+ req->Headers.pUnknownHeaders[0].pRawValue);
+
+ ret = HttpRemoveUrl(queue, localhost_urlW);
+ ok(!ret, "Got error %u.\n", ret);
+ closesocket(s);
+ ret = CloseHandle(queue);
+ ok(ret, "Failed to close queue handle, error %u.\n", GetLastError());
}
static void test_HttpCreateServerSession(void)
@@ -184,14 +994,24 @@ static void test_HttpCreateUrlGroup(void)
START_TEST(httpapi)
{
HTTPAPI_VERSION version = { 1, 0 };
+ WSADATA wsadata;
ULONG ret;
init();
+ WSAStartup(MAKEWORD(1,1), &wsadata);
+
ret = HttpInitialize(version, HTTP_INITIALIZE_SERVER, NULL);
ok(!ret, "Failed to initialize library, ret %u.\n", ret);
- test_HttpCreateHttpHandle();
+ test_v1_server();
+ test_v1_completion_port();
+ test_v1_multiple_requests();
+ test_v1_short_buffer();
+ test_v1_entity_body();
+ test_v1_bad_request();
+ test_v1_cooked_url();
+ test_v1_unknown_tokens();
test_HttpCreateServerSession();
test_HttpCreateUrlGroup();
--
2.22.0
2
1
[PATCH 1/4] widl: Track whether the type has been defined yet in the statement_t and var_t structures.
by Zebediah Figura 19 Aug '19
by Zebediah Figura 19 Aug '19
19 Aug '19
Based on a patch by Richard Pospesel.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47149
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
tools/widl/header.c | 37 +++++++++++++++++++------------------
tools/widl/parser.y | 10 +++++++---
tools/widl/widltypes.h | 3 +++
3 files changed, 29 insertions(+), 21 deletions(-)
diff --git a/tools/widl/header.c b/tools/widl/header.c
index c20fe69917..61fadcf72f 100644
--- a/tools/widl/header.c
+++ b/tools/widl/header.c
@@ -43,7 +43,7 @@ user_type_list_t user_type_list = LIST_INIT(user_type_list);
context_handle_list_t context_handle_list = LIST_INIT(context_handle_list);
generic_handle_list_t generic_handle_list = LIST_INIT(generic_handle_list);
-static void write_type_def_or_decl(FILE *f, const decl_spec_t *t, int field, const char *name);
+static void write_type_v(FILE *f, const decl_spec_t *t, int is_field, int declonly, const char *name);
static void indent(FILE *h, int delta)
{
@@ -252,7 +252,7 @@ static void write_fields(FILE *h, var_list_t *fields)
default:
;
}
- write_type_def_or_decl(h, &v->declspec, TRUE, name);
+ write_type_v(h, &v->declspec, TRUE, v->declonly, name);
fprintf(h, ";\n");
}
}
@@ -328,7 +328,8 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i
else {
switch (type_get_type_detect_alias(t)) {
case TYPE_ENUM:
- if (!declonly && t->defined && !t->written) {
+ if (!declonly && !t->written) {
+ assert(t->defined);
if (name) fprintf(h, "enum %s {\n", name);
else fprintf(h, "enum {\n");
t->written = TRUE;
@@ -341,7 +342,8 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i
break;
case TYPE_STRUCT:
case TYPE_ENCAPSULATED_UNION:
- if (!declonly && t->defined && !t->written) {
+ if (!declonly && !t->written) {
+ assert(t->defined);
if (name) fprintf(h, "struct %s {\n", name);
else fprintf(h, "struct {\n");
t->written = TRUE;
@@ -356,7 +358,8 @@ void write_type_left(FILE *h, const decl_spec_t *ds, enum name_type name_type, i
else fprintf(h, "struct %s", name ? name : "");
break;
case TYPE_UNION:
- if (!declonly && t->defined && !t->written) {
+ if (!declonly && !t->written) {
+ assert(t->defined);
if (t->name) fprintf(h, "union %s {\n", t->name);
else fprintf(h, "union {\n");
t->written = TRUE;
@@ -547,12 +550,7 @@ static void write_type_v(FILE *h, const decl_spec_t *ds, int is_field, int declo
write_type_right(h, t, is_field);
}
-static void write_type_def_or_decl(FILE *f, const decl_spec_t *t, int field, const char *name)
-{
- write_type_v(f, t, field, FALSE, name);
-}
-
-static void write_type_definition(FILE *f, type_t *t)
+static void write_type_definition(FILE *f, type_t *t, int declonly)
{
int in_namespace = t->namespace && !is_global_namespace(t->namespace);
int save_written = t->written;
@@ -564,14 +562,14 @@ static void write_type_definition(FILE *f, type_t *t)
write_namespace_start(f, t->namespace);
}
indent(f, 0);
- write_type_left(f, &ds, NAME_DEFAULT, FALSE, TRUE);
+ write_type_left(f, &ds, NAME_DEFAULT, declonly, TRUE);
fprintf(f, ";\n");
if(in_namespace) {
t->written = save_written;
write_namespace_end(f, t->namespace);
fprintf(f, "extern \"C\" {\n");
fprintf(f, "#else\n");
- write_type_left(f, &ds, NAME_C, FALSE, TRUE);
+ write_type_left(f, &ds, NAME_C, declonly, TRUE);
fprintf(f, ";\n");
fprintf(f, "#endif\n\n");
}
@@ -805,10 +803,10 @@ static void write_generic_handle_routines(FILE *header)
}
}
-static void write_typedef(FILE *header, type_t *type)
+static void write_typedef(FILE *header, type_t *type, int declonly)
{
fprintf(header, "typedef ");
- write_type_def_or_decl(header, type_alias_get_aliasee(type), FALSE, type->name);
+ write_type_v(header, type_alias_get_aliasee(type), FALSE, declonly, type->name);
fprintf(header, ";\n");
}
@@ -852,7 +850,7 @@ static void write_declaration(FILE *header, const var_t *v)
fprintf(header, "extern ");
break;
}
- write_type_def_or_decl(header, &v->declspec, FALSE, v->name);
+ write_type_v(header, &v->declspec, FALSE, v->declonly, v->name);
fprintf(header, ";\n\n");
}
}
@@ -1092,6 +1090,9 @@ void write_args(FILE *h, const var_list_t *args, const char *name, int method, i
}
else fprintf(h, ",");
}
+ /* In theory we should be writing the definition using write_type_v(..., arg->declonly),
+ * but that causes redefinition in e.g. proxy files. In fact MIDL disallows
+ * defining UDTs inside of an argument list. */
write_type_decl(h, &arg->declspec, arg->name);
if (method == 2) {
const expr_t *expr = get_attrp(arg->attrs, ATTR_DEFAULTVALUE);
@@ -1733,7 +1734,7 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons
write_coclass(header, stmt->u.type);
else
{
- write_type_definition(header, stmt->u.type);
+ write_type_definition(header, stmt->u.type, stmt->declonly);
}
break;
case STMT_TYPEREF:
@@ -1754,7 +1755,7 @@ static void write_header_stmts(FILE *header, const statement_list_t *stmts, cons
{
const type_list_t *type_entry = stmt->u.type_list;
for (; type_entry; type_entry = type_entry->next)
- write_typedef(header, type_entry->type);
+ write_typedef(header, type_entry->type, stmt->declonly);
break;
}
case STMT_LIBRARY:
diff --git a/tools/widl/parser.y b/tools/widl/parser.y
index afbe2b1799..bdbd44040c 100644
--- a/tools/widl/parser.y
+++ b/tools/widl/parser.y
@@ -116,7 +116,7 @@ static statement_t *make_statement_pragma(const char *str);
static statement_t *make_statement_cppquote(const char *str);
static statement_t *make_statement_importlib(const char *str);
static statement_t *make_statement_module(type_t *type);
-static statement_t *make_statement_typedef(var_list_t *names);
+static statement_t *make_statement_typedef(var_list_t *names, int declonly);
static statement_t *make_statement_import(const char *str);
static statement_list_t *append_statement(statement_list_t *list, statement_t *stmt);
static statement_list_t *append_statements(statement_list_t *, statement_list_t *);
@@ -1115,7 +1115,7 @@ type: tVOID { $$ = type_new_void(); }
typedef: m_attributes tTYPEDEF m_attributes decl_spec declarator_list
{ $1 = append_attribs($1, $3);
reg_typedefs($4, $5, check_typedef_attrs($1));
- $$ = make_statement_typedef($5);
+ $$ = make_statement_typedef($5, !$4->type->defined);
}
;
@@ -1546,6 +1546,7 @@ static var_t *declare_var(attr_list_t *attrs, decl_spec_t *decl_spec, declarator
v->declspec.type = decl->type;
v->declspec.qualifier = decl->qualifier;
v->attrs = attrs;
+ v->declonly = !type->defined;
if (is_attr(type->attrs, ATTR_CALLCONV) && !is_func(type))
error_loc("calling convention applied to non-function type\n");
@@ -1750,6 +1751,7 @@ var_t *make_var(char *name)
v->attrs = NULL;
v->eval = NULL;
init_loc_info(&v->loc_info);
+ v->declonly = FALSE;
return v;
}
@@ -2912,6 +2914,7 @@ static statement_t *make_statement_type_decl(type_t *type)
{
statement_t *stmt = make_statement(STMT_TYPE);
stmt->u.type = type;
+ stmt->declonly = !type->defined;
return stmt;
}
@@ -2982,7 +2985,7 @@ static statement_t *make_statement_module(type_t *type)
return stmt;
}
-static statement_t *make_statement_typedef(declarator_list_t *decls)
+static statement_t *make_statement_typedef(declarator_list_t *decls, int declonly)
{
declarator_t *decl, *next;
statement_t *stmt;
@@ -2993,6 +2996,7 @@ static statement_t *make_statement_typedef(declarator_list_t *decls)
stmt = make_statement(STMT_TYPEDEF);
stmt->u.type_list = NULL;
type_list = &stmt->u.type_list;
+ stmt->declonly = declonly;
LIST_FOR_EACH_ENTRY_SAFE( decl, next, decls, declarator_t, entry )
{
diff --git a/tools/widl/widltypes.h b/tools/widl/widltypes.h
index 3886360bd4..7a7bd8991e 100644
--- a/tools/widl/widltypes.h
+++ b/tools/widl/widltypes.h
@@ -478,6 +478,8 @@ struct _var_t {
struct _loc_info_t loc_info;
+ unsigned int declonly : 1;
+
/* parser-internal */
struct list entry;
};
@@ -560,6 +562,7 @@ struct _statement_t {
typelib_t *lib;
type_list_t *type_list;
} u;
+ unsigned int declonly : 1; /* for STMT_TYPE and STMT_TYPEDEF */
};
struct _warning_t {
--
2.22.0
1
3
19 Aug '19
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=47623
Signed-off-by: Zebediah Figura <z.figura12(a)gmail.com>
---
dlls/ntoskrnl.exe/ntoskrnl.c | 11 -----------
dlls/ntoskrnl.exe/sync.c | 14 ++++++++++++++
2 files changed, 14 insertions(+), 11 deletions(-)
diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c
index 210f42b6b9..09fb6605bc 100644
--- a/dlls/ntoskrnl.exe/ntoskrnl.c
+++ b/dlls/ntoskrnl.exe/ntoskrnl.c
@@ -3178,17 +3178,6 @@ BOOLEAN WINAPI IoSetThreadHardErrorMode(BOOLEAN EnableHardErrors)
return FALSE;
}
-
-/*****************************************************
- * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
- */
-VOID WINAPI IoInitializeRemoveLockEx(PIO_REMOVE_LOCK lock, ULONG tag,
- ULONG maxmin, ULONG high, ULONG size)
-{
- FIXME("(%p %u %u %u %u) stub\n", lock, tag, maxmin, high, size);
-}
-
-
/*****************************************************
* IoAcquireRemoveLockEx (NTOSKRNL.EXE.@)
*/
diff --git a/dlls/ntoskrnl.exe/sync.c b/dlls/ntoskrnl.exe/sync.c
index ea4165cda6..0b2ca6f6b7 100644
--- a/dlls/ntoskrnl.exe/sync.c
+++ b/dlls/ntoskrnl.exe/sync.c
@@ -1195,3 +1195,17 @@ ULONG WINAPI ExIsResourceAcquiredSharedLite( ERESOURCE *resource )
return ret;
}
+
+/***********************************************************************
+ * IoInitializeRemoveLockEx (NTOSKRNL.EXE.@)
+ */
+void WINAPI IoInitializeRemoveLockEx( IO_REMOVE_LOCK *lock, ULONG tag,
+ ULONG max_minutes, ULONG max_count, ULONG size )
+{
+ TRACE("lock %p, tag %#x, max_minutes %u, max_count %u, size %u.\n",
+ lock, tag, max_minutes, max_count, size);
+
+ KeInitializeEvent( &lock->Common.RemoveEvent, SynchronizationEvent, FALSE );
+ lock->Common.Removed = FALSE;
+ lock->Common.IoCount = 0;
+}
--
2.22.0
2
9
1
0