Commit aa7a4a50 by Edward Thomson

Merge pull request #2986 from tkelman/mingw_winhttp

WinHTTP for MinGW
parents 95d1624b b631e0d9
......@@ -27,7 +27,7 @@ matrix:
compiler: gcc
include:
- compiler: i586-mingw32msvc-gcc
env: OPTIONS="-DBUILD_CLAR=OFF -DWIN32=ON -DMINGW=ON -DUSE_SSH=OFF"
env: OPTIONS="-DCMAKE_TOOLCHAIN_FILE=../script/toolchain-mingw32.cmake" SKIP_TESTS=1
os: linux
- compiler: gcc
env: COVERITY=1
......
......@@ -13,6 +13,7 @@
PROJECT(libgit2 C)
CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
CMAKE_POLICY(SET CMP0015 NEW)
# Add find modules to the path
SET(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules/")
......@@ -58,10 +59,6 @@ IF(MSVC)
# are linking statically
OPTION( STATIC_CRT "Link the static CRT libraries" ON )
# By default, libgit2 is built with WinHTTP. To use the built-in
# HTTP transport, invoke CMake with the "-DWINHTTP=OFF" argument.
OPTION( WINHTTP "Use Win32 WinHTTP routines" ON )
# If you want to embed a copy of libssh2 into libgit2, pass a
# path to libssh2
OPTION( EMBED_SSH_PATH "Path to libssh2 to embed (Windows)" OFF )
......@@ -71,6 +68,12 @@ IF(MSVC)
ADD_DEFINITIONS(-D_CRT_NONSTDC_NO_DEPRECATE)
ENDIF()
IF(WIN32)
# By default, libgit2 is built with WinHTTP. To use the built-in
# HTTP transport, invoke CMake with the "-DWINHTTP=OFF" argument.
OPTION( WINHTTP "Use Win32 WinHTTP routines" ON )
ENDIF()
# This variable will contain the libraries we need to put into
# libgit2.pc's Requires.private. That is, what we're linking to or
# what someone who's statically linking us needs to link to.
......@@ -147,10 +150,45 @@ IF (WIN32 AND EMBED_SSH_PATH)
ADD_DEFINITIONS(-DGIT_SSH)
ENDIF()
IF (WIN32 AND WINHTTP AND NOT MINGW)
IF (WIN32 AND WINHTTP)
ADD_DEFINITIONS(-DGIT_WINHTTP)
INCLUDE_DIRECTORIES(deps/http-parser)
FILE(GLOB SRC_HTTP deps/http-parser/*.c deps/http-parser/*.h)
# Since MinGW does not come with headers or an import library for winhttp,
# we have to include a private header and generate our own import library
IF (MINGW)
FIND_PROGRAM(DLLTOOL dlltool CMAKE_FIND_ROOT_PATH_BOTH)
IF (NOT DLLTOOL)
MESSAGE(FATAL_ERROR "Could not find dlltool command")
ENDIF ()
SET(LIBWINHTTP_PATH "${CMAKE_CURRENT_BINARY_DIR}/deps/winhttp")
FILE(MAKE_DIRECTORY ${LIBWINHTTP_PATH})
IF ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8")
set(WINHTTP_DEF "${CMAKE_CURRENT_SOURCE_DIR}/deps/winhttp/winhttp64.def")
ELSE()
set(WINHTTP_DEF "${CMAKE_CURRENT_SOURCE_DIR}/deps/winhttp/winhttp.def")
ENDIF()
ADD_CUSTOM_COMMAND(
OUTPUT ${LIBWINHTTP_PATH}/libwinhttp.a
COMMAND ${DLLTOOL} -d ${WINHTTP_DEF} -k -D winhttp.dll -l libwinhttp.a
DEPENDS ${WINHTTP_DEF}
WORKING_DIRECTORY ${LIBWINHTTP_PATH}
)
SET_SOURCE_FILES_PROPERTIES(
${CMAKE_CURRENT_SOURCE_DIR}/src/transports/winhttp.c
PROPERTIES OBJECT_DEPENDS ${LIBWINHTTP_PATH}/libwinhttp.a
)
INCLUDE_DIRECTORIES(deps/winhttp)
LINK_DIRECTORIES(${LIBWINHTTP_PATH})
ENDIF ()
LINK_LIBRARIES(winhttp rpcrt4 crypt32)
ELSE ()
IF (NOT AMIGA AND USE_OPENSSL)
FIND_PACKAGE(OpenSSL)
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#if defined(__MINGW_VERSION) || defined(__MINGW32_VERSION)
#ifndef __CUSTOM_URLMON_H
#define __CUSTOM_URLMON_H
typedef struct IInternetSecurityManager IInternetSecurityManager;
typedef struct IInternetSecurityManagerVtbl
{
HRESULT(STDMETHODCALLTYPE *QueryInterface)(IInternetSecurityManager *, REFIID, void **);
ULONG(STDMETHODCALLTYPE *AddRef)(IInternetSecurityManager *);
ULONG(STDMETHODCALLTYPE *Release)(IInternetSecurityManager *);
LPVOID SetSecuritySite;
LPVOID GetSecuritySite;
HRESULT(STDMETHODCALLTYPE *MapUrlToZone)(IInternetSecurityManager *, LPCWSTR, DWORD *, DWORD);
LPVOID GetSecurityId;
LPVOID ProcessUrlAction;
LPVOID QueryCustomPolicy;
LPVOID SetZoneMapping;
LPVOID GetZoneMappings;
} IInternetSecurityManagerVtbl;
struct IInternetSecurityManager
{
CONST_VTBL struct IInternetSecurityManagerVtbl *lpVtbl;
};
#define URLZONE_LOCAL_MACHINE 0
#define URLZONE_INTRANET 1
#define URLZONE_TRUSTED 2
#endif /* __CUSTOM_URLMON_H */
#else
#include_next <urlmon.h>
#endif
LIBRARY WINHTTP
EXPORTS
WinHttpAddRequestHeaders@16
WinHttpCheckPlatform@0
WinHttpCloseHandle@4
WinHttpConnect@16
WinHttpCrackUrl@16
WinHttpCreateUrl@16
WinHttpDetectAutoProxyConfigUrl@8
WinHttpGetDefaultProxyConfiguration@4
WinHttpGetIEProxyConfigForCurrentUser@4
WinHttpGetProxyForUrl@16
WinHttpOpen@20
WinHttpOpenRequest@28
WinHttpQueryAuthSchemes@16
WinHttpQueryDataAvailable@8
WinHttpQueryHeaders@24
WinHttpQueryOption@16
WinHttpReadData@16
WinHttpReceiveResponse@8
WinHttpSendRequest@28
WinHttpSetCredentials@24
WinHttpSetDefaultProxyConfiguration@4
WinHttpSetOption@16
WinHttpSetStatusCallback@16
WinHttpSetTimeouts@20
WinHttpTimeFromSystemTime@8
WinHttpTimeToSystemTime@8
WinHttpWriteData@16
LIBRARY WINHTTP
EXPORTS
WinHttpAddRequestHeaders
WinHttpCheckPlatform
WinHttpCloseHandle
WinHttpConnect
WinHttpCrackUrl
WinHttpCreateUrl
WinHttpDetectAutoProxyConfigUrl
WinHttpGetDefaultProxyConfiguration
WinHttpGetIEProxyConfigForCurrentUser
WinHttpGetProxyForUrl
WinHttpOpen
WinHttpOpenRequest
WinHttpQueryAuthSchemes
WinHttpQueryDataAvailable
WinHttpQueryHeaders
WinHttpQueryOption
WinHttpReadData
WinHttpReceiveResponse
WinHttpSendRequest
WinHttpSetCredentials
WinHttpSetDefaultProxyConfiguration
WinHttpSetOption
WinHttpSetStatusCallback
WinHttpSetTimeouts
WinHttpTimeFromSystemTime
WinHttpTimeToSystemTime
WinHttpWriteData
......@@ -6,17 +6,25 @@ then
exit $?;
fi
mkdir _build
cd _build
# shellcheck disable=SC2086
cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS || exit $?
make -j2 install || exit $?
# If this platform doesn't support test execution, bail out now
if [ -n "$SKIP_TESTS" ];
then
exit $?;
fi
# Create a test repo which we can use for the online::push tests
mkdir "$HOME"/_temp
git init --bare "$HOME"/_temp/test.git
git daemon --listen=localhost --export-all --enable=receive-pack --base-path="$HOME"/_temp "$HOME"/_temp 2>/dev/null &
export GITTEST_REMOTE_URL="git://localhost/test.git"
mkdir _build
cd _build
# shellcheck disable=SC2086
cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS || exit $?
make -j2 install || exit $?
# Run the test suite
ctest -V . || exit $?
# Now that we've tested the raw git protocol, let's set up ssh to we
......
# CMake toolchain file for Win32 cross-compile
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER i586-mingw32msvc-gcc)
SET(CMAKE_RC_COMPILER i586-mingw32msvc-windres)
SET(CMAKE_FIND_ROOT_PATH /usr/i586-mingw32msvc)
SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
SET(ENV{PKG_CONFIG_LIBDIR} ${CMAKE_FIND_ROOT_PATH}/lib/pkgconfig)
......@@ -17,19 +17,12 @@
#include "repository.h"
#include <wincrypt.h>
#pragma comment(lib, "crypt32")
#include <winhttp.h>
#pragma comment(lib, "winhttp")
#include <strsafe.h>
/* For IInternetSecurityManager zone check */
#include <objbase.h>
#include <urlmon.h>
/* For UuidCreate */
#pragma comment(lib, "rpcrt4")
#define WIDEN2(s) L ## s
#define WIDEN(s) WIDEN2(s)
......@@ -43,7 +36,6 @@
#define WINHTTP_IGNORE_REQUEST_TOTAL_LENGTH 0
#endif
static const char *prefix_http = "http://";
static const char *prefix_https = "https://";
static const char *upload_pack_service = "upload-pack";
static const char *upload_pack_ls_service_url = "/info/refs?service=git-upload-pack";
......@@ -59,6 +51,13 @@ static const int no_check_cert_flags = SECURITY_FLAG_IGNORE_CERT_CN_INVALID |
SECURITY_FLAG_IGNORE_CERT_DATE_INVALID |
SECURITY_FLAG_IGNORE_UNKNOWN_CA;
#if defined(__MINGW32__)
const CLSID CLSID_InternetSecurityManager = { 0x7B8A2D94, 0x0AC9, 0x11D1,
{ 0x89, 0x6C, 0x00, 0xC0, 0x4F, 0xB6, 0xBF, 0xC4 } };
const IID IID_IInternetSecurityManager = { 0x79EAC9EE, 0xBAF9, 0x11CE,
{ 0x8C, 0x82, 0x00, 0xAA, 0x00, 0x4B, 0xA9, 0x0B } };
#endif
#define OWNING_SUBTRANSPORT(s) ((winhttp_subtransport *)(s)->parent.subtransport)
typedef enum {
......@@ -272,7 +271,7 @@ static int winhttp_stream_connect(winhttp_stream *s)
git_buf buf = GIT_BUF_INIT;
char *proxy_url = NULL;
wchar_t ct[MAX_CONTENT_TYPE_LEN];
wchar_t *types[] = { L"*/*", NULL };
LPCWSTR types[] = { L"*/*", NULL };
BOOL peerdist = FALSE;
int error = -1;
unsigned long disable_redirects = WINHTTP_DISABLE_REDIRECTS;
......@@ -551,8 +550,7 @@ static int winhttp_close_connection(winhttp_subtransport *t)
}
static int winhttp_connect(
winhttp_subtransport *t,
const char *url)
winhttp_subtransport *t)
{
wchar_t *ua = L"git/1.0 (libgit2 " WIDEN(LIBGIT2_VERSION) L")";
wchar_t *wide_host;
......@@ -561,8 +559,6 @@ static int winhttp_connect(
int default_timeout = TIMEOUT_INFINITE;
int default_connect_timeout = DEFAULT_CONNECT_TIMEOUT;
GIT_UNUSED(url);
t->session = NULL;
t->connection = NULL;
......@@ -860,7 +856,7 @@ replay:
winhttp_close_connection(t);
if (winhttp_connect(t, location8) < 0)
if (winhttp_connect(t) < 0)
return -1;
}
......@@ -963,7 +959,6 @@ static int winhttp_stream_write_single(
size_t len)
{
winhttp_stream *s = (winhttp_stream *)stream;
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
DWORD bytes_written;
int error;
......@@ -998,7 +993,7 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch)
{
UUID uuid;
RPC_STATUS status = UuidCreate(&uuid);
HRESULT result;
int result;
if (RPC_S_OK != status &&
RPC_S_UUID_LOCAL_ONLY != status &&
......@@ -1012,14 +1007,17 @@ static int put_uuid_string(LPWSTR buffer, size_t buffer_len_cch)
return -1;
}
result = StringCbPrintfW(
buffer, buffer_len_cch,
#if !defined(__MINGW32__) || defined(MINGW_HAS_SECURE_API)
result = swprintf_s(buffer, buffer_len_cch,
#else
result = wsprintfW(buffer,
#endif
L"%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",
uuid.Data1, uuid.Data2, uuid.Data3,
uuid.Data4[0], uuid.Data4[1], uuid.Data4[2], uuid.Data4[3],
uuid.Data4[4], uuid.Data4[5], uuid.Data4[6], uuid.Data4[7]);
if (FAILED(result)) {
if (result < UUID_LENGTH_CCH) {
giterr_set(GITERR_OS, "Unable to generate name for temp file");
return -1;
}
......@@ -1053,7 +1051,6 @@ static int winhttp_stream_write_buffered(
size_t len)
{
winhttp_stream *s = (winhttp_stream *)stream;
winhttp_subtransport *t = OWNING_SUBTRANSPORT(s);
DWORD bytes_written;
if (!s->request && winhttp_stream_connect(s) < 0)
......@@ -1135,7 +1132,7 @@ static int winhttp_stream_write_chunked(
}
else {
/* Append as much to the buffer as we can */
int count = min(CACHED_POST_BODY_BUF_SIZE - s->chunk_buffer_len, (int)len);
int count = (int)min(CACHED_POST_BODY_BUF_SIZE - s->chunk_buffer_len, len);
if (!s->chunk_buffer)
s->chunk_buffer = git__malloc(CACHED_POST_BODY_BUF_SIZE);
......@@ -1195,6 +1192,8 @@ static int winhttp_uploadpack_ls(
winhttp_subtransport *t,
winhttp_stream *s)
{
GIT_UNUSED(t);
s->service = upload_pack_service;
s->service_url = upload_pack_ls_service_url;
s->verb = get_verb;
......@@ -1206,6 +1205,8 @@ static int winhttp_uploadpack(
winhttp_subtransport *t,
winhttp_stream *s)
{
GIT_UNUSED(t);
s->service = upload_pack_service;
s->service_url = upload_pack_service_url;
s->verb = post_verb;
......@@ -1217,6 +1218,8 @@ static int winhttp_receivepack_ls(
winhttp_subtransport *t,
winhttp_stream *s)
{
GIT_UNUSED(t);
s->service = receive_pack_service;
s->service_url = receive_pack_ls_service_url;
s->verb = get_verb;
......@@ -1228,6 +1231,8 @@ static int winhttp_receivepack(
winhttp_subtransport *t,
winhttp_stream *s)
{
GIT_UNUSED(t);
/* WinHTTP only supports Transfer-Encoding: chunked
* on Windows Vista (NT 6.0) and higher. */
s->chunked = git_has_win32_version(6, 0, 0);
......@@ -1256,7 +1261,7 @@ static int winhttp_action(
if (!t->connection)
if ((ret = gitno_connection_data_from_url(&t->connection_data, url, NULL)) < 0 ||
(ret = winhttp_connect(t, url)) < 0)
(ret = winhttp_connect(t)) < 0)
return ret;
if (winhttp_stream_alloc(t, &s) < 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment